Open vSwitch 本地防火墙驱动

历史上,Open vSwitch (OVS) 无法直接与 iptables 交互以实现安全组。因此,OVS 代理和 Compute 服务在每个实例(VM)和 OVS 集成桥 br-int 之间使用 Linux 网桥来实现安全组。Linux 网桥设备包含与实例相关的 iptables 规则。通常,实例与物理网络基础设施之间的额外组件会导致可扩展性和性能问题。为了缓解这些问题,OVS 代理包含一个可选的防火墙驱动程序,该驱动程序以 OVS 中的流的形式原生实现安全组,而不是 Linux 网桥设备和 iptables。这提高了可扩展性和性能。

配置异构防火墙驱动程序

L2 代理可以配置为使用不同的防火墙驱动程序。没有要求它们都必须相同。如果代理缺少防火墙驱动程序配置,它将默认为在其服务器上配置的内容。这也意味着服务器不必配置任何防火墙驱动程序,只要代理配置正确即可。

先决条件

原生的 OVS 防火墙实现需要内核和用户空间对 conntrack 的支持,因此需要 Linux 内核和 Open vSwitch 的最低版本。所有情况都需要 Open vSwitch 版本 2.5 或更高版本。

  • 内核版本 4.3 或更高版本包含 conntrack 支持。

  • 内核版本 3.3,但低于 4.3,不包含 conntrack 支持,需要构建 OVS 模块。

它还需要加载 conntrack 内核模块,具体取决于内核版本。

  • 内核版本 4.19 或更高版本需要 nf_conntrack 模块。

  • 内核版本 4.18 或更早版本需要 nf_conntrack_ipv4nf_conntrack_ipv6 模块。

启用原生 OVS 防火墙驱动程序

  • 在运行 Open vSwitch 代理的节点上,编辑 openvswitch_agent.ini 文件并启用防火墙驱动程序。

    [securitygroup]
    firewall_driver = openvswitch
    

有关更多信息,请参阅 Open vSwitch 防火墙驱动程序视频

在 VM 中使用 GRE 隧道和 OVS 防火墙驱动程序

如果将使用 VM 到 VM 的 GRE 隧道,原生的 OVS 防火墙实现需要加载内核中运行 Open vSwitch 代理的节点上的 nf_conntrack_proto_gre 模块。可以使用以下命令加载它

# modprobe nf_conntrack_proto_gre

一些 Linux 发行版具有可用于在启动时自动加载内核模块的文件,例如 /etc/modules。请查阅您的发行版以获取更多信息。

这对于使用 gre 隧道网络类型的 Neutron 来说不是必需的。

OVS 和 iptables 防火墙驱动程序之间的差异

如果为安全组配置相同的规则,OVS 和 iptables 防火墙驱动程序都应始终以相同的方式行为。但在某些情况下并非如此,这些驱动程序之间可能存在细微的差异。

情况

OVS

iptables

conntrack 将流量标记为 INVALID,但匹配某些 SG 规则(请参阅 [1][2] 以获取详细信息)

已阻止

允许,因为它首先匹配 SG 规则,而不会到达丢弃无效数据包的规则

发送到组 224.0.0.X 的多播流量(请参阅 [3] 以获取详细信息)

始终允许

已阻止,可以通过 SG 规则启用。

Open Flow 规则处理注意事项

原生 Open vSwitch 防火墙驱动程序会增加要安装在集成桥中的 Open Flow 规则数量,具体取决于规则数量、规则类型和计算节点中的端口数量,最多可能达到数千条。

默认情况下,这些规则以批处理方式写入集成桥。常量 _constants.AGENT_RES_PROCESSING_STEP 定义了单次操作中写入的规则数量。它设置为 100。

LP#1934917 中所示,在 Open Flow 处理期间(这在 OVS 代理的初始瞬态期间可能更明显),端口规则中可能存在一些不一致之处。为了避免这种情况,配置变量 OVS.openflow_processed_per_port 允许在一个事务中处理与单个端口相关的所有 Open Flow 规则。

以下脚本提供了一个工具,用于在每次部署中测量使用 OVS.openflow_processed_per_port 或默认 _constants.AGENT_RES_PROCESSING_STEP 时的处理时间

# (1) Create a network with a single IPv4 subnet
openstack network create net-scale
openstack subnet create --subnet-range 10.250.0.0/16 --network net-scale snet-scale

# (2) Create 400 ports bound to one host
for i in {1..400}
do
    openstack port create \
      --security-group <security_group_id> \
      --device-owner testing:scale \
      --binding-profile host_id=<compute_node_host_name> \
      --network net-scale test-large-scale-port-$i
done

# (3) Create 1000 security group rules, belonging to the same security
#     group <security_group_id>
for i in {3000..4000}
do
  curl -g -i -X POST http://controller:9696/v2.0/security-group-rules \
  -H "User-Agent: python-neutronclient" -H "Content-Type: application/json" \
  -H "Accept: application/json" -H "X-Auth-Token: <token>" \
  -d '{
  "security_group_rule": {
    "direction": "ingress", "protocol": "tcp",
    "ethertype": "IPv4", "port_range_max": "'$i'",
    "port_range_min": "3000",
    "security_group_id": <security_group_id>}
  }' 2>&1 > /dev/null
done

# (4) Setup the port to the host <compute_node_host_name>
# "grep" the test port list into file port_list.
$ for p in `openstack port list -f value -c id -c name -c mac_address -c fixed_ips | grep test-large-scale-port`
  do
      mac=`echo $p | cut -f3 -d" "`
      ip_addr=`echo $p | cut -f7 -d" " | cut -f2 -d"'"`
      dev_id=`echo $p | cut -f1 -d" " | cut -b 1-11`
      dev_name="tp-$dev_id"
      echo "===" $mac "===" $ip_addr "===" $dev_id "===" $dev_name
      ovs-vsctl  --may-exist add-port br-int ${dev_name} -- set Interface \
        ${dev_name} type=internal \
        -- set Interface ${dev_name} external-ids:attached-mac="${mac}" \
        -- set Interface ${dev_name} external-ids:iface-id="${p}" \
        -- set Interface ${dev_name} external-ids:iface-status=active
      sleep 0.2

      ip link set dev ${dev_name} address ${mac}
      ip addr add ${ip_addr} dev ${dev_name}
      ip link set ${dev_name} up
  done

# (5) Restart the OVS agent and check that all flows are in place.
# (6) Check the OVS agent restart time, checking the "iteration" time and
#     number.

允许的以太类型

目前,OVS 防火墙会阻止没有 IPv4 或 IPv6 以太类型的流量。与“iptables_hybrid”防火墙相比,这是一个行为变化,后者仅对 IP 数据包进行操作,因此不会处理其他以太类型。通过配置选项 permitted_ethertypes,可以定义一组允许的以太类型。任何具有这些允许的以太类型且目的地为本地端口或从本地端口和 MAC 地址生成的流量都将被允许。

参考