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的源码,网上已经更新到适合最新内核,而我自己用的还是 ...
随机推荐
- HDU5669-Road
题意 给一个\(n\)个点的图,标号为\(1\)到\(n\),进行\(m\)次连边\((a,b,c,d,w)\): for i in range[a,b]: for j in range[c,d]: ...
- 除了GPS外的4种获得用户地理位置数据的方法
纯粹的GPS解决方案以及它所生成的经纬度标签是地理位置数据的公认标准.但是至少还有4种方法可以获得地理位置数据: 1.手机信号塔数据:当移动设备的GPS芯片不能接收到GPS信号时,移动设备就需要与它所 ...
- [AT2064] [agc005_f] Many Easy Problems
题目链接 AtCoder:https://agc005.contest.atcoder.jp/tasks/agc005_f 洛谷:https://www.luogu.org/problemnew/sh ...
- mysql数据库的存储过程
一. 什么是存储过程: 存储过程是一组可编程的函数,是为了完成特定功能的SQL语句集,经过第一次编译后再次调用不需要再次编译,创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数(需要时)来调 ...
- 【PDF】HTML中嵌入pdf的简单方法
<embed src="> 或者你不想显示某些功能的话: <embed src=">
- 【BZOJ4516】生成魔咒(后缀自动机)
[BZOJ4516]生成魔咒(后缀自动机) 题面 BZOJ Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. ...
- jetBrains 插件开发第一课-- 在主菜单栏新增一个菜单
环境搭建完了,接下来可以开始写代码了: 1.新建 plugin 项目 2.编辑 plugin.xml,修改一下里面的插件名那些信息,该文件的配置项可以看这里:plugin.xml 其中比较关键的有一个 ...
- mybatis中的resultMap与resultType、parameterMap与 parameterType的区别
Map:映射:Type:Java类型 resultMap 与 resultType.parameterMap 与 parameterType的区别在面试的时候被问到的几率非常高,项目中出现了一个小b ...
- 9.Android UiAutomator正则表达式的使用
一.正则表达式元字符: 1.一些常用元字符: 元字符 描述 . 表示任意一个字符 \s 空格字符(空格键.tab.换行.换页.回车) \S 非空字符串([^\s]) \d 一个数字(相当于[0-9]中 ...
- mysql cpu 占用高
vi /etc/my.cnf [mysqld]tmp_table_size=200M mysql> show global status like ‘created_tmp%‘; +—————— ...