Linux内核:从上向下分析网络层IP协议
作者:网络转载 发布时间:[ 2013/1/6 10:08:12 ] 推荐标签:
上篇博文分析传输层终会调用函数ip_queue_xmit()函数,将发送数据的任务交给网络层,下面分析了下该函数:
该函数的主要函数调用关系图如下:
/*
* Queues a packet to be sent, and starts the transmitter
* if necessary. if free = 1 then we free the block after
* transmit, otherwise we don't. If free==2 we not only
* free the block but also don't assign a new ip seq number.
* This routine also needs to put in the total length,
* and compute the checksum
*/
void ip_queue_xmit(struct sock *sk, //发送数据的队列所对应的sock结构
struct device *dev,//发送该数据包的网卡设备
struct sk_buff *skb,//封装好的sk_buff结构,要发送的数据在该结构中
int free)//主要配合TCP协议使用,用于数据包的重发,UDP等协议调用是free=1
{
struct iphdr *iph;//IP数据报首部指针
unsigned char *ptr;
/* Sanity check */
if (dev == NULL)
{
printk("IP: ip_queue_xmit dev = NULL
");
return;
}
IS_SKB(skb);
/*
* Do some book-keeping in the packet for later
*/
skb->dev = dev;//进一步完整sk_buff的相应字段
skb->when = jiffies;//用于TCP协议的超时重传
/*
* Find the IP header and set the length. This is bad
* but once we get the skb data handling code in the
* hardware will push its header sensibly and we will
* set skb->ip_hdr to avoid this mess and the fixed
* header length problem
*/
ptr = skb->data;//指针指向sk_buff中的数据部分
ptr += dev->hard_header_len;//hard_header_len为硬件首部长度,在net_init.c的函数eth_setup()函数中设置的,dev->hard_header_len = ETH_HLEN; 以太网首部长度为14
iph = (struct iphdr *)ptr;//prt已经指向IP数据包的首部
skb->ip_hdr = iph;
iph->tot_len = ntohs(skb->len-dev->hard_header_len);//计算IP数据报的总长度
#ifdef CONFIG_IP_FIREWALL
if(ip_fw_chk(iph, dev, ip_fw_blk_chain, ip_fw_blk_policy, 0) != 1)
/* just don't send this packet */
return;
#endif
/*
* No reassigning numbers to fragments...
*/
if(free!=2)
iph->id = htons(ip_id_count++);
else
free=1;
/* All buffers without an owner socket get freed */
if (sk == NULL)
free = 1;
skb->free = free;//设置skb的free值,free=1,发送后立即释放;free=2,不但释放缓存,而且不分配新的序列号
/*
* Do we need to fragment. Again this is inefficient.
* We need to somehow lock the original buffer and use
* bits of it.
*/
//数据帧中的数据部分必须小于等于MTU
if(skb->len > dev->mtu + dev->hard_header_len)//发送的数据长度大于数据帧的数据部分和帧首部之和,则需要分片
{
ip_fragment(sk,skb,dev,0);//对数据报分片后继续调用ip _queue_xmit()函数发送数据
IS_SKB(skb);
kfree_skb(skb,FREE_WRITE);
return;
}
/*
* Add an IP checksum
*/
ip_send_check(iph);//IP数据报首部检查
/*
* Print the frame when debugging
*/
/*
* More debugging. You cannot queue a packet already on a list
* Spot this and moan loudly.
*/
if (skb->next != NULL)//说明该数据包仍然存在于某个缓存队列
{
printk("ip_queue_xmit: next != NULL
");
skb_unlink(skb);//将其从缓存链表中删除,否则可能导致内核错误
}
/*
* If a sender wishes the packet to remain unfreed
* we add it to his send queue. This arguably belongs
* in the TCP level since nobody else uses it. BUT
* remember IPng might change all the rules.
*/
if (!free)//free=0
{
unsigned long flags;
/* The socket now has more outstanding blocks */
sk->packets_out++;
/* Protect the list for a moment */
save_flags(flags);
cli();
if (skb->link3 != NULL)//link3指向数据报道呃重发队列
{
printk("ip.c: link3 != NULL
");
skb->link3 = NULL;
}
//sk中send_tail和send_head是用户缓存的单向链表表尾和表头
if (sk->send_head == NULL)
{
sk->send_tail = skb;
sk->send_head = skb;
}
else
{
sk->send_tail->link3 = skb;//link3指针用于数据包的连接
sk->send_tail = skb;
}
/* skb->link3 is NULL */
/* Interrupt restore */
restore_flags(flags);
}
else
/* Remember who owns the buffer */
skb->sk = sk;
/*
* If the indicated interface is up and running, send the packet.
*/
ip_statistics.IpOutRequests++;
#ifdef CONFIG_IP_ACCT
ip_acct_cnt(iph,dev, ip_acct_chain);
#endif
#ifdef CONFIG_IP_MULTICAST //这部分是IP数据报的多播处理
/*
* Multicasts are looped back for other local users
*/
.......................................
#endif
if((dev->flags&IFF_BROADCAST) && iph->daddr==dev->pa_brdaddr && !(dev->flags&IFF_LOOPBACK))//广播数据包的处理
ip_loopback(dev,skb);
if (dev->flags & IFF_UP)//设备状态正常
{
/*
* If we have an owner use its priority setting,
* otherwise use NORMAL
*/
//调用设备接口层函数发送数据: dev_queue_xmit()函数
if (sk != NULL)
{
dev_queue_xmit(skb, dev, sk->priority);
}
else
{
dev_queue_xmit(skb, dev, SOPRI_NORMAL);
}
}
else//设备状态不正常
{
ip_statistics.IpOutDiscards++;
if (free)
kfree_skb(skb, FREE_WRITE);
}
}
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11