Merge "Minor refactor of the EVPN FSM"

This commit is contained in:
Zuul authored and Gerrit Code Review committed 2026-10-01 17:29:42 +00:00
commit 59fb77d697
7 files changed
+122 -114

No files matched your search

+2 -2
View File
@@ -74,7 +74,7 @@ class PortBindingLrpEvpnCreateEvent(EVPNPortBindingEvent):
vni = int(row.external_ids[svc_const.EVPN_LRP_VNI_EXT_ID_KEY])
vid = int(row.external_ids[svc_const.EVPN_LRP_VLAN_EXT_ID_KEY])
try:
self.fsm.advance(evpn_fsm.EvpnFSM.FSM_EVENT_PORT_BINDING_CREATE,
self.fsm.advance(evpn_fsm.EVPNEvent.PORT_BINDING_CREATE,
vrf, mac=row.mac[0], vni=vni, vid=vid)
except evpn_exc.FSMIllegalTransition:
LOG.error("Unexpected FSM transition for VRF %s on %s",
@@ -88,7 +88,7 @@ class PortBindingLrpEvpnDeleteEvent(EVPNPortBindingEvent):
def run(self, event, row, old):
vrf = row.options[ovn_const.LR_OPTIONS_DR_VRF_NAME]
try:
self.fsm.advance(evpn_fsm.EvpnFSM.FSM_EVENT_PORT_BINDING_DELETE,
self.fsm.advance(evpn_fsm.EVPNEvent.PORT_BINDING_DELETE,
vrf)
except evpn_exc.FSMIllegalTransition:
LOG.error("Unexpected FSM transition for VRF %s on %s",
+59 -51
View File
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import enum
import threading
from oslo_log import log
@@ -23,62 +24,68 @@ LOG = log.getLogger(__name__)
_FSM_LOCK = threading.Lock()
class Evpn:
"""Per EVPN instance tracking FSM state."""
class EVPNState(enum.Enum):
INIT = 'init'
WAITING_FOR_ROUTER = 'waiting_for_router'
WAITING_FOR_BRIDGE = 'waiting_for_bridge'
WAITING_FOR_VRF = 'waiting_for_vrf'
WAITING_FOR_PORT_BINDING = 'waiting_for_port_binding'
ADVERTISING = 'advertising'
DESTROY = 'destroy'
class EVPNEvent(enum.Enum):
PORT_BINDING_CREATE = 'port_binding_create'
PORT_BINDING_DELETE = 'port_binding_delete'
VRF_CREATE = 'vrf_create'
VRF_DELETE = 'vrf_delete'
class EVPNInstance:
"""Per EVPN instance tracking FSM state."""
def __init__(self, vrf):
self.vrf = vrf
self.vrf_up = False
self.mac = None
self.vni = None
self.vid = None
self.state = self.INIT
self.state = EVPNState.INIT
class EvpnFSM:
"""Finite State Machine for EVPN instances.
Manages one Evpn instance per VRF. Event sources
Manages one EVPNInstance per VRF. Event sources
(PortBindingLrpEvpnEvent, VrfHandler) call the public
methods; the FSM drives state transitions and triggers
provisioning actions.
"""
FSM_EVENT_PORT_BINDING_CREATE = 'port_binding_create'
FSM_EVENT_PORT_BINDING_DELETE = 'port_binding_delete'
FSM_EVENT_VRF_CREATE = 'vrf_create'
FSM_EVENT_VRF_DELETE = 'vrf_delete'
# Transitions in the FSM
# Each entry contains the following:
# (Current state, Event):(New state, transition callback)
# (Current state, Event): (New state, callback(action))
TRANSITIONS = {
(Evpn.INIT, FSM_EVENT_PORT_BINDING_CREATE):
(Evpn.WAITING_FOR_ROUTER, "_set_evpn_bridge"),
(Evpn.INIT, FSM_EVENT_VRF_CREATE):
(Evpn.WAITING_FOR_BRIDGE, "_set_evpn_router"),
(Evpn.WAITING_FOR_ROUTER, FSM_EVENT_VRF_CREATE):
(Evpn.ADVERTISING, "_set_evpn_router_and_advertise"),
(Evpn.WAITING_FOR_BRIDGE, FSM_EVENT_PORT_BINDING_CREATE):
(Evpn.ADVERTISING, "_set_evpn_bridge_and_advertise"),
(Evpn.ADVERTISING, FSM_EVENT_PORT_BINDING_DELETE):
(Evpn.WAITING_FOR_BRIDGE, "_unset_evpn_bridge_and_unadvertise"),
(Evpn.ADVERTISING, FSM_EVENT_VRF_DELETE):
(Evpn.WAITING_FOR_ROUTER, "_unset_evpn_router_and_unadvertise"),
(Evpn.WAITING_FOR_BRIDGE, FSM_EVENT_VRF_DELETE):
(Evpn.DESTROY, "_destroy"),
(Evpn.WAITING_FOR_ROUTER, FSM_EVENT_PORT_BINDING_DELETE):
(Evpn.DESTROY, "_destroy"),
(EVPNState.INIT, EVPNEvent.PORT_BINDING_CREATE):
(EVPNState.WAITING_FOR_VRF, "_set_evpn_bridge"),
(EVPNState.INIT, EVPNEvent.VRF_CREATE):
(EVPNState.WAITING_FOR_PORT_BINDING, "_set_evpn_router"),
(EVPNState.WAITING_FOR_VRF, EVPNEvent.VRF_CREATE):
(EVPNState.ADVERTISING, "_set_evpn_router_and_advertise"),
(EVPNState.WAITING_FOR_PORT_BINDING, EVPNEvent.PORT_BINDING_CREATE):
(EVPNState.ADVERTISING, "_set_evpn_bridge_and_advertise"),
(EVPNState.ADVERTISING, EVPNEvent.PORT_BINDING_DELETE):
(EVPNState.WAITING_FOR_PORT_BINDING,
"_unset_evpn_bridge_and_unadvertise"),
(EVPNState.ADVERTISING, EVPNEvent.VRF_DELETE):
(EVPNState.WAITING_FOR_VRF,
"_unset_evpn_router_and_unadvertise"),
(EVPNState.WAITING_FOR_VRF, EVPNEvent.PORT_BINDING_DELETE):
(EVPNState.DESTROY, "_destroy"),
(EVPNState.WAITING_FOR_PORT_BINDING, EVPNEvent.VRF_DELETE):
(EVPNState.DESTROY, "_destroy"),
}
def __init__(self):
self.instances = {} # vrf -> Evpn
self.instances = {} # vrf -> EVPNInstance
self._svd = None
self._cfg = None
self._driver = None
@@ -93,15 +100,23 @@ class EvpnFSM:
evpn.vni = vni
evpn.vid = vid
def _set_evpn_router(self, evpn):
evpn.vrf_up = True
def _set_evpn_router_and_advertise(self, evpn):
self._set_evpn_router(evpn)
self._advertise(evpn)
def _set_evpn_bridge_and_advertise(self, evpn, mac, vni, vid):
self._set_evpn_bridge(evpn, mac, vni, vid)
self._advertise(evpn)
def _unset_evpn_bridge_and_unadvertise(self, evpn):
self._unadvertise(evpn)
evpn.mac = None
evpn.vni = None
evpn.vid = None
def _set_evpn_router(self, evpn):
evpn.vrf_up = True
def _unset_evpn_router_and_unadvertise(self, evpn):
self._unadvertise(evpn)
evpn.vrf_up = False
@@ -117,36 +132,29 @@ class EvpnFSM:
self._driver.delete_router(evpn.vrf, evpn.vni)
LOG.debug("EVPN: unadvertised %s", evpn)
def _set_evpn_router_and_advertise(self, evpn):
self._set_evpn_router(evpn)
self._advertise(evpn)
def _set_evpn_bridge_and_advertise(self, evpn, mac, vni, vid):
self._set_evpn_bridge(evpn, mac, vni, vid)
self._advertise(evpn)
def _destroy(self, evpn):
LOG.debug("EVPN deleted: VRF %s", evpn.vrf)
self.instances.pop(evpn.vrf)
self.instances.pop(evpn.vrf, None)
def advance(self, event, vrf, **kwargs):
"""Drive FSM state transition for a VRF in response to an event."""
with _FSM_LOCK:
evpn = self.instances.setdefault(vrf, Evpn(vrf))
LOG.debug("Advancing state EVPN: vrf %s", vrf)
previous_state = evpn.state
evpn = self.instances.setdefault(vrf, EVPNInstance(vrf))
try:
evpn.state, callback_name = self.TRANSITIONS[
new_state, callback_name = self.TRANSITIONS[
(evpn.state, event)]
except KeyError:
raise evpn_exc.FSMIllegalTransition(
"Cannot transition from %s to new state!" %
(previous_state))
"Cannot transition from %s with event %s!" %
(evpn.state, event))
try:
callback = getattr(self, callback_name)
except AttributeError:
raise evpn_exc.FSMMissingTransitionCallback(
"Transition from %s to %s is missing callback function!" %
(previous_state, evpn.state))
LOG.info("EVPN VRF %s: %s -> %s", vrf, previous_state, evpn.state)
"Transition from %s is missing callback function %s!" %
(evpn.state, callback_name))
previous_state = evpn.state
callback(evpn, **kwargs)
evpn.state = new_state
LOG.info("EVPN %s: %s -> %s (event=%s)",
vrf, previous_state, evpn.state, event)
@@ -74,7 +74,7 @@ class VrfHandler:
for vrf in stale_vrfs:
LOG.debug("Stale VRF removed during replay (VRF %s)", vrf)
self._evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_VRF_DELETE, vrf)
fsm.EVPNEvent.VRF_DELETE, vrf)
self._known_vrfs = self._replay_vrfs
self._replay_vrfs = None
@@ -92,7 +92,7 @@ class VrfHandler:
if evpnvrf not in self._known_vrfs:
self._known_vrfs.add(evpnvrf)
LOG.debug("VRF created: %s", evpnvrf)
self._evpn_fsm.advance(fsm.EvpnFSM.FSM_EVENT_VRF_CREATE, evpnvrf)
self._evpn_fsm.advance(fsm.EVPNEvent.VRF_CREATE, evpnvrf)
def handle_dellink(self, msg):
try:
@@ -106,4 +106,4 @@ class VrfHandler:
# VRF not previously tracked
return
LOG.debug("VRF deleted: %s", evpnvrf)
self._evpn_fsm.advance(fsm.EvpnFSM.FSM_EVENT_VRF_DELETE, evpnvrf)
self._evpn_fsm.advance(fsm.EVPNEvent.VRF_DELETE, evpnvrf)
@@ -271,7 +271,7 @@ class PortBindingLrpEvpnCreateEventTestCase(BaseEvpnEventsTestCase):
self._wait_for_advance()
self.assertIn(vrf, self.fsm.instances)
instance = self.fsm.instances[vrf]
self.assertEqual(evpn_fsm.Evpn.WAITING_FOR_ROUTER, instance.state)
self.assertEqual(evpn_fsm.EVPNState.WAITING_FOR_VRF, instance.state)
self.assertEqual(mac, instance.mac)
self.assertEqual(vni, instance.vni)
self.assertEqual(vlan, instance.vid)
@@ -165,9 +165,9 @@ class TestFsmSvdIntegration(base.BaseNetlinkTestCase):
def _advance_to_advertising(self, vni, vid):
self._evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_VRF_CREATE, self._vrf)
fsm.EVPNEvent.VRF_CREATE, self._vrf)
self._evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_PORT_BINDING_CREATE,
fsm.EVPNEvent.PORT_BINDING_CREATE,
self._vrf, mac=self.SVI_MAC, vni=vni, vid=vid)
def test_fsm_advertise_creates_svi(self):
@@ -179,7 +179,7 @@ class TestFsmSvdIntegration(base.BaseNetlinkTestCase):
self._advance_to_advertising(vni, vid)
evpn = self._evpn_fsm.instances[self._vrf]
self.assertEqual(fsm.Evpn.ADVERTISING, evpn.state)
self.assertEqual(fsm.EVPNState.ADVERTISING, evpn.state)
self.assertTrue(ip_lib.device_exists(svi_name))
def test_fsm_port_binding_delete_deletes_svi(self):
@@ -192,10 +192,10 @@ class TestFsmSvdIntegration(base.BaseNetlinkTestCase):
self.assertTrue(ip_lib.device_exists(svi_name))
self._evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_PORT_BINDING_DELETE, self._vrf)
fsm.EVPNEvent.PORT_BINDING_DELETE, self._vrf)
evpn = self._evpn_fsm.instances[self._vrf]
self.assertEqual(fsm.Evpn.WAITING_FOR_BRIDGE, evpn.state)
self.assertEqual(fsm.EVPNState.WAITING_FOR_PORT_BINDING, evpn.state)
self.assertFalse(ip_lib.device_exists(svi_name))
def test_fsm_vrf_delete_deletes_svi(self):
@@ -208,10 +208,10 @@ class TestFsmSvdIntegration(base.BaseNetlinkTestCase):
self.assertTrue(ip_lib.device_exists(svi_name))
self._evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_VRF_DELETE, self._vrf)
fsm.EVPNEvent.VRF_DELETE, self._vrf)
evpn = self._evpn_fsm.instances[self._vrf]
self.assertEqual(fsm.Evpn.WAITING_FOR_ROUTER, evpn.state)
self.assertEqual(fsm.EVPNState.WAITING_FOR_VRF, evpn.state)
self.assertFalse(ip_lib.device_exists(svi_name))
def test_evpn_svd_del_vni_idempotent_without_prior_add(self):
@@ -37,12 +37,12 @@ class TestEvpnFSM(base.BaseTestCase):
def test_vrf_then_port_binding_create(self):
vrf = 'vr0a1b2c3d-fff'
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_VRF_CREATE, vrf)
fsm.EVPNEvent.VRF_CREATE, vrf)
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_PORT_BINDING_CREATE,
fsm.EVPNEvent.PORT_BINDING_CREATE,
vrf, mac='aa:bb:cc:dd:ee:ff', vni=10, vid=1)
evpn = self.evpn_fsm.instances[vrf]
self.assertEqual(fsm.Evpn.ADVERTISING, evpn.state)
self.assertEqual(fsm.EVPNState.ADVERTISING, evpn.state)
self.assertEqual('aa:bb:cc:dd:ee:ff', evpn.mac)
self.assertEqual(10, evpn.vni)
self.assertEqual(1, evpn.vid)
@@ -54,12 +54,12 @@ class TestEvpnFSM(base.BaseTestCase):
def test_port_binding_then_vrf_create(self):
vrf = 'vr0a1b2c3d-fff'
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_PORT_BINDING_CREATE,
fsm.EVPNEvent.PORT_BINDING_CREATE,
vrf, mac='aa:bb:cc:dd:ee:ff', vni=10, vid=1)
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_VRF_CREATE, vrf)
fsm.EVPNEvent.VRF_CREATE, vrf)
evpn = self.evpn_fsm.instances[vrf]
self.assertEqual(fsm.Evpn.ADVERTISING, evpn.state)
self.assertEqual(fsm.EVPNState.ADVERTISING, evpn.state)
self.assertEqual('aa:bb:cc:dd:ee:ff', evpn.mac)
self.assertEqual(10, evpn.vni)
self.assertEqual(1, evpn.vid)
@@ -70,36 +70,36 @@ class TestEvpnFSM(base.BaseTestCase):
def test_advertise_then_port_binding_delete(self):
vrf = 'vr0a1b2c3d-fff'
evpn = fsm.Evpn(vrf)
evpn = fsm.EVPNInstance(vrf)
evpn.mac = 'aa:bb:cc:dd:ee:ff'
evpn.vni = 10
evpn.vid = 1
evpn.vrf_up = True
evpn.state = fsm.Evpn.ADVERTISING
evpn.state = fsm.EVPNState.ADVERTISING
self.evpn_fsm.instances[vrf] = evpn
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_VRF_DELETE, vrf)
fsm.EVPNEvent.VRF_DELETE, vrf)
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_PORT_BINDING_DELETE, vrf)
fsm.EVPNEvent.PORT_BINDING_DELETE, vrf)
self.assertNotIn(vrf, self.evpn_fsm.instances)
self.mock_svd.del_vni.assert_called_once_with(10, 1)
self.mock_driver.delete_router.assert_called_once_with(vrf, 10)
def test_advertise_then_vrf_delete(self):
vrf = 'vr0a1b2c3d-fff'
evpn = fsm.Evpn(vrf)
evpn = fsm.EVPNInstance(vrf)
evpn.mac = 'aa:bb:cc:dd:ee:ff'
evpn.vni = 10
evpn.vid = 1
evpn.vrf_up = True
evpn.state = fsm.Evpn.ADVERTISING
evpn.state = fsm.EVPNState.ADVERTISING
self.evpn_fsm.instances[vrf] = evpn
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_PORT_BINDING_DELETE, vrf)
fsm.EVPNEvent.PORT_BINDING_DELETE, vrf)
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_VRF_DELETE, vrf)
fsm.EVPNEvent.VRF_DELETE, vrf)
self.assertNotIn(vrf, self.evpn_fsm.instances)
self.mock_svd.del_vni.assert_called_once_with(10, 1)
self.mock_driver.delete_router.assert_called_once_with(vrf, 10)
@@ -112,12 +112,12 @@ class TestEvpnFSM(base.BaseTestCase):
def netlink_thread():
barrier.wait()
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_VRF_CREATE, vrf)
fsm.EVPNEvent.VRF_CREATE, vrf)
def idl_thread():
barrier.wait()
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_PORT_BINDING_CREATE,
fsm.EVPNEvent.PORT_BINDING_CREATE,
vrf, mac='aa:bb:cc:dd:ee:ff', vni=10, vid=1)
threads = [threading.Thread(target=netlink_thread),
@@ -128,7 +128,7 @@ class TestEvpnFSM(base.BaseTestCase):
t.join()
evpn = self.evpn_fsm.instances[vrf]
self.assertEqual(fsm.Evpn.ADVERTISING, evpn.state)
self.assertEqual(fsm.EVPNState.ADVERTISING, evpn.state)
self.assertEqual('aa:bb:cc:dd:ee:ff', evpn.mac)
self.assertEqual(10, evpn.vni)
self.assertEqual(1, evpn.vid)
@@ -137,12 +137,12 @@ class TestEvpnFSM(base.BaseTestCase):
def test_simultaneous_vrf_and_port_binding_delete(self):
"""Netlink and SB IDL threads both delete for the same VRF."""
vrf = 'vr0a1b2c3d-fff'
evpn = fsm.Evpn(vrf)
evpn = fsm.EVPNInstance(vrf)
evpn.mac = 'aa:bb:cc:dd:ee:ff'
evpn.vni = 10
evpn.vid = 1
evpn.vrf_up = True
evpn.state = fsm.Evpn.ADVERTISING
evpn.state = fsm.EVPNState.ADVERTISING
self.evpn_fsm.instances[vrf] = evpn
barrier = threading.Barrier(2)
@@ -150,12 +150,12 @@ class TestEvpnFSM(base.BaseTestCase):
def netlink_thread():
barrier.wait()
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_VRF_DELETE, vrf)
fsm.EVPNEvent.VRF_DELETE, vrf)
def idl_thread():
barrier.wait()
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_PORT_BINDING_DELETE, vrf)
fsm.EVPNEvent.PORT_BINDING_DELETE, vrf)
threads = [threading.Thread(target=netlink_thread),
threading.Thread(target=idl_thread)]
@@ -169,21 +169,21 @@ class TestEvpnFSM(base.BaseTestCase):
def test_advertise_then_vrf_delete_then_vrf_create(self):
vrf = 'vr0a1b2c3d-fff'
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_VRF_CREATE, vrf)
fsm.EVPNEvent.VRF_CREATE, vrf)
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_PORT_BINDING_CREATE,
fsm.EVPNEvent.PORT_BINDING_CREATE,
vrf, mac='aa:bb:cc:dd:ee:ff', vni=10, vid=1)
evpn = self.evpn_fsm.instances[vrf]
self.assertEqual(fsm.Evpn.ADVERTISING, evpn.state)
self.assertEqual(fsm.EVPNState.ADVERTISING, evpn.state)
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_VRF_DELETE, vrf)
self.assertEqual(fsm.Evpn.WAITING_FOR_ROUTER, evpn.state)
fsm.EVPNEvent.VRF_DELETE, vrf)
self.assertEqual(fsm.EVPNState.WAITING_FOR_VRF, evpn.state)
self.mock_svd.del_vni.assert_called_once_with(10, 1)
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_VRF_CREATE, vrf)
self.assertEqual(fsm.Evpn.ADVERTISING, evpn.state)
fsm.EVPNEvent.VRF_CREATE, vrf)
self.assertEqual(fsm.EVPNState.ADVERTISING, evpn.state)
self.assertEqual(2, self.mock_svd.add_vni.call_count)
self.assertEqual(2, self.mock_driver.create_router.call_count)
self.mock_driver.delete_router.assert_called_once_with(vrf, 10)
@@ -191,25 +191,25 @@ class TestEvpnFSM(base.BaseTestCase):
def test_advertise_then_port_binding_delete_then_port_binding_create(self):
vrf = 'vr0a1b2c3d-fff'
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_PORT_BINDING_CREATE,
fsm.EVPNEvent.PORT_BINDING_CREATE,
vrf, mac='aa:bb:cc:dd:ee:ff', vni=10, vid=1)
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_VRF_CREATE, vrf)
fsm.EVPNEvent.VRF_CREATE, vrf)
evpn = self.evpn_fsm.instances[vrf]
self.assertEqual(fsm.Evpn.ADVERTISING, evpn.state)
self.assertEqual(fsm.EVPNState.ADVERTISING, evpn.state)
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_PORT_BINDING_DELETE, vrf)
self.assertEqual(fsm.Evpn.WAITING_FOR_BRIDGE, evpn.state)
fsm.EVPNEvent.PORT_BINDING_DELETE, vrf)
self.assertEqual(fsm.EVPNState.WAITING_FOR_PORT_BINDING, evpn.state)
self.assertIsNone(evpn.mac)
self.assertIsNone(evpn.vni)
self.assertIsNone(evpn.vid)
self.mock_svd.del_vni.assert_called_once_with(10, 1)
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_PORT_BINDING_CREATE,
fsm.EVPNEvent.PORT_BINDING_CREATE,
vrf, mac='11:22:33:44:55:66', vni=20, vid=2)
self.assertEqual(fsm.Evpn.ADVERTISING, evpn.state)
self.assertEqual(fsm.EVPNState.ADVERTISING, evpn.state)
self.assertEqual('11:22:33:44:55:66', evpn.mac)
self.assertEqual(20, evpn.vni)
self.assertEqual(2, evpn.vid)
@@ -220,9 +220,9 @@ class TestEvpnFSM(base.BaseTestCase):
def test_replay_end_deletes_stale_fsm_instance(self):
vrf1, vrf2 = 'vr0a1b2c3d-eee', 'vr1a2b3c3d-fff'
evpn = fsm.Evpn(vrf1)
evpn = fsm.EVPNInstance(vrf1)
evpn.vrf_up = True
evpn.state = fsm.Evpn.WAITING_FOR_BRIDGE
evpn.state = fsm.EVPNState.WAITING_FOR_PORT_BINDING
self.evpn_fsm.instances[vrf1] = evpn
handler = netlink_monitor.VrfHandler(self.evpn_fsm)
handler._known_vrfs = {vrf1, vrf2}
@@ -233,26 +233,26 @@ class TestEvpnFSM(base.BaseTestCase):
def test_replay_end_transitions_advertising_to_waiting(self):
vrf = 'vr0a1b2c3d-fff'
evpn = fsm.Evpn(vrf)
evpn = fsm.EVPNInstance(vrf)
evpn.mac = 'aa:bb:cc:dd:ee:ff'
evpn.vni = 10
evpn.vid = 1
evpn.vrf_up = True
evpn.state = fsm.Evpn.ADVERTISING
evpn.state = fsm.EVPNState.ADVERTISING
self.evpn_fsm.instances[vrf] = evpn
handler = netlink_monitor.VrfHandler(self.evpn_fsm)
handler._known_vrfs = {vrf}
handler._replay_vrfs = set()
handler.replay_end()
self.assertEqual(fsm.Evpn.WAITING_FOR_ROUTER, evpn.state)
self.assertEqual(fsm.EVPNState.WAITING_FOR_VRF, evpn.state)
self.assertIn(vrf, self.evpn_fsm.instances)
self.mock_driver.delete_router.assert_called_once_with(vrf, 10)
def test_replay_end_no_stale_vrfs(self):
vrf = 'vr0a1b2c3d-fff'
evpn = fsm.Evpn(vrf)
evpn = fsm.EVPNInstance(vrf)
evpn.vrf_up = True
evpn.state = fsm.Evpn.WAITING_FOR_BRIDGE
evpn.state = fsm.EVPNState.WAITING_FOR_PORT_BINDING
self.evpn_fsm.instances[vrf] = evpn
handler = netlink_monitor.VrfHandler(self.evpn_fsm)
handler._known_vrfs = {vrf}
@@ -264,18 +264,18 @@ class TestEvpnFSM(base.BaseTestCase):
def test_driver_not_called_before_advertising(self):
vrf = 'vr0a1b2c3d-fff'
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_VRF_CREATE, vrf)
fsm.EVPNEvent.VRF_CREATE, vrf)
evpn = self.evpn_fsm.instances[vrf]
self.assertEqual(fsm.Evpn.WAITING_FOR_BRIDGE, evpn.state)
self.assertEqual(fsm.EVPNState.WAITING_FOR_PORT_BINDING, evpn.state)
self.mock_driver.create_router.assert_not_called()
self.mock_driver.delete_router.assert_not_called()
def test_driver_not_called_port_binding_before_vrf(self):
vrf = 'vr0a1b2c3d-fff'
self.evpn_fsm.advance(
fsm.EvpnFSM.FSM_EVENT_PORT_BINDING_CREATE,
fsm.EVPNEvent.PORT_BINDING_CREATE,
vrf, mac='aa:bb:cc:dd:ee:ff', vni=10, vid=1)
evpn = self.evpn_fsm.instances[vrf]
self.assertEqual(fsm.Evpn.WAITING_FOR_ROUTER, evpn.state)
self.assertEqual(fsm.EVPNState.WAITING_FOR_VRF, evpn.state)
self.mock_driver.create_router.assert_not_called()
self.mock_driver.delete_router.assert_not_called()
@@ -154,9 +154,9 @@ class TestVrfHandler(base.BaseTestCase):
def test_handle_dellink_evpn_vrf(self):
vrf = 'vr0a1b2c3d-ffff'
self.handler._known_vrfs.add(vrf)
evpn = fsm.Evpn(vrf)
evpn = fsm.EVPNInstance(vrf)
evpn.vrf_up = True
evpn.state = fsm.Evpn.WAITING_FOR_BRIDGE
evpn.state = fsm.EVPNState.WAITING_FOR_PORT_BINDING
self._evpn_fsm.instances[vrf] = evpn
msg = _make_vrf_msg(vrf)
self.handler.handle_dellink(msg)
@@ -166,9 +166,9 @@ class TestVrfHandler(base.BaseTestCase):
def test_handle_dellink_unknown_vrf(self):
vrf = 'vr0a1b2c3d-ffff'
self.handler._known_vrfs.add(vrf)
evpn = fsm.Evpn(vrf)
evpn = fsm.EVPNInstance(vrf)
evpn.vrf_up = True
evpn.state = fsm.Evpn.WAITING_FOR_BRIDGE
evpn.state = fsm.EVPNState.WAITING_FOR_PORT_BINDING
self._evpn_fsm.instances[vrf] = evpn
msg = _make_vrf_msg('vr0a1b2c3d-eeee')
self.handler.handle_dellink(msg)