Skip to content

Commit

Permalink
Allow a queue id to be used in EVCs (#229)
Browse files Browse the repository at this point in the history
* Create a field in EVC to store the queue_id

EVCs can have a queue id set, to be used for QoS.

* Create a set_queue action

If the EVC has `set_queue` attribute, a set_queue action
is used in the generated flow.
Fixes #228
  • Loading branch information
Antonio Francisco authored Feb 9, 2021
1 parent c03596e commit 32c10f9
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 21 deletions.
56 changes: 37 additions & 19 deletions models.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ def __init__(self, controller, **kwargs):
# optional attributes
self.start_date = get_time(kwargs.get('start_date')) or now()
self.end_date = get_time(kwargs.get('end_date')) or None
self.queue_id = kwargs.get('queue_id', None)

self.bandwidth = kwargs.get('bandwidth', 0)
self.primary_links = Path(kwargs.get('primary_links', []))
Expand Down Expand Up @@ -338,6 +339,7 @@ def as_dict(self):
if isinstance(self.end_date, datetime):
evc_dict["end_date"] = self.end_date.strftime(time_fmt)

evc_dict['queue_id'] = self.queue_id
evc_dict['bandwidth'] = self.bandwidth
evc_dict['primary_links'] = self.primary_links.as_dict()
evc_dict['backup_links'] = self.backup_links.as_dict()
Expand Down Expand Up @@ -613,9 +615,11 @@ def _install_direct_uni_flows(self):
vlan_z = self.uni_z.user_tag.value if self.uni_z.user_tag else None

flow_mod_az = self._prepare_flow_mod(self.uni_a.interface,
self.uni_z.interface)
self.uni_z.interface,
self.queue_id)
flow_mod_za = self._prepare_flow_mod(self.uni_z.interface,
self.uni_a.interface)
self.uni_a.interface,
self.queue_id)

if vlan_a and vlan_z:
flow_mod_az['match']['dl_vlan'] = vlan_a
Expand Down Expand Up @@ -647,12 +651,14 @@ def _install_nni_flows(self, path=None):
# Flow for one direction
flows.append(self._prepare_nni_flow(incoming.endpoint_b,
outcoming.endpoint_a,
in_vlan, out_vlan))
in_vlan, out_vlan,
queue_id=self.queue_id))

# Flow for the other direction
flows.append(self._prepare_nni_flow(outcoming.endpoint_a,
incoming.endpoint_b,
out_vlan, in_vlan))
out_vlan, in_vlan,
queue_id=self.queue_id))
self._send_flow_mods(incoming.endpoint_b.switch, flows)

def _install_uni_flows(self, path=None):
Expand All @@ -674,12 +680,14 @@ def _install_uni_flows(self, path=None):
# Flow for one direction, pushing the service tag
push_flow = self._prepare_push_flow(self.uni_a.interface,
path[0].endpoint_a,
in_vlan_a, out_vlan_a, in_vlan_z)
in_vlan_a, out_vlan_a,
in_vlan_z, queue_id=self.queue_id)
flows_a.append(push_flow)

# Flow for the other direction, popping the service tag
pop_flow = self._prepare_pop_flow(path[0].endpoint_a,
self.uni_a.interface, out_vlan_a)
self.uni_a.interface,
out_vlan_a, queue_id=self.queue_id)
flows_a.append(pop_flow)

self._send_flow_mods(self.uni_a.interface.switch, flows_a)
Expand All @@ -690,12 +698,14 @@ def _install_uni_flows(self, path=None):
# Flow for one direction, pushing the service tag
push_flow = self._prepare_push_flow(self.uni_z.interface,
path[-1].endpoint_b,
in_vlan_z, out_vlan_z, in_vlan_a)
in_vlan_z, out_vlan_z,
in_vlan_a, queue_id=self.queue_id)
flows_z.append(push_flow)

# Flow for the other direction, popping the service tag
pop_flow = self._prepare_pop_flow(path[-1].endpoint_b,
self.uni_z.interface, out_vlan_z)
self.uni_z.interface,
out_vlan_z, queue_id=self.queue_id)
flows_z.append(pop_flow)

self._send_flow_mods(self.uni_z.interface.switch, flows_z)
Expand All @@ -719,21 +729,26 @@ def get_cookie(self):
"""Return the cookie integer from evc id."""
return int(self.id, 16)

def _prepare_flow_mod(self, in_interface, out_interface):
def _prepare_flow_mod(self, in_interface, out_interface, queue_id=None):
"""Prepare a common flow mod."""
default_action = {"action_type": "output",
"port": out_interface.port_number}
default_actions = [{"action_type": "output",
"port": out_interface.port_number}]
if queue_id:
default_actions.append(
{"action_type": "set_queue", "queue_id": queue_id}
)

flow_mod = {"match": {"in_port": in_interface.port_number},
"cookie": self.get_cookie(),
"actions": [default_action]}
"actions": default_actions}

return flow_mod

def _prepare_nni_flow(self,
in_interface, out_interface, in_vlan, out_vlan):
def _prepare_nni_flow(self, *args, queue_id=None):
"""Create NNI flows."""
flow_mod = self._prepare_flow_mod(in_interface, out_interface)
in_interface, out_interface, in_vlan, out_vlan = args
flow_mod = self._prepare_flow_mod(in_interface, out_interface,
queue_id)
flow_mod['match']['dl_vlan'] = in_vlan

new_action = {"action_type": "set_vlan",
Expand All @@ -742,7 +757,7 @@ def _prepare_nni_flow(self,

return flow_mod

def _prepare_push_flow(self, *args):
def _prepare_push_flow(self, *args, queue_id=None):
"""Prepare push flow.
Arguments:
Expand All @@ -759,7 +774,8 @@ def _prepare_push_flow(self, *args):
# assign all arguments
in_interface, out_interface, in_vlan, out_vlan, new_in_vlan = args

flow_mod = self._prepare_flow_mod(in_interface, out_interface)
flow_mod = self._prepare_flow_mod(in_interface, out_interface,
queue_id)

# the service tag must be always pushed
new_action = {"action_type": "set_vlan", "vlan_id": out_vlan}
Expand Down Expand Up @@ -787,9 +803,11 @@ def _prepare_push_flow(self, *args):
flow_mod["actions"].insert(0, new_action)
return flow_mod

def _prepare_pop_flow(self, in_interface, out_interface, out_vlan):
def _prepare_pop_flow(self, in_interface, out_interface, out_vlan,
queue_id=None):
"""Prepare pop flow."""
flow_mod = self._prepare_flow_mod(in_interface, out_interface)
flow_mod = self._prepare_flow_mod(in_interface, out_interface,
queue_id)
flow_mod['match']['dl_vlan'] = out_vlan
new_action = {"action_type": "pop_vlan"}
flow_mod["actions"].insert(0, new_action)
Expand Down
3 changes: 2 additions & 1 deletion tests/unit/models/test_evc_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,8 @@ def test_deploy_successfully(self, *args):
"name": "custom_name",
"uni_a": uni_a,
"uni_z": uni_z,
"primary_links": primary_links
"primary_links": primary_links,
"queue_id": 5
}
# Setup path to deploy
path = Path()
Expand Down
4 changes: 3 additions & 1 deletion tests/unit/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ def test_evc_from_dict(self, _validate_mock, uni_from_dict_mock):
"circuit_scheduler": [{
"frequency": "* * * * *",
"action": "create"
}]
}],
"queue_id": 5
}
# pylint: disable=protected-access
evc_response = self.napp._evc_from_dict(payload)
Expand All @@ -116,6 +117,7 @@ def test_evc_from_dict(self, _validate_mock, uni_from_dict_mock):
self.assertIsNotNone(evc_response.uni_z)
self.assertIsNotNone(evc_response.circuit_scheduler)
self.assertIsNotNone(evc_response.name)
self.assertIsNotNone(evc_response.queue_id)

@patch('napps.kytos.mef_eline.main.Main._uni_from_dict')
@patch('napps.kytos.mef_eline.models.EVCBase._validate')
Expand Down

0 comments on commit 32c10f9

Please sign in to comment.