Skip to content

Commit

Permalink
Merge pull request #75 from kytos-ng/fix_branch
Browse files Browse the repository at this point in the history
fix: Return a list of paths with the `PUT /traces` endpoint
  • Loading branch information
viniarck authored Feb 27, 2023
2 parents ca8d180 + 201ea8f commit 52d1c32
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 159 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ All notable changes to the sdntrace_cp NApp will be documented in this file.
[UNRELEASED] - Under development
********************************

[2022.3.1] - 2023-02-24
***********************

Changed
=======
- ``PUT /traces`` will return the results in order, without aggregating them by `dpid`. Also, failed traces are not omitted.

[2022.3.0] - 2022-12-15
***********************

Expand Down
2 changes: 1 addition & 1 deletion kytos.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"username": "amlight",
"name": "sdntrace_cp",
"description": "Run tracepaths on OpenFlow in the Control Plane",
"version": "2022.3.0",
"version": "2022.3.1",
"napp_dependencies": [],
"license": "MIT",
"tags": [],
Expand Down
32 changes: 15 additions & 17 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from napps.amlight.sdntrace_cp.utils import (convert_entries,
convert_list_entries,
find_endpoint, get_stored_flows,
prepare_json, prepare_list_json)
prepare_json)


class Main(KytosNApp):
Expand Down Expand Up @@ -70,18 +70,10 @@ def get_traces(self):
entries = request.get_json()
entries = convert_list_entries(entries)
stored_flows = get_stored_flows()
results = {}
list_ready = []
results = []
for entry in entries:
if entry in list_ready:
continue
list_ready.append(entry)
dpid = entry['dpid']
if dpid not in results:
results[dpid] = []
result = prepare_list_json(self.tracepath(entry, stored_flows))
results[dpid].append(result)
return jsonify(results)
results.append(self.tracepath(entry, stored_flows))
return jsonify(prepare_json(results))

def tracepath(self, entries, stored_flows):
"""Trace a path for a packet represented by entries."""
Expand All @@ -91,18 +83,19 @@ def tracepath(self, entries, stored_flows):
trace_type = 'starting'
do_trace = True
while do_trace:
if 'dpid' not in entries or 'in_port' not in entries:
break
trace_step = {'in': {'dpid': entries['dpid'],
'port': entries['in_port'],
'time': str(datetime.now()),
'type': trace_type}}
if 'dl_vlan' in entries:
trace_step['in'].update({'vlan': entries['dl_vlan'][-1]})

switch = self.controller.get_switch_by_dpid(entries['dpid'])
if (switch is None) or \
(switch.dpid not in stored_flows):
result = None
else:
result = self.trace_step(switch, entries, stored_flows)
if not switch:
break
result = self.trace_step(switch, entries, stored_flows)
if result:
out = {'port': result['out_port']}
if 'dl_vlan' in result['entries']:
Expand All @@ -114,15 +107,18 @@ def tracepath(self, entries, stored_flows):
next_step = {'dpid': result['dpid'],
'port': result['in_port']}
if self.has_loop(next_step, trace_result):
# Loop
do_trace = False
else:
entries = result['entries']
entries['dpid'] = result['dpid']
entries['in_port'] = result['in_port']
trace_type = 'trace'
else:
trace_step['in']['type'] = 'last'
do_trace = False
else:
# Incomplete
break
trace_result.append(trace_step)
self.traces.update({
Expand Down Expand Up @@ -204,6 +200,8 @@ def match_flows(self, switch, args, stored_flows, many=True):
:return: If many, the list of matched flows, or the matched flow
"""
response = []
if switch.dpid not in stored_flows:
return None
try:
for flow in stored_flows[switch.dpid]:
match = Main.do_match(flow, args)
Expand Down
6 changes: 3 additions & 3 deletions openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,8 @@ paths:
schema:
type: object
properties:
switch:
type: array
result:
type: array
items:
type: array
items:
Expand Down Expand Up @@ -279,4 +279,4 @@ paths:
vlan:
type: integer
description: VLAN ID
example: 100
example: 100
144 changes: 10 additions & 134 deletions tests/unit/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ def test_trace(self, mock_stored_flows):
assert len(result) == 1
assert result[0]["dpid"] == "00:00:00:00:00:00:00:01"
assert result[0]["port"] == 1
assert result[0]["type"] == "starting"
assert result[0]["type"] == "last"
assert result[0]["vlan"] == 100
assert result[0]["out"] == {"port": 2, "vlan": 200}

Expand Down Expand Up @@ -432,13 +432,13 @@ def test_get_traces(self, mock_stored_flows):
url, data=json.dumps(payload), content_type="application/json"
)
current_data = json.loads(response.data)
result1 = current_data["00:00:00:00:00:00:00:01"]
result1 = current_data["result"]

assert len(result1) == 1
assert len(result1[0]) == 1
assert result1[0][0]["dpid"] == "00:00:00:00:00:00:00:01"
assert result1[0][0]["port"] == 1
assert result1[0][0]["type"] == "starting"
assert result1[0][0]["type"] == "last"
assert result1[0][0]["vlan"] == 100
assert result1[0][0]["out"] == {"port": 2}

Expand Down Expand Up @@ -490,142 +490,18 @@ def test_traces(self, mock_stored_flows):
url, data=json.dumps(payload), content_type="application/json"
)
current_data = json.loads(response.data)
result1 = current_data["00:00:00:00:00:00:00:01"]
result2 = current_data["00:00:00:00:00:00:00:02"]

assert result1[0][0]["dpid"] == "00:00:00:00:00:00:00:01"
assert result1[0][0]["port"] == 1
assert result1[0][0]["type"] == "starting"
assert result1[0][0]["vlan"] == 100
assert result1[0][0]["out"] == {"port": 2, "vlan": 100}

assert result2[0][0]["dpid"] == "00:00:00:00:00:00:00:02"
assert result2[0][0]["port"] == 1
assert result2[0][0]["type"] == "starting"
assert result2[0][0]["vlan"] == 100
assert result2[0][0]["out"] == {"port": 2, "vlan": 100}

@patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
def test_traces_same_switch(self, mock_stored_flows):
"""Test traces rest call for two traces with samw switches."""
api = get_test_client(get_controller_mock(), self.napp)
url = f"{self.server_name_url}/traces/"

payload = [
{
"trace": {
"switch": {
"dpid": "00:00:00:00:00:00:00:01",
"in_port": 1
},
"eth": {"dl_vlan": 100},
}
},
{
"trace": {
"switch": {
"dpid": "00:00:00:00:00:00:00:01",
"in_port": 2
},
"eth": {"dl_vlan": 100},
}
}
]

stored_flow = {
"id": 1,
"flow": {
"table_id": 0,
"cookie": 84114964,
"hard_timeout": 0,
"idle_timeout": 0,
"priority": 10,
"match": {"dl_vlan": 100},
"actions": [{"action_type": "output", "port": 3}],
}
}

mock_stored_flows.return_value = {
"00:00:00:00:00:00:00:01": [stored_flow]
}

response = api.put(
url, data=json.dumps(payload), content_type="application/json"
)
current_data = json.loads(response.data)
result = current_data["00:00:00:00:00:00:00:01"]
result = current_data["result"]

assert len(current_data) == 1
assert len(result) == 2
assert len(result[0]) == 1
assert len(result[1]) == 1

assert result[0][0]["dpid"] == "00:00:00:00:00:00:00:01"
assert result[0][0]["port"] == 1
assert result[0][0]["type"] == "starting"
assert result[0][0]["type"] == "last"
assert result[0][0]["vlan"] == 100
assert result[0][0]["out"] == {"port": 3, "vlan": 100}
assert result[0][0]["out"] == {"port": 2, "vlan": 100}

assert result[1][0]["dpid"] == "00:00:00:00:00:00:00:01"
assert result[1][0]["port"] == 2
assert result[1][0]["type"] == "starting"
assert result[1][0]["dpid"] == "00:00:00:00:00:00:00:02"
assert result[1][0]["port"] == 1
assert result[1][0]["type"] == "last"
assert result[1][0]["vlan"] == 100
assert result[1][0]["out"] == {"port": 3, "vlan": 100}

@patch("napps.amlight.sdntrace_cp.main.get_stored_flows")
def test_traces_twice(self, mock_stored_flows):
"""Test traces rest call for two equal traces."""
api = get_test_client(get_controller_mock(), self.napp)
url = f"{self.server_name_url}/traces/"

payload = [
{
"trace": {
"switch": {
"dpid": "00:00:00:00:00:00:00:01",
"in_port": 1
},
"eth": {"dl_vlan": 100},
}
},
{
"trace": {
"switch": {
"dpid": "00:00:00:00:00:00:00:01",
"in_port": 1
},
"eth": {"dl_vlan": 100},
}
}
]
stored_flow = {
"id": 1,
"flow": {
"table_id": 0,
"cookie": 84114964,
"hard_timeout": 0,
"idle_timeout": 0,
"priority": 10,
"match": {"dl_vlan": 100, "in_port": 1},
"actions": [{"action_type": "output", "port": 2}],
}
}

mock_stored_flows.return_value = {
"00:00:00:00:00:00:00:01": [stored_flow]
}

response = api.put(
url, data=json.dumps(payload), content_type="application/json"
)
current_data = json.loads(response.data)
result = current_data["00:00:00:00:00:00:00:01"]

assert len(current_data) == 1
assert len(result) == 1

assert result[0][0]["dpid"] == "00:00:00:00:00:00:00:01"
assert result[0][0]["port"] == 1
assert result[0][0]["type"] == "starting"
assert result[0][0]["vlan"] == 100
assert result[0][0]["out"] == {"port": 2, "vlan": 100}
assert result[1][0]["out"] == {"port": 2, "vlan": 100}
2 changes: 1 addition & 1 deletion tests/unit/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def test_prepare_list_json(self):
}
trace_result.append(trace_step)

result = utils.prepare_list_json(trace_result)
result = utils._prepare_json(trace_result)

self.assertEqual(
result, [
Expand Down
12 changes: 9 additions & 3 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ def find_endpoint(switch, port):
return None


def prepare_list_json(trace_result):
"""Prepare return list of json for REST call."""
def _prepare_json(trace_result):
"""Auxiliar function to return the json for REST call."""
result = []
for trace_step in trace_result:
result.append(trace_step['in'])
Expand All @@ -70,7 +70,13 @@ def prepare_list_json(trace_result):

def prepare_json(trace_result):
"""Prepare return json for REST call."""
return {'result': prepare_list_json(trace_result)}
result = []
if trace_result and isinstance(trace_result[0], list):
for trace in trace_result:
result.append(_prepare_json(trace))
else:
result = _prepare_json(trace_result)
return {'result': result}


def format_result(trace):
Expand Down

0 comments on commit 52d1c32

Please sign in to comment.