中断下半部处理
中断下半部将网卡中的DMA-ring中的skb取出来,经过ip层处理,主要是netfilter
最后决定是否传递到本地传输层
中断下半部将网卡中的DMA-ring中的skb取出来,经过ip层处理,主要是netfilter
最后决定是否传递到本地传输层
如果交给本地传输层ip的最后处理ip_local_deliver_finish
中断的下半部的结束位置是哪里? 何时出中断上下文?
中断下半部的结束是把这个从DMA-ring中的skb找到归宿(传输层的队列或者转发出去)
源码版本 2.6.32
ip_local_deliver_finish(skb)
{
int protocol = ip_hdr(skb)->protocol;
int hash, raw;
const struct net_protocol *ipprot;
resubmit:
raw = raw_local_deliver(skb, protocol);
hash = protocol & (MAX_INET_PROTOS - 1);
ipprot = rcu_dereference(inet_protos[hash]);
......
ret = ipprot->handler(skb);
}
static const struct net_protocol tcp_protocol = {
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
.gso_send_check = tcp_v4_gso_send_check,
.gso_segment = tcp_tso_segment,
.gro_receive = tcp4_gro_receive,
.gro_complete = tcp4_gro_complete,
.no_policy = 1,
.netns_ok = 1,
};
从ip层头部中确定protocol,若为tcp,进入tcp_v4_rcv
tcp_v4_rcv()
{
struct sock *sk;
//确定数据包是属于哪个sock对象
sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
//将数据包放到tcp的队列中,中断的下半部就处理结束
//此处可能会有竞争要处理,就是内核态中的中断上下文和用户进程的系统调用对sock对象的访问
if (!sock_owned_by_user(sk))
{
#ifdef CONFIG_NET_DMA
struct tcp_sock *tp = tcp_sk(sk);
if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list)
tp->ucopy.dma_chan = dma_find_channel(DMA_MEMCPY);
if (tp->ucopy.dma_chan)
ret = tcp_v4_do_rcv(sk, skb);
else
#endif
{
if (!tcp_prequeue(sk, skb))
ret = tcp_v4_do_rcv(sk, skb);
}
} else
sk_add_backlog(sk, skb);
bh_unlock_sock(sk);
sock_put(sk);
}
skb这个时候才算是找到了归宿sk_receive_queue,中断的下半部结束
tcp_rcv_established()
{
__skb_queue_tail(&sk->sk_receive_queue, skb);
skb_set_owner_r(skb, sk);
tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
if (!copied_early || tp->rcv_nxt != tp->rcv_wup)
__tcp_ack_snd_check(sk, 0);
}