netif_receive_skb->__netif_receive_skb_core
在设备驱动收包之后,会通过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的更多相关文章
- ebtables hook
1 概述 netfliter框架不仅仅在ipv4中有应用,bridge,ipv4,ipv6,decnet 这四种协议中都有应用,其中ipv4中又分开了arp和ip的两种 其实netfliter是个大的 ...
- Monitoring and Tuning the Linux Networking Stack: Receiving Data
http://blog.packagecloud.io/eng/2016/06/22/monitoring-tuning-linux-networking-stack-receiving-data/ ...
- http://blog.csdn.net/zgl07/article/details/43491399
转载申明:本文转载自http://www.brendangregg.com/perf.html 请大家看了之后如果要转载一定要注上这个地址!!! ========================= ...
- LInux下桥接模式详解三
上篇文章介绍了Linux内核桥接模式涉及到的几个结构,本节就重点放在数据包的处理上! 本节所有代码参考LInux 3.10.1内核! 前面已经提到一个数据包从网卡流到Linux内核中的L2层,最终被交 ...
- 《Monitoring and Tuning the Linux Networking Stack: Receiving Data》翻译
Overview 从宏观的角度来看,一个packet从网卡到socket接收缓冲区的路径如下所示: 驱动加载并初始化 packet到达网卡 packet通过DMA被拷贝到内核中的一个ring buff ...
- Linux内核网络数据包处理流程
Linux内核网络数据包处理流程 from kernel-4.9: 0. Linux内核网络数据包处理流程 - 网络硬件 网卡工作在物理层和数据链路层,主要由PHY/MAC芯片.Tx/Rx FIFO. ...
- Linux内核网络报文简单流程
转:http://blog.csdn.net/adamska0104/article/details/45397177 Linux内核网络报文简单流程2014-08-12 10:05:09 分类: L ...
- Linux 网络栈 转载
此文章 来自 http://arthurchiao.art/blog/tuning-stack-rx-zh/ [译] Linux 网络栈监控和调优:接收数据(2016) Published ...
- Linux网络驱动--snull
snull是<Linux Device Drivers>中的一个网络驱动的例子.这里引用这个例子学习Linux网络驱动. 因为snull的源码,网上已经更新到适合最新内核,而我自己用的还是 ...
随机推荐
- 51nod-1222-最小公倍数计数
题意 给到 \(a,b\) ,求 \[ \sum _{i=a}^b\sum _x\sum _y[x\le y][\text{lcm}(x,y)=i] \] 即最小公倍数在 \([a,b]\) 中的有序 ...
- 【bzoj2600】[Ioi2011]ricehub 双指针法
题目描述 给出数轴上坐标从小到大的 $R$ 个点,坐标范围在 $1\sim L$ 之间.选出一段连续的点,满足:存在一个点,使得所有选出的点到其距离和不超过 $B$ .求最多能够选出多少点. $R\l ...
- 【明哥报错簿】可以访问jsp但是访问不到controller
此工程wms-web-enterprise启动之后,jsp页面可以访问,但是进不了controller.后来发现wms-consumer无法打包编译,在仓库m2里面发现此consumer.jar包为完 ...
- 基于ORM实现用户登录
1. 与数据库中的数据进行比较,检验用户名和密码是否正确. 2. 拿到的是QuerySet类型,类似于一个列表.验证成功/失败,返回到不同的页面. u = request.POST.get('user ...
- hive 导入数据
1.load data load data local inpath "/home/hadoop/userinfo.txt" into table userinfo; " ...
- 洛谷5月月赛T30212 玩游戏 【分治NTT + 多项式求ln】
题目链接 洛谷T30212 题解 式子很容易推出来,二项式定理展开后对于\(k\)的答案即可化简为如下: \[k!(\sum\limits_{i = 0}^{k} \frac{\sum\limits_ ...
- 洛谷 P2123 皇后游戏 解题报告
P2123 皇后游戏 题意: 给定\(T\)组长为\(n\)的\(A\),\(B\)数组和\(C\)的计算方法,求一种排列方法,使最大的\(C\)最小化. 数据范围: \(1 \le T \le 10 ...
- Linux内核设计第二周学习总结 完成一个简单的时间片轮转多道程序内核代码
陈巧然 原创作品 转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.使用实验楼的虚拟机 ...
- [POJ1094] Sorting It All Out
link 题目大意 给出$m$个不等式关系,问可以从第几个开始确定所有之间的大小关系.若无解请输出是无法确定还是与已知矛盾. 试题分析 这题是真的是坑啊,尽然放在$floyd$传到闭包上面,还用二分, ...
- jsp 的 4 种基本语法
1.JSP 注释 2.JSP 声明 3.JSP 表达式 4.JSP 脚本 JSP 注释: 注释格式: <%-- 注释内容 --%> 需要注意的是,JSP 的注释不会输出到 HTML 中. ...