Bridge(桥)是Linux上用来做TCP/IP二层协议交换的设备,与现实世界中的交换机功能相似。Bridge设备实例可以和Linux上其他网络设备实例连接,既attach一个从设备,类似于在现实世界中的交换机和一个用户终端之间连接一根网线。当有数据到达时,Bridge会根据报文中的MAC信息进行广播、转发、丢弃处理。
如图所示,Bridge的功能主要在内核里实现。当一个从设备被attach到Bridge上时,相当于现实世界里交换机的端口被插入了一根连有终端的网线。这时在内核程序里,netdev_rx_handler_register()被调用,一个用于接受数据的回调函数被注册。以后每当这个从设备收到数据时都会调用这个函数可以把数据转发到Bridge上。当Bridge接收到此数据时,br_handle_frame()被调用,进行一个和现实世界中的交换机类似的处理过程:判断包的类别(广播/单点),查找内部MAC端口映射表,定位目标端口号,将数据转发到目标端口或丢弃,自动更新内部MAC端口映射表以自我学习。
linux内核支持网口的桥接(目前只支持以太网接口)。但是与单纯的交换机不同,交换机只是一个二层设备,对于接收到的报文,要么转发、要么丢弃。小型的交换机里面只需要一块交换芯片即可,并不需要CPU。而运行着linux内核的机器本身就是一台主机,有可能就是网络报文的目的地。其收到的报文除了转发和丢弃,还可能被送到网络协议栈的上层(网络层),从而被自己消化。
概括来说,网桥实现最重要的两点:
1.MAC学习:学习MAC地址,起初,网桥是没有任何地址与端口的对应关系的,它发送数据,还是得想HUB一样,但是每发送一个数据,它都会关心数据包的来源MAC是从自己的哪个端口来的,由于学习,建立地址-端口的对照表(CAM表)。
2. 报文转发:每发送一个数据包,网桥都会提取其目的MAC地址,从自己的地址-端口对照表(CAM表)中查找由哪个端口把数据包发送出去。
Bridge可以设置IP地址,当一个bridge0拥有IP后,Linux便可以通过路由表或者IP表规则在三层定位bridge0,此时相当于Linux拥有了另外一个隐藏的虚拟网卡和Bridge的隐藏端口相连。当一个设备被attach到Bridge上时,那个设备的IP会变的无效,Linux不再使用那个IP在三层接受数据。
对于一个被attach到Bridge上的设备来说,只有它收到数据时,此包数据才会被转发到Bridge上,进而完成查表广播等后续操作。当请求是发送类型时,数据是不会被转发到Bridge上的,它会寻找下一个发送出口。
网桥需要维护一个MAC地址-端口映射表(CAM),端口是指网桥自身提供的端口,而MAC地址是指与端口相连的另一端的MAC地址。
网桥处理包遵循以下几条原则:
1.在一个接口上接收的包不会再在那个接口上发送这个数据包;
2.每个接收到的数据包都要学习其源地址;
3.如果数据包是多播或广播包,则要在同一个网段中除了接收端口外的其他所有端口发送这个数据包,如果上层协议栈对多播包感兴趣,则需要把数据包提交给上层协议栈;
4.如果数据包的目的MAC地址不能再CAM表中找到,则要在同一个网段中除了接收端口外的其他所有端口发送这个数据包;
5.如果能够在CAM表中查询到目的MAC地址,则在特定的端口上发送这个数据包,如果发送端口和接收端口是同一端口则不发送。
TAP设备是一种让用户态程序向内核协议栈注入数据的设备,工作在二层。做为虚拟网卡驱动,Tap驱动程序的数据接收和发送并不直接和真实网卡打交道,而是通过用户态来转交。Tap驱动是利用设备文件实现用户态和核心态的数据交互。
从结构上来说,Tap驱动并不单纯是实现网卡驱动,同时它还实现了字符设备驱动部分。以字符设备的方式连接用户态和核心态。下面是示意图:
Tap驱动程序中包含两个部分,一部分是字符设备驱动,还有一部分是网卡驱动部分。利用网卡驱动部分接收来自TCP/IP协议栈的网络分包并发送或者反过来将接收到的网络分包传给协议栈处理,而字符驱动部分则将网络分包在内核与用户态之间传送,模拟物理链路的数据接收和发送。Tap驱动很好的实现了两种驱动的结合。
如图所示,当一个TAP设备被创建时,在Linux设备文件目录下将会生成一个对应char设备,用户程序可以像打开普通文件一样打开这个文件进行读写;Linuxprotocol statck是linux内核的tcp/ip协议栈。当执行write()操作时,数据进入TAP设备,此时对于Linux网络层来说,相当于TAP设备收到了一包数据,请求内核接受它,如同普通的物理网卡从外界收到一包数据一样,不同的是其实数据来自Linux上的一个用户程序。Linux收到此数据后将根据网络配置进行后续处理,从而完成了用户程序向Linux内核网络层注入数据的功能。当用户程序执行read()请求时,相当于向内核查询TAP设备上是否有需要被发送出去的数据,有的话取出到用户程序里,完成TAP设备的发送数据功能。针对TAP设备的一个形象的比喻是:使用TAP设备的应用程序相当于另外一台计算机,TAP设备是本机的一个网卡,他们之间相互连接。应用程序通过read()/write()操作,和本机网络核心进行通讯。
Neutron使用linux的brctl、ip命令实现对linuxbridge和tap/veth设备的创建、删除。
brctladdbr br0 #创建一个名字为br0的网桥
iptuntap add tap0 mode tap #创建一个名字为tap0的tap设备
brctladdif bro tap0 #将tap0附着到br0上
brctldelif br0 tap0 #将tap0从br0上去附着
iptuntap delete tap0 mode tap #删除tap设备
brctldelbr br0 #删除网桥设备
iplink add tap0 type veth peer name tap2 #创建一组veth设备tap0/tap2
iplink del tap0 #删除veth设备
linuxbridge只有在设备使用了某个port时,才会在该节点上创建相应的bridge并加入tap设备。如果只是创建了网络或者该节点上没有设备使用该网络,并不会有bridge创建出来。
Linuxbridge上绑定的port有三种:虚拟机VMport、router绑定的port、dhcp port。
VM-port创建流程如下:
1) Nova调用neutron-server接口分配port;
2) Neutron将分配的port信息返回给nova,port状态为DOWN;
3) Nova根据port信息创建tap设备;
4) Linuxbridge轮询任务遍历linux系统上的tap设备,更新tap设备的状态和安全组,port状态为ACTIVE;
5) Linuxbridge上报设备状态给neutron-server,neutron-server更新数据库port状态。
Router-port创建流程如下:
1) 用户设置router的外部网关或者添加内部子网port,neutron-server会收到router_add_port消息;
2) Neutron-server分配新的port信息,发送router_update消息给l3-agent,返回router_add_port成功消息给用户;
3) L3-agent更新router信息,并根据port信息创建tap设备;
4) Linuxbridge轮询任务遍历linux系统上的tap设备,更新tap设备的状态和安全组,port状态为ACTIVE;
5) Linuxbridge上报设备状态给neutron-server,neutron-server更新数据库port状态。
Dhcp-port创建流程如下:
1) 用户创建网络,且网络使能dhcp能力。neutron-server收到创建网络消息;
2) Neutron-server发送network_create_end消息给dhcp-agent;返回网络创建成功消息给用户;
3) Dhcp-agent处理网络创建消息,由于使能dhcp能力,所以给neutron-server发创建dhcp-port的消息;
4) Neutron-server分配新的port信息,并将port信息返回给dhcp-agent;
5) Dhcp-agent根据port信息创建tap设备;
6) Linuxbridge轮询任务遍历linux系统上的tap设备,更新tap设备的状态和安全组,port状态为ACTIVE;
7) Linuxbridge上报设备状态给neutron-server,neutron-server更新数据库port状态。
Linuxbridge-tap设备的删除过程则和创建过程相反。
理论上,Linuxbridge上绑定的三种port的port信息都可以进行修改,但目前常见的port更新只应用在虚拟机VMport上。
1) 用户修改port信息,如修改port所属的子网、port的fixedip、port状态、绑定/去绑定安全组、绑定/去绑定qos策略等。Neutron-server收到port_update消息;
2) Neutron-server更新port对应的数据库信息;发送port_update消息给linuxbridge-agent,携带要修改的port信息;给用户回应port_update结果;
3) linuxbridge-agent将收到的port信息和本地保存的port信息比对,再调用对应的driver进行处理,目前这里主要是qosdriver的处理。
Linuxbridge和tap设备可通过下面的方法进行故障监测,以便及时发现故障。
可以通过ps –ef命令找到linuxbridge的进程号,然后查看该进程的CPU、内存占用情况。若CPU、内存占用较高,则可能出现异常。
[root@10-10-1-33 ~]# ps -ef|grep bridge
neutron 19414 1 2 14:09 ? 00:01:27 /usr/bin/python2 /usr/bin/neutron-linuxbridge-agent--config-file /usr/share/neutron/neutron-dist.conf --config-file/etc/neutron/neutron.conf --config-file/etc/neutron/plugins/ml2/linuxbridge_agent.ini --config-dir/etc/neutron/conf.d/common --config-dir /etc/neutron/conf.d/neutron-linuxbridge-agent--log-file /var/log/neutron/linuxbridge-agent.log
root 28142 28097 0 15:18 pts/3 00:00:00 grep --color=auto bridge
[root@10-10-1-33 ~]# top -p 19414
top - 15:28:14 up 9 days, 20:22, 3 users, load average: 0.24, 0.90, 0.99
Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.4 us, 0.0 sy, 0.0 ni, 99.6 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 32749300 total, 11707268free, 2620536 used, 18421496 buff/cache
KiB Swap: 15359996 total, 15054008free, 305988 used. 28734656 avail Mem
PIDUSER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
19414 neutron 20 0 316800 51424 5440 S 2.0 0.2 1:39.78 neutron-linuxbr
通过linux brctl命令查看网桥数量以及网桥的mac表项。
[root@10-10-1-33 ~]# brctl show
bridge name bridgeid STP enabled interfaces
brq4998b598-3b 8000.3a0f20937de1 no tap0bd0bcc1-d0
tap244481dc-4c
vxlan-36
通过ifconfig命令查看网桥及网桥绑定的端口的收发数据包。如果单位时间内数据包数量趋近于0,则网桥异常或者没有业务流量;如果单位时间内数据包数量很多,则业务流量较大或者出现异常。
[root@10-10-1-33 ~]# ifconfig
brq4998b598-3b:flags=4163
inet6 fe80::34a1:53ff:fe19:bf26 prefixlen 64 scopeid 0x20
ether 3a:0f:20:93:7d:e1 txqueuelen 0 (Ethernet)
RX packets 64 bytes 6088 (5.9KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8 bytes 648 (648.0 B)
TX errors 0 dropped 0 overruns0 carrier 0 collisions 0
eth0:flags=4163
inet 10.10.2.33 netmask255.255.255.0 broadcast 10.10.2.255
inet6 fe80::92e2:baff:fe8b:7ae0 prefixlen 64 scopeid0x20
ether 90:e2:ba:8b:7a:e0 txqueuelen 1000 (Ethernet)
RX packets 647960 bytes 92744395(88.4 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 640972 bytes 88733961(84.6 MiB)
TX errors 0 dropped 0 overruns0 carrier 0 collisions 0
eth1:flags=4163
inet 10.10.3.33 netmask255.255.255.0 broadcast 10.10.3.255
inet6 fe80::92e2:baff:fe8b:7ae1 prefixlen 64 scopeid 0x20
ether 90:e2:ba:8b:7a:e1 txqueuelen 1000 (Ethernet)
RX packets 894972285 bytes1278001845429 (1.1 TiB)
RX errors 0 dropped 3088 overruns 0 frame 0
TX packets 732893265 bytes1031733010514 (960.8 GiB)
TX errors 0 dropped 0 overruns0 carrier 0 collisions 0
eth2:flags=4163
inet6 fe80::9abe:94ff:fe45:ab22 prefixlen 64 scopeid0x20
ether 98:be:94:45:ab:22 txqueuelen 1000 (Ethernet)
RX packets 3897131 bytes 349080913 (332.9 MiB)
RX errors 0 dropped 11 overruns 0 frame 0
TX packets 579168 bytes 43669202(41.6 MiB)
TX errors 0 dropped 0 overruns0 carrier 0 collisions 0
device memory 0xc5580000-c559ffff
eth3:flags=4163
inet 10.10.1.33 netmask255.255.255.0 broadcast 10.10.1.255
inet6 fe80::9abe:94ff:fe45:ab23 prefixlen 64 scopeid0x20
ether 98:be:94:45:ab:23 txqueuelen1000 (Ethernet)
RX packets 17150317 bytes15449381795 (14.3 GiB)
RX errors 0 dropped 10 overruns 0 frame 0
TX packets 10643601 bytes4087424077 (3.8 GiB)
TX errors 0 dropped 0 overruns0 carrier 0 collisions 0
device memory 0xc55a0000-c55bffff
eth4:flags=4099
ether 98:be:94:45:ab:24 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns0 carrier 0 collisions 0
device memory 0xc55c0000-c55dffff
eth5:flags=4099
ether 98:be:94:45:ab:25 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns0 carrier 0 collisions 0
device memory 0xc55e0000-c55fffff
eth6: flags=4099
ether a0:36:9f:65:88:13 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns0 carrier 0 collisions 0
device memory 0x90800000-90ffffff
eth7:flags=4099
ether a0:36:9f:65:95:9a txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns0 carrier 0 collisions 0
device memory 0x91800000-91ffffff
lo:flags=73
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 0 (Local Loopback)
RX packets 1971145364 bytes122961924014282 (111.8 TiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1971145364 bytes122961924014282 (111.8 TiB)
TX errors 0 dropped 0 overruns0 carrier 0 collisions 0
tap0bd0bcc1-d0:flags=4163
inet6 fe80::380f:20ff:fe93:7de1 prefixlen 64 scopeid0x20
ether 3a:0f:20:93:7d:e1 txqueuelen 1000 (Ethernet)
RX packets 37 bytes 5274 (5.1 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 97 bytes 9626 (9.4 KiB)
TX errors 0 dropped 0 overruns0 carrier 0 collisions 0
tap244481dc-4c:flags=4163
inet6 fe80::fc16:3eff:fed7:7fce prefixlen 64 scopeid0x20
ether fe:16:3e:d7:7f:ce txqueuelen 500 (Ethernet)
RX packets 13 bytes 1502 (1.4KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 21 bytes 3736 (3.6KiB)
TX errors 0 dropped 0 overruns0 carrier 0 collisions 0
vxlan-36:flags=4163
inet6 fe80::e4a7:8bff:fe1c:f0d6 prefixlen 64 scopeid 0x20
ether e6:a7:8b:1c:f0:d6 txqueuelen 0 (Ethernet)
RX packets 69 bytes 6288 (6.1KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 37 bytes 6568 (6.4KiB)
TX errors 0 dropped 16 overruns0 carrier 0 collisions 0
可以查看数据库neutron的ports表:
查询命令:
select *fromports;
查询结果:
+----------------------------------+--------------------------------------+------+--------------------------------------+-------------------+----------------+--------+-------------------------------------------------------------------------------+--------------------------+----------+
| tenant_id | id | name |network_id |mac_address | admin_state_up | status | device_id | device_owner |dns_name |
+----------------------------------+--------------------------------------+------+--------------------------------------+-------------------+----------------+--------+-------------------------------------------------------------------------------+--------------------------+----------+
|629fb63dd82e46fa937accc99d417059 | 013d7a0e-34a3-47ed-809c-836b9d730d6d | | 7344a71a-2d7a-4e59-9765-28627ab29645 |fa:16:3e:af:42:5a | 1 |ACTIVE | 72ac4d7b-fc0d-4f98-a290-2e49959643ae | network:router_interface | |
|629fb63dd82e46fa937accc99d417059 | 208be203-71bc-4837-8f07-cb296d9a57c7 | | e18f583f-c8cf-433a-8095-315712525ecd |fa:16:3e:2e:c4:d8 | 1 | ACTIVE |dhcp57aa2c89-eb31-5aa6-baa3-9db19f8fe78d-e18f583f-c8cf-433a-8095-315712525ecd |network:dhcp | |
|629fb63dd82e46fa937accc99d417059 | 4531b28c-e2a9-448e-8416-860ef0af4dff | | 7b67253f-6cbc-47d7-9c5b-11f0e5daaccb |fa:16:3e:29:ce:56 | 1 | ACTIVE | ac0ad555-a84b-4fc5-8b7d-9a9863c900cf |compute:None | |
| |485f9ccc-e1d3-4350-b912-da50b7d6db1f | | e18f583f-c8cf-433a-8095-315712525ecd | fa:16:3e:c6:20:ad | 1 | ACTIVE |72ac4d7b-fc0d-4f98-a290-2e49959643ae |network:router_gateway | |
| |64f837c2-5f7d-4712-84a4-2c2a918e0001 | | e18f583f-c8cf-433a-8095-315712525ecd | fa:16:3e:2b:05:80 | 1 | N/A | eda7b6a5-8883-458d-9108-ac05895cd753 |network:floatingip | |
|629fb63dd82e46fa937accc99d417059 | 6f8bdd18-a5e4-4e85-b9f0-da1049363db3 | | 7344a71a-2d7a-4e59-9765-28627ab29645 |fa:16:3e:48:58:eb | 1 | ACTIVE | 9fedf305-0b71-451b-a8c7-813f62bef6e3 |compute:None | |
|629fb63dd82e46fa937accc99d417059 | 767e4e4d-2630-4671-bc0e-2e39c057ca40 | | 7b67253f-6cbc-47d7-9c5b-11f0e5daaccb |fa:16:3e:c9:d2:f6 | 1 | ACTIVE | 5b9ee557-ffd8-459b-8b19-4ddde957cb18 |compute:None | |
| |78a89008-f132-4395-983d-0a7f3fb8db34 | | e18f583f-c8cf-433a-8095-315712525ecd | fa:16:3e:53:82:0b | 1 | N/A | da3ce690-34e0-40a2-9efb-f4c9fe1de38c |network:floatingip | |
|629fb63dd82e46fa937accc99d417059 | 966eaa3d-7c4c-45a4-baf6-6b8afb8f4932 | | 7b67253f-6cbc-47d7-9c5b-11f0e5daaccb |fa:16:3e:f8:7d:cc | 1 | ACTIVE | c7517140-17c5-4a80-bd3f-7a0edf9f0a26 | compute:None | |
|629fb63dd82e46fa937accc99d417059 | 9bc39d6f-b9aa-4621-9f6e-395c861c794b | | 7344a71a-2d7a-4e59-9765-28627ab29645 |fa:16:3e:8e:1a:69 | 1 | ACTIVE | dhcp57aa2c89-eb31-5aa6-baa3-9db19f8fe78d-7344a71a-2d7a-4e59-9765-28627ab29645| network:dhcp | |
|629fb63dd82e46fa937accc99d417059 | 9e317e97-b469-4d8f-8f48-d0ea390dc743 | | 7b67253f-6cbc-47d7-9c5b-11f0e5daaccb |fa:16:3e:0f:1b:e2 | 1 | ACTIVE |dhcp57aa2c89-eb31-5aa6-baa3-9db19f8fe78d-7b67253f-6cbc-47d7-9c5b-11f0e5daaccb |network:dhcp | |
| |9f7c0041-10d0-421c-a4fe-f7445c214bd4 | | e18f583f-c8cf-433a-8095-315712525ecd | fa:16:3e:c9:fe:1c | 1 | N/A | b2bc1848-7c5b-4d94-a12d-6b2241c4d548 |network:floatingip | |
| |ac929ae5-d76c-4b06-b65a-809163b4ea77 | | e18f583f-c8cf-433a-8095-315712525ecd | fa:16:3e:64:40:da | 1 | N/A | e4a774ad-57c5-4d92-b9bd-0847bec5e655 |network:floatingip | |
| |e2658577-3223-46a7-bacf-dfb0fd4b7323 | | e18f583f-c8cf-433a-8095-315712525ecd |fa:16:3e:2b:78:9b | 1 | N/A |cd8add94-e74a-4f1e-ba99-f82bc094b494 |network:floatingip | |
|629fb63dd82e46fa937accc99d417059 | e83d8f29-3fbb-474c-a86e-a2c054be1c93 | | 7b67253f-6cbc-47d7-9c5b-11f0e5daaccb |fa:16:3e:a3:73:92 | 1 | DOWN |38f705fc-ef9d-4203-98e2-b92d18f910ca |compute:None | |
+----------------------------------+--------------------------------------+------+--------------------------------------+-------------------+----------------+--------+-------------------------------------------------------------------------------+--------------------------+----------+
红色一列为port的状态,其中ACTIVE表示port状态正常。N/A状态的是floatingip,DOWN表示port不可用。
当tap设备状态发生变化时,linuxbridge-agent会给neutron-server发送状态变化的RPC消息:update_device_up和update_device_down。这两个消息中都携带tap设备名字。
正常情况,对于一个tap设备,linuxbridge-agent只会在tap可用时给neutron-server发送一次RPC消息update_device_up。如果rabbirmq消息中出现一个tap设备的多条update_device_up和update_device_down消息,则说明出现异常。
可以通过分析linuxbridge-agent的日志文件中的错误日志来发现linuxbridge和tap设备异常。linuxbridge-agent的日志文件默认存放在/var/log/neutron/linuxbridge-agent.log。
问题现象:rabbitmq消息中同一tap设备的update_device_up消息多次出现。
问题分析:
1)在linuxbridge-agent的轮询任务daemon_loop函数增加import ipdb;ipdb.set_trace()进行进程调试。发现两次处理的device_info相同,added内容和current内容一致,是当前服务器上的所有tap设备:
pp device_info
{'added': set(['tap013d7a0e-34',
'tap208be203-71',
'tap485f9ccc-e1',
'tap52b212be-db',
'tap6f8bdd18-a5',
'tap767e4e4d-26',
'tap9bc39d6f-b9',
'tap9e317e97-b4',
'tapaaa8e9e1-c3']),
'current':set(['tap013d7a0e-34',
'tap208be203-71',
'tap485f9ccc-e1',
'tap52b212be-db',
'tap6f8bdd18-a5',
'tap767e4e4d-26',
'tap9bc39d6f-b9',
'tap9e317e97-b4',
'tapaaa8e9e1-c3']),
'removed': set(),
'updated': set()}
而device_info信息是从scan_devices函数中获取的:
def daemon_loop(self):
LOG.info(_LI("LinuxBridge Agent RPC Daemon Started!"))
device_info = None
sync = True
while True:
start =time.time()
device_info =self.scan_devices(previous=device_info, sync=sync)
2)分析scan_devices函数:
def scan_devices(self,previous, sync):
device_info = {}
# Save and reinitialise the setvariable that the port_update RPC uses.
# This should be thread-safe as thegreenthread should not yield
# between these two statements.
updated_devices = self.updated_devices
self.updated_devices = set()
current_devices =self.br_mgr.get_tap_devices()
device_info['current']= current_devices
if previous is None:
# This is the first iteration ofdaemon_loop().
previous = {'added': set(),
'current': set(),
'updated': set(),
'removed': set()}
# clear any orphaned ARP spoofingrules (e.g. interface was
# manually deleted)
if self.prevent_arp_spoofing:
arp_protect.delete_unreferenced_arp_protection(current_devices)
if sync:
# This is the first iteration, orthe previous one had a problem.
# Re-add all existing devices.
device_info['added']= current_devices
# Retry cleaning devices that maynot have been cleaned properly.
# And clean any that disappearedsince the previous iteration.
device_info['removed'] =(previous['removed'] | previous['current']
-current_devices)
# Retry updating devices that maynot have been updated properly.
# And any that were updated sincethe previous iteration.
# Only update devices thatcurrently exist.
device_info['updated'] =(previous['updated'] | updated_devices
& current_devices)
else:
device_info['added'] =current_devices - previous['current']
device_info['removed'] =previous['current'] - current_devices
device_info['updated'] =updated_devices & current_devices
return device_info
在sync为true时,added内容和current内容一致,而轮询任务daemon_loop只有在_device_info_has_changes为true是才会处理。_device_info_has_changes的判断逻辑为added/updated/removed至少有一个不为空:
def_device_info_has_changes(self, device_info):
return (device_info.get('added')
or device_info.get('updated')
or device_info.get('removed'))
3)进一步分析sync设置的位置
if (self._device_info_has_changes(device_info)
orself.sg_agent.firewall_refresh_needed()):
LOG.debug("Agent loop found changes! %s", device_info)
try:
sync =self.process_network_devices(device_info)
exceptException:
LOG.exception(_LE("Error in agent loop. Devices info: %s"),
device_info)
sync = True
当处理网络设备异常时,sync会被置为True。
4)进一步跟踪,发现在处理tap208be203-71设备时出现异常,而tap208be203-71绑定在连接外网的网桥brqe18f583f-c8上
bridge name bridge id STPenabled interfaces
brqe18f583f-c8 8000.000c290206fd no eno16777736
tap208be203-71
tap485f9ccc-e1
异常时在代码执行命令
ip -4 addr add 192.168.44.160/32 scopeglobal dev brqe18f583f-c8 brd 192.168.44.160
的时候出现的,原因是返回值不是0。
手工执行该命令,提示错误:
ip -4 addr add 192.168.44.160/32 scope global dev brqe18f583f-c8brd 192.168.44.160
RTNETLINK answers: File exists
执行ip addr命令:
2: eno16777736:
link/ether00:0c:29:02:06:fd brd ff:ff:ff:ff:ff:ff
inet 192.168.44.160/32scope global eno16777736
valid_lft foreverpreferred_lft forever
inet6fe80::20c:29ff:fe02:6fd/64 scope link
valid_lft forever preferred_lft forever
38: brqe18f583f-c8:
link/ether00:0c:29:02:06:fd brd ff:ff:ff:ff:ff:ff
inet 192.168.44.130/24brd 192.168.44.255 scope global brqe18f583f-c8
valid_lft foreverpreferred_lft forever
inet 192.168.44.160/32brd 192.168.44.160 scope global brqe18f583f-c8
valid_lft foreverpreferred_lft forever
inet 192.168.44.150/24brd 192.168.44.255 scope global secondary brqe18f583f-c8
valid_lft foreverpreferred_lft forever
inet6fe80::387e:1eff:fe8d:fd75/64 scope link
valid_lft forever preferred_lft forever
发现eno16777736和brqe18f583f-c8都存在192.168.44.160/32的ip,至此,原因找到。
问题原因:
1) eno16777736(物理网卡)设备加入brqe18f583f-c8(外网网桥)后,eno16777736上的ip地址(192.168.44.160/32)要移到brqe18f583f-c8上,需要两步操作:在brqe18f583f-c8上添加ip,在eno16777736上删除ip。当添加ip成功,但删除ip没成功,便会出现两个设备上都有ip地址192.168.44.160/32。
2) 在linuxbridge-agent重启后,会读取所有tap设备,进行一次add处理,在add处理过程中,处理到tap208be203-71设备时,会进行其绑定网桥brqe18f583f-c8的确认工作,在确认工作中,会尝试将物理网卡eno16777736的ip移到brqe18f583f-c8上。由于brqe18f583f-c8上已经存在192.168.44.160/32,所以出现异常;
3) 出现异常会导致linuxbridge-agent轮询任务中sync标记为True,进而导致获取的device_info中added部分始终和current部分一致;
4) 由于device_info中added部分一致非空,linuxbridge-agent轮询任务开始新一轮add处理,会上报neutron-server所有tap设备update_device_up消息。然后再次出现异常。。。
解决办法:
手工删除brqe18f583f-c8上的ip地址192.168.44.160/32。再次启动linuxbridge-agent。linuxbridge-agent将物理网卡eno16777736的ip移到brqe18f583f-c8上执行成功,轮询任务中sync标记为False。获取的device_info中added/updated/removed均为空,linuxbridge-agent轮询任务不再处理tap设备,不再上报tap设备update_device_up消息。
结论:
Linuxbridge-agent中处理tap设备出现异常,就可能导致轮询任务进行重复无效的操作,上报海量tap设备update_device_up消息。
1、 http://os.51cto.com/art/201310/414335.htmLinux 上的基础网络设备详解
2、 http://www.ibm.com/developerworks/cn/linux/l-tuntap/虚拟网卡 TUN/TAP 驱动程序设计原理
3、 http://blog.csdn.net/mrwangwang/article/details/8393973Linux-网桥原理分析