Linux内核收包过程

net/core/dev.c

1int __init net_dev_init(void) 2{ 3 queue->backlog.poll = process_backlog; 4 open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL); 5 open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL); 6}

/net/core/dev.c

1int process_backlog(struct napi_struct *napi, int quota) 2{ 3 int work = 0; 4 struct softnet_data *queue = &__get_cpu_var(softnet_data); // 取出cpu变量(就一个指针) 5 unsigned long start_time = jiffies; 6 7 napi->weight = weight_p; 8 do { 9 struct sk_buff *skb; // 关键 10 struct net_device *dev; 11 12 local_irq_disable(); // 关中断 13 skb = __skb_dequeue(&queue->input_pkt_queue); // 从队列中取出来(暂不管怎么挂到队列的) 14 if (!skb) { 15 __napi_complete(napi); 16 local_irq_enable(); 17 break; 18 } 19 20 local_irq_enable(); // 开中断 21 dev = skb->dev; 22 netif_receive_skb(skb); // 交给IP层 23 dev_put(dev); // 允许释放dev结构体 24 } while (++work < quota && jiffies == start_time); 25 26 return work; 27}

include/linux/skbuff.h

1struct sk_buff *__skb_dequeue(struct sk_buff_head *list) 2{ 3 struct sk_buff *next, *prev, *result; 4 5 prev = (struct sk_buff *) list; 6 next = prev->next; 7 result = NULL; 8 if (next != prev) { 9 result = next; 10 next = next->next; 11 list->qlen--; 12 next->prev = prev; 13 prev->next = next; 14 result->next = result->prev = NULL; 15 } 16 return result; 17}

net/core/dev.c

1/* 2 * netif_receive_skb - process receive buffer from network 3 * @skb: buffer to process 4 * 5 * netif_receive_skb() is the main receive data processing function. 6 * It always succeeds. The buffer may be dropped during processing 7 * for congestion control or by the protocol layers. 8 * 9 * This function may only be called from softirq context and interrupts 10 * should be enabled. (看这行) 11 * 12 * Return values (usually ignored): 13 * NET_RX_SUCCESS: no congestion 14 * NET_RX_DROP: packet was dropped 15 */ 16int netif_receive_skb(struct sk_buff *skb) 17{ 18 struct packet_type *ptype, *pt_prev; 19 struct net_device *orig_dev; 20 int ret = NET_RX_DROP; 21 __be16 type; 22 23 /* if we've gotten here through NAPI, check netpoll */ 24 if (netpoll_receive_skb(skb)) 25 return NET_RX_DROP; 26 27 if (!skb->tstamp.tv64) 28 net_timestamp(skb); 29 30 if (!skb->iif) 31 skb->iif = skb->dev->ifindex; 32 33 orig_dev = skb_bond(skb); 34 35 if (!orig_dev) 36 return NET_RX_DROP; 37 38 __get_cpu_var(netdev_rx_stat).total++; 39 40 skb_reset_network_header(skb); // 调整相关header指针 41 skb_reset_transport_header(skb); 42 skb->mac_len = skb->network_header - skb->mac_header; 43 44 pt_prev = NULL; 45 46 rcu_read_lock(); 47 48#ifdef CONFIG_NET_CLS_ACT 49 if (skb->tc_verd & TC_NCLS) { 50 skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); 51 goto ncls; 52 } 53#endif 54 55 // 这里 ptype_all 是针对任何协议的,视为空即可 56 list_for_each_entry_rcu(ptype, &ptype_all, list) { 57 if (!ptype->dev || ptype->dev == skb->dev) { 58 if (pt_prev) 59 ret = deliver_skb(skb, pt_prev, orig_dev); // 交给上层 60 pt_prev = ptype; 61 } 62 } 63 64#ifdef CONFIG_NET_CLS_ACT 65 skb = handle_ing(skb, &pt_prev, &ret, orig_dev); 66 if (!skb) 67 goto out; 68ncls: 69#endif 70 71 skb = handle_bridge(skb, &pt_prev, &ret, orig_dev); 72 if (!skb) 73 goto out; 74 skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev); 75 if (!skb) 76 goto out; 77 78 type = skb->protocol; 79 list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) { 80 // ptype_base是协议栈,见inet_init(void)中的dev_add_pack(&ip_packet_type) 81 if (ptype->type == type && (!ptype->dev || ptype->dev == skb->dev)) { 82 if (pt_prev) 83 ret = deliver_skb(skb, pt_prev, orig_dev); // 交给上层 84 pt_prev = ptype; 85 } 86 } 87 88 if (pt_prev) { 89 ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev); // 这个也关键 90 } else { 91 kfree_skb(skb); 92 ret = NET_RX_DROP; 93 } 94 95out: 96 rcu_read_unlock(); 97 return ret; 98}

net/core/dev.c

1static struct packet_type ip_packet_type = { 2 .type = __constant_htons(ETH_P_IP), 3 .func = ip_rcv, 4 .gso_send_check = inet_gso_send_check, 5 .gso_segment = inet_gso_segment, 6}; 7static int __init inet_init(void) 8{ 9 ... 10 dev_add_pack(&ip_packet_type); 11 ... 12}

net/core/dev.c

1/** 2 * dev_add_pack - add packet handler 3 * @pt: packet type declaration 4 * 5 * Add a protocol handler to the networking stack. The passed &packet_type 6 * is linked into kernel lists and may not be freed until it has been 7 * removed from the kernel lists. 8 * 9 * This call does not sleep therefore it can not 10 * guarantee all CPU's that are in middle of receiving packets 11 * will see the new packet type (until the next received packet). 12 */ 13void dev_add_pack(struct packet_type *pt) 14{ 15 int hash; 16 17 spin_lock_bh(&ptype_lock); 18 if (pt->type == htons(ETH_P_ALL)) 19 list_add_rcu(&pt->list, &ptype_all); 20 else { 21 hash = ntohs(pt->type) & 15; 22 list_add_rcu(&pt->list, &ptype_base[hash]); // 这里的ptype_base 23 } 24 spin_unlock_bh(&ptype_lock); 25}

net/ipv4/ip_input.c

1/* 2 * Main IP Receive routine. 3 * IP层入口函数 4 */ 5int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) 6{ 7 struct iphdr *iph; 8 u32 len; 9 10 if (dev->nd_net != &init_net) 11 goto drop; 12 13 if (skb->pkt_type == PACKET_OTHERHOST) 14 goto drop; 15 16 IP_INC_STATS_BH(IPSTATS_MIB_INRECEIVES); 17 18 if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { 19 IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS); 20 goto out; 21 } 22 23 // 若包不完整,考虑重组 24 if (!pskb_may_pull(skb, sizeof(struct iphdr))) 25 goto inhdr_error; 26 27 iph = ip_hdr(skb); 28 if (iph->ihl < 5 || iph->version != 4) 29 goto inhdr_error; 30 31 if (!pskb_may_pull(skb, iph->ihl*4)) 32 goto inhdr_error; 33 34 iph = ip_hdr(skb); 35 36 if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) 37 goto inhdr_error; 38 39 len = ntohs(iph->tot_len); 40 if (skb->len < len) { 41 IP_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS); 42 goto drop; 43 } else if (len < (iph->ihl*4)) 44 goto inhdr_error; 45 46 if (pskb_trim_rcsum(skb, len)) { 47 IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS); 48 goto drop; 49 } 50 51 /* Remove any debris in the socket control block */ 52 memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); 53 54 // 钩子: NF_IP_PRE_ROUTING,关键看ip_rcv_finish。 55 return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL, 56 ip_rcv_finish); 57 58inhdr_error: 59 IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); 60drop: 61 kfree_skb(skb); 62out: 63 return NET_RX_DROP; 64}

net/ipv4/ip_input.c

1static int ip_rcv_finish(struct sk_buff *skb) 2{ 3 const struct iphdr *iph = ip_hdr(skb); 4 struct rtable *rt; 5 6 if (skb->dst == NULL) { 7 // 初始化skb->dst,即路由过程 8 int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, 9 skb->dev); 10 if (unlikely(err)) { 11 if (err == -EHOSTUNREACH) 12 IP_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); 13 else if (err == -ENETUNREACH) 14 IP_INC_STATS_BH(IPSTATS_MIB_INNOROUTES); 15 goto drop; 16 } 17 } 18 19#ifdef CONFIG_NET_CLS_ROUTE 20 if (unlikely(skb->dst->tclassid)) { 21 struct ip_rt_acct *st = ip_rt_acct + 256*smp_processor_id(); 22 u32 idx = skb->dst->tclassid; 23 st[idx&0xFF].o_packets++; 24 st[idx&0xFF].o_bytes+=skb->len; 25 st[(idx>>16)&0xFF].i_packets++; 26 st[(idx>>16)&0xFF].i_bytes+=skb->len; 27 } 28#endif 29 30 if (iph->ihl > 5 && ip_rcv_options(skb)) 31 goto drop; 32 33 rt = (struct rtable*)skb->dst; 34 if (rt->rt_type == RTN_MULTICAST) 35 IP_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS); 36 else if (rt->rt_type == RTN_BROADCAST) 37 IP_INC_STATS_BH(IPSTATS_MIB_INBCASTPKTS); 38 39 return dst_input(skb); // 交给上层 40 41drop: 42 kfree_skb(skb); 43 return NET_RX_DROP; 44}

net/ipv4/ip_input.c

1// 交给上层,没什么好看的 2int dst_input(struct sk_buff *skb) 3{ 4 int err; 5 6 for (;;) { 7 err = skb->dst->input(skb); // 执行 8 9 if (likely(err == 0)) 10 return err; 11 /* Oh, Jamal... Seems, I will not forgive you this mess. :-) */ 12 if (unlikely(err != NET_XMIT_BYPASS)) 13 return err; 14 } 15}

对于ipv4来说,路由结果其实只有两种:ip_local_deliver和ip_forward,分别表示提交到本地、转发。咱只关注提交到本地的。

net/ipv4/ip_input.c

1/* 2 * Deliver IP Packets to the higher protocol layers. 3 */ 4int ip_local_deliver(struct sk_buff *skb) 5{ 6 /* 7 * Reassemble IP fragments. 8 */ 9 10 if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { 11 if (ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER)) 12 return 0; 13 } 14 // 又一钩子 15 return NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL, 16 ip_local_deliver_finish); // 看回调 17}

net/ipv4/ip_input.c

1static int ip_local_deliver_finish(struct sk_buff *skb) 2{ 3 __skb_pull(skb, ip_hdrlen(skb)); 4 5 /* Point into the IP datagram, just past the header. */ 6 skb_reset_transport_header(skb); 7 8 rcu_read_lock(); 9 { 10 /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */ 11 int protocol = ip_hdr(skb)->protocol; 12 int hash; 13 struct sock *raw_sk; 14 struct net_protocol *ipprot; 15 16 resubmit: 17 hash = protocol & (MAX_INET_PROTOS - 1); 18 raw_sk = sk_head(&raw_v4_htable[hash]); 19 20 /* If there maybe a raw socket we must check - if not we 21 * don't care less 22 */ 23 if (raw_sk && !raw_v4_input(skb, ip_hdr(skb), hash)) // 关键 24 raw_sk = NULL; 25 26 if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) { 27 int ret; 28 29 if (!ipprot->no_policy) { 30 if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { 31 kfree_skb(skb); 32 goto out; 33 } 34 nf_reset(skb); 35 } 36 ret = ipprot->handler(skb); 37 if (ret < 0) { 38 protocol = -ret; 39 goto resubmit; 40 } 41 IP_INC_STATS_BH(IPSTATS_MIB_INDELIVERS); 42 } else { 43 if (!raw_sk) { 44 if (xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { 45 IP_INC_STATS_BH(IPSTATS_MIB_INUNKNOWNPROTOS); 46 icmp_send(skb, ICMP_DEST_UNREACH, 47 ICMP_PROT_UNREACH, 0); 48 } 49 } else 50 IP_INC_STATS_BH(IPSTATS_MIB_INDELIVERS); 51 kfree_skb(skb); 52 } 53 } 54 out: 55 rcu_read_unlock(); 56 57 return 0; 58}

/net/ipv4/raw.c

1int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash) 2{ 3 struct sock *sk; 4 struct hlist_head *head; 5 int delivered = 0; 6 7 read_lock(&raw_v4_lock); 8 head = &raw_v4_htable[hash]; 9 if (hlist_empty(head)) 10 goto out; 11 sk = __raw_v4_lookup(__sk_head(head), iph->protocol, 12 iph->saddr, iph->daddr, 13 skb->dev->ifindex); 14 15 while (sk) { 16 delivered = 1; 17 if (iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) { 18 struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); 19 20 /* Not releasing hash table! */ 21 if (clone) 22 raw_rcv(sk, clone); // 关键 23 } 24 sk = __raw_v4_lookup(sk_next(sk), iph->protocol, 25 iph->saddr, iph->daddr, 26 skb->dev->ifindex); 27 } 28out: 29 read_unlock(&raw_v4_lock); 30 return delivered; 31}

/net/ipv4/raw.c

1int raw_rcv(struct sock *sk, struct sk_buff *skb) 2{ 3 if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) { 4 kfree_skb(skb); 5 return NET_RX_DROP; 6 } 7 nf_reset(skb); 8 9 skb_push(skb, skb->data - skb_network_header(skb)); 10 11 raw_rcv_skb(sk, skb); // 关键 12 return 0; 13}

/net/ipv4/raw.c

1static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb) 2{ 3 /* Charge it to the socket. */ 4 5 if (sock_queue_rcv_skb(sk, skb) < 0) { // 关键 6 /* FIXME: increment a raw drops counter here */ 7 kfree_skb(skb); 8 return NET_RX_DROP; 9 } 10 11 return NET_RX_SUCCESS; 12}

/net/core/sock.c

1int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) 2{ 3 int err = 0; 4 int skb_len; 5 6 /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces 7 number of warnings when compiling with -W --ANK 8 */ 9 if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= 10 (unsigned)sk->sk_rcvbuf) { 11 err = -ENOMEM; 12 goto out; 13 } 14 15 err = sk_filter(sk, skb); 16 if (err) 17 goto out; 18 19 skb->dev = NULL; 20 skb_set_owner_r(skb, sk); 21 22 /* Cache the SKB length before we tack it onto the receive 23 * queue. Once it is added it no longer belongs to us and 24 * may be freed by other threads of control pulling packets 25 * from the queue. 26 */ 27 skb_len = skb->len; 28 29 skb_queue_tail(&sk->sk_receive_queue, skb); // 关键 30 31 if (!sock_flag(sk, SOCK_DEAD)) 32 sk->sk_data_ready(sk, skb_len); // 通知已有数据了,如果有block的监听者就可以返回。 33out: 34 return err; 35}

/net/core/skbuff.c

1void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk) 2{ 3 unsigned long flags; 4 5 spin_lock_irqsave(&list->lock, flags); 6 __skb_queue_tail(list, newsk); // 关键 7 spin_unlock_irqrestore(&list->lock, flags); 8}
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

java将前端的json数组字符串转换为列表

记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang

个人博客开发之blog-api项目统一结果集api封装

前言由于返回jsonapi格式接口,所以我们需要通过javabean封装一个统一数据返回格式,便于和前端约定交互,状态码枚举ResultCodejavapackagecn.soboys.core.ret;importlombok.Getter;/@authorkenx@version1.0@date2021/6/1715:35