• 设备收发包之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 }
  • 相关阅读:
    Rancher之Pipeline JAVA demo
    rancher使用fluentd-pilot收集日志分享
    SFTP 命令列表以备查询
    WPF中异步更新UI元素
    Android 开发环境在 Windows7 下的部署安装
    Android Studio vs. Eclipse ADT Comparison
    JQuery 滚动条插件perfect-scrollbar
    nginx+php 在windows下的简单配置安装
    MySql 管理操作常用命令
    JS事件调试
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/7577088.html
Copyright © 2020-2023  润新知