TCP/IP协议--IP层ip_local_deliver实现
来源:互联网 发布:微博mac客户端是什么 编辑:程序博客网 时间:2024/05/18 03:03
上一节说到当判断该数据报文是发送给本机的话那么就会直接到ip_local_deliver()
进行处理
ip_local_deliver
对于收到的IP报文需要传递给更上层的协议去处理,但是如果收到的是IP分片的那么就需要在往上层传递之前先进行重组,这些就是在ip_local_deliver()
函数里面进行的。我们看下代码:
/* * Deliver IP Packets to the higher protocol layers. */ int ip_local_deliver(struct sk_buff *skb) { /* * Reassemble IP fragments. */ struct net *net = dev_net(skb->dev); //check if it is a fragment if (ip_is_fragment(ip_hdr(skb))) { //fragment recombination if (ip_defrag(net, skb, IP_DEFRAG_LOCAL_DELIVER)) return 0; } return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN, net, NULL, skb, skb->dev, NULL, ip_local_deliver_finish);}
首先使用ip_hdr()获取ip头部, 然后使用ip_is_fragment()来判断当前IP报文是否是一个分组:
static inline bool ip_is_fragment(const struct iphdr *iph){ //check the ip packet is a fragment or not, why check IP_OFFSET?? return (iph->frag_off & htons(IP_MF | IP_OFFSET)) != 0;}
在上面ip头部结构里面我们看到有一个16位的frag_off,其中前三位是标志位,后13位是偏移位置,(如果不是一个分组 MF和OFFSET都是0,如果是是最后一个分组那么MF==0 但是OFFSET不为0)。那如果判断是一个分组的话那么就会调用ip_defrag()进行重组,重组成功就直接返回了,不会调用到ip_local_deliver_finish()。当最后一个报文过来或者是非分组的报文过来的话,ip_is_fragment()判断不通过直接就会进入ip_local_deliver_finish()。
下面我们就看下ip_defrag()是如何进行ip分片重组的:
/* Process an incoming IP datagram fragment. */int ip_defrag(struct net *net, struct sk_buff *skb, u32 user){ struct net_device *dev = skb->dev ? : skb_dst(skb)->dev; int vif = l3mdev_master_ifindex_rcu(dev); struct ipq *qp; __IP_INC_STATS(net, IPSTATS_MIB_REASMREQDS); skb_orphan(skb); /* Lookup (or create) queue header */ qp = ip_find(net, ip_hdr(skb), user, vif); if (qp) { int ret; spin_lock(&qp->q.lock); ret = ip_frag_queue(qp, skb); spin_unlock(&qp->q.lock); ipq_put(qp); return ret; } __IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS); kfree_skb(skb); return -ENOMEM;}EXPORT_SYMBOL(ip_defrag);
上面的这个函数首先调用ip_find()去查找是否已经在分组队列里存在相应的queue,如果没有那么就新建一个queue等待收集之后的报文,如果已经存在那么就返回queue的入口。ip_find()主要是调用iphashfn(),使用ip头部里的identifier、source addr、dest addr、protocol四个元素去进行hash计算。而iphashfn()调用的是jash_3words(), 该函数是高性能的查找算法。之后就是调用inet_frag_find()函数进行查找。
ip_local_deliver_finish
这边会通过skb头部里面的协议类型在inet_protos里面查找处理该协议的结构指针,是net_protocol指针类型。然后调用net_protocol->handler(),我们这边只是跟踪tcp报文,因为这边就是调用的tcp_v4_rcv(),报文处理流程进入到Inet Socket层。
static int ip_local_deliver_finish(struct net *net, struct sock *sk, struct sk_buff *skb){ __skb_pull(skb, skb_network_header_len(skb)); rcu_read_lock(); { //get the protocol of this packet int protocol = ip_hdr(skb)->protocol; const struct net_protocol *ipprot; ..... //from inet_protos list to get the correct protocol struct depending on protocol as index ipprot = rcu_dereference(inet_protos[protocol]); if(ipprot) { ... ret = ipprot->handler(skb);//call the Lay4 handler function. ... } } ....}
上面的代码只是对于正常的报文的流程进行分析,另外我们看到在source code中如果找不到相关的协议处理函数会通过icmp_send()
发送一个ICMP_DEST_UNREACH
的消息。
- TCP/IP协议--IP层ip_local_deliver实现
- 【Linux4.1.12源码分析】协议栈报文接收之IP层处理分析(ip_local_deliver)
- TCP/IP应用层协议
- TCP/IP 七层协议
- TCP/IP四层协议
- TCP/IP 四层协议
- TCP/IP 5层协议
- 实现TCP/IP协议
- TCP/IP简易聊天软件C++实现 - 应用层协议
- TCP/IP协议各层主要协议
- 【TCP/IP协议】四层协议系统
- TCP /IP 协议-应用层协议
- TCP/IP协议:传输层协议
- TCP/IP协议:数据链路层协议
- 【tcp-ip学习笔记】关于IP协议层、IP地址
- TCP/IP协议学习笔记----3.网络层IP协议
- TCP/IP协议栈实现
- TCP/IP各层对应的协议
- HDU~5546 Ancient Go(暴力dfs)
- [LeetCode]563. Binary Tree Tilt(二叉树的差值)
- 2017河南工业大学校赛 C 魔法宝石
- python学习_控制结构
- 对象的赋值、对象的复制(拷贝构造函数)
- TCP/IP协议--IP层ip_local_deliver实现
- 备忘(自用)
- LeetCode OJ-4.Median of Two Sorted Arrays
- 合唱队问题
- 查看那些连接elasticsearch集群
- Java中的常用API
- SpringMVC拦截器
- linux基础之分区限额
- 案例十三、模仿微信打飞机游戏