Skip to content

Commit 33d9589

Browse files
authored
Merge pull request #16 from stackhpc/upstream/yoga-2022-12-05
Synchronise yoga with upstream
2 parents 0114942 + fe077c5 commit 33d9589

File tree

7 files changed

+163
-86
lines changed

7 files changed

+163
-86
lines changed

doc/source/admin/config-sriov.rst

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,22 +64,14 @@ The following manufacturers are known to work:
6464
- QLogic
6565
- Broadcom
6666

67-
For information on **Mellanox SR-IOV Ethernet ConnectX cards**, see:
67+
For information on **Mellanox SR-IOV Ethernet ConnectX cards**, see the
68+
`Mellanox: How To Configure SR-IOV VFs on ConnectX-4 or newer <https://support.mellanox.com/s/article/HowTo-Configure-SR-IOV-for-ConnectX-4-ConnectX-5-ConnectX-6-with-KVM-Ethernet>`_.
6869

69-
- `Mellanox: How To Configure SR-IOV VFs on ConnectX-4 or newer <https://community.mellanox.com/s/article/HowTo-Configure-SR-IOV-for-ConnectX-4-ConnectX-5-ConnectX-6-with-KVM-Ethernet>`_.
70-
- `Mellanox: How To Configure SR-IOV VFs on ConnectX-3/ConnectX-3 Pro <https://community.mellanox.com/docs/DOC-1484>`_.
70+
For information on **QLogic SR-IOV Ethernet cards**, see the
71+
`User's Guide OpenStack Deployment with SR-IOV Configuration <http://www.qlogic.com/solutions/Documents/UsersGuide_OpenStack_SR-IOV.pdf>`_.
7172

72-
For information on **QLogic SR-IOV Ethernet cards**, see:
73-
74-
- `User's Guide OpenStack Deployment with SR-IOV Configuration <http://www.qlogic.com/solutions/Documents/UsersGuide_OpenStack_SR-IOV.pdf>`_.
75-
76-
For information on **Broadcom NetXtreme-E Series Ethernet cards**, see the
77-
`Broadcom NetXtreme-C/NetXtreme-E User Guide
78-
<https://docs.broadcom.com/docs/NetXtreme-UG>`_.
79-
80-
For information on **Broadcom NetXtreme-S Series Ethernet cards**, see the
81-
`Broadcom NetXtreme-S Product Page
82-
<https://www.broadcom.com/products/ethernet-connectivity/smartnic/bcm58800>`_.
73+
For information on **Broadcom NetXtreme Series Ethernet cards**, see the
74+
`Broadcom NetXtreme Product Page <https://www.broadcom.com/products/ethernet-connectivity/network-adapters>`_.
8375

8476
Using SR-IOV interfaces
8577
~~~~~~~~~~~~~~~~~~~~~~~

neutron/agent/ovn/metadata/agent.py

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,12 @@ def _get_ovn_bridge(self):
315315
"br-int instead.")
316316
return 'br-int'
317317

318+
def get_networks(self):
319+
ports = self.sb_idl.get_ports_on_chassis(self.chassis)
320+
return {(str(p.datapath.uuid),
321+
ovn_utils.get_network_name_from_datapath(p.datapath))
322+
for p in self._vif_ports(ports)}
323+
318324
@_sync_lock
319325
def sync(self):
320326
"""Agent sync.
@@ -323,16 +329,26 @@ def sync(self):
323329
chassis are serving metadata. Also, it will tear down those namespaces
324330
which were serving metadata but are no longer needed.
325331
"""
326-
metadata_namespaces = self.ensure_all_networks_provisioned()
332+
333+
# first, clean up namespaces that should no longer deploy
327334
system_namespaces = tuple(
328335
ns.decode('utf-8') if isinstance(ns, bytes) else ns
329336
for ns in ip_lib.list_network_namespaces())
337+
nets = self.get_networks()
338+
metadata_namespaces = [
339+
self._get_namespace_name(net[1])
340+
for net in nets
341+
]
330342
unused_namespaces = [ns for ns in system_namespaces if
331343
ns.startswith(NS_PREFIX) and
332344
ns not in metadata_namespaces]
333345
for ns in unused_namespaces:
334346
self.teardown_datapath(self._get_datapath_name(ns))
335347

348+
# now that all obsolete namespaces are cleaned up, deploy required
349+
# networks
350+
self.ensure_all_networks_provisioned(nets)
351+
336352
@staticmethod
337353
def _get_veth_name(datapath):
338354
return ['{}{}{}'.format(n_const.TAP_DEVICE_PREFIX,
@@ -424,8 +440,6 @@ def provision_datapath(self, datapath, net_name):
424440
and assign the IP addresses to the interface corresponding to the
425441
metadata port of the network. It will also remove existing IP
426442
addresses that are no longer needed.
427-
428-
:return: The metadata namespace name of this datapath
429443
"""
430444
LOG.debug("Provisioning metadata for network %s", net_name)
431445
port = self.sb_idl.get_metadata_port_network(datapath)
@@ -533,28 +547,13 @@ def provision_datapath(self, datapath, net_name):
533547
self.conf, bind_address=n_const.METADATA_V4_IP,
534548
network_id=net_name)
535549

536-
return namespace
550+
def ensure_all_networks_provisioned(self, nets):
551+
"""Ensure that all requested datapaths are provisioned.
537552
538-
def ensure_all_networks_provisioned(self):
539-
"""Ensure that all datapaths are provisioned.
540-
541-
This function will make sure that all datapaths with ports bound to
542-
our chassis have its namespace, VETH pair and OVS port created and
543-
metadata proxy is up and running.
544-
545-
:return: A list with the namespaces that are currently serving
546-
metadata
553+
This function will make sure that requested datapaths have their
554+
namespaces, VETH pair and OVS ports created and metadata proxies are up
555+
and running.
547556
"""
548-
# Retrieve all VIF ports in our Chassis
549-
ports = self.sb_idl.get_ports_on_chassis(self.chassis)
550-
nets = {(str(p.datapath.uuid),
551-
ovn_utils.get_network_name_from_datapath(p.datapath))
552-
for p in self._vif_ports(ports)}
553-
namespaces = []
554557
# Make sure that all those datapaths are serving metadata
555558
for datapath, net_name in nets:
556-
netns = self.provision_datapath(datapath, net_name)
557-
if netns:
558-
namespaces.append(netns)
559-
560-
return namespaces
559+
self.provision_datapath(datapath, net_name)

neutron/services/logapi/drivers/ovn/driver.py

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,46 @@ def create_log_precommit(self, context, log_obj):
302302
if not self.network_logging_supported(self.ovn_nb):
303303
raise LoggingNotSupported()
304304

305+
def _unset_disabled_acls(self, context, log_obj, ovn_txn):
306+
"""Check if we need to disable any ACLs after an update.
307+
308+
Will return True if there were more logs, and False if there was
309+
nothing to check.
310+
311+
:param context: current running context information
312+
:param log_obj: a log_object which was updated
313+
:returns: True if there were other logs enabled, otherwise False.
314+
"""
315+
if log_obj.enabled:
316+
return False
317+
318+
pgs = self._pgs_from_log_obj(context, log_obj)
319+
other_logs = [log for log in self._get_logs(context)
320+
if log.id != log_obj.id and log.enabled]
321+
if not other_logs:
322+
return False
323+
324+
if log_obj.event == log_const.ALL_EVENT:
325+
acls_to_check = pgs[0]["acls"].copy()
326+
if not acls_to_check:
327+
return True
328+
for log in other_logs:
329+
for acl in self._pgs_from_log_obj(context, log)[0]["acls"]:
330+
if acl in acls_to_check:
331+
acls_to_check.remove(acl)
332+
if not acls_to_check:
333+
return True
334+
acls_to_remove = [{"name": pgs[0]["name"], "acls": acls_to_check}]
335+
self._remove_acls_log(acls_to_remove, ovn_txn)
336+
else:
337+
all_events = set([log.event for log in other_logs
338+
if (not log.resource_id or
339+
log.resource_id == log_obj.resource_id)])
340+
if (log_const.ALL_EVENT not in all_events and
341+
log_obj.event not in all_events):
342+
self._remove_acls_log(pgs, ovn_txn)
343+
return True
344+
305345
def update_log(self, context, log_obj):
306346
"""Update a log_obj invocation.
307347
@@ -311,11 +351,13 @@ def update_log(self, context, log_obj):
311351
"""
312352
LOG.debug("Update_log %s", log_obj)
313353

314-
pgs = self._pgs_from_log_obj(context, log_obj)
315-
actions_enabled = self._acl_actions_enabled(log_obj)
316354
with self.ovn_nb.transaction(check_error=True) as ovn_txn:
317-
self._set_acls_log(pgs, ovn_txn, actions_enabled,
318-
utils.ovn_name(log_obj.id))
355+
356+
if not self._unset_disabled_acls(context, log_obj, ovn_txn):
357+
pgs = self._pgs_from_log_obj(context, log_obj)
358+
actions_enabled = self._acl_actions_enabled(log_obj)
359+
self._set_acls_log(pgs, ovn_txn, actions_enabled,
360+
utils.ovn_name(log_obj.id))
319361

320362
def delete_log(self, context, log_obj):
321363
"""Delete a log_obj invocation.

neutron/tests/functional/agent/l3/framework.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
from neutron.conf.agent import common as agent_config
4141
from neutron.conf.agent.l3 import config as l3_config
4242
from neutron.conf import common as common_config
43+
from neutron.tests import base as test_base
4344
from neutron.tests.common import l3_test_common
4445
from neutron.tests.common import net_helpers
4546
from neutron.tests.functional import base
@@ -703,8 +704,8 @@ def fail_ha_router(self, router):
703704
ha_device = ip_lib.IPDevice(device_name, router.ha_namespace)
704705
ha_device.link.set_down()
705706

706-
@staticmethod
707-
def wait_until_ha_router_has_state(router, expected_state):
707+
@test_base.unstable_test("bug 1956958")
708+
def wait_until_ha_router_has_state(self, router, expected_state):
708709

709710
def router_has_expected_state():
710711
state = router.ha_state

neutron/tests/functional/services/logapi/drivers/ovn/test_driver.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,3 +338,59 @@ def test_events_one_sg(self):
338338
self._add_logs_then_remove(
339339
log_const.DROP_EVENT, log_const.ACCEPT_EVENT, sg=self.sg3,
340340
sgrs=self.sg3rs)
341+
342+
def test_disable_logs(self):
343+
# This test ensures that acls are correctly disabled when having
344+
# multiple log objects.
345+
346+
# Check there are no acls with their logging active
347+
sgrs = self.sg1rs
348+
self._check_sgrs(sgrs, is_enabled=False)
349+
self._check_acl_log_drop(is_enabled=False)
350+
351+
# Add accept log object
352+
log_data1 = self._log_data(sg_id=self.sg1)
353+
event1 = log_const.ACCEPT_EVENT
354+
log_data1['log']['event'] = event1
355+
log_obj1 = self.log_plugin.create_log(self.ctxt, log_data1)
356+
self._check_acl_log_drop(is_enabled=False)
357+
self._check_sgrs(sgrs=sgrs, is_enabled=True)
358+
359+
# Add drop log object
360+
log_data2 = self._log_data(sg_id=self.sg1)
361+
event2 = log_const.DROP_EVENT
362+
log_data2['log']['event'] = event2
363+
log_obj2 = self.log_plugin.create_log(self.ctxt, log_data2)
364+
self._check_acl_log_drop(is_enabled=True)
365+
self._check_sgrs(sgrs=sgrs, is_enabled=True)
366+
367+
# Disable drop log object and check it worked correctly
368+
log_data2['log']['enabled'] = False
369+
self.log_plugin.update_log(self.ctxt, log_obj2['id'], log_data2)
370+
self._check_acl_log_drop(is_enabled=False)
371+
self._check_sgrs(sgrs=sgrs, is_enabled=True)
372+
373+
# Enable drop log and create all log object
374+
log_data2['log']['enabled'] = True
375+
self.log_plugin.update_log(self.ctxt, log_obj2['id'], log_data2)
376+
self._check_acl_log_drop(is_enabled=True)
377+
self._check_sgrs(sgrs=sgrs, is_enabled=True)
378+
379+
log_data3 = self._log_data(sg_id=self.sg1)
380+
log_data3['log']['event'] = log_const.ALL_EVENT
381+
log_obj3 = self.log_plugin.create_log(self.ctxt, log_data3)
382+
self._check_sgrs(sgrs=sgrs, is_enabled=True)
383+
self._check_acl_log_drop(is_enabled=True)
384+
385+
# Disable all log object and check all acls are still enabled (because
386+
# of the other objects)
387+
log_data3['log']['enabled'] = False
388+
self.log_plugin.update_log(self.ctxt, log_obj3['id'], log_data3)
389+
self._check_sgrs(sgrs=sgrs, is_enabled=True)
390+
self._check_acl_log_drop(is_enabled=True)
391+
392+
# Disable accept log object and only drop traffic gets logged
393+
log_data1['log']['enabled'] = False
394+
self.log_plugin.update_log(self.ctxt, log_obj1['id'], log_data1)
395+
self._check_sgrs(sgrs=sgrs, is_enabled=False)
396+
self._check_acl_log_drop(is_enabled=True)

neutron/tests/unit/agent/ovn/metadata/test_agent.py

Lines changed: 28 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -73,19 +73,29 @@ def setUp(self):
7373
self.agent.chassis = 'chassis'
7474
self.agent.ovn_bridge = 'br-int'
7575

76+
self.ports = []
77+
for i in range(0, 3):
78+
self.ports.append(makePort(datapath=DatapathInfo(uuid=str(i),
79+
external_ids={'name': 'neutron-%d' % i})))
80+
self.agent.sb_idl.get_ports_on_chassis.return_value = self.ports
81+
7682
def test_sync(self):
83+
7784
with mock.patch.object(
7885
self.agent, 'ensure_all_networks_provisioned') as enp,\
7986
mock.patch.object(
8087
ip_lib, 'list_network_namespaces') as lnn,\
8188
mock.patch.object(
8289
self.agent, 'teardown_datapath') as tdp:
83-
enp.return_value = ['ovnmeta-1', 'ovnmeta-2']
8490
lnn.return_value = ['ovnmeta-1', 'ovnmeta-2']
8591

8692
self.agent.sync()
8793

88-
enp.assert_called_once_with()
94+
enp.assert_called_once_with({
95+
(p.datapath.uuid, p.datapath.uuid)
96+
for p in self.ports
97+
})
98+
8999
lnn.assert_called_once_with()
90100
tdp.assert_not_called()
91101

@@ -97,18 +107,20 @@ def test_sync_teardown_namespace(self):
97107
ip_lib, 'list_network_namespaces') as lnn,\
98108
mock.patch.object(
99109
self.agent, 'teardown_datapath') as tdp:
100-
enp.return_value = ['ovnmeta-1', 'ovnmeta-2']
101110
lnn.return_value = ['ovnmeta-1', 'ovnmeta-2', 'ovnmeta-3',
102111
'ns1', 'ns2']
103112

104113
self.agent.sync()
105114

106-
enp.assert_called_once_with()
115+
enp.assert_called_once_with({
116+
(p.datapath.uuid, p.datapath.uuid)
117+
for p in self.ports
118+
})
107119
lnn.assert_called_once_with()
108120
tdp.assert_called_once_with('3')
109121

110-
def test_ensure_all_networks_provisioned(self):
111-
"""Test networks are provisioned.
122+
def test_get_networks(self):
123+
"""Test which networks are provisioned.
112124
113125
This test simulates that this chassis has the following ports:
114126
* datapath '0': 1 port
@@ -117,61 +129,37 @@ def test_ensure_all_networks_provisioned(self):
117129
* datapath '3': 1 port with type 'external'
118130
* datapath '5': 1 port with type 'unknown'
119131
120-
It is expected that only datapaths '0', '1' and '2' are provisioned
121-
once.
132+
It is expected that only datapaths '0', '1' and '2' are scheduled for
133+
provisioning.
122134
"""
123135

124-
ports = []
125-
for i in range(0, 3):
126-
ports.append(makePort(datapath=DatapathInfo(uuid=str(i),
127-
external_ids={'name': 'neutron-%d' % i})))
128-
ports.append(makePort(datapath=DatapathInfo(uuid='1',
136+
self.ports.append(makePort(datapath=DatapathInfo(uuid='1',
129137
external_ids={'name': 'neutron-1'})))
130-
ports.append(makePort(datapath=DatapathInfo(uuid='3',
138+
self.ports.append(makePort(datapath=DatapathInfo(uuid='3',
131139
external_ids={'name': 'neutron-3'}), type='external'))
132-
ports.append(makePort(datapath=DatapathInfo(uuid='5',
140+
self.ports.append(makePort(datapath=DatapathInfo(uuid='5',
133141
external_ids={'name': 'neutron-5'}), type='unknown'))
134142

135-
with mock.patch.object(self.agent, 'provision_datapath',
136-
return_value=None) as pdp,\
137-
mock.patch.object(self.agent.sb_idl, 'get_ports_on_chassis',
138-
return_value=ports):
139-
self.agent.ensure_all_networks_provisioned()
140-
141-
expected_calls = [mock.call(str(i), str(i)) for i in range(0, 4)]
142-
self.assertEqual(sorted(expected_calls),
143-
sorted(pdp.call_args_list))
143+
expected_networks = {(str(i), str(i)) for i in range(0, 4)}
144+
self.assertEqual(expected_networks, self.agent.get_networks())
144145

145146
def test_update_datapath_provision(self):
146-
ports = []
147-
for i in range(0, 3):
148-
ports.append(makePort(datapath=DatapathInfo(uuid=str(i),
149-
external_ids={'name': 'neutron-%d' % i})))
150-
ports.append(makePort(datapath=DatapathInfo(uuid='3',
147+
self.ports.append(makePort(datapath=DatapathInfo(uuid='3',
151148
external_ids={'name': 'neutron-3'}), type='external'))
152149

153150
with mock.patch.object(self.agent, 'provision_datapath',
154151
return_value=None) as pdp,\
155-
mock.patch.object(self.agent, 'teardown_datapath') as tdp,\
156-
mock.patch.object(self.agent.sb_idl, 'get_ports_on_chassis',
157-
return_value=ports):
152+
mock.patch.object(self.agent, 'teardown_datapath') as tdp:
158153
self.agent.update_datapath('1', 'a')
159154
self.agent.update_datapath('3', 'b')
160155
expected_calls = [mock.call('1', 'a'), mock.call('3', 'b')]
161156
pdp.assert_has_calls(expected_calls)
162157
tdp.assert_not_called()
163158

164159
def test_update_datapath_teardown(self):
165-
ports = []
166-
for i in range(0, 3):
167-
ports.append(makePort(datapath=DatapathInfo(uuid=str(i),
168-
external_ids={'name': 'neutron-%d' % i})))
169-
170160
with mock.patch.object(self.agent, 'provision_datapath',
171161
return_value=None) as pdp,\
172-
mock.patch.object(self.agent, 'teardown_datapath') as tdp,\
173-
mock.patch.object(self.agent.sb_idl, 'get_ports_on_chassis',
174-
return_value=ports):
162+
mock.patch.object(self.agent, 'teardown_datapath') as tdp:
175163
self.agent.update_datapath('5', 'a')
176164
tdp.assert_called_once_with('5', 'a')
177165
pdp.assert_not_called()

0 commit comments

Comments
 (0)