作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
- /*
- ...... ......
- * @cork - info to build ip hdr on each ip frag while socket is corked
-
*/
-
struct inet_sock {
-
/* sk and pinet6 has to be the first two members of inet_sock */
-
struct sock sk;
- ...... ......
- struct {
-
unsigned int flags;
-
unsigned int fragsize;
-
struct ip_options *opt;
-
struct dst_entry *dst;
-
int length; /* Total length of all frames */
-
__be32 addr;
-
struct flowi fl;
-
} cork;
- };
从注释上看,这个cork是用于ip报文分片。那么究竟是不是这样的呢,如果是的话,它在分片中起得作用又是什么呢?
搜索整个linux目录,cork在四个文件中被使用,分别是ip6_output.c,ip_output.c,raw.c,和udp.c。其中ip6_output是为了支持IPv6,逻辑与ip_output.c应该大同小异,所以就不需要关注这个文件。
首先,关注一下cork何时被赋值
1. ip_output.c中的ip_append_data函数
- if (skb_queue_empty(&sk->sk_write_queue)) {
- /*
- * setup for corking.
- */
- /* 设置cork*/
- opt = ipc->opt;
- if (opt) {
- /* 将ip option保存到cork中 */
- if (inet->cork.opt == NULL) {
- inet->cork.opt = kmalloc(sizeof(struct ip_options) + 40, sk->sk_allocation);
-
if (unlikely(inet->cork.opt == NULL))
- return -ENOBUFS;
-
}
-
memcpy(inet->cork.opt, opt, sizeof(struct ip_options)+opt->optlen);
-
inet->cork.flags |= IPCORK_OPT;
-
inet->cork.addr = ipc->addr;
-
}
-
rt = *rtp;
-
if (unlikely(!rt))
-
return -EFAULT;
-
/*
-
* We steal reference to this route, caller should not release it
-
*/
-
*rtp = NULL;
- /*
- 保存分片大小。根据是否enable了PMTU探测,来得到分片的大小,PMTU或者MTU。
- */
-
inet->cork.fragsize = mtu = inet->pmtudisc == IP_PMTUDISC_PROBE ?
-
rt->dst.dev->mtu :
-
dst_mtu(rt->dst.path);
- /* 保存下一跳信息 */
- inet->cork.dst = &rt->dst;
- inet->cork.length = 0;
- }
2. udp.c中 udp_sendmsg
- back_from_confirm:
- ...... ......
- /*
- * Now cork the socket to pend data.
- */
- /* 保存流量控制信息 */ inet->cork.fl.fl4_dst = daddr;
- inet->cork.fl.fl_ip_dport = dport;
- inet->cork.fl.fl4_src = saddr;
- inet->cork.fl.fl_ip_sport = inet->inet_sport;
而对cork的使用也集中于这两个文件。
1. 在ip_append_data中,如果该sk的sk_write_queue不为空的话,就会直接使用cork中的下一跳信息(cork->dst),ip报文的option(cork->opt),MTU值(cork->fragsize)。且每次ip_append_data成功时,cork->length都会加上该次的数据长度。这说明了这个length为所有sk_write_queue中的数据总长度。
2. 在udp_push_pending_frames中,linux需要从cork中获得udp头部所需要的信息源地址,目的地址,包长等。
cork的释放是通过ip_cork_release来完成的。调用ip_cork_release的函数一共有两个函数ip_push_pending_frames和ip_flush_pending_frames。当数据成功append或者push后,就会调用ip_push_pending_frames完成发送动作,并是否cork。如果出错,则调用ip_flush_pending_frames。
到此,可以明确了cork的用途了。
1.cork保存了同一个IP包中的一些共用信息。主要用于分片,或者多个数据组成一个IP报文发送时;
2.cork在udp中可以保存UDP首部需要的信息。这样当append UDP数据时,不需要通过参数传递这些信息;