From df9f2c3b5856bcec008c78ab19e5d3fa4100ed3d Mon Sep 17 00:00:00 2001 From: Aldo Ortega Date: Tue, 20 Aug 2024 14:42:51 -0400 Subject: [PATCH 1/3] Corrected wrong flow_mod sent to deletion --- main.py | 14 +++++++----- tests/unit/test_main.py | 9 +++++++- tests/unit/test_utils.py | 34 +++++++++++++++++++++++++++++- ui/k-info-panel/show_circuit.kytos | 4 ++-- utils.py | 18 ++++++++++++++++ 5 files changed, 70 insertions(+), 9 deletions(-) diff --git a/main.py b/main.py index f04f2148..6df111d1 100755 --- a/main.py +++ b/main.py @@ -31,7 +31,7 @@ from napps.kytos.mef_eline.utils import (aemit_event, check_disabled_component, emit_event, get_vlan_tags_and_masks, map_evc_event_content, - merge_flow_dicts, + merge_flow_dicts, prepare_delete_flow, send_flow_mods_event) @@ -952,11 +952,15 @@ def handle_cleanup_evcs_old_path(self, event): with evc.lock: removed_flows = {} try: - nni_flows = evc._prepare_nni_flows(evc.old_path) - uni_flows = evc._prepare_uni_flows( - evc.old_path, skip_in=True + nni_flows = prepare_delete_flow( + evc._prepare_nni_flows(evc.old_path) + ) + uni_flows = prepare_delete_flow( + evc._prepare_uni_flows(evc.old_path, skip_in=True) + ) + removed_flows = merge_flow_dicts( + nni_flows, uni_flows ) - removed_flows = merge_flow_dicts(nni_flows, uni_flows) # pylint: disable=broad-except except Exception: err = traceback.format_exc().replace("\n", ", ") diff --git a/tests/unit/test_main.py b/tests/unit/test_main.py index b859f77f..fce56ae2 100644 --- a/tests/unit/test_main.py +++ b/tests/unit/test_main.py @@ -2097,7 +2097,9 @@ def test_cleanup_evcs_old_path(self, monkeypatch): current_path, map_evc_content, emit_event = [ MagicMock(), MagicMock(), MagicMock() ] - send_flows, merge_flows = MagicMock(), MagicMock() + send_flows, merge_flows, create_flows = [ + MagicMock(), MagicMock(), MagicMock() + ] monkeypatch.setattr( "napps.kytos.mef_eline.main.map_evc_event_content", map_evc_content @@ -2114,6 +2116,10 @@ def test_cleanup_evcs_old_path(self, monkeypatch): "napps.kytos.mef_eline.main.merge_flow_dicts", merge_flows ) + monkeypatch.setattr( + "napps.kytos.mef_eline.main.prepare_delete_flow", + create_flows + ) merge_flows.return_value = ['1', '2'] evc1 = create_autospec(EVC, id="1", old_path=["1"], current_path=current_path, lock=MagicMock()) @@ -2130,6 +2136,7 @@ def test_cleanup_evcs_old_path(self, monkeypatch): evc2._prepare_uni_flows.assert_called_with(["2"], skip_in=True) evc3._prepare_nni_flows.assert_not_called() evc3._prepare_uni_flows.assert_not_called() + assert create_flows.call_count == 4 assert emit_event.call_count == 1 assert emit_event.call_args[0][1] == "failover_old_path" assert len(emit_event.call_args[1]["content"]) == 2 diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 6568da4a..3ec4a490 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -9,7 +9,7 @@ compare_endpoint_trace, compare_uni_out_trace, get_vlan_tags_and_masks, map_dl_vlan, - merge_flow_dicts) + merge_flow_dicts, prepare_delete_flow) # pylint: disable=too-many-public-methods, too-many-lines @@ -163,3 +163,35 @@ def test_check_disabled_component(self): def test_merge_flow_dicts(self, src1, src2, src3, expected) -> None: """test merge flow dicts.""" assert merge_flow_dicts({}, src1, src2, src3) == expected + + def test_prepare_delete_flow(self): + """Test prepare_delete_flow""" + cookie_mask = int(0xffffffffffffffff) + flow_mod = {'00:01': [ + { + 'match': {'in_port': 1, 'dl_vlan': 22}, + 'cookie': 12275899796742638400, + 'actions': [{'action_type': 'pop_vlan'}], + 'owner': 'mef_eline', + 'table_group': 'evpl', + 'table_id': 0, + 'priority': 20000 + }, + { + 'match': {'in_port': 3, 'dl_vlan': 1}, + 'cookie': 12275899796742638400, + 'actions': [{'action_type': 'pop_vlan'}], + 'owner': 'mef_eline', + 'table_group': 'evpl', + 'table_id': 0, + 'priority': 20000 + } + ]} + actual_flows = prepare_delete_flow(flow_mod) + assert '00:01' in actual_flows + for i in range(len(actual_flows['00:01'])): + assert (actual_flows['00:01'][i]['cookie'] == + flow_mod["00:01"][i]['cookie']) + assert (actual_flows['00:01'][i]['match'] == + flow_mod["00:01"][i]['match']) + assert actual_flows['00:01'][i]['cookie_mask'] == cookie_mask diff --git a/ui/k-info-panel/show_circuit.kytos b/ui/k-info-panel/show_circuit.kytos index 83ea509f..014b5b82 100644 --- a/ui/k-info-panel/show_circuit.kytos +++ b/ui/k-info-panel/show_circuit.kytos @@ -770,14 +770,14 @@ module.exports = { title: 'EVC id: ' + id + ' | name: ' + name + ' redeployed.', description: "" } - _this.$kytos.$emit("setNotification" , notification); + _this.$kytos.eventBus.$emit("setNotification" , notification); }); request.fail(function(data) { let notification = { title: 'Redeploy EVC failed', description: 'Error redeploying EVC ' + id +'. ' + data.responseJSON.description } - _this.$kytos.$emit("setNotification" , notification); + _this.$kytos.eventBus.$emit("setNotification" , notification); }); }, saveEvc: function() { diff --git a/utils.py b/utils.py index c6dbd744..ccd440b2 100644 --- a/utils.py +++ b/utils.py @@ -177,3 +177,21 @@ def send_flow_mods_event( "force": force, }, ) + + +def prepare_delete_flow(evc_flows: dict[str, list[dict]]): + """Create flow mods suited for flow deletion.""" + dpid_flows: dict[str, list[dict]] = {} + + if not evc_flows: + return dpid_flows + + for dpid, flows in evc_flows.items(): + dpid_flows.setdefault(dpid, []) + for flow in flows: + dpid_flows[dpid].append({ + "cookie": flow["cookie"], + "match": flow["match"], + "cookie_mask": int(0xffffffffffffffff) + }) + return dpid_flows From ee496b4f18dbf7ef9450ccc7fefaa8e175442df9 Mon Sep 17 00:00:00 2001 From: Aldo Ortega Date: Wed, 21 Aug 2024 11:12:59 -0400 Subject: [PATCH 2/3] Updated changelog --- CHANGELOG.rst | 4 ++++ kytos.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7b46a3fc..7a8909cb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,10 @@ All notable changes to the MEF_ELine NApp will be documented in this file. [UNRELEASED] - Under development ******************************** +Fixed +===== +- Fixed flow mods when deleting ``old_path`` + [2024.1.0] - 2024-07-23 *********************** diff --git a/kytos.json b/kytos.json index 555690d7..2c27f63d 100644 --- a/kytos.json +++ b/kytos.json @@ -3,7 +3,7 @@ "username": "kytos", "name": "mef_eline", "description": "NApp to provision circuits from user request", - "version": "2024.1.0", + "version": "2024.1.1", "napp_dependencies": ["kytos/flow_manager", "kytos/pathfinder", "amlight/sndtrace_cp"], "license": "MIT", "tags": [], From 22c65edb98c408ba078554ffc537ebf7d5e7597e Mon Sep 17 00:00:00 2001 From: Aldo Ortega Date: Wed, 21 Aug 2024 16:20:01 -0400 Subject: [PATCH 3/3] Added owner to every flow mod to be deleted --- models/evc.py | 6 +++++- tests/unit/models/test_evc_deploy.py | 13 ++++++++++--- utils.py | 1 + 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/models/evc.py b/models/evc.py index 84e22929..8b7001aa 100644 --- a/models/evc.py +++ b/models/evc.py @@ -694,6 +694,7 @@ def remove_failover_flows(self, exclude_uni_switches=True, { "cookie": cookie, "cookie_mask": int(0xffffffffffffffff), + "owner": "mef_eline", } ], "delete", @@ -725,7 +726,8 @@ def remove_current_flows(self, force=True, sync=True): switches.add(self.uni_z.interface.switch) match = { "cookie": self.get_cookie(), - "cookie_mask": int(0xffffffffffffffff) + "cookie_mask": int(0xffffffffffffffff), + "owner": "mef_eline", } for switch in switches: @@ -766,6 +768,7 @@ def remove_path_flows( dpid_flows_match[dpid].append({ "cookie": flow["cookie"], "match": flow["match"], + "owner": "mef_eline", "cookie_mask": int(0xffffffffffffffff) }) @@ -783,6 +786,7 @@ def remove_path_flows( dpid_flows_match[dpid].append({ "cookie": flow["cookie"], "match": flow["match"], + "owner": "mef_eline", "cookie_mask": int(0xffffffffffffffff) }) diff --git a/tests/unit/models/test_evc_deploy.py b/tests/unit/models/test_evc_deploy.py index 6691e7b2..0d478464 100644 --- a/tests/unit/models/test_evc_deploy.py +++ b/tests/unit/models/test_evc_deploy.py @@ -1008,7 +1008,8 @@ def test_remove_current_flows(self, *args): assert send_flow_mods_mocked.call_count == 5 assert evc.is_active() is False flows = [ - {"cookie": evc.get_cookie(), "cookie_mask": 18446744073709551615} + {"cookie": evc.get_cookie(), "cookie_mask": 18446744073709551615, + "owner": "mef_eline"} ] switch_1 = evc.primary_links[0].endpoint_a.switch switch_2 = evc.primary_links[0].endpoint_b.switch @@ -1076,7 +1077,8 @@ def test_remove_failover_flows_exclude_uni_switches(self, *args): assert send_flow_mods_mocked.call_count == 1 flows = [ {"cookie": evc.get_cookie(), - "cookie_mask": int(0xffffffffffffffff)} + "cookie_mask": int(0xffffffffffffffff), + "owner": "mef_eline"} ] send_flow_mods_mocked.assert_any_call(switch_b.id, flows, 'delete', force=True) @@ -1140,7 +1142,8 @@ def test_remove_failover_flows_include_all(self, *args): assert send_flow_mods_mocked.call_count == 3 flows = [ {"cookie": evc.get_cookie(), - "cookie_mask": int(0xffffffffffffffff)} + "cookie_mask": int(0xffffffffffffffff), + "owner": "mef_eline"} ] send_flow_mods_mocked.assert_any_call(switch_a.id, flows, 'delete', force=True) @@ -1367,6 +1370,7 @@ def test_remove_path_flows(self, *args): { 'cookie': 12249790986447749121, 'cookie_mask': 18446744073709551615, + "owner": "mef_eline", 'match': {'in_port': 9, 'dl_vlan': 5} }, ] @@ -1374,11 +1378,13 @@ def test_remove_path_flows(self, *args): { 'cookie': 12249790986447749121, 'cookie_mask': 18446744073709551615, + "owner": "mef_eline", 'match': {'in_port': 10, 'dl_vlan': 5} }, { 'cookie': 12249790986447749121, 'cookie_mask': 18446744073709551615, + "owner": "mef_eline", 'match': {'in_port': 11, 'dl_vlan': 6} }, ] @@ -1386,6 +1392,7 @@ def test_remove_path_flows(self, *args): { 'cookie': 12249790986447749121, 'cookie_mask': 18446744073709551615, + "owner": "mef_eline", 'match': {'in_port': 12, 'dl_vlan': 6} }, ] diff --git a/utils.py b/utils.py index ccd440b2..32db4cbc 100644 --- a/utils.py +++ b/utils.py @@ -192,6 +192,7 @@ def prepare_delete_flow(evc_flows: dict[str, list[dict]]): dpid_flows[dpid].append({ "cookie": flow["cookie"], "match": flow["match"], + "owner": "mef_eline", "cookie_mask": int(0xffffffffffffffff) }) return dpid_flows