//向协议栈注册l3处理函数
1.1 void dev_add_pack(struct packet_type *pt)
{
int hash;
//ptype_all ptype_base共用一把锁 ptype_lock
spin_lock_bh(&ptype_lock);
if (pt->type == htons(ETH_P_ALL)) {//ETH_P_ALL类型的l3协议,从外接收到的数据帧,和从本地发送的数据帧,都会向ptype_all链表中的l3协议,传递一份
netdev_nit++;
list_add_rcu(&pt->list, &ptype_all);
} else {
hash = ntohs(pt->type) & 15;//ptype_base有16个bucket
list_add_rcu(&pt->list, &ptype_base[hash]);//链接到bucket的链表中
}
spin_unlock_bh(&ptype_lock);
} //ip协议控制块
//每个l3协议,通过struct packet_type描述自己
1.2 static struct packet_type ip_packet_type = {
.type = __constant_htons(ETH_P_IP),//.type使用网络字节序,大端模式
.func = ip_rcv,//ip接收函数
}; //ip协议的接收函数
1.3 int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
{
struct iphdr *iph;
//skb->pkt_type由接收设备的驱动程序,调用eth_type_trans设定
//当设备处于混杂模式下,对于非本机,非广播,非多播的数据帧,设置其pkt_type=PACKET_OTHERHOST
//ip协议不处理PACKET_OTHERHOST类型的封包,此类型的封包应该由l3协议之前被bonding,或者网桥来处理
if (skb->pkt_type == PACKET_OTHERHOST)
goto drop; IP_INC_STATS_BH(IPSTATS_MIB_INRECEIVES);//snmp协议 if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {//如果skb被共享的话,复制一份
IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
goto out;
} if (!pskb_may_pull(skb, sizeof(struct iphdr)))//使skb->data到skb->tail之间足够20字节的ip头(此时不包括选项字段)
goto inhdr_error; iph = skb->nh.iph;//ip头 //数据帧可接收的条件
//1.包含ip头,ipv4,校验和正确,数据包长度正确
if (iph->ihl < 5 || iph->version != 4)
goto inhdr_error; if (!pskb_may_pull(skb, iph->ihl*4))//ihl以4字节为单位,表示ip头的长度
goto inhdr_error; iph = skb->nh.iph;//此时iph包含选项字段 if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)//对ip头和选项(如果存在的话),计算校验和
goto inhdr_error; {
__u32 len = ntohs(iph->tot_len); //ip报文总长(包括ip报头,选项,ip有效载荷)
if (skb->len < len || len < (iph->ihl<<2))//skb中l3数据总长度小于接收到的长度,或者接收到的长度不足ip报头和选项的长度
goto inhdr_error; if (skb->len > len) {//skb中l3数据总长度大于ip报头中指示的总长度
__pskb_trim(skb, len);//切割skb从data开始的数据长度到len字节
if (skb->ip_summed == CHECKSUM_HW)//如果校验和已经由硬件求得,但是由于对数据进行了切割操作
skb->ip_summed = CHECKSUM_NONE;//则指示需要网络层通过软件再进行校验和计算
}
} return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
ip_rcv_finish);//经过netfilter钩子函数的处理,最终由ip_rcv_finish完成处理 inhdr_error:
IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
drop:
kfree_skb(skb);
out:
return NET_RX_DROP;
} 1.4 static inline int ip_rcv_finish(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
struct iphdr *iph = skb->nh.iph; if (skb->dst == NULL) {//目标路由未设置
if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))//输入路径上的路由,设置skb->dst
goto drop;
}
... if (iph->ihl > 5) {//需要处理ip选项
struct ip_options *opt; if (skb_cow(skb, skb_headroom(skb))) {//skb->data 到 skb->head之间,保证16个字节的空间
IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
goto drop;
}
iph = skb->nh.iph;
//在报文接收路径的多处,由不同函数对各个选项进行处理
if (ip_options_compile(NULL, skb))//此处分析ip选项,初始化skb->cb中ip_options结构,为后边处理ip选项做准备。
goto inhdr_error; opt = &(IPCB(skb)->opt);
if (opt->srr) {//处理源路由选项
struct in_device *in_dev = in_dev_get(dev);
if (in_dev) {
if (!IN_DEV_SOURCE_ROUTE(in_dev)) {//入口设备的inet配置不支持源路由选项
if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
printk(KERN_INFO "source route option %u.%u.%u.%u -> %u.%u.%u.%u\n",
NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
in_dev_put(in_dev);
goto drop;//直接丢弃封包
}
in_dev_put(in_dev);
}
if (ip_options_rcv_srr(skb))//处理员路由选项
goto drop;
}
} return dst_input(skb);//skb->dst->input处理,input函数指针由ip_route_input,根据目标地址,进行设置。 inhdr_error:
IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
drop:
kfree_skb(skb);
return NET_RX_DROP;
}
//ip选项处理路径 参考 深入理解linux网络技术内幕

网络子系统42_ip协议处理函数_数据帧的接收的更多相关文章

  1. 网络子系统54_ip协议分片重组_定位ipq

    //为分片确定正确的ipq结构 // 定位5元组 // 1.<id, 源ip, 目的ip, l4协议> 可通过ip报文获取 // 2.user 通过ip_defrag给出,指出重组是由谁发 ...

  2. 网络子系统55_ip协议分片重组_加入ipq

    //ip分片加入到正确的ipq结构 //调用路径:ip_defrag->ip_frag_queue // 处理过程: // 1.正在被释放的ipq,不处理新加入的分片(ipq正在被释放由last ...

  3. 网络子系统53_ip协议分片重组_内存阈值

    //调用路径:ip_defrag->ip_evictor // 分片重组时,可使用内存上下限: // 1.sysctl_ipfrag_high_thresh 可用内存上限 // 2.sysctl ...

  4. 网络子系统48_ip协议数据帧的发送

    //ip协议与l4协议接口,l4通过此接口向下l3传递数据帧 //函数主要任务: // 1.通过路由子系统路由封包 // 2.填充l3报头 // 3.ip分片 // 4.计算校验和 // 5.衔接邻居 ...

  5. 网络子系统46_ip协议数据帧的转发

    //调用路径ip_rcv->ip_rcv_finish->dst_input->(skb->dst->input) //ip_forward以回调函数的形式,保存在skb ...

  6. 网络子系统45_ip协议tos处理

    //ip报头tos字段,一个字节 // 二进制位:[0 1 2] [3] [4] [5] [6] [7] // 1.[0 1 2] 表示优先级: // 000 路由 // 001 优先级 // 010 ...

  7. Linux 网络子系统之网络协议接口层(一)

    Linux 网络设备驱动之网络协议接口层介绍. 网络协议接口层最主要的功能是给上层协议提供透明的数据包发送和接收接口. 当上层ARP或IP需要发送数据包时,它将调用网络协议接口层的dev_queue_ ...

  8. Linux内核笔记--网络子系统初探

    内核版本:linux-2.6.11 本文对Linux网络子系统的收发包的流程进行一个大致梳理,以流水账的形式记录从应用层write一个socket开始到这些数据被应用层read出来的这个过程中linu ...

  9. Linux 网络子系统

    今天记录一下Linux网络子系统相关的东西. 因为感觉对这一块还是有一个很大的空白,这件事情太可怕了. 摘抄多份博客进行总结一下Linux网络子系统的相关东西. 一. Linux网络子系统体系结构 L ...

随机推荐

  1. Hibernate的关联映射

    单向N-1关联 <many-to-one> 单向N-1关系,比如多个人对应同一个住址,只需要从人实体端找到对应的住址实体,无须关系某个地址的全部住户.程序在N的一端增加一个属性,该属性引用 ...

  2. wamp 中如何管理两个dedeCms站点

    本文以WampServer2.1为例,图文说明开启wamp虚拟主机功能,也就是绑定多域名,开启多站点搭建功能. 1.  我们一键安装wamp到E盘,并可以正常启动,状态如下图所示:  

  3. python抓取伯乐在线的全部文章,对标题分词后存入mongodb中

    依赖包: 1.pymongo 2.jieba # -*- coding: utf-8 -*- """ @author: jiangfuqiang "" ...

  4. 配置java项目的intellij idea的运行环境

    才疏学浅,只懂一点点前端的皮毛东西,对于项目运行环境的配置一无所知,今天简单记录一下! 前提:装好了jdk.maven.intellij idea. 1. file菜单->Open...打开从S ...

  5. 如何解决在ie下,Echarts多次使用setOption更改数据时,数据错乱问题

    一.问题描述 根据用户的操作,通过Ajax请求,获取某段时间内的某数据趋势折线图数据.用户切换数据项或更改时间段时,ie中渲染的折线图包含了上一次获取的数据,导致数据错乱,如下图所示: 二.代码 数据 ...

  6. 线程锁Lock

    from threading import Thread, Lock import time def func(): global n n -= 1 n = 10 t_list = [] for i ...

  7. HQL-Query接口

    org.hibernate.Query接口 1.Query接口定义有执行查询的方法(完成HQL语句的解析和执行过程并返回查询结果,就像SQL语句没了JDBC接口就成了一个普通的字符串变量) 2.Que ...

  8. 重启虚拟目录或站点,不重启iis

    更改站点或虚拟目录的.net Framework 版本会导致重启整个iis服务,所以需要单独重启某个站点或虚拟目录 首先右键点击网站-所有任务-将配置保存到一个文件,从文件中查找到 Location ...

  9. Learning coding online

    A lot of online courses for coding skills are available nowadays, both free and non-free. I will col ...

  10. ZH奶酪:中文依存句法分析概述及应用

    句法分析是自然语言处理领域的一个关键问题,如能将其有效解决,一方面,可对相应树库构建体系的正确性和完善性进行验证;另一方面,也可直接服务于各种上层应用,比如搜索引擎用户日志分析和关键词识别,比如信息抽 ...