Skip to content
Snippets Groups Projects
Commit 7b86b36e authored by Georgios Katsikas's avatar Georgios Katsikas
Browse files

feat: P4 endpoints support and several bug fixes

parent 2d23b59d
No related branches found
No related tags found
2 merge requests!359Release TeraFlowSDN 5.0,!300feat: P4 endpoints support and several bug fixes
...@@ -25,6 +25,7 @@ RESOURCE_ROUTING_POLICIES = '__routing_policies__' ...@@ -25,6 +25,7 @@ RESOURCE_ROUTING_POLICIES = '__routing_policies__'
RESOURCE_SERVICES = '__services__' RESOURCE_SERVICES = '__services__'
RESOURCE_ACL = '__acl__' RESOURCE_ACL = '__acl__'
RESOURCE_INVENTORY = '__inventory__' RESOURCE_INVENTORY = '__inventory__'
RESOURCE_RULES = "__rules__"
class _Driver: class _Driver:
......
...@@ -27,10 +27,12 @@ import math ...@@ -27,10 +27,12 @@ import math
import re import re
import socket import socket
import ipaddress import ipaddress
from typing import Any, Dict, List, Optional, Tuple
from ctypes import c_uint16, sizeof from ctypes import c_uint16, sizeof
import macaddress import macaddress
from common.type_checkers.Checkers import chk_type from common.type_checkers.Checkers import \
chk_attribute, chk_string, chk_type, chk_issubclass
try: try:
from .p4_exception import UserBadValueError from .p4_exception import UserBadValueError
except ImportError: except ImportError:
...@@ -38,6 +40,7 @@ except ImportError: ...@@ -38,6 +40,7 @@ except ImportError:
P4_ATTR_DEV_ID = "id" P4_ATTR_DEV_ID = "id"
P4_ATTR_DEV_NAME = "name" P4_ATTR_DEV_NAME = "name"
P4_ATTR_DEV_ENDPOINTS = "endpoints"
P4_ATTR_DEV_VENDOR = "vendor" P4_ATTR_DEV_VENDOR = "vendor"
P4_ATTR_DEV_HW_VER = "hw_ver" P4_ATTR_DEV_HW_VER = "hw_ver"
P4_ATTR_DEV_SW_VER = "sw_ver" P4_ATTR_DEV_SW_VER = "sw_ver"
...@@ -50,6 +53,7 @@ P4_VAL_DEF_HW_VER = "BMv2 simple_switch" ...@@ -50,6 +53,7 @@ P4_VAL_DEF_HW_VER = "BMv2 simple_switch"
P4_VAL_DEF_SW_VER = "Stratum" P4_VAL_DEF_SW_VER = "Stratum"
P4_VAL_DEF_TIMEOUT = 60 P4_VAL_DEF_TIMEOUT = 60
RESOURCE_ENDPOINTS_ROOT_PATH = "/endpoints"
# Logger instance # Logger instance
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
...@@ -422,6 +426,28 @@ def parse_action_parameters_from_json(resource): ...@@ -422,6 +426,28 @@ def parse_action_parameters_from_json(resource):
return action_params return action_params
def parse_replicas_from_json(resource):
"""
Parse the session replicas within a JSON-based object.
:param resource: JSON-based object
:return: map of replicas
"""
if not resource or ("replicas" not in resource):
LOGGER.warning(
"JSON entry misses 'replicas' list of attributes")
return None
chk_type("replicas", resource["replicas"], list)
replicas = {}
for rep in resource["replicas"]:
chk_type("egress-port", rep["egress-port"], int)
chk_type("instance", rep["instance"], int)
replicas[rep["egress-port"]] = rep["instance"]
return replicas
def parse_integer_list_from_json(resource, resource_list, resource_item): def parse_integer_list_from_json(resource, resource_list, resource_item):
""" """
Parse the list of integers within a JSON-based object. Parse the list of integers within a JSON-based object.
...@@ -443,3 +469,77 @@ def parse_integer_list_from_json(resource, resource_list, resource_item): ...@@ -443,3 +469,77 @@ def parse_integer_list_from_json(resource, resource_list, resource_item):
integers_list.append(item[resource_item]) integers_list.append(item[resource_item])
return integers_list return integers_list
def process_optional_string_field(
#TODO: Consider adding this in common methdos as it is taken by the Emulated driver
endpoint_data : Dict[str, Any], field_name : str, endpoint_resource_value : Dict[str, Any]
) -> None:
field_value = chk_attribute(field_name, endpoint_data, 'endpoint_data', default=None)
if field_value is None: return
chk_string('endpoint_data.{:s}'.format(field_name), field_value)
if len(field_value) > 0: endpoint_resource_value[field_name] = field_value
def compose_resource_endpoints(endpoints_list : List[Tuple[str, Any]]):
#TODO: Consider adding this in common methods; currently taken by the Emulated driver
endpoint_resources = []
for i, endpoint in enumerate(endpoints_list):
LOGGER.debug("P4 endpoint {}: {}".format(i, endpoint))
endpoint_resource = compose_resource_endpoint(endpoint)
if endpoint_resource is None: continue
endpoint_resources.append(endpoint_resource)
return endpoint_resources
def compose_resource_endpoint(endpoint_data : Dict[str, Any]) -> Optional[Tuple[str, Dict]]:
#TODO: Consider adding this in common methods; currently taken by the Emulated driver
try:
endpoint_uuid = chk_attribute('uuid', endpoint_data, 'endpoint_data')
chk_string('endpoint_data.uuid', endpoint_uuid, min_length=1)
endpoint_resource_path = RESOURCE_ENDPOINTS_ROOT_PATH
endpoint_resource_key = '{:s}/endpoint[{:s}]'.format(endpoint_resource_path, endpoint_uuid)
endpoint_resource_value = {'uuid': endpoint_uuid}
# Check endpoint's optional string fields
process_optional_string_field(endpoint_data, 'name', endpoint_resource_value)
process_optional_string_field(endpoint_data, 'type', endpoint_resource_value)
process_optional_string_field(endpoint_data, 'context_uuid', endpoint_resource_value)
process_optional_string_field(endpoint_data, 'topology_uuid', endpoint_resource_value)
return endpoint_resource_key, endpoint_resource_value
except: # pylint: disable=bare-except
LOGGER.error('Problem composing endpoint({:s})'.format(str(endpoint_data)))
return None
def compose_resource_rules(rules_list : List[Tuple[str, Any]]):
rule_resources = []
for i, rule in enumerate(rules_list):
rule_resource = compose_resource_rule(rule_data=rule, rule_cnt=i)
if rule_resource is None: continue
rule_resources.append(rule_resource)
return rule_resources
def compose_resource_rule(rule_data : Dict[str, Any], rule_cnt : int) -> Optional[Tuple[str, Dict]]:
try:
LOGGER.info("Rule: {}".format(rule_data))
rule_resource_key = chk_attribute('resource_key', rule_data, 'rule_data')
chk_string('rule_data.resource_key', rule_resource_key, min_length=1)
rule_resource_value = chk_attribute('resource_value', rule_data, 'rule_data')
chk_issubclass('rule_data.resource_value', rule_resource_value, dict)
rule_key_unique = ""
if "table" == rule_resource_key:
table_name = parse_resource_string_from_json(rule_resource_value, "table-name")
assert table_name, "Invalid table name in rule"
rule_key_unique = '/{0}s/{0}/{1}[{2}]'.format(rule_resource_key, table_name, rule_cnt)
else:
msg = f"Parsed an invalid key {rule_resource_key}"
LOGGER.error(msg)
raise Exception(msg)
assert rule_key_unique, "Invalid unique resource key"
return rule_key_unique, rule_resource_value
except: # pylint: disable=bare-except
LOGGER.error('Problem composing rule({:s})'.format(str(rule_data)))
return None
...@@ -34,6 +34,7 @@ class P4Type(enum.Enum): ...@@ -34,6 +34,7 @@ class P4Type(enum.Enum):
meter = 6 meter = 6
direct_meter = 7 direct_meter = 7
controller_packet_metadata = 8 controller_packet_metadata = 8
digest = 9
P4Type.table.p4info_name = "tables" P4Type.table.p4info_name = "tables"
...@@ -44,6 +45,7 @@ P4Type.direct_counter.p4info_name = "direct_counters" ...@@ -44,6 +45,7 @@ P4Type.direct_counter.p4info_name = "direct_counters"
P4Type.meter.p4info_name = "meters" P4Type.meter.p4info_name = "meters"
P4Type.direct_meter.p4info_name = "direct_meters" P4Type.direct_meter.p4info_name = "direct_meters"
P4Type.controller_packet_metadata.p4info_name = "controller_packet_metadata" P4Type.controller_packet_metadata.p4info_name = "controller_packet_metadata"
P4Type.digest.p4info_name = "digests"
for object_type in P4Type: for object_type in P4Type:
object_type.pretty_name = object_type.name.replace('_', ' ') object_type.pretty_name = object_type.name.replace('_', ' ')
...@@ -58,11 +60,12 @@ class P4RuntimeEntity(enum.Enum): ...@@ -58,11 +60,12 @@ class P4RuntimeEntity(enum.Enum):
table_entry = 1 table_entry = 1
action_profile_member = 2 action_profile_member = 2
action_profile_group = 3 action_profile_group = 3
meter_entry = 4 counter_entry = 4
direct_meter_entry = 5 direct_counter_entry = 5
counter_entry = 6 meter_entry = 6
direct_counter_entry = 7 direct_meter_entry = 7
packet_replication_engine_entry = 8 packet_replication_engine_entry = 8
digest_entry = 9
class Context: class Context:
......
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment