免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: scutan
打印 上一主题 下一主题

请教关于UDP的一个问题 [复制链接]

论坛徽章:
0
1 [报告]
发表于 2008-08-25 20:37 |显示全部楼层
tcp/ip卷1上说的是IP分片的,但是实现可能在UDP层就分片了,为了效率的原因
我看了一下,代码很多,不知下面的有没有错

udp_sendmsg:

do_append_data:
    up->len += ulen;
    err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen,
            sizeof(struct udphdr), &ipc, rt,
            corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
    if (err)
        udp_flush_pending_frames(sk);
    else if (!corkreq)
        err = udp_push_pending_frames(sk, up);





ip_append_data:

    while (length > 0) {
        /* Check if the remaining data fits into current packet. */
        copy = mtu - skb->len;
        if (copy < length)
            copy = maxfraglen - skb->len;
        if (copy <= 0) {
            char *data;
            unsigned int datalen;
            unsigned int fraglen;
            unsigned int fraggap;
            unsigned int alloclen;
            struct sk_buff *skb_prev;
alloc_new_skb:
            skb_prev = skb;
            if (skb_prev)
                fraggap = skb_prev->len - maxfraglen;
            else
                fraggap = 0;

            /*
             * If remaining data exceeds the mtu,
             * we know we need more fragment(s).
             */

            datalen = length + fraggap;
            if (datalen > mtu - fragheaderlen)
                datalen = maxfraglen - fragheaderlen;
            fraglen = datalen + fragheaderlen;

            if ((flags & MSG_MORE) &&
                !(rt->u.dst.dev->features&NETIF_F_SG))
                alloclen = mtu;
            else
                alloclen = datalen + fragheaderlen;

            /* The last fragment gets additional space at tail.
             * Note, with MSG_MORE we overallocate on fragments,
             * because we have no idea what fragment will be
             * the last.
             */

            if (datalen == length)
                alloclen += rt->u.dst.trailer_len;

            if (transhdrlen) {
                skb = sock_alloc_send_skb(sk,
                        alloclen + hh_len + 15,
                        (flags & MSG_DONTWAIT), &err);
            } else {
                skb = NULL;
                if (atomic_read(&sk->sk_wmem_alloc) <=
                    2 * sk->sk_sndbuf)
                    skb = sock_wmalloc(sk,
                               alloclen + hh_len + 15, 1,
                               sk->sk_allocation);
                if (unlikely(skb == NULL))
                    err = -ENOBUFS;
            }
            if (skb == NULL)
                goto error;

            /*
             *    Fill in the control structures
             */

            skb->ip_summed = csummode;
            skb->csum = 0;
            skb_reserve(skb, hh_len);

            /*
             *    Find where to start putting bytes.
             */

            data = skb_put(skb, fraglen);
            skb->nh.raw = data + exthdrlen;
            data += fragheaderlen;
            skb->h.raw = data + exthdrlen;

            if (fraggap) {
                skb->csum = skb_copy_and_csum_bits(
                    skb_prev, maxfraglen,
                    data + transhdrlen, fraggap, 0);
                skb_prev->csum = csum_sub(skb_prev->csum,
                              skb->csum);
                data += fraggap;
                skb_trim(skb_prev, maxfraglen);
            }

            copy = datalen - transhdrlen - fraggap;
            if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) {
                err = -EFAULT;
                kfree_skb(skb);
                goto error;
            }

            offset += copy;
            length -= datalen - fraggap;
            transhdrlen = 0;
            exthdrlen = 0;
            csummode = CHECKSUM_NONE;

            /*
             * Put the packet on the pending queue.
             */

            __skb_queue_tail(&sk->sk_write_queue, skb);
            continue;
        }

        if (copy > length)
            copy = length;

        if (!(rt->u.dst.dev->features&NETIF_F_SG)) {
            unsigned int off;

            off = skb->len;
            if (getfrag(from, skb_put(skb, copy),
                    offset, copy, off, skb) < 0) {
                __skb_trim(skb, off);
                err = -EFAULT;
                goto error;
            }
        } else {
            int i = skb_shinfo(skb)->nr_frags;
            skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];
            struct page *page = sk->sk_sndmsg_page;
            int off = sk->sk_sndmsg_off;
            unsigned int left;

            if (page && (left = PAGE_SIZE - off) > 0) {
                if (copy >= left)
                    copy = left;
                if (page != frag->page) {
                    if (i == MAX_SKB_FRAGS) {
                        err = -EMSGSIZE;
                        goto error;
                    }
                    get_page(page);
                     skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0);
                    frag = &skb_shinfo(skb)->frags[i];
                }
            } else if (i < MAX_SKB_FRAGS) {
                if (copy > PAGE_SIZE)
                    copy = PAGE_SIZE;
                page = alloc_pages(sk->sk_allocation, 0);
                if (page == NULL)  {
                    err = -ENOMEM;
                    goto error;
                }
                sk->sk_sndmsg_page = page;
                sk->sk_sndmsg_off = 0;

                skb_fill_page_desc(skb, i, page, 0, 0);
                frag = &skb_shinfo(skb)->frags[i];
                skb->truesize += PAGE_SIZE;
                atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc);
            } else {
                err = -EMSGSIZE;
                goto error;
            }
            if (getfrag(from, page_address(frag->page)+frag->page_offset+frag->size, offset, copy, skb->len, skb) < 0) {
                err = -EFAULT;
                goto error;
            }
            sk->sk_sndmsg_off += copy;
            frag->size += copy;
            skb->len += copy;
            skb->data_len += copy;
        }
        offset += copy;
        length -= copy;
    }


从这段代码中我认为是分片在udp中就结束了,因为udp从路由表中找到了mtu

论坛徽章:
0
2 [报告]
发表于 2008-08-25 22:31 |显示全部楼层
代码是2.6.11

论坛徽章:
0
3 [报告]
发表于 2008-08-26 16:23 |显示全部楼层
原帖由 Solaris12 于 2008-8-26 16:16 发表



不清楚Linux的实现,但我要说的是,所谓的协议栈的层,是抽象的概念,其实某层的code很可能就是一个个函数,UDP调用IP的函数就可以了。

所以所谓分层只不过是抽象和总结而已,在内核看,可能某一层不存 ...

同意,确实有的时候就是一个函数的调用,而且越是这样简单的接口,层的概念反到清晰
udp包大了,肯定是要分片的,不过这个地方tcpdump是无法区别在哪儿分片的

论坛徽章:
0
4 [报告]
发表于 2008-08-26 16:51 |显示全部楼层
原帖由 scutan 于 2008-8-26 16:38 发表
找到了下面这个链接, 讲ip_append_data的
http://hi.baidu.com/linux_kernel ... 363343fbf2c0dc.html

果然
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP