标签:e30 world via 运行 master arp 接收 组织 ova
http://www.cnblogs.com/sammyliu/p/4985907.html
VXLAN 是一个新兴的SDN 标准,它定义了一种新的 overlay 网络,它主要的创造者是 VMware, Cisco 和 Arista。它被设计来消除虚拟化网络世界中的 VLAN 数目的限制。VXLAN 本身是一个多播标准,但是大多数的企业既不情愿启用多播,而且许多网络设备也不支持多播。因此,许多 VXLAN 的实现,比如 Linux vxlan, 就既支持多播也支持单播。VXLAN 的两个主要概念是 VTEP 和 VXLAN ID。 其中,VTEP 负责解包和封包,以及包的传送。它可以由专有硬件来实现,也可以使用纯软件实现。目前比较成熟的软件实现的 VTEP 包括:
以 vSphere 为例,下面是它所实现的 VXLAN 虚拟二层网络的一个参考架构:
可以看出来,这和 Open vSwitch 的网络架构非常类似。对于 Linux 作为 VTEP 来说,使用 linux bridge 替代 VMware 的 VDS 或者 Open vSwitch,其它也是一样的了。
特点:
因此:
VXLAN 组件 | vSphere | Linux | Open vSwitch (OVS) |
VTEP | vSphere | Linux | OVS |
Bridge | VDS | Linux bridge | OVS |
这是单播、多播和广播的概念:
一个多播IP网络示例:
多播的一些基础知识:
要支持多播,需要物理网络上做一些设置:
比如:
在支持 vxlan 的 Linux 主机上,可以创建多个多播或者单播的 vxlan interface,每个interface 是一个 vxlan tunnel 的 endpoint。比如在主机1上:
创建多播 interface 1:ip link add vxlan0 type vxlan id 42 group 239.1.1.1 dev eth1 dstport 4789 创建多播 interface 2:ip link add vxlan2 type vxlan id 43 group 239.1.1.2 dev eth1 dstport 4790 创建单播 interface 3:ip link add vxlan2 type vxlan id 44 dev eth1 port 32768 61000 proxy ageing 300
然后在每一个设备启动后,如果使用的是多播地址,vxlan 就会加入相应的多播组,并且创建相应的 UDP socket。
/* Start ageing timer and join group when device is brought up */ static int vxlan_open(struct net_device *dev) #对每个 vxlan dev 使用 { ...... ret = vxlan_sock_add(vxlan); #创建 UDP socket if (ret < 0) return ret; if (vxlan_addr_multicast(&vxlan->default_dst.remote_ip)) { ret = vxlan_igmp_join(vxlan); #加入多播组 ...... } } ..... }
在主机2上,使用同样的 dstport, group 和 vxlan id 创建相应的 vxlan interface,即可创建多个虚拟的 vxlan tunnel。
因此,只要没有冲突,一个Linux 主机上可以加入多个多播组,创建多个 UDP socket。
Linux vxlan 模块的代码在 https://github.com/torvalds/linux/blob/master/drivers/net/vxlan.c
我们都知道,OpenStack 社区官方的安装文档的步骤都是以 Open vSwitch 为例子的。而且从OpenStack 用户调查来看,使用 OVS 的人比使用 linux bridge 多很多。
那还有人使用 Linux bridge 吗?答案是有的,据我所知,国内厂商比如海云捷迅就推荐私有云中的两种配置:Linux bridge + VLAN 以及 Linux bridge + VxLAN。而且,Liberty 版本之前社区官方文档都是使用 neutron-plugin-openvswitch-agent, 但是 Liberty 版本转为使用 neutron-plugin-linuxbridge-agent, 不知道这背后究竟发生了什么。国外的 Rackspace 也已经使用Linux bridge 替代 Open vSwitch,请参见下图:
本段以 Rackspace 为例,说明他们使用 Linux bridge 的理由:
(4)长期来看,随着稳定性的进一步提高,Open vSwitch 会在生产环境中成为主流。
Linux bridge 和 Open vSwitch 的功能对比:
可以看出:
(1)OVS 将各种功能都原生地实现在其中,这在起始阶段不可避免地带来潜在的稳定性和可调试性问题
(2)Linux bridge 依赖各种其他模块来实现各种功能,而这些模块的发布时间往往都已经很长,稳定性较高
(3)两者在核心功能上没有什么差距,只是在集中管控和性能优化这一块OVS有一些新的功能或者优化。但是,从测试结果看,两者的性能没有明显差异:
总之,目前,除了 SDN 对集中管控的需求,Linux bridge 是个较好的选择。
在控制、网络和计算节点上修改 /etc/neutron/plugins/ml2/ml2_conf.ini 中的如下配置项:
[ml2] type_drivers = flat,vlan,gre,vxlan tenant_network_types = vxlan mechanism_drivers = linuxbridge [ml2_type_vxlan] vni_ranges = 1001:2000 [vxlan] local_ip = 10.0.0.13 enable_vxlan = true [securitygroup] firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver [agent] tunnel_types = vxlan
计算节点1上有三个虚机,分布在两个网络上:
(1)两个 Linux bridge
root@compute1:~# brctl show bridge name bridge id STP enabled interfaces brq18fc2ba1-05 8000.9292780d149d no tap5d8a021b-64 tapf64dcdd0-0e vxlan-1074 brq243661e7-f7 8000.66239c87f16c no tap818682fe-a6 vxlan-1027
(2)VXLAN 在端口 8472 上创建了一个 UDP Socket
root@compute1:~# netstat -lu Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State udp 0 0 192.168.122.1:domain *:* udp 0 0 *:bootps *:* udp 768 0 *:8472 *:*
(3)创建了两个 vxlan network interface
root@compute1:~# ip -d link show dev vxlan-1074 14: vxlan-1074: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master brq18fc2ba1-05 state UNKNOWN mode DEFAULT group default link/ether 92:92:78:0d:14:9d brd ff:ff:ff:ff:ff:ff promiscuity 1 vxlan id 1074 group 224.0.0.1 dev eth1 port 32768 61000 ageing 300 root@compute1:~# ip -d link show dev vxlan-1027 12: vxlan-1027: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master brq243661e7-f7 state UNKNOWN mode DEFAULT group default link/ether 66:23:9c:87:f1:6c brd ff:ff:ff:ff:ff:ff promiscuity 1 vxlan id 1027 group 224.0.0.1 dev eth1 port 32768 61000 ageing 300
(4)vxlan interface 使用网卡 eth1
网络节点上:
(1)一个 qrouter network namespace
(2)三个 dhcp network namespace,每个 enable DHCP 的网络各一个
(3)三个 Linux bridge,每个 network 一个
(4)三个 vxlan network interface(ip link),每个 network 一个 bridge, 每个 linux bridge 上只有一个 vxlan interface
root@controller:~/s1# ip -d link show dev vxlan-1027 11: vxlan-1027: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master brq243661e7-f7 state UNKNOWN mode DEFAULT group default link/ether a6:6b:39:67:60:68 brd ff:ff:ff:ff:ff:ff promiscuity 1 vxlan id 1027 group 224.0.0.1 dev eth1 port 32768 61000 ageing 300 root@controller:~/s1# ip -d link show dev vxlan-1074 5: vxlan-1074: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master brq18fc2ba1-05 state UNKNOWN mode DEFAULT group default link/ether 8a:e2:2f:2d:e7:48 brd ff:ff:ff:ff:ff:ff promiscuity 1 vxlan id 1074 group 224.0.0.1 dev eth1 port 32768 61000 ageing 300 root@controller:~/s1# ip -d link show dev vxlan-1054 8: vxlan-1054: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master brq1e7052dc-7f state UNKNOWN mode DEFAULT group default link/ether 5e:c7:d4:85:23:fc brd ff:ff:ff:ff:ff:ff promiscuity 1 vxlan id 1054 group 224.0.0.1 dev eth1 port 32768 61000 ageing 300
(5)vxlan 在 8472 端口上监听 UDP 请求
(6)vxlan interface 的广播网卡是 eth1
注:红色线条为计算节点1上的vm3访问 DHCP Agent 来获取 IP 地址;蓝色线条为同一个网段的 VM3 和 VM2 互访
Neutron Linux bridge agent 使用 "ip link add type vxlan" 命令来创建 vxlan interface。这是该命令的帮助信息:
Command: [‘ip link add type vxlan help‘] Usage: ... vxlan id VNI [ { group | remote } ADDR ] [ local ADDR ] [ ttl TTL ] [ tos TOS ] [ dev PHYS_DEV ] [ port MIN MAX ] [ [no]learning ] [ [no]proxy ] [ [no]rsc ] [ [no]l2miss ] [ [no]l3miss ] Where: VNI := 0-16777215 #network 的 segemntation_id ADDR := { IP_ADDRESS | any } #IP 地址 TOS := { NUMBER | inherit } #可以由 tos 配置项指定 TTL := { 1..255 | inherit } #可以由 ttl 配置项指定,不设置时默认为1
以 vxlan id 1027 group 224.0.0.1 dev eth1 port 32768 61000 ageing 300 为例,它使用如下的配置项:
(1)id 1027,这是 vxlan interface id,其值为 neutron network 的 provider:segmentation_id 属性。
(2)group 224.0.0.1。表示这个是一个多播 VXLAN interface,使用 Neutron 默认的多播组 224.0.0.1,你可以使用 vxlan_group 配置项指定其它的多播组。需要注意的是:
(a)每个 Neutron linux bridge agent 只能配置一个 vxlan_group 地址,这意味着只能加入一个多播组。
(b)在需要广播时使用多播组地址为目的地址,比如:
17:01:28.524935 IP (tos 0x0, ttl 1, id 45252, offset 0, flags [none], proto UDP (17), length 78) 10.0.0.10.49332 > 224.0.0.1.8472: [no cksum] OTV, flags [I] (0x08), overlay 0, instance 1074 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 70.0.0.105 tell 70.0.0.100, length 28
(c)Neutron linux bridge agent 会优先使用单播(ucast),只有在单播不能使用的时候才会尝试多播(mcast),而该配置项只有在使用多播时候才有效。看代码:
检查是使用单播还是多播:
if self.vxlan_ucast_supported(): self.vxlan_mode = lconst.VXLAN_UCAST #使用单播 elif self.vxlan_mcast_supported(): self.vxlan_mode = lconst.VXLAN_MCAST #使用多播 else: raise exceptions.VxlanNetworkUnsupported()
而 vxlan_group 配置项只有在 MCAST 时候才生效:
if self.vxlan_mode == lconst.VXLAN_MCAST: args[‘group‘] = cfg.CONF.VXLAN.vxlan_group
而使用单播的条件比较苛刻(可以看代码中的详细条件),基本上(1)如果没有配置 l2population,则肯定不使用单播 (2)如果配置了l2population,支持 iproute2,vxlan 支持 proxy 等等一系列检查,都合格是才使用单播。而使用单播时,vxlan interface 没有 group 属性,比如:
vxlan id 1074 dev eth1 port 32768 61000 proxy ageing 300
需要注意的是,目前的代码只检查 vxlan interface 的名称(name)而不检查具体的属性包括 group 等,如果你变换 l2population 的配置,导致需要切换使用单播和多播,则需要手工删除已有的 vxlan interface,然后重启 neutron linux bridge agent 让它重建 vxlan interface,否认, 你的租户网络可能会不通。
(3)dev eth1 是 UDP 出去的网卡,由配置项 local_ip 指定。
(4)port 32768 61000 是 linux vxlan 实现的 UDP 源端口号范围,这个不可以配置。
/* The below used as the min/max for the UDP port range */ >> +#define VXLAN_SRC_PORT_MIN 32768 >> +#define VXLAN_SRC_PORT_MAX 61000
在计算该端口的时候,可以考虑每个虚机的特定属性,来实现底层转发网络上多条转发路径上的负载均衡。
+/* Compute source port for outgoing packet. >> + * Currently we use the flow hash. >> + */ >> +static u16 get_src_port(struct sk_buff *skb) >> +{ >> + unsigned int range = (VXLAN_SRC_PORT_MAX - VXLAN_SRC_PORT_MIN) + 1; >> + u32 hash = OVS_CB(skb)->flow->hash; >> + >> + return (__force u16)(((u64) hash * range) >> 32) + VXLAN_SRC_PORT_MIN; >> +}
(5)ageing 300,这是 unreachable-vtep-aging-timer,单位是秒。其含义是,经过学习得到的远端 VTEP 后面的虚机的 MAC 地址过期时长。
(6)目前 Neutron linux bridge agent 无法配置 VXLAN UDP 端口,只能使用linux的默认端口,具体见这个 ticket:[Juno]: Cannot set the VXLAN UDP destination port to 4789 using Linux Bridge。到目前为止其状态依然是 “In progress”。一般来讲,linux 默认使用的端口号是 8472。修改配置文件 /etc/modprobe.d/vxlan-port.conf 来向 vxlan 内核模块传递端口参数可以修改该端口号,比如如下的配置会使得系统改为使用 4789 端口:
cat /etc/modprobe.d/vxlan-port.conf options vxlan udp_port=4789
或者在创建 vxlan interface 时指定 dstport 参数 (这是 Neutron linux bridge fix 的做法)。创建好以后,需要设置其 IP 地址或者加入一个bridge。Neutron 的方案是将它加入到一个 linux bridge 上。然后,将其设置为 up (使用 ip link set up 命令)。
该 interface 会:
(1)创建并连接到一个 UDP 端口 8472 的 socket。IANA 标准化组织规定的端口是 4789,而 Linux 内核为了后向兼容需要而使用的端口是 8472.
/* UDP port for VXLAN traffic. 62 * The IANA assigned port is 4789, but the Linux default is 8472 63 * for compatibility with early adopters. 64 */
err = sock_create(AF_INET, SOCK_DGRAM, 0, &vxlan_port->vxlan_rcv_socket); kernel_bind(vxlan_port->vxlan_rcv_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)); udp_sk(vxlan_port->vxlan_rcv_socket->sk)->encap_rcv = vxlan_rcv;
(2)在支持多播的情况下,加入一个多播组。可使用 netstat -g 命令查看多播组成员。
(3)虚机经过 linux bridge 由 vxlan 出去的流量,由 vxlan interface 封装 VXLAN 头,然后使用 UDP 由指定网卡发出
src_port = udp_flow_src_port(net, skb, 0, 0, true); #计算源 UDP 端口 md.vni = htonl(be64_to_cpu(tun_key->tun_id) << 8); md.gbp = vxlan_ext_gbp(skb); vxflags = vxlan_port->exts |(tun_key->tun_flags & TUNNEL_CSUM ? VXLAN_F_UDP_CSUM : 0); err = vxlan_xmit_skb(rt, sk, skb, fl.saddr, tun_key->ipv4_dst, #经过 UDP socket 发出 tun_key->ipv4_tos, tun_key->ipv4_ttl, df, src_port, dst_port, &md, false, vxflags);
(4)进来的 vxlan 流量,首先到达 UDP 端口,再交给 vxlan 钩子函数,由 vxlan 做解包处理后,经过 vxlan interface 通过 linux bridge 转发给虚机
/* Called with rcu_read_lock and BH disabled. */ >> +static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
注:
(1)以上示例代码都是 OVS 对 vxlan 的实现,linux 内核的实现原理其实也差不多。
(2)其实更准确地说以上这些都是Linux vxlan 内核模块的功能,只不过都是通过 vxlan interface 来体现给用户的。
在不使用 l2population 的情况下,VXLAN 通过多播学习来得到 fdb 表项即(VM-MAC, VTEP-IP)。这个成本是蛮高的。你可以使用 bridge 命令来查看 FDB,该命令由 iproute2 包提供。我们通过下面的实验来观察该过程:
(1)vxlan interface 被创建后,fdb 只有一个表项,就是所有的流量都发往多播组
root@compute1:~# bridge fdb show dev vxlan-1074 c6:a5:bf:5b:67:a3 vlan 0 permanent 00:00:00:00:00:00 dst 224.0.0.1 via eth1 self permanent
(2)连接该 vxlan interface 的 vm1 先获得ip 地址,然后 ping 另一个网段上的vm2
root@compute1:~# bridge fdb show dev vxlan-1074 fa:16:3e:19:15:fe vlan 0 fa:16:3e:32:35:ef vlan 0 c6:a5:bf:5b:67:a3 vlan 0 permanent 00:00:00:00:00:00 dst 224.0.0.1 via eth1 self permanent fa:16:3e:32:35:ef dst 10.0.0.10 self fa:16:3e:19:15:fe dst 10.0.0.10 self
可见,这两个过程中,vxlan VTETP 学习到了两个地址:qdhcp 的一个端口和 qrouter 的一个端口
(3)vm1 ping vm3, vm3 在 vm1 同网段,但是在不同的机器上
root@compute1:~# bridge fdb show dev vxlan-1074 fa:16:3e:c4:c8:58 vlan 0 fa:16:3e:19:15:fe vlan 0 fa:16:3e:32:35:ef vlan 0 c6:a5:bf:5b:67:a3 vlan 0 permanent 00:00:00:00:00:00 dst 224.0.0.1 via eth1 self permanent fa:16:3e:32:35:ef dst 10.0.0.10 self fa:16:3e:c4:c8:58 dst 10.0.0.14 self fa:16:3e:19:15:fe dst 10.0.0.10 self
可见它学习到了另一个主机上的VTEP 信息。
(5)我们也可以看到,这些表项都不是 permanent 的,因此,一定时间后,它们就会因过期被删除。vxlan interface 的 aging 属性值决定,默认为5分钟。因此,五分钟后,这些学到的表项都会过期了,重新回到状态(1),开始新的一轮学习过程。
c6:a5:bf:5b:67:a3 vlan 0 permanent 00:00:00:00:00:00 dst 224.0.0.1 via eth1 self permanent
(6)需要注意的是,ip n 表在整个过程中都没有变化,因为这时候,vxlan 不会承担 ARP Proxy 的任务。
详细情况,可以参考 Neutron 理解 (3): Open vSwitch + GRE/VxLAN 组网 [Netruon Open vSwitch + GRE/VxLAN Virutal Network] 中的 VTEP 学习部分。
fdb 表通过帮助帮助解决两个问题来使得 Linux VTEP 可以使用单播而不是需要使用多播:
(1)获得远端 VM IP 和 MAC 地址的映射关系,从而本地虚机不需要使用 ARP 广播来获取该地址
(2)获得远端 VM MAC 和 它的 VTEP IP 的 映射关系,从而使得本地 VTEP 不需要通过多播来获取该地址
普通情况下,这些映射关系都是 VTEP 使用多播通过地址学习获得的。
Linux bridge agent 在使用 l2population 的情况下,使用该表来保存远端 VM IP 和 MAC 地址的映射关系。要使用 l2population,需要在配置文件 /etc/neutron/plugins/ml2/ml2_conf.ini 中做如下配置:
[ml2]
mechanism_drivers = linuxbridge,l2population
[vxlan]
l2_population = true
在l2pop 生效后,并且启用了 arp_reponder 之后,新建的 vxlan interface 上就会增加 “proxy” 功能:
root@controller:~# ip -d link show dev vxlan-1027 20: vxlan-1027: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master brq243661e7-f7 state UNKNOWN mode DEFAULT group default link/ether d6:40:1e:47:38:59 brd ff:ff:ff:ff:ff:ff promiscuity 1 vxlan id 1027 dev eth1 port 32768 61000 proxy ageing 300
这使得 vxlan interface 能够通过查询 ip neighbour table 来响应本地虚机对远端虚机的 ARP 请求,从而作为这些虚机的 ARP Proxy。
关于l2pop的实现原理,可参考 Neutron 理解 (4): Neutron OVS OpenFlow 流表 和 L2 Population [Netruon OVS OpenFlow tables + L2 Population]。
VXLAN Interface 实现 Proxy ARP 的原理:
linux bridge agent 的实现采用的是直接调用 ip neighbour 命令行来操作 fdb 表。该命令同样是 iproute2 包提供的命令之一。
def add_fdb_ip_entry(self, mac, ip, interface): ip_lib.IPDevice(interface).neigh.add(ip, mac) def remove_fdb_ip_entry(self, mac, ip, interface): ip_lib.IPDevice(interface).neigh.delete(ip, mac)
格式:ip neighbor add REMOTE_VM_IP lladdr REMOTE_VM_MAC dev vx-NET_ID nud permanent。注意这些entry 是 PERMANENT 即永久的,它们不受 vxlan aging 时长的限制。
以 vxlan-1074 interface示例:
root@compute1:~# ip n | grep vxlan-1074
70.0.0.129 dev vxlan-1074 lladdr fa:16:3e:c4:c8:58 PERMANENT #在计算节点2上的虚机
70.0.0.100 dev vxlan-1074 lladdr fa:16:3e:32:35:ef PERMANENT #qdhcp 的 ns-63ee3080-94 interface
70.0.0.1 dev vxlan-1074 lladdr fa:16:3e:19:15:fe PERMANENT #qrouter 的 qr-cd430335-dd interface
这样的话,vxlan interface 就可以直接向虚机的 ARP 广播请求提供 ARP 响应了。但是,这里只有远端虚机和 qroute/qdhcp Interface 的条目。对于本机上的同网络虚机,看来 Neutron 是放任 linux bridge 去做广播了,反正范围也很小。可见,这里的目的只是为了减少对外的多播。
再看看 VTEP 的 MAC 地址是如何保存的:
root@compute1:~# ip n | grep 10.0 10.0.0.10 dev eth1 lladdr 52:54:00:7c:c0:79 STALE 10.0.0.14 dev eth1 lladdr 52:54:00:c6:4d:42 STALE 10.0.0.100 dev eth1 lladdr fa:80:13:21:6b:56 STALE
它们的来源还待查。
linux 实现的这个表和 vSphere 中的 fdb 表是对应的(除了 VTEP MAC 保存在主机的 ip neigh 表中):
这些表保存 远端 VM MAC (mac)- 远端 VTEP IP(dst) - VXLAN ID (dev) 的关系。linux-linuxbridge-agent 实现了通过 “bridge” 命令来操作 fdb 表项的各个方法(代码在这里):
def add_fdb_bridge_entry(self, mac, agent_ip, interface, operation="add"): utils.execute([‘bridge‘, ‘fdb‘, operation, mac, ‘dev‘, interface, ‘dst‘, agent_ip], run_as_root=True, check_exit_code=False) def remove_fdb_bridge_entry(self, mac, agent_ip, interface): utils.execute([‘bridge‘, ‘fdb‘, ‘del‘, mac, ‘dev‘, interface, ‘dst‘, agent_ip], run_as_root=True, check_exit_code=False) def add_fdb_entries(self, agent_ip, ports, interface): for mac, ip in ports: if mac != constants.FLOODING_ENTRY[0]: self.add_fdb_ip_entry(mac, ip, interface) self.add_fdb_bridge_entry(mac, agent_ip, interface, operation="replace") elif self.vxlan_mode == lconst.VXLAN_UCAST: if self.fdb_bridge_entry_exists(mac, interface): self.add_fdb_bridge_entry(mac, agent_ip, interface, "append") else: self.add_fdb_bridge_entry(mac, agent_ip, interface) def remove_fdb_entries(self, agent_ip, ports, interface): for mac, ip in ports: if mac != constants.FLOODING_ENTRY[0]: self.remove_fdb_ip_entry(mac, ip, interface) self.remove_fdb_bridge_entry(mac, agent_ip, interface) elif self.vxlan_mode == lconst.VXLAN_UCAST: self.remove_fdb_bridge_entry(mac, agent_ip, interface)
fdb 条目格式:bridge fdb add REMOTE_VM_MAC dev vx-NET_ID dst REMOTE_HOST_IP
比如:
root@compute1:~# bridge fdb show dev vxlan-1074
fa:16:3e:19:15:fe vlan 0
b6:dc:2f:dd:8b:81 vlan 0 permanent
00:00:00:00:00:00 dst 10.0.0.10 self permanent #需要多播或者广播时,比如一个虚机的MAC地址在 fdb 表不存在的时候,需要使用多次单播来模拟多播
00:00:00:00:00:00 dst 10.0.0.14 self permanent #多播或者广播目标之二。在不使用多播的情况下,如果需要多播的功能,则通过多次发送单播的方式来模拟多播
fa:16:3e:32:35:ef dst 10.0.0.10 self permanent # qdhcp 的 ns-63ee3080-94 interface
fa:16:3e:c4:c8:58 dst 10.0.0.14 self permanent # 在另一个计算节点上的同网络的虚机
fa:16:3e:19:15:fe dst 10.0.0.10 self permanent # qrouter 的 qr-cd430335-dd interface
这样的话,VTEP 就不需要通过多播来获取目的虚机的 VTEP 的 IP 地址了。
问题定位步骤如下:
(1)在 tap 设备上做 tcpdump,能看到BOOTP 请求发出,但是没用响应
(2)在 vxlan interface 设备上做 tcpdump,看不到包发出
(3)查看该设备的 fdb 表,只有一条记录
root@compute1:~# bridge fdb show dev vxlan-1074 3e:c0:e5:74:f7:49 vlan 0 permanent
可见,这时候 vxlan 是无法通过 UDP 将包发出去的,因为没用单播或者多播 fdb 表表项。
(4)重启 Neutron linux bridge agent,在查看 fdb 表
root@compute1:~# bridge fdb show dev vxlan-1074 3e:c0:e5:74:f7:49 vlan 0 permanent 00:00:00:00:00:00 dst 10.0.0.14 self permanent 00:00:00:00:00:00 dst 10.0.0.10 self permanent fa:16:3e:32:35:ef dst 10.0.0.10 self permanent fa:16:3e:c4:c8:58 dst 10.0.0.14 self permanent fa:16:3e:19:15:fe dst 10.0.0.10 self permanent
可见此时表项都正常了
(5)重新在虚机内运行 ifup eth0,正常获取固定IP
该问题同时也说明,如果 l2population 功能不正常的话,虚机的网络可能会断;如果使用多播,这种情况应该会避免。
更深入地看一下到底是什么原因:
(1)对 linux bridge 来说,它自身有个 fdb。在转发之前,它会查这个表。如果有查到一条记录,那么就将二层帧转发到该记录对应的 bridge port;如果找不到,它就会泛洪。也就是说,linux bridge 是无论如何都会将它收到的帧转发出去的。
(2) vxlan interface 也有自己的 fdb,它由 vxlan driver 来维护。当 linux bridge 将帧发到 vxlan interface 之后,vxlan driver 在将封包发给 udp 协议栈之前,它需要查 fdb 表,从中找出目的 MAC 地址对应的 fdb 条目中的对方 VTEP 的 IP 地址。vxlan.c 中的相关代码如下:
f = vxlan_find_mac(vxlan, eth->h_dest); did_rsc = false; ...if (f == NULL) { f = vxlan_find_mac(vxlan, all_zeros_mac); if (f == NULL) { if ((vxlan->flags & VXLAN_F_L2MISS) && !is_multicast_ether_addr(eth->h_dest)) vxlan_fdb_miss(vxlan, eth->h_dest); dev->stats.tx_dropped++; kfree_skb(skb); return NETDEV_TX_OK; } }
这代码说明:(1)首先根据 目的 MAC 地址查表 (2)如果查不到,则根据全0的 MAC查表 (3)再查不到,则丢弃该帧。
在不使用单播的情况下,Linux vxlan 需要使用多播。而在选择多播地址上,还是有一些讲究:
Neutron Linux bridge agent的实现中,默认情况下,所有的计算和网络节点上的 VTEP 都必须在同一个多播组中,这个组的地址可以配置,不配置的话使用默认的组 224.0.0.1。需要注意的是,224.0.0.1 是 “The All Hosts multicast group addresses all hosts on the same network segment.”,因此,它的成员只能在一个物理网段内,也就是说,如果各节点跨网段的话,需要修改多播组的IP。另外,还不清楚 Neutron 是否支持配置多个多播组,如果支持的话,结合 Nova 的 AZ 概念,可以将特定 AZ 内的计算节点加入到一个特定的多播组,而网络节点使用多个AZ的多个多播组,这样将会有利于控制多播组内成员的数量。
一个示例:
加入多播组:
多播过程:
以上是理论部分,具体还要进一步的实践。TBD。
github 上的源代码在这里。支持 ipset。使用 iptables,作用在各个 linux bridge 上。
在 /etc/neutron/plugins/ml2/ml2_conf.ini 中的配置:
[securitygroup] # enable_ipset = True enable_security_group = True enable_ipset = True firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver
从实现上看,OVSHybridIptablesFirewallDriver 类是从IptablesFirewallDriver 继承过来的,只有小幅的改动。因此,可以参考 Neutron 理解 (8): Neutron 是如何实现虚机防火墙的 [How Neutron Implements Security Group],不同的部分的细节待将来再进一步的分析。
github 上的源代码在这里。其代码逻辑并不复杂,主要实现了如下的逻辑:
(1)main()函数。在启动 neutron-plugin-linuxbridge-agent 服务时被调用,它初始化一个 LinuxBridgeNeutronAgentRPC 实例,并调用其 start 方法启动它。
(2)LinuxBridgeNeutronAgentRPC 类是主类,它初始化SecurityGroupAgentRpc 类的实例用来处理安全组;设置并启动该Rpc (setup_rpc);启动一个循环来不断地 scan tap devices (scan_devices)来获取待处理的 tap 设备,并在设备列表有变化时进行相应的处理(包括 add 或者 remove interface)
(3)对于 Rpc,LinuxBridgeNeutronAgentRPC 会启动一个 LinuxBridgeRpcCallbacks 实例,默认情况下,会处理 PORT_UPDATE,NETWORK_DELETE 和 SG_UPDATE RPC 消息;在设置了 l2pop 的情况下,会增加处理 L2POP_UPDATE 消息;并且还会启动一个循环来不断调用 _report_state 来想 neutron server 报告其状态。
consumers = [[topics.PORT, topics.UPDATE],[topics.NETWORK, topics.DELETE],[topics.SECURITY_GROUP, topics.UPDATE]] if cfg.CONF.VXLAN.l2_population: consumers.append([topics.L2POPULATION, topics.UPDATE])
(4)RPC 处理
画了一个大致的流程图:
详细内容,可参考 Neutron 理解 (4): Neutron OVS OpenFlow 流表 和 L2 Population
现在,越来越多的网卡设备支持 offload 特性,来提升网络收/发性能。offload 是将本来该操作系统进行的一些数据包处理(如分片、重组等)放到网卡硬件中去做,降低系统 CPU 消耗的同时,提高处理的性能。包括 LSO/LRO、GSO/GRO、TSO/UFO 等。
诸于 VXLAN 的网络虚拟化技术给服务器的CPU带来了额外的负担,比如封包、解包和校验等。因此,一些中高端网卡已经添加了 Hardware Offload 的能力,将原本需要服务器CPU处理的事情交给网卡自己来处理。
LSO/LRO:Large Segment Offload 和 Large Receive Offload
分别对应到发送和接收两个方向
首先来看 LSO。我们知道计算机网络上传输的数据基本单位是离散的网包,既然是网包,就有大小限制,这个限制就是 MTU(Maximum Transmission Unit)的大小,一般是1518字节。比如我们想发送很多数据出去,经过os协议栈的时候,会自动帮你拆分成几个不超过MTU的网包。然而,这个拆分是比较费计算资源的(比如很多时候还要计算分别的checksum),由 CPU 来做的话,往往会造成使用率过高。那可不可以把这些简单重复的操作 offload 到网卡上呢?
于是就有了 LSO,在发送数据超过 MTU 限制的时候(太容易发生了),OS 只需要提交一次传输请求给网卡,网卡会自动的把数据拿过来,然后进行切,并封包发出,发出的网包不超过 MTU 限制。
接下来看 LRO,当网卡收到很多碎片包的时候,LRO 可以辅助自动组合成一段较大的数据,一次性提交给 OS处理。
一般的,LSO 和 LRO 主要面向 TCP 报文。
GSO/GRO: Generic Segmentation Offload 和 Generic Receive Offload
分别比 LSO 和 LRO 更通用,自动检测网卡支持特性,支持分包则直接发给网卡,否则先分包后发给网卡。新的驱动一般用 GSO/GRO。
GRO 是在内核 2.6.29 之后合并进去的,作者是一个华裔Herbert Xu ,GRO的简介可以看这里:http://lwn.net/Articles/358910/
GSO 是在内核 Linux 2.6.18 之后合并进去的。
先来描述一下GRO的作用,GRO 是针对网络接受包的处理的,并且只是针对 NAPI 类型的驱动,因此如果要支持 GRO,不仅要内核支持,而且驱动也必须调用相应的接口,用 ethtool -K gro on 来设置,如果报错就说明网卡驱动本身就不支持GRO。
GRO 类似 TSO,可是 TSO 只支持发送数据包,这样你 tcp 层大的段会在网卡被切包,然后再传递给对端,而如果没有gro,则小的段会被一个个送到协议栈,有了gro之后,就会在接收端做一个反向的操作(想对于tso).也就是将tso切好的数据包组合成大包再传递给协议栈。
详细信息及代码分析,请阅读 linux kernel 网络协议栈之GRO(Generic receive offload)
TSO/UFO:TCP Segmentation Offload 和 UDP fragmentation offload
分别对应 TCP 报文和 UDP 报文。
TSO 将 TCP 协议的一些处理下放到网卡完成以减轻协议栈处理占用 CPU 的负载。通常以太网的 MTU 是1500Bytes,除去 IP 头(标准情况下20Bytes)、TCP头(标准情况下20Bytes),TCP的MSS (Max Segment Size)大小是1460Bytes。当应用层下发的数据超过 MSS 时,协议栈会对这样的 payload 进行分片,保证生成的报文长度不超过MTU的大小。但是对于支持 TSO/GSO 的网卡而言,就没这个必要了,可以把最多 64K 大小的 payload 直接往下传给协议栈,此时 IP 层也不会进行分片,一直会传给网卡驱动,支持TSO/GSO的网卡会自己生成TCP/IP包头和帧头,这样可以offload很多协议栈上的内存操作,checksum计算等原本靠CPU来做的工作都移给了网卡。
VMware 产品中实现了 TSO 和 LRO 来提高网络性能。
RSS:Receive Side Scaling
多核服务器中的网卡还推荐考虑 RSS,将网流分配到多个 RSS 队列上,多个队列绑定到不同的核心上,分散负载。
发送端 | 接收端 | 注释 |
LSO/TSO/UFO | LRO | LRO 是 linux 2.6.24 中引入的。 |
GSO | GRO |
GRO 是 linux 2.6.29 中引入的。 GSO 和 GRO 更加通用,G*O 是对 T*O 的增强,新的驱动都是用G*O。 注意两个可以同时使用,所以要禁止offload的话需要检查是否都被禁止了 |
检查你的网卡是否具备Offload 能力:
root@hkg02kvm001ccz023:~# ethtool -k eth0 | grep tx-udp tx-udp_tnl-segmentation: off [fixed] (悲剧的是我的网卡不具备)
你可以打开或者关闭该功能:
ethtool -K ethX tx-udp_tnl-segmentation [off|on]
而从一些网卡提供商的报告中可以看出来Offload 带来的好处 (资料来源):
(1)带宽提高了
(2)服务器CPU压力下降了
参考
http://www.slideshare.net/JamesDenton1/2014-openstack-summit-neutron-ovs-to-linuxbridge-migration
https://blogs.vmware.com/vsphere/2013/05/vxlan-series-multicast-basics-part-2.html
http://blogs.vmware.com/vsphere/2013/05/vxlan-series-multicast-usage-in-vxlan-part-3.html
https://github.com/torvalds/linux/blob/master/drivers/net/vxlan.c
https://docs.google.com/document/d/1sUrvOQ9GIl9IWMGg3qbx2mX0DdXvMiyvCw2Lm6snaWQ/edit
http://www.cs.virginia.edu/~cs458/slides/module21-mcast.pdf
http://www.juniper.net/documentation/en_US/junos13.2/topics/concept/multicast-ip-overview.html
http://blog.csdn.net/yeasy/article/details/19204639
http://seitran.com/2015/04/13/01-gso-gro-lro/
Neutron 理解(14):Neutron ML2 + Linux bridge + VxLAN 组网
标签:e30 world via 运行 master arp 接收 组织 ova
原文地址:http://www.cnblogs.com/allcloud/p/6061118.html