设备收发包之netif_receive_skb

在设备驱动收包之后,会通过netif_receive_skb将收取的包,按照注册的协议回调,传递到上层进行处理;

  1 /* 将skb传递到上层 */
  2 static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc)
  3 {
  4     struct packet_type *ptype, *pt_prev;
  5     rx_handler_func_t *rx_handler;
  6     struct net_device *orig_dev;
  7     bool deliver_exact = false;
  8     int ret = NET_RX_DROP;
  9     __be16 type;
 10 
 11     /* 记录收包时间,netdev_tstamp_prequeue为0,表示可能有包延迟 */
 12     net_timestamp_check(!netdev_tstamp_prequeue, skb);
 13 
 14     trace_netif_receive_skb(skb);
 15 
 16     /* 记录收包设备 */
 17     orig_dev = skb->dev;
 18 
 19     /* 重置各层头部 */
 20     skb_reset_network_header(skb);
 21     if (!skb_transport_header_was_set(skb))
 22         skb_reset_transport_header(skb);
 23     skb_reset_mac_len(skb);
 24 
 25     /* 
 26         留下一个节点,最后一次向上层传递时,
 27         不需要在inc引用,回调中会free
 28         这样相当于少调用了一次free
 29     */
 30     pt_prev = NULL;
 31 
 32 another_round:
 33 
 34     /* 接收设备索引号 */
 35     skb->skb_iif = skb->dev->ifindex;
 36 
 37     /* 处理包数统计 */
 38     __this_cpu_inc(softnet_data.processed);
 39 
 40     /* vlan包,则去掉vlan头 */
 41     if (skb->protocol == cpu_to_be16(ETH_P_8021Q) ||
 42         skb->protocol == cpu_to_be16(ETH_P_8021AD)) {
 43 
 44         /*
 45             这里改了三层协议,protocol指向ip等
 46             another_round不会再走这里
 47         */
 48         skb = skb_vlan_untag(skb);
 49         if (unlikely(!skb))
 50             goto out;
 51     }
 52 
 53     /* 不对数据包进行分类 */
 54     if (skb_skip_tc_classify(skb))
 55         goto skip_classify;
 56 
 57     /* prmemalloc */
 58     if (pfmemalloc)
 59         goto skip_taps;
 60 
 61 
 62     /* 下面两个是未(指定)设备的所有协议传递的上层传递 */
 63 
 64 
 65     /* 如抓包程序未指定设备 */    
 66     /* 进行未指定设备的全局链表对应协议的skb上层传递 */
 67     list_for_each_entry_rcu(ptype, &ptype_all, list) {
 68         if (pt_prev)
 69             ret = deliver_skb(skb, pt_prev, orig_dev);
 70         pt_prev = ptype;
 71     }
 72 
 73     /* 如抓包程序指定了设备 */
 74     /* 进行指定设备的协议链表的skb上层传递 */
 75     list_for_each_entry_rcu(ptype, &skb->dev->ptype_all, list) {
 76         if (pt_prev)
 77             ret = deliver_skb(skb, pt_prev, orig_dev);
 78         pt_prev = ptype;
 79     }
 80 
 81 skip_taps:
 82 #ifdef CONFIG_NET_INGRESS
 83     if (static_key_false(&ingress_needed)) {
 84         skb = sch_handle_ingress(skb, &pt_prev, &ret, orig_dev);
 85         if (!skb)
 86             goto out;
 87 
 88         if (nf_ingress(skb, &pt_prev, &ret, orig_dev) < 0)
 89             goto out;
 90     }
 91 #endif
 92     skb_reset_tc(skb);
 93 skip_classify:
 94 
 95     /* 不支持使用pfmemalloc */
 96     if (pfmemalloc && !skb_pfmemalloc_protocol(skb))
 97         goto drop;
 98 
 99     /* 如果是vlan包 */
100     if (skb_vlan_tag_present(skb)) {
101         /* 处理prev */
102         if (pt_prev) {
103             ret = deliver_skb(skb, pt_prev, orig_dev);
104             pt_prev = NULL;
105         }
106 
107         /* 根据实际的vlan设备调整信息,再走一遍 */
108         if (vlan_do_receive(&skb))
109             goto another_round;
110         else if (unlikely(!skb))
111             goto out;
112     }
113 
114     /* 如果有注册handler,那么调用,比如网桥模块 */
115     rx_handler = rcu_dereference(skb->dev->rx_handler);
116     if (rx_handler) {
117         if (pt_prev) {
118             ret = deliver_skb(skb, pt_prev, orig_dev);
119             pt_prev = NULL;
120         }
121         switch (rx_handler(&skb)) {
122             /* 已处理,无需进一步处理 */
123         case RX_HANDLER_CONSUMED:
124             ret = NET_RX_SUCCESS;
125             goto out;
126             /* 修改了skb->dev,在处理一次 */
127         case RX_HANDLER_ANOTHER:
128             goto another_round;
129             /* 精确传递到ptype->dev == skb->dev */
130         case RX_HANDLER_EXACT:
131             deliver_exact = true;
132             /* 正常传递即可 */
133         case RX_HANDLER_PASS:
134             break;
135         default:
136             BUG();
137         }
138     }
139 
140     /* 还有vlan标记,说明找不到vlanid对应的设备 */
141     if (unlikely(skb_vlan_tag_present(skb))) {
142         /* 存在vlanid,则判定是到其他设备的包 */
143         if (skb_vlan_tag_get_id(skb))
144             skb->pkt_type = PACKET_OTHERHOST;
145         /* Note: we might in the future use prio bits
146          * and set skb->priority like in vlan_do_receive()
147          * For the time being, just ignore Priority Code Point
148          */
149         skb->vlan_tci = 0;
150     }
151 
152     /* 设置三层协议,下面提交都是按照三层协议提交的 */
153     type = skb->protocol;
154 
155     /* deliver only exact match when indicated */
156     /* 未设置精确发送,则向未指定设备的指定协议全局发送一份 */
157     if (likely(!deliver_exact)) {
158         deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type,
159                        &ptype_base[ntohs(type) &
160                            PTYPE_HASH_MASK]);
161     }
162 
163     /* 指定设备的,向原设备上层传递  */
164     deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type,
165                    &orig_dev->ptype_specific);
166 
167     /*  当前设备与原设备不同,向当前设备传递 */
168     if (unlikely(skb->dev != orig_dev)) {
169         deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type,
170                        &skb->dev->ptype_specific);
171     }
172 
173     if (pt_prev) {
174         if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC)))
175             goto drop;
176         else
177             /*
178                 使用pt_prev这里就不需要deliver_skb来inc应用数了
179                 func执行内部会free,减少了一次skb_free
180             */
181             /* 传递到上层*/
182             ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
183     } else {
184 drop:
185         if (!deliver_exact)
186             atomic_long_inc(&skb->dev->rx_dropped);
187         else
188             atomic_long_inc(&skb->dev->rx_nohandler);
189         kfree_skb(skb);
190         /* Jamal, now you will not able to escape explaining
191          * me how you were going to use this. :-)
192          */
193         ret = NET_RX_DROP;
194     }
195 
196 out:
197     return ret;
198 }

 

posted @ 2017-09-22 20:47  AlexAlex  阅读(5651)  评论(0编辑  收藏  举报