Skip to content

Commit eb4bd1a

Browse files
authored
Merge pull request #39 from stackhpc/upstream/yoga-2023-04-03
Synchronise yoga with upstream
2 parents 140a5d4 + 9bbb97f commit eb4bd1a

File tree

9 files changed

+148
-34
lines changed

9 files changed

+148
-34
lines changed

doc/source/admin/config-ovsfwdriver.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,18 @@ not true and there may be slight differences between those drivers.
8888
| (please check [3]_ for details) | | rule. |
8989
+----------------------------------------+-----------------------+-----------------------+
9090

91+
92+
Permitted ethertypes
93+
~~~~~~~~~~~~~~~~~~~~
94+
95+
The OVS Firewall blocks traffic that does not have either the IPv4 or IPv6
96+
ethertypes at present. This is a behavior change compared to the
97+
"iptables_hybrid" firewall, which only operates on IP packets and thus does
98+
not address other ethertypes. With the configuration option
99+
``permitted_ethertypes`` it is possible to define a set of allowed ethertypes.
100+
Any traffic with these allowed ethertypes with destination to a local port or
101+
generated from a local port and MAC address, will be allowed.
102+
91103
References
92104
~~~~~~~~~~
93105

neutron/agent/linux/openvswitch_firewall/firewall.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,25 @@ def _initialize_ingress(self, port):
13711371
actions='output:{:d}'.format(port.ofport)
13721372
)
13731373

1374+
# Allow custom ethertypes
1375+
for permitted_ethertype in self.permitted_ethertypes:
1376+
if permitted_ethertype[:2] == '0x':
1377+
try:
1378+
hex_ethertype = hex(int(permitted_ethertype, base=16))
1379+
self._add_flow(
1380+
table=ovs_consts.BASE_INGRESS_TABLE,
1381+
priority=100,
1382+
dl_type=hex_ethertype,
1383+
reg_port=port.ofport,
1384+
actions='output:{:d}'.format(port.ofport)
1385+
)
1386+
continue
1387+
except ValueError:
1388+
pass
1389+
LOG.warning('Custom ethertype %(permitted_ethertype)s is not '
1390+
'a hexadecimal number.',
1391+
{'permitted_ethertype': permitted_ethertype})
1392+
13741393
self._initialize_ingress_ipv6_icmp(port)
13751394

13761395
# DHCP offers

neutron/common/ovn/constants.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,6 @@
384384
LSP_OPTIONS_MCAST_FLOOD = 'mcast_flood'
385385

386386
LRP_OPTIONS_RESIDE_REDIR_CH = 'reside-on-redirect-chassis'
387-
LRP_OPTIONS_REDIRECT_TYPE = 'redirect-type'
388-
BRIDGE_REDIRECT_TYPE = "bridged"
389387

390388
# Port Binding types
391389
PB_TYPE_VIRTUAL = 'virtual'

neutron/db/db_base_plugin_v2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ def create_network_db(self, context, network):
407407
args = {'tenant_id': project_id,
408408
'id': n.get('id') or uuidutils.generate_uuid(),
409409
'name': n['name'],
410-
'mtu': n.get('mtu', constants.DEFAULT_NETWORK_MTU),
410+
'mtu': n.get('mtu', 0),
411411
'admin_state_up': n['admin_state_up'],
412412
'status': n.get('status', constants.NET_STATUS_ACTIVE),
413413
'description': n.get('description')}

neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -833,7 +833,10 @@ def check_vlan_distributed_ports(self):
833833
# Get router ports belonging to VLAN networks
834834
vlan_nets = self._ovn_client._plugin.get_networks(
835835
context, {pnet.NETWORK_TYPE: [n_const.TYPE_VLAN]})
836-
vlan_net_ids = [vn['id'] for vn in vlan_nets]
836+
# FIXME(ltomasbo): Once Bugzilla 2162756 is fixed the
837+
# is_provider_network check should be removed
838+
vlan_net_ids = [vn['id'] for vn in vlan_nets
839+
if not utils.is_provider_network(vn)]
837840
router_ports = self._ovn_client._plugin.get_ports(
838841
context, {'network_id': vlan_net_ids,
839842
'device_owner': n_const.ROUTER_PORT_OWNERS})

neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,29 +1557,21 @@ def _gen_router_port_options(self, port, network=None):
15571557
if network is None:
15581558
network = self._plugin.get_network(admin_context,
15591559
port['network_id'])
1560-
15611560
# For VLAN type networks we need to set the
15621561
# "reside-on-redirect-chassis" option so the routing for this
15631562
# logical router port is centralized in the chassis hosting the
15641563
# distributed gateway port.
15651564
# https://github.com/openvswitch/ovs/commit/85706c34d53d4810f54bec1de662392a3c06a996
1565+
# FIXME(ltomasbo): Once Bugzilla 2162756 is fixed the
1566+
# is_provider_network check should be removed
15661567
if network.get(pnet.NETWORK_TYPE) == const.TYPE_VLAN:
15671568
options[ovn_const.LRP_OPTIONS_RESIDE_REDIR_CH] = (
1568-
'false' if ovn_conf.is_ovn_distributed_floating_ip()
1569+
'false' if (ovn_conf.is_ovn_distributed_floating_ip() and
1570+
not utils.is_provider_network(network))
15691571
else 'true')
15701572

15711573
is_gw_port = const.DEVICE_OWNER_ROUTER_GW == port.get(
15721574
'device_owner')
1573-
1574-
# NOTE(ltomasbo): For VLAN type networks connected through the gateway
1575-
# port there is a need to set the redirect-type option to bridge to
1576-
# ensure traffic is not centralized through the controller.
1577-
# For geneve based tenant networks it won't have any effect as it only
1578-
# applies to network with a localnet associated to it
1579-
if is_gw_port and ovn_conf.is_ovn_distributed_floating_ip():
1580-
options[ovn_const.LRP_OPTIONS_REDIRECT_TYPE] = (
1581-
ovn_const.BRIDGE_REDIRECT_TYPE)
1582-
15831575
if is_gw_port and ovn_conf.is_ovn_emit_need_to_frag_enabled():
15841576
try:
15851577
router_ports = self._get_router_ports(admin_context,
@@ -2380,17 +2372,26 @@ def _find_metadata_port_ip(self, context, subnet):
23802372
return fixed_ip['ip_address']
23812373

23822374
def create_metadata_port(self, context, network):
2383-
if ovn_conf.is_ovn_metadata_enabled():
2384-
metadata_port = self._find_metadata_port(context, network['id'])
2385-
if not metadata_port:
2386-
# Create a neutron port for DHCP/metadata services
2387-
port = {'port':
2388-
{'network_id': network['id'],
2375+
if not ovn_conf.is_ovn_metadata_enabled():
2376+
return
2377+
2378+
if self._find_metadata_port(context, network['id']):
2379+
return
2380+
2381+
# Create a neutron port for DHCP/metadata services
2382+
filters = {'network_id': [network['id']]}
2383+
subnets = self._plugin.get_subnets(context, filters=filters)
2384+
fixed_ips = [{'subnet_id': s['id']}
2385+
for s in subnets if s['enable_dhcp']]
2386+
port = {'port': {'network_id': network['id'],
23892387
'tenant_id': network['project_id'],
23902388
'device_owner': const.DEVICE_OWNER_DISTRIBUTED,
2391-
'device_id': 'ovnmeta-%s' % network['id']}}
2392-
# TODO(boden): rehome create_port into neutron-lib
2393-
p_utils.create_port(self._plugin, context, port)
2389+
'device_id': 'ovnmeta-%s' % network['id'],
2390+
'fixed_ips': fixed_ips,
2391+
}
2392+
}
2393+
# TODO(boden): rehome create_port into neutron-lib
2394+
p_utils.create_port(self._plugin, context, port)
23942395

23952396
def update_metadata_port(self, context, network_id, subnet=None):
23962397
"""Update metadata port.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Copyright 2023 Red Hat, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
from neutron_lib import constants
16+
17+
from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf as ovn_config
18+
from neutron.tests.functional import base
19+
20+
21+
class TestOVNClient(base.TestOVNFunctionalBase):
22+
23+
def test_create_metadata_port(self):
24+
def check_metadata_port(enable_dhcp):
25+
ports = self.plugin.get_ports(
26+
self.context, filters={'network_id': [network['id']]})
27+
self.assertEqual(1, len(ports))
28+
if enable_dhcp:
29+
self.assertEqual(1, len(ports[0]['fixed_ips']))
30+
else:
31+
self.assertEqual(0, len(ports[0]['fixed_ips']))
32+
return ports
33+
34+
ovn_config.cfg.CONF.set_override('ovn_metadata_enabled', True,
35+
group='ovn')
36+
ovn_client = self.mech_driver._ovn_client
37+
for enable_dhcp in (True, False):
38+
network_args = {'tenant_id': 'project_1',
39+
'name': 'test_net_1',
40+
'admin_state_up': True,
41+
'shared': False,
42+
'status': constants.NET_STATUS_ACTIVE}
43+
network = self.plugin.create_network(self.context,
44+
{'network': network_args})
45+
subnet_args = {'tenant_id': 'project_1',
46+
'name': 'test_snet_1',
47+
'network_id': network['id'],
48+
'ip_version': constants.IP_VERSION_4,
49+
'cidr': '10.210.10.0/28',
50+
'enable_dhcp': enable_dhcp,
51+
'gateway_ip': constants.ATTR_NOT_SPECIFIED,
52+
'allocation_pools': constants.ATTR_NOT_SPECIFIED,
53+
'dns_nameservers': constants.ATTR_NOT_SPECIFIED,
54+
'host_routes': constants.ATTR_NOT_SPECIFIED}
55+
self.plugin.create_subnet(self.context, {'subnet': subnet_args})
56+
57+
# The metadata port has been created during the network creation.
58+
ports = check_metadata_port(enable_dhcp)
59+
60+
# Force the deletion and creation the metadata port.
61+
self.plugin.delete_port(self.context, ports[0]['id'])
62+
ovn_client.create_metadata_port(self.context, network)
63+
check_metadata_port(enable_dhcp)
64+
65+
# Call again the "create_metadata_port" method as is idempotent
66+
# because it checks first if the metadata port exists.
67+
ovn_client.create_metadata_port(self.context, network)
68+
check_metadata_port(enable_dhcp)

neutron/tests/unit/agent/linux/openvswitch_firewall/test_firewall.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from neutron.agent.linux.openvswitch_firewall import exceptions
3131
from neutron.agent.linux.openvswitch_firewall import firewall as ovsfw
3232
from neutron.conf.agent import securitygroups_rpc
33+
from neutron.conf.plugins.ml2.drivers import ovs_conf
3334
from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants \
3435
as ovs_consts
3536
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.native \
@@ -514,6 +515,7 @@ def __init__(self, name, port, mac):
514515
class TestOVSFirewallDriver(base.BaseTestCase):
515516
def setUp(self):
516517
super(TestOVSFirewallDriver, self).setUp()
518+
ovs_conf.register_ovs_agent_opts(cfg=cfg.CONF)
517519
mock_bridge = mock.patch.object(
518520
ovs_lib, 'OVSBridge', autospec=True).start()
519521
securitygroups_rpc.register_securitygroups_opts()
@@ -840,6 +842,26 @@ def test_initialize_port_flows_vlan_dvr_conntrack_direct_vlan(self):
840842
return_value={"vlan1": "br-vlan1"}):
841843
self.firewall.initialize_port_flows(port)
842844

845+
def test_initialize_port_flows_permitted_ethertypes(self):
846+
self.firewall.permitted_ethertypes = ['0x1234', '0x5678']
847+
port_dict = {'device': 'port-id',
848+
'security_groups': [1]}
849+
of_port = create_ofport(port_dict,
850+
network_type=constants.TYPE_VLAN,
851+
physical_network='vlan1')
852+
self.firewall.sg_port_map.ports[of_port.id] = of_port
853+
port = self.firewall.get_or_create_ofport(port_dict)
854+
with mock.patch.object(self.firewall, '_add_flow') as mock_add_flow:
855+
self.firewall.initialize_port_flows(port)
856+
857+
calls = [mock.call(table=ovs_consts.BASE_INGRESS_TABLE,
858+
priority=100, dl_type='0x1234',
859+
reg_port=1, actions='output:1'),
860+
mock.call(table=ovs_consts.BASE_INGRESS_TABLE,
861+
priority=100, dl_type='0x5678',
862+
reg_port=1, actions='output:1')]
863+
mock_add_flow.assert_has_calls(calls, any_order=True)
864+
843865
def test_delete_all_port_flows(self):
844866
port_dict = {
845867
'device': 'port-id',

releasenotes/notes/bug-2003455-dff0d0f00b5a18e2.yaml

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)