zoukankan      html  css  js  c++  java
  • 设备收发包之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 }
  • 相关阅读:
    129 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 03 饿汉模式 VS 懒汉模式 02 懒汉式的代码实现
    128 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 03 饿汉模式 VS 懒汉模式 01 饿汉式的代码实现
    127 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 02 单例模式概述 01 单例模式的定义和作用
    126 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 01 设计模式概述 01 设计模式简介
    125 01 Android 零基础入门 02 Java面向对象 05 Java继承(下)05 Java继承(下)总结 01 Java继承(下)知识点总结
    leetcode-----121. 买卖股票的最佳时机
    leetcode-----104. 二叉树的最大深度
    Json串的字段如果和类中字段不一致,如何映射、转换?
    Mybatis-Plus的Service方法使用 之 泛型方法default <V> List<V> listObjs(Function<? super Object, V> mapper)
    模糊查询
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/7577088.html
Copyright © 2011-2022 走看看