ip_rcv ip_rcv_finish
(1) 在inet_init中注册了类型为ETH_P_IP协议的数据包的回调ip_rcv
(2) 当二层数据包接收完毕,会调用netif_receive_skb根据协议进行向上层分发
(3) 类型为ETH_P_IP类型的数据包,被传递到三层,调用ip_rcv函数
(4) ip_rcv完成基本的校验和处理工作后,经过PRE_ROUTING钩子点
(5) 经过PRE_ROUTING钩子点之后,调用ip_rcv_finish完成数据包接收,包括选项处理,路由查询,并且根据路由决定数据包是发往本机还是转发
1 static struct packet_type ip_packet_type __read_mostly = { 2 .type = cpu_to_be16(ETH_P_IP), 3 .func = ip_rcv, 4 };
1 /* 2 * Main IP Receive routine. 3 */ 4 int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) 5 { 6 const struct iphdr *iph; 7 struct net *net; 8 u32 len; 9 10 /* When the interface is in promisc. mode, drop all the crap 11 * that it receives, do not try to analyse it. 12 */ 13 /* 混杂模式下,非本机包 */ 14 if (skb->pkt_type == PACKET_OTHERHOST) 15 goto drop; 16 17 18 /* 获取net */ 19 net = dev_net(dev); 20 __IP_UPD_PO_STATS(net, IPSTATS_MIB_IN, skb->len); 21 22 /* 检查skb共享 */ 23 skb = skb_share_check(skb, GFP_ATOMIC); 24 if (!skb) { 25 __IP_INC_STATS(net, IPSTATS_MIB_INDISCARDS); 26 goto out; 27 } 28 29 /* 测试是否可以取得ip头 */ 30 if (!pskb_may_pull(skb, sizeof(struct iphdr))) 31 goto inhdr_error; 32 33 /* 取ip头 */ 34 iph = ip_hdr(skb); 35 36 /* 37 * RFC1122: 3.2.1.2 MUST silently discard any IP frame that fails the checksum. 38 * 39 * Is the datagram acceptable? 40 * 41 * 1. Length at least the size of an ip header 42 * 2. Version of 4 43 * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums] 44 * 4. Doesn't have a bogus length 45 */ 46 47 /* 头部长度不足20 或者版本不是4 */ 48 if (iph->ihl < 5 || iph->version != 4) 49 goto inhdr_error; 50 51 BUILD_BUG_ON(IPSTATS_MIB_ECT1PKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_ECT_1); 52 BUILD_BUG_ON(IPSTATS_MIB_ECT0PKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_ECT_0); 53 BUILD_BUG_ON(IPSTATS_MIB_CEPKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_CE); 54 __IP_ADD_STATS(net, 55 IPSTATS_MIB_NOECTPKTS + (iph->tos & INET_ECN_MASK), 56 max_t(unsigned short, 1, skb_shinfo(skb)->gso_segs)); 57 58 /* 测试实际应取的ip头 */ 59 if (!pskb_may_pull(skb, iph->ihl*4)) 60 goto inhdr_error; 61 62 /* 取ip头 */ 63 iph = ip_hdr(skb); 64 65 /* 校验和错误 */ 66 if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) 67 goto csum_error; 68 69 /* 取总长度 */ 70 len = ntohs(iph->tot_len); 71 72 /* skb长度比ip包总长度小 */ 73 if (skb->len < len) { 74 __IP_INC_STATS(net, IPSTATS_MIB_INTRUNCATEDPKTS); 75 goto drop; 76 } 77 /* 比头部长度还小 */ 78 else if (len < (iph->ihl*4)) 79 goto inhdr_error; 80 81 /* Our transport medium may have padded the buffer out. Now we know it 82 * is IP we can trim to the true length of the frame. 83 * Note this now means skb->len holds ntohs(iph->tot_len). 84 */ 85 /* 设置总长度为ip包的长度 */ 86 if (pskb_trim_rcsum(skb, len)) { 87 __IP_INC_STATS(net, IPSTATS_MIB_INDISCARDS); 88 goto drop; 89 } 90 91 /* 取得传输层头部 */ 92 skb->transport_header = skb->network_header + iph->ihl*4; 93 94 /* Remove any debris in the socket control block */ 95 /* 重置cb */ 96 memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); 97 98 /* 保存输入设备信息 */ 99 IPCB(skb)->iif = skb->skb_iif; 100 101 /* Must drop socket now because of tproxy. */ 102 skb_orphan(skb); 103 104 /* 经过PRE_ROUTING钩子点 */ 105 return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, 106 net, NULL, skb, dev, NULL, 107 ip_rcv_finish); 108 109 csum_error: 110 __IP_INC_STATS(net, IPSTATS_MIB_CSUMERRORS); 111 inhdr_error: 112 __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS); 113 drop: 114 kfree_skb(skb); 115 out: 116 return NET_RX_DROP; 117 }
static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) {const struct iphdr *iph = ip_hdr(skb);struct rtable *rt;struct net_device *dev = skb->dev;void (*edemux)(struct sk_buff *skb);/* if ingress device is enslaved to an L3 master device pass the* skb to its handler for processing*/skb = l3mdev_ip_rcv(skb);if (!skb)return NET_RX_SUCCESS;/* 启用了early_demuxskb路由缓存为空skb的sock为空不是分片包*/if (net->ipv4.sysctl_ip_early_demux &&!skb_dst(skb) &&!skb->sk &&!ip_is_fragment(iph)) {const struct net_protocol *ipprot;/* 找到上层协议 */int protocol = iph->protocol;/* 获取协议对应的prot */ipprot = rcu_dereference(inet_protos[protocol]);/* 找到early_demux函数,如tcp_v4_early_demux */if (ipprot && (edemux = READ_ONCE(ipprot->early_demux))) {/* 调用该函数,将路由信息缓存到skb->refdst */edemux(skb);/* must reload iph, skb->head might have changed *//* 重新取ip头 */iph = ip_hdr(skb);}}/** Initialise the virtual path cache for the packet. It describes* how the packet travels inside Linux networking.*//* 校验路由失败 */if (!skb_valid_dst(skb)) {/* 查路由 */int err = ip_route_input_noref(skb, iph->daddr, iph->saddr,iph->tos, dev);if (unlikely(err)) {if (err == -EXDEV)__NET_INC_STATS(net, LINUX_MIB_IPRPFILTER);goto drop;}}#ifdef CONFIG_IP_ROUTE_CLASSIDif (unlikely(skb_dst(skb)->tclassid)) {struct ip_rt_acct *st = this_cpu_ptr(ip_rt_acct);u32 idx = skb_dst(skb)->tclassid;st[idx&0xFF].o_packets++;st[idx&0xFF].o_bytes += skb->len;st[(idx>>16)&0xFF].i_packets++;st[(idx>>16)&0xFF].i_bytes += skb->len;} #endif/* 处理ip选项 */if (iph->ihl > 5 && ip_rcv_options(skb))goto drop;/* 找到路由缓存项 */rt = skb_rtable(skb);if (rt->rt_type == RTN_MULTICAST) {__IP_UPD_PO_STATS(net, IPSTATS_MIB_INMCAST, skb->len);} else if (rt->rt_type == RTN_BROADCAST) {__IP_UPD_PO_STATS(net, IPSTATS_MIB_INBCAST, skb->len);} else if (skb->pkt_type == PACKET_BROADCAST ||skb->pkt_type == PACKET_MULTICAST) {struct in_device *in_dev = __in_dev_get_rcu(dev);/* RFC 1122 3.3.6:** When a host sends a datagram to a link-layer broadcast* address, the IP destination address MUST be a legal IP* broadcast or IP multicast address.** A host SHOULD silently discard a datagram that is received* via a link-layer broadcast (see Section 2.4) but does not* specify an IP multicast or broadcast destination address.** This doesn't explicitly say L2 *broadcast*, but broadcast is* in a way a form of multicast and the most common use case for* this is 802.11 protecting against cross-station spoofing (the* so-called "hole-196" attack) so do it for both.*/if (in_dev &&IN_DEV_ORCONF(in_dev, DROP_UNICAST_IN_L2_MULTICAST))goto drop;}/* 调用路由项的input函数,可能为ip_local_deliver或者ip_forward */return dst_input(skb);drop:kfree_skb(skb);return NET_RX_DROP; }
转载于:https://www.cnblogs.com/wanpengcoder/p/7577398.html
ip_rcv ip_rcv_finish相关推荐
- linux ip rcv处理,linux ip选项处理(二)
ip选项处理(一)中讨论了syn包的发送过程对ip选项的处理,接下来分析接收syn并转发的过程 (2)路由节点接收syn到转发syn 我们知道ip层接收数据的函数调用过程是ip_rcv ---> ...
- OVS之vhost-net中VM通信(九)
一.版本说明 qemu版本:2.6.0 内核版本:3.10.102 二.简而言之 vhost模块需要提前加载,注册一个misc的设备,供虚拟机启动时候使用. 虚拟机创建的时候,会初始化一个tap设备, ...
- Linux原始套接字学习总结
Linux网络编程:原始套接字的魔力[上] http://blog.chinaunix.net/uid-23069658-id-3280895.html 基于原始套接字编程 在开发面向连 ...
- Linux原始套接字实现分析---转
http://blog.chinaunix.net/uid-27074062-id-3388166.html 本文从IPV4协议栈原始套接字的分类入手,详细介绍了链路层和网络层原始套接字的特点及其内核 ...
- linux .forward,linux forward的实现
对于linux的数据包流向,大家应该是比较了解,如果还不是很了解,可以参考<OReilly.Understanding.Linux.Network.Internals.Dec.2005>, ...
- linux ip to int,linux ip选项处理(二)
ip选项处理(一)中讨论了syn包的发送过程对ip选项的处理,接下来分析接收syn并转发的过程 (2)路由节点接收syn到转发syn 我们知道ip层接收数据的函数调用过程是ip_rcv ---> ...
- Linux内核分析 - 网络[十四]:IP选项
内核版本:2.6.34 在发送报文时,可以调用函数setsockopt()来设置相应的选项,本文主要分析IP选项的生成,发送以及接收所执行的流程,选取了LSRR为例子进行说明,主要分为选项 ...
- IP 层收发报文简要剖析1-ip报文的输入
ip层数据包处理场景如下: 网络层处理数据包文时需要和路由表以及邻居系统打交道.输入数据时,提供输入接口给链路层调用,并调用传输层的输入接口将数据输入到传输层. 在输出数据时,提供输出接口给传输层,并 ...
- Linux应用程序开发 基础知识
Linux应用程序开发 本文讲述了linux应用程序开发的基本内容.值得学习! Copyright © 2006 本文遵从GNU 的自由文档许可证(Free Documentation Lice ...
- gre包分片及gro、gso等offload特性的应用
图1 直接上图,再分别简单介绍各部分: PC:笔记本电脑. gw1:使用一台微型服务器模拟企业用户网关,同时添加静态路由使具备简单路由功能. gw2:模拟ISP,同时添加静态路由使具备简单路由功能. ...
最新文章
- Oracle慌了!华为终于对JDK下手了!
- 无人驾驶技术排名:百度居中游,苹果特斯拉垫底 | 行业
- 百度可观测系列 | 采集亿级别指标,Prometheus 集群方案这样设计
- mysql模糊查询LIKE、REGEXP(正则)的详解(在可视化工具navicat下)
- linux stat文件,Linux stat命令:显示文件或文件系统的详细信息
- 2021高考文科成绩怎样查询,2021年本科分数线是多少?如何查询分数
- 【Codeforces Round #519 by Botan Investments D】Mysterious Crime
- 28th Dec, 2012 我自己的问题
- 优化算法 | 多车型车辆路径问题-初始解构造方法
- Java如何把文档转换成PDF
- ppm调制matlab程序,求助:谁能帮我编写一个4ppm的解调程序 谢谢了
- 视频字幕 硬字幕 软字幕 外挂字幕 简介
- 书评 | 赋能 - 打造应对不确定性的敏捷团队
- 计算机视觉牛人、网站、资源
- 沙龙报名 | 区块链落地难? 六位专家揭秘京东区块链全景应用
- iPhone XS系列降价一千元;Intel雷电接口将融合USB4;蔚来汽车收入、亏损均增长百分百 | 雷锋早报...
- [PM2] Spawning PM2 daemon with pm2_home=/root/.pm2 错误
- stateflow基本操作
- SQL Server 常见的7种约束以及where条件表达式
- python使用多线程读写数据到文件2
热门文章
- Django+bootstrap启动登录模板页面(Django第三篇)
- 刘夏真的简历中国科学院计算机所,刘夏_广西医科大学研究生导师信息
- js制作走马灯和选项卡
- 一个selenium python网页脚本(机器人),针对随聊520(www.suiliao520.com)匿名聊天匹配陌生人的网站
- html页面跳转传值原生,html页面跳转传递参数问题
- owncloud server replied : locked 故障处理
- python表示颜色的代码_python 中颜色的表示
- 《大型网站技术架构》《K8S进阶实战》等书籍!送45本!
- asp.net配置web.config显示详细错误信息
- Hyperledger Fabric系统架构