天天看點

tcp/ip源碼(18)——struct inet_sock中的cork用途

作者:[email protected]

部落格:linuxfocus.blog.chinaunix.net

在前面的學習過程中,遇到了位于struct inet_sock中的cork,當時沒有把這個變量搞得很明白,沒有完全搞清這個變量的用途。

 /*

 ...... ......

 * @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資料時,不需要通過參數傳遞這些資訊;

繼續閱讀