Add support for nftables

This patch adds support for nftables (an iptables replacement) to
the devstack plugin and the amphora agent.

Change-Id: I9e2c4d6e68da67d68c6dfeb3b47edd600d1ba397
This commit is contained in:
Michael Johnson 2020-06-23 17:30:04 -07:00
parent 4a4a2344de
commit 1a3b56a0d5
13 changed files with 174 additions and 62 deletions

View File

@ -64,6 +64,11 @@ function build_octavia_worker_image {
export DIB_LOCAL_ELEMENTS=$DIB_LOCAL_ELEMENTS
fi
# Pull in the option to install nftables in the amphora
if [ -n "$DIB_OCTAVIA_AMP_USE_NFTABLES" ]; then
export DIB_OCTAVIA_AMP_USE_NFTABLES=$DIB_OCTAVIA_AMP_USE_NFTABLES
fi
# pull the agent code from the current code zuul has a reference to
if [ -n "$DIB_REPOLOCATION_pip_and_virtualenv" ]; then
export DIB_REPOLOCATION_pip_and_virtualenv=$DIB_REPOLOCATION_pip_and_virtualenv
@ -463,18 +468,35 @@ function create_mgmt_network_interface {
die "Unknown network controller. Please define octavia_create_network_interface_device"
fi
sudo ip link set dev o-hm0 address $MGMT_PORT_MAC
if [ $SERVICE_IP_VERSION == '6' ] ; then
# Allow the required IPv6 ICMP messages
sudo ip6tables -I INPUT -i o-hm0 -p ipv6-icmp -j ACCEPT
sudo ip6tables -I INPUT -i o-hm0 -p udp --dport $OCTAVIA_HM_LISTEN_PORT -j ACCEPT
sudo ip6tables -I INPUT -i o-hm0 -p udp --dport $OCTAVIA_AMP_LOG_ADMIN_PORT -j ACCEPT
sudo ip6tables -I INPUT -i o-hm0 -p udp --dport $OCTAVIA_AMP_LOG_TENANT_PORT -j ACCEPT
# Check if the host is using nftables, an alternative to iptables
if [ -x "$(sudo bash -c 'command -v nft')" ]; then
sudo nft add table inet octavia
sudo nft add chain inet octavia o-hm0-incoming { type filter hook input priority 0\;}
sudo nft flush chain inet octavia o-hm0-incoming
# Note: Order is important here and using counter here as this is
# devstack for testing.
sudo nft insert rule inet octavia o-hm0-incoming iifname "o-hm0" counter log drop
sudo nft insert rule inet octavia o-hm0-incoming iifname "o-hm0" meta l4proto ipv6-icmp counter accept
sudo nft insert rule inet octavia o-hm0-incoming iifname "o-hm0" udp dport $OCTAVIA_HM_LISTEN_PORT counter accept
sudo nft insert rule inet octavia o-hm0-incoming iifname "o-hm0" udp dport $OCTAVIA_AMP_LOG_ADMIN_PORT counter accept
sudo nft insert rule inet octavia o-hm0-incoming iifname "o-hm0" udp dport $OCTAVIA_AMP_LOG_TENANT_PORT counter accept
sudo nft insert rule inet octavia o-hm0-incoming iifname "o-hm0" ct state related,established accept
else
sudo iptables -I INPUT -i o-hm0 -p udp --dport $OCTAVIA_HM_LISTEN_PORT -j ACCEPT
sudo iptables -I INPUT -i o-hm0 -p udp --dport $OCTAVIA_AMP_LOG_ADMIN_PORT -j ACCEPT
sudo iptables -I INPUT -i o-hm0 -p udp --dport $OCTAVIA_AMP_LOG_TENANT_PORT -j ACCEPT
if [ $SERVICE_IP_VERSION == '6' ] ; then
# Allow the required IPv6 ICMP messages
sudo ip6tables -I INPUT -i o-hm0 -p ipv6-icmp -j ACCEPT
sudo ip6tables -I INPUT -i o-hm0 -p udp --dport $OCTAVIA_HM_LISTEN_PORT -j ACCEPT
sudo ip6tables -I INPUT -i o-hm0 -p udp --dport $OCTAVIA_AMP_LOG_ADMIN_PORT -j ACCEPT
sudo ip6tables -I INPUT -i o-hm0 -p udp --dport $OCTAVIA_AMP_LOG_TENANT_PORT -j ACCEPT
else
sudo iptables -I INPUT -i o-hm0 -p udp --dport $OCTAVIA_HM_LISTEN_PORT -j ACCEPT
sudo iptables -I INPUT -i o-hm0 -p udp --dport $OCTAVIA_AMP_LOG_ADMIN_PORT -j ACCEPT
sudo iptables -I INPUT -i o-hm0 -p udp --dport $OCTAVIA_AMP_LOG_TENANT_PORT -j ACCEPT
fi
fi
if [ $OCTAVIA_CONTROLLER_IP_PORT_LIST == 'auto' ] ; then
iniset $OCTAVIA_CONF health_manager controller_ip_port_list $MGMT_PORT_IP:$OCTAVIA_HM_LISTEN_PORT
else

View File

@ -289,6 +289,9 @@ else
export ELEMENTS_PATH=$OCTAVIA_ELEMENTS_PATH
fi
# Make sure we have a value set for DIB_OCTAVIA_AMP_USE_NFTABLES
export DIB_OCTAVIA_AMP_USE_NFTABLES=${DIB_OCTAVIA_AMP_USE_NFTABLES:-False}
export CLOUD_INIT_DATASOURCES=${CLOUD_INIT_DATASOURCES:-"ConfigDrive"}
# Additional RHEL environment checks

View File

@ -59,3 +59,6 @@ ureadahead:
uuid-runtime:
vim-tiny:
vlan:
nftables:
when: DIB_OCTAVIA_AMP_USE_NFTABLES = True

View File

@ -0,0 +1,81 @@
#!/bin/bash
#
# Copyright 2020 Red Hat, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
set -e
usage() {
echo
echo "Usage: $(basename "$0") [add|delete] [ipv4|ipv6] <interface>"
echo
exit 1
}
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then
usage
fi
if [ "$1" == "add" ]; then
if [ -x "$(sudo bash -c 'command -v nft')" ]; then
# Note: inet for nat requires a 5.2 or newer kernel.
if [ "$2" == "ipv4" ]; then
nft add table ip octavia-ipv4
nft add chain ip octavia-ipv4 ip-udp-masq { type nat hook postrouting priority 100\;}
nft add rule ip octavia-ipv4 ip-udp-masq oifname "$3" meta l4proto udp masquerade
elif [ "$2" == "ipv6" ]; then
nft add table ip6 octavia-ipv6
nft add chain ip6 octavia-ipv6 ip6-udp-masq { type nat hook postrouting priority 100\;}
nft add rule ip6 octavia-ipv6 ip6-udp-masq oifname "$3" meta l4proto udp masquerade
else
usage
fi
else # nft not found, fall back to iptables
if [ "$2" == "ipv4" ]; then
/sbin/iptables -t nat -A POSTROUTING -p udp -o $3 -j MASQUERADE
elif [ "$2" == "ipv6" ]; then
/sbin/ip6tables -t nat -A POSTROUTING -p udp -o $3 -j MASQUERADE
else
usage
fi
fi
elif [ "$1" == "delete" ]; then
if [ -x "$(sudo bash -c 'command -v nft')" ]; then
if [ "$2" == "ipv4" ]; then
nft flush chain ip octavia-ipv4 ip-udp-masq
nft delete chain ip octavia-ipv4 ip-udp-masq
elif [ "$2" == "ipv6" ]; then
nft flush chain ip6 octavia-ipv6 ip-udp-masq
nft delete chain ip6 octavia-ipv6 ip-udp-masq
else
usage
fi
else # nft not found, fall back to iptables
if [ "$2" == "ipv4" ]; then
/sbin/iptables -t nat -D POSTROUTING -p udp -o $3 -j MASQUERADE
elif [ "$2" == "ipv6" ]; then
/sbin/ip6tables -t nat -D POSTROUTING -p udp -o $3 -j MASQUERADE
else
usage
fi
fi
else
usage
fi

View File

@ -33,8 +33,8 @@ up route add -net {{ hr.network }} gw {{ hr.gw }} dev {{ interface }}
down route del -net {{ hr.network }} gw {{ hr.gw }} dev {{ interface }}
{%- endif %}
{%- endfor %}
post-up /sbin/ip{{ '6' if ipv6 }}tables -t nat -A POSTROUTING -p udp -o {{ interface }} -j MASQUERADE
post-down /sbin/ip{{ '6' if ipv6 }}tables -t nat -D POSTROUTING -p udp -o {{ interface }} -j MASQUERADE
post-up /usr/local/bin/udp-masquerade.sh add {{ 'ipv6' if ipv6 else 'ipv4' }} {{ interface }}
post-down /usr/local/bin/udp-masquerade.sh delete {{ 'ipv6' if ipv6 else 'ipv4' }} {{ interface }}
{%- else %}
iface {{ interface }} inet dhcp
auto {{ interface }}:0

View File

@ -78,5 +78,5 @@ post-up /sbin/ip {{ '-6 ' if vip_ipv6 }}rule add from {{ vip }}/{{ '128' if vip_
post-down /sbin/ip {{ '-6 ' if vip_ipv6 }}rule del from {{ vip }}/{{ '128' if vip_ipv6 else '32' }} table 1 priority 100
{%- endif %}
post-up /sbin/ip{{ '6' if vip_ipv6 }}tables -t nat -A POSTROUTING -p udp -o {{ interface }} -j MASQUERADE
post-down /sbin/ip{{ '6' if vip_ipv6 }}tables -t nat -D POSTROUTING -p udp -o {{ interface }} -j MASQUERADE
post-up /usr/local/bin/udp-masquerade.sh add {{ 'ipv6' if vip_ipv6 else 'ipv4' }} {{ interface }}
post-down /usr/local/bin/udp-masquerade.sh delete {{ 'ipv6' if vip_ipv6 else 'ipv4' }} {{ interface }}

View File

@ -14,6 +14,6 @@
#!/bin/bash
if [[ "$1" != "lo" ]]
then
/sbin/iptables -t nat -D POSTROUTING -o $1 -p udp -j MASQUERADE
/sbin/ip6tables -t nat -D POSTROUTING -o $1 -p udp -j MASQUERADE
/usr/local/bin/udp-masquerade.sh delete ipv4 $1
/usr/local/bin/udp-masquerade.sh delete ipv6 $1
fi

View File

@ -14,6 +14,6 @@
#!/bin/bash
if [[ "$1" != "lo" ]]
then
/sbin/iptables -t nat -A POSTROUTING -o $1 -p udp -j MASQUERADE
/sbin/ip6tables -t nat -A POSTROUTING -o $1 -p udp -j MASQUERADE
/usr/local/bin/udp-masquerade.sh add ipv4 $1
/usr/local/bin/udp-masquerade.sh add ipv6 $1
fi

View File

@ -1178,10 +1178,10 @@ class TestServerTestCase(base.TestCase):
'address 10.0.0.5\nbroadcast 10.0.0.255\n'
'netmask 255.255.255.0\n'
'mtu 1450\n'
'post-up /sbin/iptables -t nat -A POSTROUTING -p udp '
'-o eth{int} -j MASQUERADE\n'
'post-down /sbin/iptables -t nat -D POSTROUTING -p udp '
'-o eth{int} -j MASQUERADE\n'.format(int=test_int_num))
'post-up /usr/local/bin/udp-masquerade.sh add ipv4 '
'eth{int}\n'
'post-down /usr/local/bin/udp-masquerade.sh delete ipv4 '
'eth{int}\n'.format(int=test_int_num))
elif distro == consts.CENTOS:
handle.write.assert_any_call(
'\n\n# Generated by Octavia agent\n'
@ -1253,10 +1253,10 @@ class TestServerTestCase(base.TestCase):
'address 2001:0db8:0000:0000:0000:0000:0000:0002\n'
'broadcast 2001:0db8:ffff:ffff:ffff:ffff:ffff:ffff\n'
'netmask 32\nmtu 1450\n'
'post-up /sbin/ip6tables -t nat -A POSTROUTING -p udp '
'-o eth{int} -j MASQUERADE\n'
'post-down /sbin/ip6tables -t nat -D POSTROUTING -p udp '
'-o eth{int} -j MASQUERADE\n'.format(int=test_int_num))
'post-up /usr/local/bin/udp-masquerade.sh add ipv6 '
'eth{int}\n'
'post-down /usr/local/bin/udp-masquerade.sh delete ipv6 '
'eth{int}\n'.format(int=test_int_num))
elif distro == consts.CENTOS:
handle.write.assert_any_call(
'\n\n# Generated by Octavia agent\n'
@ -1441,11 +1441,10 @@ class TestServerTestCase(base.TestCase):
' dev ' + consts.NETNS_PRIMARY_INTERFACE + '\n'
'down route del -host ' + DEST2 + ' gw ' + NEXTHOP +
' dev ' + consts.NETNS_PRIMARY_INTERFACE + '\n' +
'post-up /sbin/iptables -t nat -A POSTROUTING -p udp -o ' +
consts.NETNS_PRIMARY_INTERFACE + ' -j MASQUERADE' + '\n' +
'post-down /sbin/iptables -t nat -D POSTROUTING -p udp '
'-o ' + consts.NETNS_PRIMARY_INTERFACE +
' -j MASQUERADE' + '\n')
'post-up /usr/local/bin/udp-masquerade.sh add ipv4 ' +
consts.NETNS_PRIMARY_INTERFACE + '\n' +
'post-down /usr/local/bin/udp-masquerade.sh delete ipv4 ' +
consts.NETNS_PRIMARY_INTERFACE + '\n')
elif distro == consts.CENTOS:
handle.write.assert_any_call(
'\n\n# Generated by Octavia agent\n'
@ -1702,11 +1701,9 @@ class TestServerTestCase(base.TestCase):
'priority 100\n'
'post-down /sbin/ip rule del from 203.0.113.2/32 table 1 '
'priority 100\n\n'
'post-up /sbin/iptables -t nat -A POSTROUTING -p udp '
'-o eth1 -j MASQUERADE\n'
'post-down /sbin/iptables -t nat -D POSTROUTING -p udp '
'-o eth1 -j MASQUERADE'.format(
netns_int=consts.NETNS_PRIMARY_INTERFACE))
'post-up /usr/local/bin/udp-masquerade.sh add ipv4 eth1\n'
'post-down /usr/local/bin/udp-masquerade.sh delete ipv4 '
'eth1'.format(netns_int=consts.NETNS_PRIMARY_INTERFACE))
elif distro == consts.CENTOS:
handle.write.assert_any_call(
'\n# Generated by Octavia agent\n'
@ -1809,11 +1806,9 @@ class TestServerTestCase(base.TestCase):
'priority 100\n'
'post-down /sbin/ip rule del from 203.0.113.2/32 table 1 '
'priority 100\n\n'
'post-up /sbin/iptables -t nat -A POSTROUTING -p udp '
'-o eth1 -j MASQUERADE\n'
'post-down /sbin/iptables -t nat -D POSTROUTING -p udp '
'-o eth1 -j MASQUERADE'.format(
netns_int=consts.NETNS_PRIMARY_INTERFACE))
'post-up /usr/local/bin/udp-masquerade.sh add ipv4 eth1\n'
'post-down /usr/local/bin/udp-masquerade.sh delete ipv4 '
'eth1'.format(netns_int=consts.NETNS_PRIMARY_INTERFACE))
elif distro == consts.CENTOS:
handle.write.assert_any_call(
'\n# Generated by Octavia agent\n'
@ -2061,11 +2056,9 @@ class TestServerTestCase(base.TestCase):
'post-down /sbin/ip -6 rule del from '
'2001:0db8:0000:0000:0000:0000:0000:0002/128 table 1 '
'priority 100\n\n'
'post-up /sbin/ip6tables -t nat -A POSTROUTING -p udp '
'-o eth1 -j MASQUERADE\n'
'post-down /sbin/ip6tables -t nat -D POSTROUTING -p udp '
'-o eth1 -j MASQUERADE'.format(
netns_int=consts.NETNS_PRIMARY_INTERFACE))
'post-up /usr/local/bin/udp-masquerade.sh add ipv6 eth1\n'
'post-down /usr/local/bin/udp-masquerade.sh delete ipv6 '
'eth1'.format(netns_int=consts.NETNS_PRIMARY_INTERFACE))
elif distro == consts.CENTOS:
handle.write.assert_any_call(
'\n# Generated by Octavia agent\n'
@ -2168,11 +2161,9 @@ class TestServerTestCase(base.TestCase):
'post-down /sbin/ip -6 rule del from '
'2001:0db8:0000:0000:0000:0000:0000:0002/128 table 1 '
'priority 100\n\n'
'post-up /sbin/ip6tables -t nat -A POSTROUTING -p udp '
'-o eth1 -j MASQUERADE\n'
'post-down /sbin/ip6tables -t nat -D POSTROUTING -p udp '
'-o eth1 -j MASQUERADE'.format(
netns_int=consts.NETNS_PRIMARY_INTERFACE))
'post-up /usr/local/bin/udp-masquerade.sh add ipv6 eth1\n'
'post-down /usr/local/bin/udp-masquerade.sh delete ipv6 '
'eth1'.format(netns_int=consts.NETNS_PRIMARY_INTERFACE))
elif distro == consts.CENTOS:
handle.write.assert_any_call(
'\n# Generated by Octavia agent\n'

View File

@ -241,10 +241,8 @@ class TestPlugNetwork(base.TestCase):
'down route del -net {dest1} gw {nexthop} dev {netns_interface}\n'
'up route add -net {dest2} gw {nexthop} dev {netns_interface}\n'
'down route del -net {dest2} gw {nexthop} dev {netns_interface}\n'
'post-up /sbin/iptables -t nat -A POSTROUTING -p udp -o '
'eth1234 -j MASQUERADE\n'
'post-down /sbin/iptables -t nat -D POSTROUTING -p udp -o eth1234 '
'-j MASQUERADE\n')
'post-up /usr/local/bin/udp-masquerade.sh add ipv4 eth1234\n'
'post-down /usr/local/bin/udp-masquerade.sh delete ipv4 eth1234\n')
template_port = osutils.j2_env.get_template('plug_port_ethX.conf.j2')
text = self.test_plug._osutils._generate_network_file_text(
@ -295,10 +293,10 @@ class TestPlugNetwork(base.TestCase):
'down route del -net {dest1} gw {nexthop} dev {netns_interface}\n'
'up route add -net {dest2} gw {nexthop} dev {netns_interface}\n'
'down route del -net {dest2} gw {nexthop} dev {netns_interface}\n'
'post-up /sbin/iptables -t nat -A POSTROUTING -p udp -o '
'{netns_interface} -j MASQUERADE\n'
'post-down /sbin/iptables -t nat -D POSTROUTING -p udp -o '
'{netns_interface} -j MASQUERADE\n'
'post-up /usr/local/bin/udp-masquerade.sh add ipv4 '
'{netns_interface}\n'
'post-down /usr/local/bin/udp-masquerade.sh delete ipv4 '
'{netns_interface}\n'
'\n\n# Generated by Octavia agent\n'
'auto {netns_interface}\n'
'iface {netns_interface} inet6 static\n'
@ -306,10 +304,10 @@ class TestPlugNetwork(base.TestCase):
'broadcast {broadcast_ipv6}\n'
'netmask {netmask_ipv6}\n'
'mtu {mtu}\n'
'post-up /sbin/ip6tables -t nat -A POSTROUTING -p udp -o '
'{netns_interface} -j MASQUERADE\n'
'post-down /sbin/ip6tables -t nat -D POSTROUTING -p udp -o '
'{netns_interface} -j MASQUERADE\n')
'post-up /usr/local/bin/udp-masquerade.sh add ipv6 '
'{netns_interface}\n'
'post-down /usr/local/bin/udp-masquerade.sh delete ipv6 '
'{netns_interface}\n')
template_port = osutils.j2_env.get_template('plug_port_ethX.conf.j2')
text = self.test_plug._osutils._generate_network_file_text(

View File

@ -0,0 +1,4 @@
---
features:
- |
Added support for nftables to the devstack plugin and the amphora.

View File

@ -164,3 +164,10 @@
vars:
amphora_os: centos
amphora_os_release: 8
- job:
name: octavia-v2-dsvm-scenario-nftables
parent: octavia-v2-dsvm-scenario
vars:
devstack_localrc:
OCTAVIA_AMP_USE_NFTABLES: True

View File

@ -90,3 +90,6 @@
branches: ^(?!stable/.*).*$
- octavia-amphora-image-build
- octavia-grenade-ffu
experimental:
jobs:
- octavia-v2-dsvm-scenario-nftables