实现细节

以 OpenvSwitch plugin 为例,主要在 neutron\plugins\openvswitch\agent\ovs_dvr_neutron_agent.py 文件中。

OVSDVRNeutronAgent 类是本地处理的 agent,启动后会在三个网桥上添加初始化的规则,主要过程如下。

  1. def setup_dvr_flows(self):
  2. self.setup_dvr_flows_on_integ_br()
  3. self.setup_dvr_flows_on_tun_br()
  4. self.setup_dvr_flows_on_phys_br()
  5. self.setup_dvr_mac_flows_on_all_brs()

其中,br-int 是本地交换网桥;br-tun 是跟其它计算节点通信的承载网桥;br-phy 是跟外部公共网络通信的网桥。

integration 网桥规则添加

integrate 网桥负责本地同一子网内的网包交换。

主要过程为

  1. # Add a canary flow to int_br to track OVS restarts
  2. self.int_br.add_flow(table=constants.CANARY_TABLE, priority=0,
  3. actions="drop")
  4. # Insert 'drop' action as the default for Table DVR_TO_SRC_MAC
  5. self.int_br.add_flow(table=constants.DVR_TO_SRC_MAC,
  6. priority=1,
  7. actions="drop")
  8. self.int_br.add_flow(table=constants.DVR_TO_SRC_MAC_VLAN,
  9. priority=1,
  10. actions="drop")
  11. # Insert 'normal' action as the default for Table LOCAL_SWITCHING
  12. self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
  13. priority=1,
  14. actions="normal")
  15. for physical_network in self.bridge_mappings:
  16. self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
  17. priority=2,
  18. in_port=self.int_ofports[physical_network],
  19. actions="drop")

首先,网桥上采用了多个流表,定义在 openvswitch/common 目录下的 constants.py。主要流表包括:

  • LOCAL_SWITCHING 表:0,顾名思义,用于本地的交换。
  • CANARY 表:23
  • DVR_TO_SRC_MAC 表:1
  • DVR_TO_SRC_MAC_VLAN 表:2

上面的代码配置 LOCAL_SWITCHING 表默认规则为 NORMAL(作为本地的正常学习交换机),并不允许宿主机本地端口进来的包。配置其它表默认行为为丢弃。

tunnel 网桥规则添加

主要过程为

  1. self.tun_br.add_flow(priority=1,
  2. in_port=self.patch_int_ofport,
  3. actions="resubmit(,%s)" %
  4. constants.DVR_PROCESS)
  5. # table-miss should be sent to learning table
  6. self.tun_br.add_flow(table=constants.DVR_NOT_LEARN,
  7. priority=0,
  8. actions="resubmit(,%s)" %
  9. constants.LEARN_FROM_TUN)
  10. self.tun_br.add_flow(table=constants.DVR_PROCESS,
  11. priority=0,
  12. actions="resubmit(,%s)" %
  13. constants.PATCH_LV_TO_TUN)

主要流表包括:

  • DVR_PROCESS 表:1,顾名思义,用于 DVR 处理。
  • DVR_NOT_LEARN 表:9。
  • LEARN_FROM_TUN 表:10,学习从 tunnel 收到的网包。
  • PATCH_LV_TO_TUN 表:2。

所有从 br-int 过来的网包,发到 DVR_PROCESS 表处理。

DVR_NOT_LEARN 表,默认将网包发给表 LEARN_FROM_TUN。

DVR_PROCESS 表,默认将网包发给表 PATCH_LV_TO_TUN。

physical 网桥规则添加

主要过程为

  1. for physical_network in self.bridge_mappings:
  2. self.phys_brs[physical_network].add_flow(priority=2,
  3. in_port=self.phys_ofports[physical_network],
  4. actions="resubmit(,%s)" %
  5. constants.DVR_PROCESS_VLAN)
  6. self.phys_brs[physical_network].add_flow(priority=1,
  7. actions="resubmit(,%s)" %
  8. constants.DVR_NOT_LEARN_VLAN)
  9. self.phys_brs[physical_network].add_flow(
  10. table=constants.DVR_PROCESS_VLAN,
  11. priority=0,
  12. actions="resubmit(,%s)" %
  13. constants.LOCAL_VLAN_TRANSLATION)
  14. self.phys_brs[physical_network].add_flow(
  15. table=constants.LOCAL_VLAN_TRANSLATION,
  16. priority=2,
  17. in_port=self.phys_ofports[physical_network],
  18. actions="drop")
  19. self.phys_brs[physical_network].add_flow(
  20. table=constants.DVR_NOT_LEARN_VLAN,
  21. priority=1,
  22. actions="NORMAL")

对所有的连接到外部的物理网桥都添加类似规则。

主要流表包括:

  • DVR_PROCESS_VLAN:1
  • LOCAL_VLAN_TRANSLATION:2
  • DVR_NOT_LEARN_VLAN:3。

默认从 br-int 来的所有网包发送给表 DVR_PROCESS_VLAN。

DVR_PROCESS_VLAN 表,默认发给表 LOCAL_VLAN_TRANSLATION。

LOCAL_VLAN_TRANSLATION 表丢弃从 br-int 来的所有网包。

其他所有网包发送给表 DVR_NOT_LEARN_VLAN。

表 DVR_NOT_LEARN_VLAN 默认规则为 NORMAL。

所有网桥上添加 mac 规则

主要过程为

  1. for physical_network in self.bridge_mappings:
  2. self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
  3. priority=4,
  4. in_port=self.int_ofports[physical_network],
  5. dl_src=mac['mac_address'],
  6. actions="resubmit(,%s)" %
  7. constants.DVR_TO_SRC_MAC_VLAN)
  8. self.phys_brs[physical_network].add_flow(
  9. table=constants.DVR_NOT_LEARN_VLAN,
  10. priority=2,
  11. dl_src=mac['mac_address'],
  12. actions="output:%s" %
  13. self.phys_ofports[physical_network])
  14. if self.enable_tunneling:
  15. # Table 0 (default) will now sort DVR traffic from other
  16. # traffic depending on in_port
  17. self.int_br.add_flow(table=constants.LOCAL_SWITCHING,
  18. priority=2,
  19. in_port=self.patch_tun_ofport,
  20. dl_src=mac['mac_address'],
  21. actions="resubmit(,%s)" %
  22. constants.DVR_TO_SRC_MAC)
  23. # Table DVR_NOT_LEARN ensures unique dvr macs in the cloud
  24. # are not learnt, as they may
  25. # result in flow explosions
  26. self.tun_br.add_flow(table=constants.DVR_NOT_LEARN,
  27. priority=1,
  28. dl_src=mac['mac_address'],
  29. actions="output:%s" %
  30. self.patch_int_ofport)
  31. self.registered_dvr_macs.add(mac['mac_address'])

这里主要是添加对其他主机上的 DVR 网关发过来的网包的处理。

外部网络为 vlan 的情况下

br-int 网桥上,表 LOCAL_SWITCHING 添加优先级为 4 的流,如果从外面过来的网包,MAC 源地址是其他的 DVR 网关地址,则扔给表 DVR_TO_SRC_MAC_VLAN 处理。

br-eth 网桥上,表 DVR_NOT_LEARN_VLAN 则添加优先级为 2 的规则,MAC 源地址是其他的 DVR 网关地址,则发给 br-int。

外部网络为 tunnel 的情况下

类似,分别在 br-int 网桥的 LOCAL_SWITCHING 表和 br-tun 网桥的 DVR_NOT_LEARN 表添加流,优先级分别改为 2 和 1。