返回 登录
7

理解 Linux 网络栈(3):QEMU/KVM + VxLAN 环境下的 Segmentation Offloading 技术(发送端)

1. 测试环境

1.1 总体环境

  • 宿主机:Ubuntu Linux/KVM + VxLAN + Linux bridge,网卡 MTU 9000
  • 客户机:Ubuntu Linux + Virtio-net NIC,网卡 MTU 1500,使用 OpenStack Kilo 管理虚机

图片描述

发送端宿主机和客户机示意图

在发送端,虚机要把一个数据包发出去,需要首先把 packet 经过 virtio 设备发到宿主机的某个 linux bridge,网桥再转发到 xvlan 的虚拟网卡,虚拟网卡把它变成 VxLAN UDP frame,然后发往UDP 层,再通过TCP/IP层再次进行路由,数据包这次会被发往物理网络,并最终抵达接收端端。

1.2 客户机中使用的 virtio-net 虚拟网卡

客户机的 virtio-net 超虚拟化网卡其实是一个使用中断和 DMA 技术实现的 PCI 设备,因此可以使用 lspci 命令查看它的信息:

00:03.0 Ethernet controller [0200]: Red Hat, Inc Virtio network device [1af4:1000]

默认情况下,该网卡的 Segmentation Offloading 全部是打开的:

root@sammyubuntu1:~# ethtool -k eth0
Features for eth0:
rx-checksumming: on [fixed]
tx-checksumming: on
scatter-gather: on
tcp-segmentation-offload: on
udp-fragmentation-offload: on
generic-segmentation-offload: on
generic-receive-offload: on
large-receive-offload: off [fixed]

2. 发送端的实验和实现

2.1 实验

2.1.1 在客户机和宿主机网卡的 GSO/TSO/UFO 全部打开情况下的实验

(1)iperf 的 MSS 是 1448 bytes

root@sammyubuntu1:~# iperf -c 20.0.0.103 -l 65550 -m -M 400000
WARNING: attempt to set TCP maxmimum segment size to 400000 failed.
Setting the MSS may not be implemented on this OS.
------------------------------------------------------------
Client connecting to 20.0.0.103, TCP port 5001
TCP window size: 85.0 KByte (default)
------------------------------------------------------------
[  3] local 20.0.0.150 port 56228 connected with 20.0.0.103 port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-10.0 sec  1.06 GBytes   908 Mbits/sec
[  3] MSS size 1448 bytes (MTU 1500 bytes, ethernet)

实验表明,客户机中的TCP MSS 只和客户机网卡的 MTU 有关,和其它因素比如宿主机网卡 MTU 没有关系。而且,一个 TCP 连接的两个方向上的 MSS 是可以不同的。正是因为 MSS 的独立性,它可能会产生不同的后果,下文会有阐述。

另外一个有趣的结果是,客户机网卡的 MTU 的大小对网络性能的影响不大。在下面的测试中,客户机网卡 MTU 由 1500 提高到 8000,性能只提高了 6.8%。

<客户机网卡 MTU 1500,宿主机网卡 MTU 9000>
root@sammyubuntu1:~# iperf -c 20.0.0.103   -m
------------------------------------------------------------
Client connecting to 20.0.0.103, TCP port 5001
TCP window size: 85.0 KByte (default)
------------------------------------------------------------
[  3] local 20.0.0.150 port 56275 connected with 20.0.0.103 port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-10.0 sec  1.06 GBytes   909 Mbits/sec
[  3] MSS size 1448 bytes (MTU 1500 bytes, ethernet)

<客户机网卡 MTU 8000,宿主机网卡 MTU 9000>
root@sammyubuntu1:~# iperf -c 20.0.0.103   -m
------------------------------------------------------------
Client connecting to 20.0.0.103, TCP port 5001
TCP window size:  325 KByte (default)
------------------------------------------------------------
[  3] local 20.0.0.150 port 56274 connected with 20.0.0.103 port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-10.0 sec  1.14 GBytes   977 Mbits/sec
[  3] MSS size 7948 bytes (MTU 7988 bytes, unknown interface)

(2)客户机网卡:Frame 的 size 明显超过了 MSS,说明在启用了 GSO/TSO 的情况下,只要每个数据包不超过 IP 包的最大大小 64k,virtio-net 网卡就可以直接经过 virtqueue 发给 QEMU 中的backend。检验码报错,说明校验和计算被卸载到了网卡上,但是可能网卡计算错误。

07:56:04.857427 IP (tos 0x0, ttl 64, id 43384, offset 0, flags [DF], proto TCP (6), length 1500)
    20.0.0.150.56230 > 20.0.0.103.5001: Flags [.], cksum 0x2ecb (incorrect -> 0xc064), seq 438742392:438743840, ack 1, win 229, options [nop,nop,TS val 7353870 ecr 564507], length 1448 
07:56:10.861709 IP (tos 0x0, ttl 64, id 56589, offset 0, flags [DF], proto TCP (6), length 65212)
    20.0.0.150.56230 > 20.0.0.103.5001: Flags [.], cksum 0x27ac (incorrect -> 0x74c2), seq 1119980056:1120045216, ack 1, win 229, options [nop,nop,TS val 7355371 ecr 566008], length 65160

(3)宿主机上客户机网卡对应的 tap 设备:跟客户机网卡中看到的一样,说明 QEMU 中的 virtio-queue(backend)和 宿主机中的 tap 网络设备都是对这些 packets 直接发送的,没有做任何分包等操作。

08:12:23.443278 fa:16:3e:a3:a0:55 > fa:16:3e:1e:d9:f4, ethertype IPv4 (0x0800), length 61322: (tos 0x0, ttl 64, id 52865, offset 0, flags [DF], proto TCP (6), length 61308)
    20.0.0.150.56238 > 20.0.0.103.5001: Flags [.], cksum 0x186c (incorrect -> 0xad42), seq 896238816:896300072, ack 1, win 157, options [nop,nop,TS val 7598521 ecr 809156], length 61256
08:12:23.443355 fa:16:3e:a3:a0:55 > fa:16:3e:1e:d9:f4, ethertype IPv4 (0x0800), length 3030: (tos 0x0, ttl 64, id 52927, offset 0, flags [DF], proto TCP (6), length 3016)
    20.0.0.150.56238 > 20.0.0.103.5001: Flags [.], cksum 0x34b7 (incorrect -> 0x97b3), seq 896300072:896303036, ack 1, win 157, options [nop,nop,TS val 7598521 ecr 809156], length 2964

(4)宿主机内的连接 tap 设备和vxlan interface 的 linux bridge:帧的大小超过其 MTU,说明它直接转发经过 GSO/TSO 合并后的帧。

oot@hkg02kvm004ccz023:~# ifconfig brq137db7ce-a4
brq137db7ce-a4 Link encap:Ethernet  HWaddr 36:7e:1f:8e:65:a0
          UP BROADCAST RUNNING MULTICAST  MTU:8950  Metric:1
          RX packets:594948 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1058392082 (1.0 GB)  TX bytes:0 (0.0 B)

08:18:39.574679 fa:16:3e:a3:a0:55 > fa:16:3e:1e:d9:f4, ethertype IPv4 (0x0800), length 52430: (tos 0x0, ttl 64, id 1585, offset 0, flags [DF], proto TCP (6), length 52416)
    20.0.0.150.56238 > 20.0.0.103.5001: Flags [.], cksum 0xf5af (incorrect -> 0x47b1), seq 7027645:7080009, ack 0, win 157, options [nop,nop,TS val 7692554 ecr 903188], length 52364
08:18:39.574784 fa:16:3e:a3:a0:55 > fa:16:3e:1e:d9:f4, ethertype IPv4 (0x0800), length 52430: (tos 0x0, ttl 64, id 1638, offset 0, flags [DF], proto TCP (6), length 52416)

(5)宿主机内的 vxlan-interface:帧的大小超过其 MTU,说明它直接转发经过 GSO/TSO 合并后的帧

root@hkg02kvm004ccz023:~# ifconfig vxlan-97
vxlan-97  Link encap:Ethernet  HWaddr d6:7e:83:70:40:b2
          UP BROADCAST RUNNING MULTICAST  MTU:8950  Metric:1
          RX packets:44754025 errors:0 dropped:0 overruns:0 frame:0
          TX packets:5179964 errors:0 dropped:2 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:2381558146 (2.3 GB)  TX bytes:89661075401 (89.6 GB)

08:16:54.685914 fa:16:3e:a3:a0:55 > fa:16:3e:1e:d9:f4, ethertype IPv4 (0x0800), length 1054: (tos 0x0, ttl 64, id 14493, offset 0, flags [DF], proto TCP (6), length 1040)
    20.0.0.150.56238 > 20.0.0.103.5001: Flags [.], cksum 0x2cff (incorrect -> 0x3143), seq 60291712:60292700, ack 1, win 157, options [nop,nop,TS val 7666332 ecr 876964], length 988
08:16:54.685936 fa:16:3e:a3:a0:55 > fa:16:3e:1e:d9:f4, ethertype IPv4 (0x0800), length 24766: (tos 0x0, ttl 64, id 14494, offset 0, flags [DF], proto TCP (6), length 24752)
    20.0.0.150.56238 > 20.0.0.103.5001: Flags [.], cksum 0x899f (incorrect -> 0xf01d), seq 60292700:60317400, ack 1, win 157, options [nop,nop,TS val 7666332 ecr 876964], length 24700

(6)宿主机 VxLAN UDP socket 所绑定的物理网卡:测试了三种情况,证明了网卡是按照 MSS 进行 IP 分片的。

TCP 连接的 MSS 是 988 时:
08:19:34.286094 IP 10.110.156.43.33980 > 10.110.156.42.4789: VXLAN, flags [I] (0x08), vni 97
IP 20.0.0.150.56238 > 20.0.0.103.5001: Flags [.], seq 96306288:96307276, ack 1, win 157, options [nop,nop,TS val 7706232 ecr 916866], length 988

当 TCP 连接的 MSS 是 1448 时:
07:45:24.008510 IP 10.110.156.43.44429 > 10.110.156.42.4789: VXLAN, flags [I] (0x08), vni 97
IP 20.0.0.150.56228 > 20.0.0.103.5001: Flags [.], seq 126000:127448, ack 1, win 229, options [nop,nop,TS val 7193663 ecr 404323], length 1448

如果将网卡的 MTU 调到比 MSS (1448)还小,比如 1400,则会出现 IP 分片,说明 GSO 还是按照 MSS 分段,而不是按照 MTU 或者 [MTU, MSS] 中的较小值来分段:
08:39:35.743048 IP 10.110.156.43.41903 > 10.110.156.42.4789: VXLAN, flags [I] (0x08), vni 97
IP truncated-ip - 154 bytes missing! 20.0.0.150.56246 > 20.0.0.103.5001: Flags [.], seq 12179152:12180600, ack 1, win 188, options [nop,nop,TS val 8006596 ecr 1217232], length 1448

2.1.2 在客户机关闭 GSO/TSO/UFO

root@sammyubuntu1:~# iperf -c 20.0.0.103 -l 65550  -m
------------------------------------------------------------
Client connecting to 20.0.0.103, TCP port 5001
TCP window size:  325 KByte (default)
------------------------------------------------------------
[  3] local 20.0.0.150 port 56269 connected with 20.0.0.103 port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-10.0 sec  1.00 GBytes   859 Mbits/sec
[  3] MSS size 1448 bytes (MTU 1500 bytes, ethernet)

客户机网卡:在客户机 CPU 中进行了 TCP 分段
10:02:41.474750 IP (tos 0x0, ttl 64, id 59282, offset 0, flags [DF], proto TCP (6), length 1500)
    20.0.0.150.56269 > 20.0.0.103.5001: Flags [.], cksum 0x2ecb (incorrect -> 0x1924), seq 1795544:1796992, ack 1, win 229, options [nop,nop,TS val 9253025 ecr 2463660], length 1448

该过程说明客户机中产生了 TCP 分段;对网络性能有一定的下降。

2.1.3 虚机 TSO/GSO 打开 和宿主机的 GSO/TSO 关闭

客户机网卡:传输 GSO 大帧
09:47:35.894971 IP (tos 0x0, ttl 64, id 5902, offset 0, flags [DF], proto TCP (6), length 65212)
    20.0.0.150.56263 > 20.0.0.103.5001: Flags [.], cksum 0x27ac (incorrect -> 0xdeb7), seq 893020126:893085286, ack 1, win 229, options [nop,nop,TS val 9026630 ecr 2237265], length 65160vxlan-interface 设备:直接转发
09:53:15.457088 fa:16:3e:a3:a0:55 > fa:16:3e:1e:d9:f4, ethertype IPv4 (0x0800), length 65226: (tos 0x0, ttl 64, id 43361, offset 0, flags [DF], proto TCP (6), length 65212)
    20.0.0.150.56267 > 20.0.0.103.5001: Flags [.], cksum 0x27ac (incorrect -> 0x2e18), seq 1127931208:1127996368, ack 1, win 229, options [nop,nop,TS val 9111525 ecr 2322160], length 65160

宿主机物理网卡:发送sizeTCP MSS 的小帧
09:50:41.251821 IP 10.110.156.43.12914 > 10.110.156.42.4789: VXLAN, flags [I] (0x08), vni 97
IP 20.0.0.150.56265 > 20.0.0.103.5001: Flags [.], seq 80044016:80045464, ack 1, win 229, options [nop,nop,TS val 9072973 ecr 2283609], length 1448

该过程说明这里产生了 UDP/IP 分片。

2.1.4 TCP 传输性能比较

客户机和宿主机GSO/TSO/UFO都打开 > 客户机打开宿主机关闭 > 客户机关闭。

2.2 Linux 内核支持 GSO for UDP tunnels:“udp: Generalize GSO for UDP tunnels”

这个支持是在 2014 年才加入 Linux 内核的,更多信息请参考原文 https://lwn.net/Articles/613999/。这个 patch 在 GSO 中添加了对 UDP 隧道技术的支持。

  • 需要在 skb 发到 UDP 协议栈之前,添加一个新的 option:inner_protocol,可以使用方法 skb_set_inner_ipproto 或者 skb_set_inner_protocol 来设置。vxlan driver 中的相关代码为 skb_set_inner_protocol(skb, htons(ETH_P_TEB));
  • 函数skb_udp_tunnel_segment 会检查该 option 再处理分段。
  • 支持多种类型的封装,包括 SKB_GSO_UDP_TUNNEL{_CSUM}

2.3 VxLAN 的实现

代码在这里:https://github.com/torvalds/linux/blob/master/drivers/net/vxlan.c

2.3.1 VxLAN interface

跟名字一样,VxLAN interface 也是当做一个 network device interface 来使用的,vxlan.c 文件中实现了其驱动的逻辑。它处于数据链路层的 device driver 层,实现了 vxlan interface 的 device driver。vxlan interface 同样可以使用 ethtool 查看其 segmentation offloading 能力:

root@hkg02kvm004ccz023:~# ethtool -k vxlan-4 | grep offload
tcp-segmentation-offload: on
udp-fragmentation-offload: on
generic-segmentation-offload: on
generic-receive-offload: on
large-receive-offload: off [fixed]
rx-vlan-offload: off [fixed]
tx-vlan-offload: on
l2-fwd-offload: off [fixed]

其驱动设置了 net_device_ops结构体变量, 其中定义了操作 net_device 的重要函数,vxlan在驱动程序中根据需要的操作要填充这些函数,其中主要是 packets 的接收和发送处理函数。

static const struct net_device_ops vxlan_netdev_ops = {
    .ndo_init        = vxlan_init,      
    .ndo_uninit        = vxlan_uninit,
    .ndo_open        = vxlan_open,
    .ndo_stop        = vxlan_stop,
    .ndo_start_xmit        = vxlan_xmit,  #向 vxlan interface 发送 packet
    ...
};

来看看代码实现:

(1)首先看 static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) 方法,它的输入就是要传输的 packets 所对应的 sk_buff 以及要经过的 vxlan interface dev:

图片描述

它的主要逻辑是获取 vxlan dev,然后为 sk_buff 中的每一个 skb 调用 vxlan_xmit_skb 方法。

#该方法主要逻辑是,计算 tos,ttl,df,src_port,dst_port,md 以及 flags等,然后调用 vxlan_xmit_skb 方法。
err = vxlan_xmit_skb(rt, sk, skb, fl4.saddr,
                     dst->sin.sin_addr.s_addr, tos, ttl, df,
                     src_port, dst_port, htonl(vni << 8), md,
                     !net_eq(vxlan->net, dev_net(vxlan->dev)),
                     flags);

(2)vxlan_xmit_skb 函数修改了 skb,添加了 VxLAN Header,以及设置 GSO 参数。

static int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
              __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
              __be16 src_port, __be16 dst_port, __be32 vni,
              struct vxlan_metadata *md, bool xnet, u32 vxflags)
{
    ...int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; #计算 GSO UDP 相关的 offload type,使得能够利用内核 GSO for UDP Tunnel
    u16 hdrlen = sizeof(struct vxlanhdr); #计算 vxlan header 的长度
    ...
    #计算 skb 新的 headroom,其中包含了 VXLAN Header 的长度
    min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len + VXLAN_HLEN + sizeof(struct iphdr)
            + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);

    /* Need space for new headers (invalidates iph ptr) */
    err = skb_cow_head(skb, min_headroom); #使得 skb head 可写
    ...
    skb = vlan_hwaccel_push_inside(skb); #处理 vlan 相关事情
    ...
    skb = iptunnel_handle_offloads(skb, udp_sum, type); #设置 checksum 和 type
    ...
    vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); #扩展 skb data area,来容纳 vxlan header
    vxh->vx_flags = htonl(VXLAN_HF_VNI);
    vxh->vx_vni = vni;
    ... if (vxflags & VXLAN_F_GBP)
        vxlan_build_gbp_hdr(vxh, vxflags, md);

    skb_set_inner_protocol(skb, htons(ETH_P_TEB)); #设置 Ethernet protocol,这是 GSO 在 UDP tunnel 中必须要的

    udp_tunnel_xmit_skb(rt, sk, skb, src, dst, tos, ttl, df, #调用 linux 网络栈接口,将 skb 传给 udp tunnel 协议栈继续处理
                src_port, dst_port, xnet, !(vxflags & VXLAN_F_UDP_CSUM));
    return 0;
}

图片描述

(3)接下来就进入了 Linux TCP/IP 协议栈,从 UDP 进入,然后再到 IP 层。如果硬件支持,则由硬件调用 linux 内核中的 UDP GSO 函数;如果硬件不支持,则在进入 device driver queue 之前由 linux 内核调用 UDP GSO 分片函数。然后再一直往下到网卡。

最终在这个函数 ip_finish_output_gso 里面,先调用 GSO分段函数,如果需要的话,再进行 IP 分片:

static int ip_finish_output_gso(struct net *net, struct sock *sk,
                                 struct sk_buff *skb, unsigned int mtu)
 {
         netdev_features_t features;
         struct sk_buff *segs;
         int ret = 0;

         /* Slowpath -  GSO segment length is exceeding the dst MTU.
          *
          * This can happen in two cases:
          * 1) TCP GRO packet, DF bit not set
          * 2) skb arrived via virtio-net, we thus get TSO/GSO skbs directly
          * from host network stack.
          */
         features = netif_skb_features(skb);
         segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); #这里最终会调用到 UDP 的 gso_segment 回调函数进行 UDP GSO 分段
         if (IS_ERR_OR_NULL(segs)) {
                 kfree_skb(skb);
                 return -ENOMEM;
         }

         consume_skb(skb);

         do {
                 struct sk_buff *nskb = segs->next;
                 int err;

                 segs->next = NULL;
                 err = ip_fragment(net, sk, segs, mtu, ip_finish_output2); #需要的话,再进行 IP 分片,因为 UDP GSO 是按照 MSS 进行,MSS 还是有可能超过 IP 分段所使用的宿主机物理网卡 MTU 的 
                 if (err && ret == 0)
                         ret = err;
                 segs = nskb;
         } while (segs);

         return ret;
 }

这是 UDP 层所注册的 gso 回调函数:

static const struct net_offload udpv4_offload = {
    .callbacks = {
        .gso_segment = udp4_ufo_fragment,
        .gro_receive  =    udp4_gro_receive,
        .gro_complete =    udp4_gro_complete,
    },
};

它的实现在这里:

static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb, netdev_features_t features,
    struct sk_buff *(*gso_inner_segment)(struct sk_buff *skb, netdev_features_t features), __be16 new_protocol)
{
    .../* segment inner packet. */ #先调用内层的 分段函数进行分段
    enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
    segs = gso_inner_segment(skb, enc_features);
    ...
    skb = segs;
    do { #执行 UDP GSO 分段
        struct udphdr *uh;
        int len;

        skb_reset_inner_headers(skb);
        skb->encapsulation = 1;

        skb->mac_len = mac_len;

        skb_push(skb, outer_hlen);
        skb_reset_mac_header(skb);
        skb_set_network_header(skb, mac_len);
        skb_set_transport_header(skb, udp_offset);
        len = skb->len - udp_offset;
        uh = udp_hdr(skb);
        uh->len = htons(len);
        ...
        skb->protocol = protocol;
    } while ((skb = skb->next));
out:
    return segs;
}

struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, netdev_features_t features, bool is_ipv6)
{
    ...switch (skb->inner_protocol_type) { #计算内层的分片方法
    case ENCAP_TYPE_ETHER: #感觉 vxlan 的 GSO 应该是走这个分支,相当于是将 VXLAN 所封装的二层帧当做 payload 来分段,而不是将包含 VXLAN Header 的部分来分
        protocol = skb->inner_protocol;
        gso_inner_segment = skb_mac_gso_segment;
        break;
    case ENCAP_TYPE_IPPROTO:
        offloads = is_ipv6 ? inet6_offloads : inet_offloads;
        ops = rcu_dereference(offloads[skb->inner_ipproto]);
        if (!ops || !ops->callbacks.gso_segment)
            goto out_unlock;
        gso_inner_segment = ops->callbacks.gso_segment;
        break;
    default:
        goto out_unlock;
    }

    segs = __skb_udp_tunnel_segment(skb, features, gso_inner_segment,
                    protocol);
    ...
    return segs; #返回分片好的seg list
}

这里比较有疑问的是,VXLAN 没有定义 gso_segment 回调函数,这导致有可能在 UDP GSO 分段里面没有完整的 VXLAN Header。。这需要进一步研究。原因可能是在 inner segment 那里,分段是将 UDP 所封装的二层帧当做 payload 来分段,因此,VXLAN Header 就会保持在每个分段中。

(4)可见,在整个过程中,有客户机上 TCP 协议层设置的 skb_shinfo(skb)->gso_size 始终保持不变为 MSS,因此,在网卡中最终所做的针对 UDP GSO 数据报的 GSO 分片所依据的分片的长度还是根据 skb_shinfo(skb)->gso_size 的值即 TCP MSS。

3. 发送端现有方案的问题和改进方法

3.1 问题

从上面所描述的过程可以看出来,目前的 VXLAN 协议和实现中存在一个问题,那就是:最终在宿主机上所做的 IP 分片是根据客户机中 TCP 连接的 MSS 来进行的,而实际的网络环境中,宿主机的网卡的 MTU 往往采用巨帧技术设置为 9000 bytes,而客户机的网卡 MTU 往往使用默认的 1500 bytes,在接收端也是同样类型的节点的情况下,目前的分片方式存在很大的资源浪费。

理想的情况分为几种:

(1)如果接收端是同样的采用 VXLAN VETP 的节点,IP 分片应该按照物理网卡的 MTU 进行,到了对端做了 IP 分片重组后,直接由 VXLAN VTEP 交给虚机。

(2)如果对方是将会连接外网的 VXLAN Gateway 节点,那对端 VXLAN VTEP 收到 IP 分片重组后的大网络包后,它自己或者使用 Linux 网络协议栈 segmentation offloading 技术对大包进行分片,然后再转发到外网。

(3)如果对方是普通网络节点(此时发送端是 VXLAN Gateway 节点),那么走当前的模式,根据 TCP MSS 使用 UDP/IP 分片,再发出去。

3.2 一种实现方案

文章Segmentation Offloading Extension for VXLAN提出了一种 VXLAN Segmentation Offloading Extension (VXLAN-soe) 实现方案。该方案扩展了 VXLAN Header,添加了几个新的标志位:(S - 标志位,是否使用该技术; Overlay MSS Hi 和 Lo:对 TCP,就是 MSS;对 UDP,就是 MTU)

图片描述

发送端 VXLAN VTEP 根据配置或者别的条件

  • 设置 S = 1,表示 offload segmentation 到对端节点上的 VXLAN VTEP,并设置 Overlay MSS Hi 和 Lo
  • 设置 S= 0,表示不做 remote segmentation offloading,做普通的处理

接收端 VXLAN Hypervisor VTEP 将检查 S 标志位:

  • 如果为 1,则不做 MTU 检查,直接将包交给虚机
  • S 标志位,如果为 0,则走普通处理流程

接收端 VXLAN Gateway VTEP:

  • 检查 S 标志位,如果为 1,则它自己或者利用 segmentation offloading 技术做分片

该方案的问题是当 S = 1 时,会产生 UDP/IP 分片。


作者信息:刘世民(Sammy Liu),IBM 云架构师,十余年IT行业从业经历,在电信、企业软件、存储以及云计算等领域做过研发、管理和架构设计等工作。从 2012 年开始学习 OpenStack,对其核心模块有较深入的了解;带领过团队开发OpenStack模块。

责编:陈晨 欢迎投稿,chenchenjs#csdn.net


2016年4月22日-23日,由CSDN重磅打造的SDCC 2016数据库&架构技术峰会将在深圳举行,目前18位讲师和议题已全部确认。两场峰会大牛讲师来自百度、腾讯、阿里、京东、小米、唯品会、滴滴出行、携程等知名互联网公司,共同探讨高可用/高并发/高稳定/高流量的系统架构设计、秒杀系统架构、搜索架构、中小企业架构之道、数据平台系统演进历程和技术剖析、传统数据库与分布式数据库选型/备份/恢复原理及优化实践、大数据应用实战等领域的热点话题与技术。【目前限时6折,点击这里抢票

评论