Skip to content

Commit f2e224a

Browse files
authored
Merge pull request #93 from stackhpc/upstream/zed-2023-12-11
Synchronise zed with upstream
2 parents 45e83f5 + de5b724 commit f2e224a

File tree

8 files changed

+110
-32
lines changed

8 files changed

+110
-32
lines changed

neutron/agent/linux/dhcp.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,7 +1144,8 @@ def _get_ovn_metadata_port_ip(self, subnet):
11441144
m_ports = [port for port in self.network.ports if
11451145
self._is_ovn_metadata_port(port, self.network.id)]
11461146
if m_ports:
1147-
for fixed_ip in m_ports[0].fixed_ips:
1147+
port = self.device_manager.plugin.get_dhcp_port(m_ports[0].id)
1148+
for fixed_ip in port.fixed_ips:
11481149
if fixed_ip.subnet_id == subnet.id:
11491150
return fixed_ip.ip_address
11501151

@@ -1220,7 +1221,7 @@ def _generate_opts_per_subnet(self):
12201221
if subnet_dhcp_ip:
12211222
metadata_route_ip = subnet_dhcp_ip
12221223

1223-
if not isolated_subnets[subnet.id] and gateway:
1224+
elif not isolated_subnets[subnet.id] and gateway:
12241225
metadata_route_ip = gateway
12251226

12261227
if metadata_route_ip:

neutron/conf/agent/metadata/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@
9494
cfg.IntOpt('metadata_workers',
9595
sample_default='<num_of_cpus> / 2',
9696
help=_('Number of separate worker processes for metadata '
97-
'server (defaults to 2 when used with ML2/OVN and half '
97+
'server (defaults to 0 when used with ML2/OVN and half '
9898
'of the number of CPUs with other backend drivers)')),
9999
cfg.IntOpt('metadata_backlog',
100100
default=4096,

neutron/privileged/agent/linux/ip_lib.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,10 @@ def delete_neigh_entry(ip_version, ip_address, mac_address, device, namespace,
473473
if e.code == errno.ENOENT:
474474
return
475475
raise
476+
except OSError as e:
477+
if e.errno == errno.ENOENT:
478+
raise NetworkNamespaceNotFound(netns_name=namespace)
479+
raise
476480

477481

478482
@tenacity.retry(
@@ -682,6 +686,11 @@ def delete_ip_rule(namespace, **kwargs):
682686
try:
683687
with get_iproute(namespace) as ip:
684688
ip.rule('del', **kwargs)
689+
except netlink_exceptions.NetlinkError as e:
690+
# trying to delete a non-existent entry shouldn't raise an error
691+
if e.code == errno.ENOENT:
692+
return
693+
raise
685694
except OSError as e:
686695
if e.errno == errno.ENOENT:
687696
raise NetworkNamespaceNotFound(netns_name=namespace)
@@ -787,6 +796,11 @@ def delete_ip_route(namespace, cidr, ip_version, device=None, via=None,
787796
try:
788797
with get_iproute(namespace) as ip:
789798
ip.route('del', **kwargs)
799+
except netlink_exceptions.NetlinkError as e:
800+
# trying to delete a non-existent entry shouldn't raise an error
801+
if e.code == errno.ESRCH:
802+
return
803+
raise
790804
except OSError as e:
791805
if e.errno == errno.ENOENT:
792806
raise NetworkNamespaceNotFound(netns_name=namespace)
@@ -821,6 +835,11 @@ def _command_bridge_fdb(command, mac, device, dst_ip=None, namespace=None,
821835
kwargs['dst'] = dst_ip
822836
with get_iproute(namespace) as ip:
823837
return make_serializable(ip.fdb(command, **kwargs))
838+
except netlink_exceptions.NetlinkError as e:
839+
# trying to delete a non-existent entry shouldn't raise an error
840+
if command == 'del' and e.code == errno.ENOENT:
841+
return
842+
raise
824843
except OSError as e:
825844
if e.errno == errno.ENOENT:
826845
raise NetworkNamespaceNotFound(netns_name=namespace)
@@ -836,20 +855,20 @@ def add_bridge_fdb(mac, device, dst_ip=None, namespace=None, **kwargs):
836855

837856
@privileged.default.entrypoint
838857
def append_bridge_fdb(mac, device, dst_ip=None, namespace=None, **kwargs):
839-
"""Add a FDB entry"""
858+
"""Append a FDB entry"""
840859
_command_bridge_fdb('append', mac, device, dst_ip=dst_ip,
841860
namespace=namespace, **kwargs)
842861

843862

844863
@privileged.default.entrypoint
845864
def replace_bridge_fdb(mac, device, dst_ip=None, namespace=None, **kwargs):
846-
"""Add a FDB entry"""
865+
"""Replace a FDB entry"""
847866
_command_bridge_fdb('replace', mac, device, dst_ip=dst_ip,
848867
namespace=namespace, **kwargs)
849868

850869

851870
@privileged.default.entrypoint
852871
def delete_bridge_fdb(mac, device, dst_ip=None, namespace=None, **kwargs):
853-
"""Add a FDB entry"""
872+
"""Delete a FDB entry"""
854873
_command_bridge_fdb('del', mac, device, dst_ip=dst_ip,
855874
namespace=namespace, **kwargs)

neutron/tests/fullstack/base.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import itertools
1717
import os
1818
import random
19+
import time
1920

2021
import netaddr
2122
from neutron_lib.tests import tools
@@ -96,6 +97,17 @@ def _agent_up():
9697
def _wait_until_agent_down(self, agent_id):
9798
def _agent_down():
9899
agent = self.client.show_agent(agent_id)['agent']
100+
if not agent.get('alive'):
101+
# NOTE(slaweq): to avoid race between heartbeat written in the
102+
# database and response to this API call, lets make sure that
103+
# agent is really dead. See bug
104+
# https://bugs.launchpad.net/neutron/+bug/2045757
105+
# for details.
106+
# 2 seconds delay should be more than enough to make sure that
107+
# all pending heartbeats are already written in the Neutron
108+
# database
109+
time.sleep(2)
110+
agent = self.client.show_agent(agent_id)['agent']
99111
return not agent.get('alive')
100112

101113
common_utils.wait_until_true(_agent_down)

neutron/tests/functional/agent/linux/test_bridge_lib.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,13 @@ def test_add_delete(self):
211211
namespace=self.namespace)
212212
self._assert_mac(self.MAC1, self.device, present=False)
213213

214+
try:
215+
# This should not raise for a non-existent entry
216+
bridge_lib.FdbInterface.delete(self.MAC1, self.device,
217+
namespace=self.namespace)
218+
except Exception:
219+
self.fail('Delete FDB entry threw unexpected exception')
220+
214221
def test_add_delete_dst(self):
215222
self._assert_mac(self.MAC1, self.device_vxlan, present=False)
216223
bridge_lib.FdbInterface.add(

neutron/tests/functional/privileged/agent/linux/test_ip_lib.py

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -239,19 +239,34 @@ def test_get_devices_info_veth_same_namespaces(self):
239239
self.assertEqual(veth1_2['index'], veth1_1_link)
240240

241241

242-
class ListIpRulesTestCase(functional_base.BaseSudoTestCase):
243-
244-
RULE_TABLES = {'default': 253, 'main': 254, 'local': 255}
242+
class BaseIpRuleTestCase(functional_base.BaseSudoTestCase):
245243

246244
def setUp(self):
247-
super(ListIpRulesTestCase, self).setUp()
245+
super().setUp()
248246
self.namespace = 'ns_test-' + uuidutils.generate_uuid()
249247
self.ns = priv_ip_lib.create_netns(self.namespace)
250248
self.addCleanup(self._remove_ns)
251249

252250
def _remove_ns(self):
253251
priv_ip_lib.remove_netns(self.namespace)
254252

253+
def _check_rules(self, rules, parameters, values, exception_string=None,
254+
raise_exception=True):
255+
for rule in rules:
256+
if all(rule.get(parameter) == value
257+
for parameter, value in zip(parameters, values)):
258+
return True
259+
else:
260+
if raise_exception:
261+
self.fail('Rule with %s was expected' % exception_string)
262+
else:
263+
return False
264+
265+
266+
class ListIpRulesTestCase(BaseIpRuleTestCase):
267+
268+
RULE_TABLES = {'default': 253, 'main': 254, 'local': 255}
269+
255270
def test_list_default_rules_ipv4(self):
256271
rules_ipv4 = priv_ip_lib.list_ip_rules(self.namespace, 4)
257272
self.assertEqual(3, len(rules_ipv4))
@@ -291,28 +306,7 @@ def test_list_rules_ipv6(self):
291306
self.fail('Rule added (2001:db8::1/64, table 20) not found')
292307

293308

294-
class RuleTestCase(functional_base.BaseSudoTestCase):
295-
296-
def setUp(self):
297-
super(RuleTestCase, self).setUp()
298-
self.namespace = 'ns_test-' + uuidutils.generate_uuid()
299-
self.ns = priv_ip_lib.create_netns(self.namespace)
300-
self.addCleanup(self._remove_ns)
301-
302-
def _remove_ns(self):
303-
priv_ip_lib.remove_netns(self.namespace)
304-
305-
def _check_rules(self, rules, parameters, values, exception_string=None,
306-
raise_exception=True):
307-
for rule in rules:
308-
if all(rule.get(parameter) == value
309-
for parameter, value in zip(parameters, values)):
310-
return True
311-
else:
312-
if raise_exception:
313-
self.fail('Rule with %s was expected' % exception_string)
314-
else:
315-
return False
309+
class AddIpRulesTestCase(BaseIpRuleTestCase):
316310

317311
def test_add_rule_ip(self):
318312
ip_addresses = ['192.168.200.250', '2001::250']
@@ -439,6 +433,23 @@ def test_add_rule_exists(self):
439433
self.assertEqual(4, len(rules))
440434

441435

436+
class DeleteIpRulesTestCase(BaseIpRuleTestCase):
437+
438+
def test_delete_rule_no_entry(self):
439+
iif = 'iif_device'
440+
priv_ip_lib.create_interface(iif, self.namespace, 'dummy')
441+
442+
try:
443+
# This should not raise for a non-existent entry
444+
priv_ip_lib.delete_ip_rule(self.namespace, iifname=iif)
445+
except Exception:
446+
self.fail('Delete IP rule threw unexpected exception')
447+
448+
rules = ip_lib.list_ip_rules(self.namespace, 4)
449+
# There are always 3 rules by default
450+
self.assertEqual(3, len(rules))
451+
452+
442453
class GetIpAddressesTestCase(functional_base.BaseSudoTestCase):
443454

444455
def _remove_ns(self, namespace):
@@ -665,6 +676,21 @@ def test_add_multipath_route(self):
665676
n_cons.IP_VERSION_4, via=multipath)
666677
self._check_routes(['192.168.0.0/24'], gateway=multipath)
667678

679+
def test_delete_route_no_entry(self):
680+
cidr = '192.168.0.0/24'
681+
self.device.addr.add('10.1.0.1/24')
682+
try:
683+
# This should not raise for a non-existent entry
684+
priv_ip_lib.delete_ip_route(self.namespace, cidr,
685+
n_cons.IP_VERSION_4,
686+
device=self.device_name)
687+
except Exception:
688+
self.fail('Delete IP route threw unexpected exception')
689+
690+
routes = ip_lib.list_ip_routes(self.namespace, n_cons.IP_VERSION_4)
691+
# There will be a single interface route since we added an IP
692+
self.assertEqual(1, len(routes))
693+
668694

669695
class GetLinkAttributesTestCase(functional_base.BaseSudoTestCase):
670696

neutron/tests/unit/agent/linux/test_dhcp.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3126,6 +3126,8 @@ def test__generate_opts_per_subnet_no_metadata(self):
31263126
def test__generate_opts_per_subnet_with_metadata_port(self):
31273127
config = {'enable_isolated_metadata': False,
31283128
'force_metadata': False}
3129+
self.mock_mgr.return_value.plugin.get_dhcp_port.return_value = \
3130+
FakeOvnMetadataPort()
31293131
self._test__generate_opts_per_subnet_helper(config, True,
31303132
network_class=FakeNetworkDhcpandOvnMetadataPort)
31313133

neutron/tests/unit/privileged/agent/linux/test_ip_lib.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,17 @@ def test_run_iproute_neigh_namespace_not_exists(self):
157157
priv_lib._run_iproute_neigh,
158158
"test_cmd", "eth0", None, test_param="test_value")
159159

160+
def test_run_iproute_neigh_no_entry(self):
161+
with mock.patch.object(pyroute2, "IPRoute") as iproute_mock:
162+
iproute_mock.side_effect = netlink_exceptions.NetlinkError(
163+
code=errno.ENOENT)
164+
try:
165+
priv_lib._run_iproute_neigh(
166+
"test_cmd", "eth0", None, test_param="test_value")
167+
self.fail("NetlinkError exception not raised")
168+
except netlink_exceptions.NetlinkError as e:
169+
self.assertEqual(errno.ENOENT, e.code)
170+
160171
def test_run_iproute_neigh_error(self):
161172
with mock.patch.object(pyroute2, "IPRoute") as iproute_mock:
162173
iproute_mock.side_effect = OSError(

0 commit comments

Comments
 (0)