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

 /* 将skb传递到上层 */
static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc)
{
struct packet_type *ptype, *pt_prev;
rx_handler_func_t *rx_handler;
struct net_device *orig_dev;
bool deliver_exact = false;
int ret = NET_RX_DROP;
__be16 type; /* 记录收包时间,netdev_tstamp_prequeue为0,表示可能有包延迟 */
net_timestamp_check(!netdev_tstamp_prequeue, skb); trace_netif_receive_skb(skb); /* 记录收包设备 */
orig_dev = skb->dev; /* 重置各层头部 */
skb_reset_network_header(skb);
if (!skb_transport_header_was_set(skb))
skb_reset_transport_header(skb);
skb_reset_mac_len(skb); /*
留下一个节点,最后一次向上层传递时,
不需要在inc引用,回调中会free
这样相当于少调用了一次free
*/
pt_prev = NULL; another_round: /* 接收设备索引号 */
skb->skb_iif = skb->dev->ifindex; /* 处理包数统计 */
__this_cpu_inc(softnet_data.processed); /* vlan包,则去掉vlan头 */
if (skb->protocol == cpu_to_be16(ETH_P_8021Q) ||
skb->protocol == cpu_to_be16(ETH_P_8021AD)) { /*
这里改了三层协议,protocol指向ip等
another_round不会再走这里
*/
skb = skb_vlan_untag(skb);
if (unlikely(!skb))
goto out;
} /* 不对数据包进行分类 */
if (skb_skip_tc_classify(skb))
goto skip_classify; /* prmemalloc */
if (pfmemalloc)
goto skip_taps; /* 下面两个是未(指定)设备的所有协议传递的上层传递 */ /* 如抓包程序未指定设备 */
/* 进行未指定设备的全局链表对应协议的skb上层传递 */
list_for_each_entry_rcu(ptype, &ptype_all, list) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
} /* 如抓包程序指定了设备 */
/* 进行指定设备的协议链表的skb上层传递 */
list_for_each_entry_rcu(ptype, &skb->dev->ptype_all, list) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
} skip_taps:
#ifdef CONFIG_NET_INGRESS
if (static_key_false(&ingress_needed)) {
skb = sch_handle_ingress(skb, &pt_prev, &ret, orig_dev);
if (!skb)
goto out; if (nf_ingress(skb, &pt_prev, &ret, orig_dev) < )
goto out;
}
#endif
skb_reset_tc(skb);
skip_classify: /* 不支持使用pfmemalloc */
if (pfmemalloc && !skb_pfmemalloc_protocol(skb))
goto drop; /* 如果是vlan包 */
if (skb_vlan_tag_present(skb)) {
/* 处理prev */
if (pt_prev) {
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = NULL;
} /* 根据实际的vlan设备调整信息,再走一遍 */
if (vlan_do_receive(&skb))
goto another_round;
else if (unlikely(!skb))
goto out;
} /* 如果有注册handler,那么调用,比如网桥模块 */
rx_handler = rcu_dereference(skb->dev->rx_handler);
if (rx_handler) {
if (pt_prev) {
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = NULL;
}
switch (rx_handler(&skb)) {
/* 已处理,无需进一步处理 */
case RX_HANDLER_CONSUMED:
ret = NET_RX_SUCCESS;
goto out;
/* 修改了skb->dev,在处理一次 */
case RX_HANDLER_ANOTHER:
goto another_round;
/* 精确传递到ptype->dev == skb->dev */
case RX_HANDLER_EXACT:
deliver_exact = true;
/* 正常传递即可 */
case RX_HANDLER_PASS:
break;
default:
BUG();
}
} /* 还有vlan标记,说明找不到vlanid对应的设备 */
if (unlikely(skb_vlan_tag_present(skb))) {
/* 存在vlanid,则判定是到其他设备的包 */
if (skb_vlan_tag_get_id(skb))
skb->pkt_type = PACKET_OTHERHOST;
/* Note: we might in the future use prio bits
* and set skb->priority like in vlan_do_receive()
* For the time being, just ignore Priority Code Point
*/
skb->vlan_tci = ;
} /* 设置三层协议,下面提交都是按照三层协议提交的 */
type = skb->protocol; /* deliver only exact match when indicated */
/* 未设置精确发送,则向未指定设备的指定协议全局发送一份 */
if (likely(!deliver_exact)) {
deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type,
&ptype_base[ntohs(type) &
PTYPE_HASH_MASK]);
} /* 指定设备的,向原设备上层传递 */
deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type,
&orig_dev->ptype_specific); /* 当前设备与原设备不同,向当前设备传递 */
if (unlikely(skb->dev != orig_dev)) {
deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type,
&skb->dev->ptype_specific);
} if (pt_prev) {
if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC)))
goto drop;
else
/*
使用pt_prev这里就不需要deliver_skb来inc应用数了
func执行内部会free,减少了一次skb_free
*/
/* 传递到上层*/
ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
} else {
drop:
if (!deliver_exact)
atomic_long_inc(&skb->dev->rx_dropped);
else
atomic_long_inc(&skb->dev->rx_nohandler);
kfree_skb(skb);
/* Jamal, now you will not able to escape explaining
* me how you were going to use this. :-)
*/
ret = NET_RX_DROP;
} out:
return ret;
}

netif_receive_skb->__netif_receive_skb_core的更多相关文章

  1. ebtables hook

    1 概述 netfliter框架不仅仅在ipv4中有应用,bridge,ipv4,ipv6,decnet 这四种协议中都有应用,其中ipv4中又分开了arp和ip的两种 其实netfliter是个大的 ...

  2. Monitoring and Tuning the Linux Networking Stack: Receiving Data

    http://blog.packagecloud.io/eng/2016/06/22/monitoring-tuning-linux-networking-stack-receiving-data/ ...

  3. http://blog.csdn.net/zgl07/article/details/43491399

    转载申明:本文转载自http://www.brendangregg.com/perf.html   请大家看了之后如果要转载一定要注上这个地址!!! ========================= ...

  4. LInux下桥接模式详解三

    上篇文章介绍了Linux内核桥接模式涉及到的几个结构,本节就重点放在数据包的处理上! 本节所有代码参考LInux 3.10.1内核! 前面已经提到一个数据包从网卡流到Linux内核中的L2层,最终被交 ...

  5. 《Monitoring and Tuning the Linux Networking Stack: Receiving Data》翻译

    Overview 从宏观的角度来看,一个packet从网卡到socket接收缓冲区的路径如下所示: 驱动加载并初始化 packet到达网卡 packet通过DMA被拷贝到内核中的一个ring buff ...

  6. Linux内核网络数据包处理流程

    Linux内核网络数据包处理流程 from kernel-4.9: 0. Linux内核网络数据包处理流程 - 网络硬件 网卡工作在物理层和数据链路层,主要由PHY/MAC芯片.Tx/Rx FIFO. ...

  7. Linux内核网络报文简单流程

    转:http://blog.csdn.net/adamska0104/article/details/45397177 Linux内核网络报文简单流程2014-08-12 10:05:09 分类: L ...

  8. Linux 网络栈 转载

    此文章  来自      http://arthurchiao.art/blog/tuning-stack-rx-zh/ [译] Linux 网络栈监控和调优:接收数据(2016) Published ...

  9. Linux网络驱动--snull

    snull是<Linux Device Drivers>中的一个网络驱动的例子.这里引用这个例子学习Linux网络驱动. 因为snull的源码,网上已经更新到适合最新内核,而我自己用的还是 ...

随机推荐

  1. 【bzoj2656】[Zjoi2012]数列(sequence) 高精度

    题目描述 给出数列 $A$ 的递推公式如下图所示,$T$ 次给定 $n$ ,求 $A_n$ . 输入 输入文件第一行有且只有一个正整数T,表示测试数据的组数.第2-T+1行,每行一个非负整数N. 输出 ...

  2. Wedding UVA - 11294(2-SAT男女分点)

    题意: 有N-1对夫妻参加一个婚宴,所有人都坐在一个长长的餐桌左侧或者右侧,新郎和新娘面做面坐在桌子的两侧.由于新娘的头饰很复杂,她无法看到和她坐在同一侧餐桌的人,只能看到对面餐桌的人.任意一对夫妻不 ...

  3. CF623D birthday 贪心 概率期望

    题意:n个人,玩抓人游戏,每抓住一个人都要猜这个人是谁.对于每一局,第i个人有$p_{i}$的概率被抓到.游戏结束当且仅当每个人都在某局中被抓到并且猜中自己的名字,求一个合适的策略来使得期望游戏局数最 ...

  4. redis的Pub/Sub功能

    Pub/Sub功能(即Publish,Subscribe)意思是发布及订阅功能.简单的理解就像我们订阅blog一样,不同的是,这里的客户端与server端采用长连接建立推送机制,一个客户端发布消息,可 ...

  5. oracle 远程登录sqlplus TNS:无监听

    1.将localhost 改成 计算机名 best-PC,或者ip地址 .  我修改成计算机名,因为经常在无线网络和有限网络之间切换 SID_LIST_LISTENER =  (SID_LIST =  ...

  6. 全面支持Angular2的Web后台Bootstrap模板Sing App - Web & Angular 2.0 Dashboard

    在线预览 Sing App v3.3.0 (包含Angular 2.0版本实现) 现在,本模板完全支持Angular2.0版本啦. Sing Web App 是由专业前端工程师采用行业内流行的技术构建 ...

  7. 扶苏的bitset浅谈

    bitset作为C++一个非常好用的STL,在一些题目中巧妙地使用会产生非常不错的效果.今天扶苏来分享一点bitset的基础语法和应用 本文同步发布于个人其他博客,同时作为P3674题解发布. 本文感 ...

  8. 新的JavaScript数据结构Streams

    最近在网上看到了一个新的 Javascript 小程序——Streams,起初以为是一个普通的 Javascript 类库,但读了关于它的介绍后,我发现,这不是一个简单的类库,而且作者的重点也不是这个 ...

  9. MySQL查询和修改auto_increment的方法

    查询表名为tableName的auto_increment值: 复制代码 代码如下: SELECT AUTO_INCREMENT FROM information_schema.tables WHER ...

  10. need

    php面试题: http://lib.csdn.net/article/php/43624 小程序: 官方手册: https://mp.weixin.qq.com/debug/wxadoc/dev/d ...