From f5b6c2afd8c4d4c47d7f0efd91a23d3cc550aabd Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Sun, 5 Mar 2023 22:12:55 +0100 Subject: [PATCH] [OVS] Allow custom ethertype traffic in the ingress table This patch is a partial revert of [1], reinstantiating the code merged in [2]. This patch is the complementary to [1]: the traffic with custom ethertypes is allowed in the ingress processing tables, same as [1] is allowing all traffic from the virtual machine ports in this host to leave the node. Both, this patch and [1], are bypassing the OVS firewall just for the traffic with the configured allowed ethertypes and just for/to the local ports and MAC addresses. Any other traffic not coming from a local port or with destination a local port, will be blocked as is now. [1]https://review.opendev.org/c/openstack/neutron/+/678021 [2]https://review.opendev.org/c/openstack/neutron/+/668224/ Conflicts: doc/source/admin/config-ovsfwdriver.rst neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py Closes-Bug: #2009221 Related-Bug: #1832758 Change-Id: Ib8340d9430b946a446edf80886c49fbac729073c (cherry picked from commit 008277b8c12d99438951a308b278203fa7a7c3ef) (cherry picked from commit 5026d805fe01aaf237081c606f1d1bf87bbff6d4) --- doc/source/admin/config-ovsfwdriver.rst | 12 ++++++++++ .../linux/openvswitch_firewall/firewall.py | 19 ++++++++++++++++ .../openvswitch_firewall/test_firewall.py | 22 +++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/doc/source/admin/config-ovsfwdriver.rst b/doc/source/admin/config-ovsfwdriver.rst index e915700b462..061c77cea6c 100644 --- a/doc/source/admin/config-ovsfwdriver.rst +++ b/doc/source/admin/config-ovsfwdriver.rst @@ -88,6 +88,18 @@ not true and there may be slight differences between those drivers. | (please check [3]_ for details) | | rule. | +----------------------------------------+-----------------------+-----------------------+ + +Permitted ethertypes +~~~~~~~~~~~~~~~~~~~~ + +The OVS Firewall blocks traffic that does not have either the IPv4 or IPv6 +ethertypes at present. This is a behavior change compared to the +"iptables_hybrid" firewall, which only operates on IP packets and thus does +not address other ethertypes. With the configuration option +``permitted_ethertypes`` it is possible to define a set of allowed ethertypes. +Any traffic with these allowed ethertypes with destination to a local port or +generated from a local port and MAC address, will be allowed. + References ~~~~~~~~~~ diff --git a/neutron/agent/linux/openvswitch_firewall/firewall.py b/neutron/agent/linux/openvswitch_firewall/firewall.py index d30d99cdd16..db72ffdbfc1 100644 --- a/neutron/agent/linux/openvswitch_firewall/firewall.py +++ b/neutron/agent/linux/openvswitch_firewall/firewall.py @@ -1366,6 +1366,25 @@ class OVSFirewallDriver(firewall.FirewallDriver): actions='output:{:d}'.format(port.ofport) ) + # Allow custom ethertypes + for permitted_ethertype in self.permitted_ethertypes: + if permitted_ethertype[:2] == '0x': + try: + hex_ethertype = hex(int(permitted_ethertype, base=16)) + self._add_flow( + table=ovs_consts.BASE_INGRESS_TABLE, + priority=100, + dl_type=hex_ethertype, + reg_port=port.ofport, + actions='output:{:d}'.format(port.ofport) + ) + continue + except ValueError: + pass + LOG.warning('Custom ethertype %(permitted_ethertype)s is not ' + 'a hexadecimal number.', + {'permitted_ethertype': permitted_ethertype}) + self._initialize_ingress_ipv6_icmp(port) # DHCP offers diff --git a/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py b/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py index 6f44b93b14d..943aeb08540 100644 --- a/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py +++ b/neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py @@ -30,6 +30,7 @@ from neutron.agent.linux.openvswitch_firewall import constants as ovsfw_consts from neutron.agent.linux.openvswitch_firewall import exceptions from neutron.agent.linux.openvswitch_firewall import firewall as ovsfw from neutron.conf.agent import securitygroups_rpc +from neutron.conf.plugins.ml2.drivers import ovs_conf from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants \ as ovs_consts from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.native \ @@ -514,6 +515,7 @@ class FakeOVSPort(object): class TestOVSFirewallDriver(base.BaseTestCase): def setUp(self): super(TestOVSFirewallDriver, self).setUp() + ovs_conf.register_ovs_agent_opts(cfg=cfg.CONF) mock_bridge = mock.patch.object( ovs_lib, 'OVSBridge', autospec=True).start() securitygroups_rpc.register_securitygroups_opts() @@ -840,6 +842,26 @@ class TestOVSFirewallDriver(base.BaseTestCase): return_value={"vlan1": "br-vlan1"}): self.firewall.initialize_port_flows(port) + def test_initialize_port_flows_permitted_ethertypes(self): + self.firewall.permitted_ethertypes = ['0x1234', '0x5678'] + port_dict = {'device': 'port-id', + 'security_groups': [1]} + of_port = create_ofport(port_dict, + network_type=constants.TYPE_VLAN, + physical_network='vlan1') + self.firewall.sg_port_map.ports[of_port.id] = of_port + port = self.firewall.get_or_create_ofport(port_dict) + with mock.patch.object(self.firewall, '_add_flow') as mock_add_flow: + self.firewall.initialize_port_flows(port) + + calls = [mock.call(table=ovs_consts.BASE_INGRESS_TABLE, + priority=100, dl_type='0x1234', + reg_port=1, actions='output:1'), + mock.call(table=ovs_consts.BASE_INGRESS_TABLE, + priority=100, dl_type='0x5678', + reg_port=1, actions='output:1')] + mock_add_flow.assert_has_calls(calls, any_order=True) + def test_delete_all_port_flows(self): port_dict = { 'device': 'port-id',