Skip to content

Commit 2d0f8dc

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "[OVN] Set the Neutron port status based on "lsp.up" and "lsp.enabled"" into stable/2023.1
2 parents f0c7222 + 1514fbe commit 2d0f8dc

File tree

4 files changed

+120
-65
lines changed

4 files changed

+120
-65
lines changed

neutron/common/ovn/utils.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,33 @@ def get_lsp_security_groups(port, skip_trusted_port=True):
299299
) else port.get('security_groups', [])
300300

301301

302+
def is_lsp_enabled(lsp):
303+
"""Return if a Logical Switch Port is enabled
304+
305+
This method mimics the OVN northd method ``lsp_is_enabled``
306+
https://shorturl.at/rBSZ7. The "enabled" field can have three values:
307+
* []: from older OVN versions, in this case the LSP is enabled by default.
308+
* [True]: the LSP is enabled.
309+
* [False]: the LSP is disabled.
310+
311+
:param lsp: ``ovs.db.Row`` with a Logical Switch Port register.
312+
:return: True if the port is enabled, False if not.
313+
"""
314+
return not lsp.enabled or lsp.enabled == [True]
315+
316+
317+
def is_lsp_up(lsp):
318+
"""Return if a Logical Switch Port is UP
319+
320+
This method mimics the OVN northd method ``lsp_is_up``
321+
https://shorturl.at/aoKR6
322+
323+
:param lsp: ``ovs.db.Row`` with a Logical Switch Port register.
324+
:return: True if the port is UP, False if not.
325+
"""
326+
return lsp.up == [True]
327+
328+
302329
def is_snat_enabled(router):
303330
return router.get(l3.EXTERNAL_GW_INFO, {}).get('enable_snat', True)
304331

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

Lines changed: 46 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ def match_fn(self, event, row, old=None):
286286
# ``LogicalSwitchPortUpdateUpEvent`` events.
287287
return False
288288

289-
return bool(lsp.up)
289+
return utils.is_lsp_enabled(lsp) and utils.is_lsp_up(lsp)
290290

291291
def run(self, event, row, old=None):
292292
self.driver.set_port_status_up(row.logical_port)
@@ -461,81 +461,84 @@ def run(self, event, row, old):
461461
router, host)
462462

463463

464-
class LogicalSwitchPortCreateUpEvent(row_event.RowEvent):
465-
"""Row create event - Logical_Switch_Port 'up' = True.
464+
class LogicalSwitchPortCreateEvent(row_event.RowEvent):
465+
"""Row create event - Checks Logical_Switch_Port is UP and enabled.
466466
467467
On connection, we get a dump of all ports, so if there is a neutron
468-
port that is down that has since been activated, we'll catch it here.
469-
This event will not be generated for new ports getting created.
468+
port that has been activated or deactivated, we'll catch it here.
470469
"""
471470

472471
def __init__(self, driver):
473472
self.driver = driver
474473
table = 'Logical_Switch_Port'
475474
events = (self.ROW_CREATE,)
476-
super(LogicalSwitchPortCreateUpEvent, self).__init__(
477-
events, table, (('up', '=', True),))
478-
self.event_name = 'LogicalSwitchPortCreateUpEvent'
475+
super().__init__(events, table, [])
476+
self.event_name = 'LogicalSwitchPortCreateEvent'
479477

480478
def run(self, event, row, old):
481-
self.driver.set_port_status_up(row.name)
482-
483-
484-
class LogicalSwitchPortCreateDownEvent(row_event.RowEvent):
485-
"""Row create event - Logical_Switch_Port 'up' = False
486-
487-
On connection, we get a dump of all ports, so if there is a neutron
488-
port that is up that has since been deactivated, we'll catch it here.
489-
This event will not be generated for new ports getting created.
490-
"""
491-
def __init__(self, driver):
492-
self.driver = driver
493-
table = 'Logical_Switch_Port'
494-
events = (self.ROW_CREATE,)
495-
super(LogicalSwitchPortCreateDownEvent, self).__init__(
496-
events, table, (('up', '=', False),))
497-
self.event_name = 'LogicalSwitchPortCreateDownEvent'
498-
499-
def run(self, event, row, old):
500-
self.driver.set_port_status_down(row.name)
479+
if utils.is_lsp_up(row) and utils.is_lsp_enabled(row):
480+
self.driver.set_port_status_up(row.name)
481+
else:
482+
self.driver.set_port_status_down(row.name)
501483

502484

503485
class LogicalSwitchPortUpdateUpEvent(row_event.RowEvent):
504-
"""Row update event - Logical_Switch_Port 'up' going from False to True
486+
"""Row update event - Logical_Switch_Port UP or enabled going True
505487
506488
This happens when the VM goes up.
507-
New value of Logical_Switch_Port 'up' will be True and the old value will
508-
be False.
509489
"""
510490
def __init__(self, driver):
511491
self.driver = driver
512492
table = 'Logical_Switch_Port'
513493
events = (self.ROW_UPDATE,)
514494
super(LogicalSwitchPortUpdateUpEvent, self).__init__(
515-
events, table, (('up', '=', True),),
516-
old_conditions=(('up', '!=', True),))
495+
events, table, None)
517496
self.event_name = 'LogicalSwitchPortUpdateUpEvent'
518497

498+
def match_fn(self, event, row, old):
499+
if not (utils.is_lsp_up(row) and utils.is_lsp_enabled(row)):
500+
return False
501+
502+
if hasattr(old, 'up') and not utils.is_lsp_up(old):
503+
# The port has transitioned from DOWN to UP, and the admin state
504+
# is UP (lsp.enabled=True)
505+
return True
506+
if hasattr(old, 'enabled') and not utils.is_lsp_enabled(old):
507+
# The user has set the admin state to UP and the port is UP too.
508+
return True
509+
return False
510+
519511
def run(self, event, row, old):
520512
self.driver.set_port_status_up(row.name)
521513

522514

523515
class LogicalSwitchPortUpdateDownEvent(row_event.RowEvent):
524-
"""Row update event - Logical_Switch_Port 'up' going from True to False
516+
"""Row update event - Logical_Switch_Port UP or enabled going to False
525517
526-
This happens when the VM goes down.
527-
New value of Logical_Switch_Port 'up' will be False and the old value will
528-
be True.
518+
This happens when the VM goes down or the port is disabled.
529519
"""
530520
def __init__(self, driver):
531521
self.driver = driver
532522
table = 'Logical_Switch_Port'
533523
events = (self.ROW_UPDATE,)
534524
super(LogicalSwitchPortUpdateDownEvent, self).__init__(
535-
events, table, (('up', '=', False),),
536-
old_conditions=(('up', '=', True),))
525+
events, table, None)
537526
self.event_name = 'LogicalSwitchPortUpdateDownEvent'
538527

528+
def match_fn(self, event, row, old):
529+
if (hasattr(old, 'up') and
530+
utils.is_lsp_up(old) and
531+
not utils.is_lsp_up(row)):
532+
# If the port goes DOWN, update the port status to DOWN.
533+
return True
534+
if (hasattr(old, 'enabled') and
535+
utils.is_lsp_enabled(old) and
536+
not utils.is_lsp_enabled(row)):
537+
# If the port is disabled by the user, update the port status to
538+
# DOWN.
539+
return True
540+
return False
541+
539542
def run(self, event, row, old):
540543
self.driver.set_port_status_down(row.name)
541544

@@ -779,12 +782,10 @@ def __init__(self, driver, remote, schema):
779782
super(OvnNbIdl, self).__init__(driver, remote, schema)
780783
self._lsp_update_up_event = LogicalSwitchPortUpdateUpEvent(driver)
781784
self._lsp_update_down_event = LogicalSwitchPortUpdateDownEvent(driver)
782-
self._lsp_create_up_event = LogicalSwitchPortCreateUpEvent(driver)
783-
self._lsp_create_down_event = LogicalSwitchPortCreateDownEvent(driver)
785+
self._lsp_create_event = LogicalSwitchPortCreateEvent(driver)
784786
self._fip_create_delete_event = FIPAddDeleteEvent(driver)
785787

786-
self.notify_handler.watch_events([self._lsp_create_up_event,
787-
self._lsp_create_down_event,
788+
self.notify_handler.watch_events([self._lsp_create_event,
788789
self._lsp_update_up_event,
789790
self._lsp_update_down_event,
790791
self._fip_create_delete_event])
@@ -804,10 +805,8 @@ def unwatch_logical_switch_port_create_events(self):
804805
After the startup, there is no need to watch these events.
805806
So unwatch these events.
806807
"""
807-
self.notify_handler.unwatch_events([self._lsp_create_up_event,
808-
self._lsp_create_down_event])
809-
self._lsp_create_up_event = None
810-
self._lsp_create_down_event = None
808+
self.notify_handler.unwatch_events([self._lsp_create_event])
809+
del self._lsp_create_event
811810

812811
def post_connect(self):
813812
self.unwatch_logical_switch_port_create_events()

neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovsdb_monitor.py

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@
6060
"port_security": {"type": {"key": "string",
6161
"min": 0,
6262
"max": "unlimited"}},
63-
"up": {"type": {"key": "boolean", "min": 0, "max": 1}}},
63+
"up": {"type": {"key": "boolean", "min": 0, "max": 1}},
64+
"enabled": {"type": {"key": "boolean", "min": 0, "max": 1}},
65+
},
6466
"indexes": [["name"]],
6567
"isRoot": False,
6668
},
@@ -366,7 +368,8 @@ def test_event_matches(self):
366368
pbtable = fakes.FakeOvsdbTable.create_one_ovsdb_table(
367369
attrs={'name': 'Port_Binding'})
368370
ovsdb_row = fakes.FakeOvsdbRow.create_one_ovsdb_row
369-
self.driver.nb_ovn.lookup.return_value = ovsdb_row(attrs={'up': True})
371+
self.driver.nb_ovn.lookup.return_value = ovsdb_row(
372+
attrs={'up': True, 'enabled': True})
370373

371374
# Port binding change.
372375
self._test_event(
@@ -422,28 +425,46 @@ def _test_lsp_helper(self, event, new_row_json, old_row_json=None,
422425
# Execute the notifications queued
423426
self.idl.notify_handler.notify_loop()
424427

425-
def test_lsp_up_create_event(self):
426-
row_data = {"up": True, "name": "foo-name"}
428+
def test_lsp_create_event(self):
429+
row_data = {'name': 'foo'}
430+
431+
# up and enabled
432+
row_data.update({'up': True, 'enabled': True})
427433
self._test_lsp_helper('create', row_data)
428-
self.mech_driver.set_port_status_up.assert_called_once_with("foo-name")
434+
self.mech_driver.set_port_status_up.assert_called_once_with('foo')
429435
self.assertFalse(self.mech_driver.set_port_status_down.called)
436+
self.mech_driver.set_port_status_up.reset_mock()
430437

431-
def test_lsp_down_create_event(self):
432-
row_data = {"up": False, "name": "foo-name"}
438+
# up and disabled
439+
row_data.update({'up': True, 'enabled': False})
433440
self._test_lsp_helper('create', row_data)
434-
self.mech_driver.set_port_status_down.assert_called_once_with(
435-
"foo-name")
436441
self.assertFalse(self.mech_driver.set_port_status_up.called)
442+
self.mech_driver.set_port_status_down.assert_called_once_with('foo')
443+
self.mech_driver.set_port_status_down.reset_mock()
437444

438-
def test_lsp_up_not_set_event(self):
439-
row_data = {"up": ['set', []], "name": "foo-name"}
445+
# down and enabled
446+
row_data.update({'up': False, 'enabled': True})
440447
self._test_lsp_helper('create', row_data)
441448
self.assertFalse(self.mech_driver.set_port_status_up.called)
442-
self.assertFalse(self.mech_driver.set_port_status_down.called)
449+
self.mech_driver.set_port_status_down.assert_called_once_with('foo')
450+
self.mech_driver.set_port_status_down.reset_mock()
451+
452+
# down and disabled
453+
row_data.update({'up': False, 'enabled': False})
454+
self._test_lsp_helper('create', row_data)
455+
self.assertFalse(self.mech_driver.set_port_status_up.called)
456+
self.mech_driver.set_port_status_down.assert_called_once_with('foo')
457+
self.mech_driver.set_port_status_down.reset_mock()
458+
459+
# Not set to up
460+
row_data.update({'up': ['set', []], 'enabled': True})
461+
self._test_lsp_helper('create', row_data)
462+
self.assertFalse(self.mech_driver.set_port_status_up.called)
463+
self.mech_driver.set_port_status_down.assert_called_once_with('foo')
443464

444465
def test_unwatch_logical_switch_port_create_events(self):
445466
self.idl.unwatch_logical_switch_port_create_events()
446-
row_data = {"up": True, "name": "foo-name"}
467+
row_data = {'up': False, 'name': 'foo-name'}
447468
self._test_lsp_helper('create', row_data)
448469
self.assertFalse(self.mech_driver.set_port_status_up.called)
449470
self.assertFalse(self.mech_driver.set_port_status_down.called)
@@ -455,19 +476,18 @@ def test_unwatch_logical_switch_port_create_events(self):
455476

456477
def test_post_connect(self):
457478
self.idl.post_connect()
458-
self.assertIsNone(self.idl._lsp_create_up_event)
459-
self.assertIsNone(self.idl._lsp_create_down_event)
479+
self.assertIsNone(getattr(self.idl, '_lsp_create_event', None))
460480

461481
def test_lsp_up_update_event(self):
462-
new_row_json = {"up": True, "name": "foo-name"}
482+
new_row_json = {'up': True, 'enabled': True, 'name': 'foo-name'}
463483
old_row_json = {"up": False}
464484
self._test_lsp_helper('update', new_row_json,
465485
old_row_json=old_row_json)
466486
self.mech_driver.set_port_status_up.assert_called_once_with("foo-name")
467487
self.assertFalse(self.mech_driver.set_port_status_down.called)
468488

469489
def test_lsp_down_update_event(self):
470-
new_row_json = {"up": False, "name": "foo-name"}
490+
new_row_json = {'up': False, 'enabled': False, 'name': 'foo-name'}
471491
old_row_json = {"up": True}
472492
self._test_lsp_helper('update', new_row_json,
473493
old_row_json=old_row_json)
@@ -476,7 +496,7 @@ def test_lsp_down_update_event(self):
476496
self.assertFalse(self.mech_driver.set_port_status_up.called)
477497

478498
def test_lsp_up_update_event_no_old_data(self):
479-
new_row_json = {"up": True, "name": "foo-name"}
499+
new_row_json = {'up': True, 'enabled': True, 'name': 'foo-name'}
480500
self._test_lsp_helper('update', new_row_json,
481501
old_row_json=None)
482502
self.assertFalse(self.mech_driver.set_port_status_up.called)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
fixes:
3+
- |
4+
[`bug 2036705 <https://bugs.launchpad.net/neutron/+bug/2036705>`_]
5+
The Neutron ``port.status`` field ("ACTIVE", "DOWN") is now set based on
6+
the ML2/OVN Logical Switch Port ``up`` and ``enabled`` flags. The user can
7+
now set the ``port.admin_state_up``, that is replicated in the
8+
``lsp.enabled`` flag, to enable or disable the port. If the port is
9+
disabled, the traffic is stopped and the ``port.status`` is set to "DOWN".

0 commit comments

Comments
 (0)