Loading src/device/service/drivers/gnmi_openconfig/handlers/Acl.py 0 → 100644 +166 −0 Original line number Diff line number Diff line # Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import json import logging from typing import Any, Dict, List, Tuple import libyang from ._Handler import _Handler from .YangHandler import YangHandler LOGGER = logging.getLogger(__name__) # ────────────────────────── enum translations ────────────────────────── _TFS_OC_RULE_TYPE = { 'ACLRULETYPE_IPV4': 'ACL_IPV4', 'ACLRULETYPE_IPV6': 'ACL_IPV6', } _TFS_OC_FWD_ACTION = { 'ACLFORWARDINGACTION_DROP': 'DROP', 'ACLFORWARDINGACTION_ACCEPT': 'ACCEPT', 'ACLFORWARDINGACTION_REJECT': 'REJECT', } _OC_TFS_RULE_TYPE = {v: k for k, v in _TFS_OC_RULE_TYPE.items()} _OC_TFS_FWD_ACTION = {v: k for k, v in _TFS_OC_FWD_ACTION.items()} # ───────────────────────────────────────────────────────────────────────── class AclHandler(_Handler): def get_resource_key(self) -> str: return '/device/endpoint/acl_ruleset' def get_path(self) -> str: return '/openconfig-acl:acl' def compose( # pylint: disable=too-many-locals self, resource_key: str, resource_value: Dict[str, Any], yang: YangHandler, delete: bool = False, ) -> Tuple[str, str]: rs = resource_value['rule_set'] rs_name = rs['name'] oc_type = _TFS_OC_RULE_TYPE[rs['type']] device = resource_value['endpoint_id']['device_id']['device_uuid']['uuid'] iface = resource_value['endpoint_id']['endpoint_uuid']['uuid'] if delete: path = f'/acl/acl-sets/acl-set[name={rs_name}][type={oc_type}]' return path, '' yang_acl: libyang.DContainer = yang.get_data_path('/openconfig-acl:acl') y_sets = yang_acl.create_path('acl-sets') y_set = y_sets.create_path(f'acl-set[name="{rs_name}"][type="{oc_type}"]') y_set.create_path('config/name', rs_name) y_set.create_path('config/type', oc_type) # Entries (ACEs) y_entries = y_set.create_path('acl-entries') for entry in rs.get('entries', []): seq = int(entry['sequence_id']) m_ = entry["match"] src_address = m_.get('src_address', '0.0.0.0/0') dst_address = m_.get('dst_address', '0.0.0.0/0') src_port = m_.get("src_port") dst_port = m_.get("dst_port") act = _TFS_OC_FWD_ACTION[entry['action']['forward_action']] y_e = y_entries.create_path(f'acl-entry[sequence-id="{seq}"]') y_e.create_path('config/sequence-id', seq) y_ipv4 = y_e.create_path('ipv4') y_ipv4.create_path('config/source-address', src_address) y_ipv4.create_path('config/destination-address', dst_address) if src_port or dst_port: proto = m_.get("protocol") y_trans = y_e.create_path("transport") if src_port: y_trans.create_path("config/source-port", int(src_port)) if dst_port: y_trans.create_path("config/destination-port", int(dst_port)) y_ipv4.create_path('config/protocol', int(proto)) y_act = y_e.create_path('actions') y_act.create_path('config/forwarding-action', act) # Interface binding y_intfs = yang_acl.create_path('interfaces') y_intf = y_intfs.create_path(f'interface[id="{iface}"]') y_ing = y_intf.create_path('ingress-acl-sets') y_ing_set = y_ing.create_path(f'ingress-acl-set[set-name="{rs_name}"][type="{oc_type}"]') y_ing_set.create_path('config/set-name', rs_name) y_ing_set.create_path('config/type', oc_type) json_data = yang_acl.print_mem('json') LOGGER.debug('JSON data: %s', json_data) json_obj = json.loads(json_data)['openconfig-acl:acl'] return '/acl', json.dumps(json_obj) def parse( # pylint: disable=too-many-locals self, json_data: Dict[str, Any], yang: YangHandler, ) -> List[Tuple[str, Dict[str, Any]]]: acl_tree = json_data.get('openconfig-acl:acl') or json_data results: List[Tuple[str, Dict[str, Any]]] = [] for acl_set in acl_tree.get('acl-sets', {}).get('acl-set', []): rs_name = acl_set['name'] oc_type = acl_set['config']['type'] rs_type = _OC_TFS_RULE_TYPE[oc_type] rule_set: Dict[str, Any] = { 'name': rs_name, 'type': rs_type, 'description': acl_set.get('config', {}).get('description', ''), 'entries': [], } for ace in acl_set.get('acl-entries', {}).get('acl-entry', []): seq = ace['sequence-id'] act = ace.get('actions', {}).get('config', {}).get('forwarding-action', 'DROP') fwd_tfs = _OC_TFS_FWD_ACTION[act] ipv4_cfg = ace.get('ipv4', {}).get('config', {}) rule_set['entries'].append( { 'sequence_id': seq, 'match': { 'src_address': ipv4_cfg.get('source-address', ''), 'dst_address': ipv4_cfg.get('destination-address', ''), }, 'action': {'forward_action': fwd_tfs}, } ) # find where that ACL is bound (first matching interface) iface = '' for intf in acl_tree.get('interfaces', {}).get('interface', []): for ing in intf.get('ingress-acl-sets', {}).get('ingress-acl-set', []): if ing['set-name'] == rs_name: iface = intf['id'] break results.append(('/acl', {'interface': iface, 'rule_set': rule_set})) return results src/device/service/drivers/gnmi_openconfig/handlers/YangHandler.py +2 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ YANG_MODULES = [ 'openconfig-mpls-types', 'openconfig-network-instance-types', 'openconfig-network-instance', 'openconfig-acl', 'openconfig-platform', 'openconfig-platform-controller-card', Loading @@ -59,6 +60,7 @@ YANG_MODULES = [ 'openconfig-platform-software', 'openconfig-platform-transceiver', 'openconfig-platform-types', 'openconfig-platform-healthz', ] LOGGER = logging.getLogger(__name__) Loading src/device/service/drivers/gnmi_openconfig/handlers/__init__.py +8 −1 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ import logging from typing import Any, Dict, List, Optional, Tuple, Union from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES, RESOURCE_ACL from ._Handler import _Handler from .Component import ComponentHandler from .Interface import InterfaceHandler Loading @@ -23,6 +23,7 @@ from .NetworkInstance import NetworkInstanceHandler from .NetworkInstanceInterface import NetworkInstanceInterfaceHandler from .NetworkInstanceProtocol import NetworkInstanceProtocolHandler from .NetworkInstanceStaticRoute import NetworkInstanceStaticRouteHandler from .Acl import AclHandler from .Tools import get_schema from .YangHandler import YangHandler Loading @@ -35,17 +36,20 @@ nih = NetworkInstanceHandler() niifh = NetworkInstanceInterfaceHandler() niph = NetworkInstanceProtocolHandler() nisrh = NetworkInstanceStaticRouteHandler() aclh = AclHandler() ALL_RESOURCE_KEYS = [ RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES, RESOURCE_ACL, ] RESOURCE_KEY_MAPPER = { RESOURCE_ENDPOINTS : comph.get_resource_key(), RESOURCE_INTERFACES : ifaceh.get_resource_key(), RESOURCE_NETWORK_INSTANCES : nih.get_resource_key(), RESOURCE_ACL : aclh.get_resource_key(), } PATH_MAPPER = { Loading @@ -53,6 +57,7 @@ PATH_MAPPER = { '/components/component' : comph.get_path(), '/interfaces' : ifaceh.get_path(), '/network-instances' : nih.get_path(), '/acl' : aclh.get_path(), } RESOURCE_KEY_TO_HANDLER = { Loading @@ -63,6 +68,7 @@ RESOURCE_KEY_TO_HANDLER = { niifh.get_resource_key() : niifh, niph.get_resource_key() : niph, nisrh.get_resource_key() : nisrh, aclh.get_resource_key() : aclh, } PATH_TO_HANDLER = { Loading @@ -73,6 +79,7 @@ PATH_TO_HANDLER = { niifh.get_path() : niifh, niph.get_path() : niph, nisrh.get_path() : nisrh, aclh.get_path() : aclh, } def get_handler( Loading src/nbi/service/ietf_acl/Acl.py +2 −2 Original line number Diff line number Diff line Loading @@ -64,8 +64,8 @@ class Acl(Resource): _config_rule.CopyFrom(config_rule) _config_rule.action = ConfigActionEnum.CONFIGACTION_DELETE delete_config_rules.append(_config_rule) if len(delete_config_rules) == 0: break else: raise NotFound('Acl({:s}) not found in Device({:s})'.format(str(acl_name), str(device_uuid))) device_client = DeviceClient() Loading src/nbi/service/ietf_acl/ietf_acl_parser.py +103 −89 Original line number Diff line number Diff line Loading @@ -13,104 +13,124 @@ # limitations under the License. from enum import Enum from typing import List, Dict from typing import List, Dict, Optional from pydantic import BaseModel, Field from werkzeug.exceptions import NotImplemented from common.proto.acl_pb2 import AclForwardActionEnum, AclRuleTypeEnum, AclEntry from common.proto.context_pb2 import ConfigActionEnum, ConfigRule class AclDirectionEnum(Enum): INGRESS = 'ingress' EGRESS = 'egress' class Ipv4(BaseModel): dscp: int = 0 source_ipv4_network: str = Field(serialization_alias="source-ipv4-network", default="") destination_ipv4_network: str = Field(serialization_alias="destination-ipv4-network", default="") source_ipv4_network: str = Field(serialization_alias='source-ipv4-network', default='') destination_ipv4_network: str = Field( serialization_alias='destination-ipv4-network', default='' ) class Port(BaseModel): port: int = 0 operator: str = "eq" operator: str = 'eq' class Tcp(BaseModel): flags: str = "" source_port: Port = Field(serialization_alias="source-port", default_factory=lambda: Port()) destination_port: Port = Field(serialization_alias="destination-port", default_factory=lambda: Port()) flags: Optional[str] = None source_port: Optional[Port] = Field(serialization_alias='source-port', default=None) destination_port: Optional[Port] = Field(serialization_alias='destination-port', default=None) class Matches(BaseModel): ipv4: Ipv4 = Ipv4() tcp: Tcp = Tcp() tcp: Optional[Tcp] = None class Action(BaseModel): forwarding: str = "" forwarding: str = '' class Ace(BaseModel): name: str = "custom_rule" name: str = '' matches: Matches = Matches() actions: Action = Action() class Aces(BaseModel): ace: List[Ace] = [Ace()] class Acl(BaseModel): name: str = "" type: str = "" name: str = '' type: str = '' aces: Aces = Aces() class Name(BaseModel): name: str = "" name: str = '' class AclSet(BaseModel): acl_set: List[Name] = Field(serialization_alias="acl-set", default=[Name()]) acl_set: List[Name] = Field(serialization_alias='acl-set', default=[Name()]) class AclSets(BaseModel): acl_sets: AclSet = Field(serialization_alias="acl-sets", default=AclSet()) acl_sets: AclSet = Field(serialization_alias='acl-sets', default=AclSet()) class Ingress(BaseModel): ingress: AclSets = AclSets() class Egress(BaseModel): egress: AclSets = AclSets() class Interface(BaseModel): interface_id: str = Field(serialization_alias="interface-id", default="") ingress : Ingress = Ingress() egress : Egress = Egress() interface_id: str = Field(serialization_alias='interface-id', default='') ingress: Optional[AclSets] = None egress: Optional[AclSets] = None class Interfaces(BaseModel): interface: List[Interface] = [Interface()] class AttachmentPoints(BaseModel): attachment_points: Interfaces = Field(serialization_alias="attachment-points", default=Interfaces()) class Acls(BaseModel): acl: List[Acl] = [Acl()] attachment_points: AttachmentPoints = Field(serialization_alias="attachment-points", default=AttachmentPoints()) attachment_points: Optional[Interfaces] = Field( serialization_alias='attachment-points', default=None ) class IETF_ACL(BaseModel): acls: Acls = Acls() acls: Optional[Acls] = Field(serialization_alias='ietf-access-control-list:acls', default=None) IETF_TFS_RULE_TYPE_MAPPING = { "ipv4-acl-type": "ACLRULETYPE_IPV4", "ipv6-acl-type": "ACLRULETYPE_IPV6", 'ipv4-acl-type': 'ACLRULETYPE_IPV4', 'ipv6-acl-type': 'ACLRULETYPE_IPV6', } IETF_TFS_FORWARDING_ACTION_MAPPING = { "accept": "ACLFORWARDINGACTION_ACCEPT", "drop" : "ACLFORWARDINGACTION_DROP", 'accept': 'ACLFORWARDINGACTION_ACCEPT', 'drop': 'ACLFORWARDINGACTION_DROP', } TFS_IETF_RULE_TYPE_MAPPING = { "ACLRULETYPE_IPV4": "ipv4-acl-type", "ACLRULETYPE_IPV6": "ipv6-acl-type", 'ACLRULETYPE_IPV4': 'ipv4-acl-type', 'ACLRULETYPE_IPV6': 'ipv6-acl-type', } TFS_IETF_FORWARDING_ACTION_MAPPING = { "ACLFORWARDINGACTION_ACCEPT": "accept", "ACLFORWARDINGACTION_DROP" : "drop", 'ACLFORWARDINGACTION_ACCEPT': 'accept', 'ACLFORWARDINGACTION_DROP': 'drop', } def config_rule_from_ietf_acl( device_name: str, endpoint_name: str, acl_set_data: Dict ) -> ConfigRule: Loading Loading @@ -139,7 +159,7 @@ def config_rule_from_ietf_acl( acl_entry = AclEntry() acl_entry.sequence_id = sequence_id + 1 #acl_entry.description = ... acl_entry.description = ace_name if 'ipv4' in ace_matches: ipv4_data = ace_matches['ipv4'] Loading Loading @@ -203,55 +223,49 @@ def config_rule_from_ietf_acl( return acl_config_rule def ietf_acl_from_config_rule_resource_value(config_rule_rv: Dict) -> Dict: rule_set = config_rule_rv['rule_set'] acl_entry = rule_set['entries'][0] match_ = acl_entry['match'] ace = [] for acl_entry in rule_set['entries']: match_ = acl_entry['match'] ipv4 = Ipv4( dscp=match_["dscp"], source_ipv4_network=match_["src_address"], destination_ipv4_network=match_["dst_address"] dscp=match_['dscp'], source_ipv4_network=match_['src_address'], destination_ipv4_network=match_['dst_address'], ) tcp = None if match_['tcp_flags']: tcp = Tcp( flags=match_["tcp_flags"], source_port=Port(port=match_["src_port"]), destination_port=Port(port=match_["dst_port"]) flags=match_['tcp_flags'], source_port=Port(port=match_['src_port']), destination_port=Port(port=match_['dst_port']), ) matches = Matches(ipvr=ipv4, tcp=tcp) aces = Aces(ace=[ matches = Matches(ipv4=ipv4, tcp=tcp) ace.append( Ace( name=acl_entry['description'], matches=matches, actions=Action( forwarding=TFS_IETF_FORWARDING_ACTION_MAPPING[acl_entry["action"]["forward_action"]] ) ) ]) acl = Acl( name=rule_set["name"], type=TFS_IETF_RULE_TYPE_MAPPING[rule_set["type"]], aces=aces ) acl_sets = AclSets( acl_sets=AclSet( acl_set=[ Name(name=rule_set["name"]) forwarding=TFS_IETF_FORWARDING_ACTION_MAPPING[ acl_entry['action']['forward_action'] ] ), ) ) ingress = Ingress(ingress=acl_sets) interfaces = Interfaces(interface=[ aces = Aces(ace=ace) acl = Acl(name=rule_set['name'], type=TFS_IETF_RULE_TYPE_MAPPING[rule_set['type']], aces=aces) acl_sets = AclSets(acl_sets=AclSet(acl_set=[Name(name=rule_set['name'])])) interfaces = Interfaces( interface=[ Interface( interface_id=config_rule_rv["interface"], ingress=ingress ) ]) acls = Acls( acl=[acl], attachment_points=AttachmentPoints( attachment_points=interfaces interface_id=config_rule_rv['endpoint_id']['endpoint_uuid']['uuid'], ingress=acl_sets, ) ] ) acls = Acls(acl=[acl], attachment_points=interfaces) ietf_acl = IETF_ACL(acls=acls) return ietf_acl.model_dump(by_alias=True) return ietf_acl.model_dump(by_alias=True, exclude_none=True) Loading
src/device/service/drivers/gnmi_openconfig/handlers/Acl.py 0 → 100644 +166 −0 Original line number Diff line number Diff line # Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import json import logging from typing import Any, Dict, List, Tuple import libyang from ._Handler import _Handler from .YangHandler import YangHandler LOGGER = logging.getLogger(__name__) # ────────────────────────── enum translations ────────────────────────── _TFS_OC_RULE_TYPE = { 'ACLRULETYPE_IPV4': 'ACL_IPV4', 'ACLRULETYPE_IPV6': 'ACL_IPV6', } _TFS_OC_FWD_ACTION = { 'ACLFORWARDINGACTION_DROP': 'DROP', 'ACLFORWARDINGACTION_ACCEPT': 'ACCEPT', 'ACLFORWARDINGACTION_REJECT': 'REJECT', } _OC_TFS_RULE_TYPE = {v: k for k, v in _TFS_OC_RULE_TYPE.items()} _OC_TFS_FWD_ACTION = {v: k for k, v in _TFS_OC_FWD_ACTION.items()} # ───────────────────────────────────────────────────────────────────────── class AclHandler(_Handler): def get_resource_key(self) -> str: return '/device/endpoint/acl_ruleset' def get_path(self) -> str: return '/openconfig-acl:acl' def compose( # pylint: disable=too-many-locals self, resource_key: str, resource_value: Dict[str, Any], yang: YangHandler, delete: bool = False, ) -> Tuple[str, str]: rs = resource_value['rule_set'] rs_name = rs['name'] oc_type = _TFS_OC_RULE_TYPE[rs['type']] device = resource_value['endpoint_id']['device_id']['device_uuid']['uuid'] iface = resource_value['endpoint_id']['endpoint_uuid']['uuid'] if delete: path = f'/acl/acl-sets/acl-set[name={rs_name}][type={oc_type}]' return path, '' yang_acl: libyang.DContainer = yang.get_data_path('/openconfig-acl:acl') y_sets = yang_acl.create_path('acl-sets') y_set = y_sets.create_path(f'acl-set[name="{rs_name}"][type="{oc_type}"]') y_set.create_path('config/name', rs_name) y_set.create_path('config/type', oc_type) # Entries (ACEs) y_entries = y_set.create_path('acl-entries') for entry in rs.get('entries', []): seq = int(entry['sequence_id']) m_ = entry["match"] src_address = m_.get('src_address', '0.0.0.0/0') dst_address = m_.get('dst_address', '0.0.0.0/0') src_port = m_.get("src_port") dst_port = m_.get("dst_port") act = _TFS_OC_FWD_ACTION[entry['action']['forward_action']] y_e = y_entries.create_path(f'acl-entry[sequence-id="{seq}"]') y_e.create_path('config/sequence-id', seq) y_ipv4 = y_e.create_path('ipv4') y_ipv4.create_path('config/source-address', src_address) y_ipv4.create_path('config/destination-address', dst_address) if src_port or dst_port: proto = m_.get("protocol") y_trans = y_e.create_path("transport") if src_port: y_trans.create_path("config/source-port", int(src_port)) if dst_port: y_trans.create_path("config/destination-port", int(dst_port)) y_ipv4.create_path('config/protocol', int(proto)) y_act = y_e.create_path('actions') y_act.create_path('config/forwarding-action', act) # Interface binding y_intfs = yang_acl.create_path('interfaces') y_intf = y_intfs.create_path(f'interface[id="{iface}"]') y_ing = y_intf.create_path('ingress-acl-sets') y_ing_set = y_ing.create_path(f'ingress-acl-set[set-name="{rs_name}"][type="{oc_type}"]') y_ing_set.create_path('config/set-name', rs_name) y_ing_set.create_path('config/type', oc_type) json_data = yang_acl.print_mem('json') LOGGER.debug('JSON data: %s', json_data) json_obj = json.loads(json_data)['openconfig-acl:acl'] return '/acl', json.dumps(json_obj) def parse( # pylint: disable=too-many-locals self, json_data: Dict[str, Any], yang: YangHandler, ) -> List[Tuple[str, Dict[str, Any]]]: acl_tree = json_data.get('openconfig-acl:acl') or json_data results: List[Tuple[str, Dict[str, Any]]] = [] for acl_set in acl_tree.get('acl-sets', {}).get('acl-set', []): rs_name = acl_set['name'] oc_type = acl_set['config']['type'] rs_type = _OC_TFS_RULE_TYPE[oc_type] rule_set: Dict[str, Any] = { 'name': rs_name, 'type': rs_type, 'description': acl_set.get('config', {}).get('description', ''), 'entries': [], } for ace in acl_set.get('acl-entries', {}).get('acl-entry', []): seq = ace['sequence-id'] act = ace.get('actions', {}).get('config', {}).get('forwarding-action', 'DROP') fwd_tfs = _OC_TFS_FWD_ACTION[act] ipv4_cfg = ace.get('ipv4', {}).get('config', {}) rule_set['entries'].append( { 'sequence_id': seq, 'match': { 'src_address': ipv4_cfg.get('source-address', ''), 'dst_address': ipv4_cfg.get('destination-address', ''), }, 'action': {'forward_action': fwd_tfs}, } ) # find where that ACL is bound (first matching interface) iface = '' for intf in acl_tree.get('interfaces', {}).get('interface', []): for ing in intf.get('ingress-acl-sets', {}).get('ingress-acl-set', []): if ing['set-name'] == rs_name: iface = intf['id'] break results.append(('/acl', {'interface': iface, 'rule_set': rule_set})) return results
src/device/service/drivers/gnmi_openconfig/handlers/YangHandler.py +2 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ YANG_MODULES = [ 'openconfig-mpls-types', 'openconfig-network-instance-types', 'openconfig-network-instance', 'openconfig-acl', 'openconfig-platform', 'openconfig-platform-controller-card', Loading @@ -59,6 +60,7 @@ YANG_MODULES = [ 'openconfig-platform-software', 'openconfig-platform-transceiver', 'openconfig-platform-types', 'openconfig-platform-healthz', ] LOGGER = logging.getLogger(__name__) Loading
src/device/service/drivers/gnmi_openconfig/handlers/__init__.py +8 −1 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ import logging from typing import Any, Dict, List, Optional, Tuple, Union from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES, RESOURCE_ACL from ._Handler import _Handler from .Component import ComponentHandler from .Interface import InterfaceHandler Loading @@ -23,6 +23,7 @@ from .NetworkInstance import NetworkInstanceHandler from .NetworkInstanceInterface import NetworkInstanceInterfaceHandler from .NetworkInstanceProtocol import NetworkInstanceProtocolHandler from .NetworkInstanceStaticRoute import NetworkInstanceStaticRouteHandler from .Acl import AclHandler from .Tools import get_schema from .YangHandler import YangHandler Loading @@ -35,17 +36,20 @@ nih = NetworkInstanceHandler() niifh = NetworkInstanceInterfaceHandler() niph = NetworkInstanceProtocolHandler() nisrh = NetworkInstanceStaticRouteHandler() aclh = AclHandler() ALL_RESOURCE_KEYS = [ RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES, RESOURCE_ACL, ] RESOURCE_KEY_MAPPER = { RESOURCE_ENDPOINTS : comph.get_resource_key(), RESOURCE_INTERFACES : ifaceh.get_resource_key(), RESOURCE_NETWORK_INSTANCES : nih.get_resource_key(), RESOURCE_ACL : aclh.get_resource_key(), } PATH_MAPPER = { Loading @@ -53,6 +57,7 @@ PATH_MAPPER = { '/components/component' : comph.get_path(), '/interfaces' : ifaceh.get_path(), '/network-instances' : nih.get_path(), '/acl' : aclh.get_path(), } RESOURCE_KEY_TO_HANDLER = { Loading @@ -63,6 +68,7 @@ RESOURCE_KEY_TO_HANDLER = { niifh.get_resource_key() : niifh, niph.get_resource_key() : niph, nisrh.get_resource_key() : nisrh, aclh.get_resource_key() : aclh, } PATH_TO_HANDLER = { Loading @@ -73,6 +79,7 @@ PATH_TO_HANDLER = { niifh.get_path() : niifh, niph.get_path() : niph, nisrh.get_path() : nisrh, aclh.get_path() : aclh, } def get_handler( Loading
src/nbi/service/ietf_acl/Acl.py +2 −2 Original line number Diff line number Diff line Loading @@ -64,8 +64,8 @@ class Acl(Resource): _config_rule.CopyFrom(config_rule) _config_rule.action = ConfigActionEnum.CONFIGACTION_DELETE delete_config_rules.append(_config_rule) if len(delete_config_rules) == 0: break else: raise NotFound('Acl({:s}) not found in Device({:s})'.format(str(acl_name), str(device_uuid))) device_client = DeviceClient() Loading
src/nbi/service/ietf_acl/ietf_acl_parser.py +103 −89 Original line number Diff line number Diff line Loading @@ -13,104 +13,124 @@ # limitations under the License. from enum import Enum from typing import List, Dict from typing import List, Dict, Optional from pydantic import BaseModel, Field from werkzeug.exceptions import NotImplemented from common.proto.acl_pb2 import AclForwardActionEnum, AclRuleTypeEnum, AclEntry from common.proto.context_pb2 import ConfigActionEnum, ConfigRule class AclDirectionEnum(Enum): INGRESS = 'ingress' EGRESS = 'egress' class Ipv4(BaseModel): dscp: int = 0 source_ipv4_network: str = Field(serialization_alias="source-ipv4-network", default="") destination_ipv4_network: str = Field(serialization_alias="destination-ipv4-network", default="") source_ipv4_network: str = Field(serialization_alias='source-ipv4-network', default='') destination_ipv4_network: str = Field( serialization_alias='destination-ipv4-network', default='' ) class Port(BaseModel): port: int = 0 operator: str = "eq" operator: str = 'eq' class Tcp(BaseModel): flags: str = "" source_port: Port = Field(serialization_alias="source-port", default_factory=lambda: Port()) destination_port: Port = Field(serialization_alias="destination-port", default_factory=lambda: Port()) flags: Optional[str] = None source_port: Optional[Port] = Field(serialization_alias='source-port', default=None) destination_port: Optional[Port] = Field(serialization_alias='destination-port', default=None) class Matches(BaseModel): ipv4: Ipv4 = Ipv4() tcp: Tcp = Tcp() tcp: Optional[Tcp] = None class Action(BaseModel): forwarding: str = "" forwarding: str = '' class Ace(BaseModel): name: str = "custom_rule" name: str = '' matches: Matches = Matches() actions: Action = Action() class Aces(BaseModel): ace: List[Ace] = [Ace()] class Acl(BaseModel): name: str = "" type: str = "" name: str = '' type: str = '' aces: Aces = Aces() class Name(BaseModel): name: str = "" name: str = '' class AclSet(BaseModel): acl_set: List[Name] = Field(serialization_alias="acl-set", default=[Name()]) acl_set: List[Name] = Field(serialization_alias='acl-set', default=[Name()]) class AclSets(BaseModel): acl_sets: AclSet = Field(serialization_alias="acl-sets", default=AclSet()) acl_sets: AclSet = Field(serialization_alias='acl-sets', default=AclSet()) class Ingress(BaseModel): ingress: AclSets = AclSets() class Egress(BaseModel): egress: AclSets = AclSets() class Interface(BaseModel): interface_id: str = Field(serialization_alias="interface-id", default="") ingress : Ingress = Ingress() egress : Egress = Egress() interface_id: str = Field(serialization_alias='interface-id', default='') ingress: Optional[AclSets] = None egress: Optional[AclSets] = None class Interfaces(BaseModel): interface: List[Interface] = [Interface()] class AttachmentPoints(BaseModel): attachment_points: Interfaces = Field(serialization_alias="attachment-points", default=Interfaces()) class Acls(BaseModel): acl: List[Acl] = [Acl()] attachment_points: AttachmentPoints = Field(serialization_alias="attachment-points", default=AttachmentPoints()) attachment_points: Optional[Interfaces] = Field( serialization_alias='attachment-points', default=None ) class IETF_ACL(BaseModel): acls: Acls = Acls() acls: Optional[Acls] = Field(serialization_alias='ietf-access-control-list:acls', default=None) IETF_TFS_RULE_TYPE_MAPPING = { "ipv4-acl-type": "ACLRULETYPE_IPV4", "ipv6-acl-type": "ACLRULETYPE_IPV6", 'ipv4-acl-type': 'ACLRULETYPE_IPV4', 'ipv6-acl-type': 'ACLRULETYPE_IPV6', } IETF_TFS_FORWARDING_ACTION_MAPPING = { "accept": "ACLFORWARDINGACTION_ACCEPT", "drop" : "ACLFORWARDINGACTION_DROP", 'accept': 'ACLFORWARDINGACTION_ACCEPT', 'drop': 'ACLFORWARDINGACTION_DROP', } TFS_IETF_RULE_TYPE_MAPPING = { "ACLRULETYPE_IPV4": "ipv4-acl-type", "ACLRULETYPE_IPV6": "ipv6-acl-type", 'ACLRULETYPE_IPV4': 'ipv4-acl-type', 'ACLRULETYPE_IPV6': 'ipv6-acl-type', } TFS_IETF_FORWARDING_ACTION_MAPPING = { "ACLFORWARDINGACTION_ACCEPT": "accept", "ACLFORWARDINGACTION_DROP" : "drop", 'ACLFORWARDINGACTION_ACCEPT': 'accept', 'ACLFORWARDINGACTION_DROP': 'drop', } def config_rule_from_ietf_acl( device_name: str, endpoint_name: str, acl_set_data: Dict ) -> ConfigRule: Loading Loading @@ -139,7 +159,7 @@ def config_rule_from_ietf_acl( acl_entry = AclEntry() acl_entry.sequence_id = sequence_id + 1 #acl_entry.description = ... acl_entry.description = ace_name if 'ipv4' in ace_matches: ipv4_data = ace_matches['ipv4'] Loading Loading @@ -203,55 +223,49 @@ def config_rule_from_ietf_acl( return acl_config_rule def ietf_acl_from_config_rule_resource_value(config_rule_rv: Dict) -> Dict: rule_set = config_rule_rv['rule_set'] acl_entry = rule_set['entries'][0] match_ = acl_entry['match'] ace = [] for acl_entry in rule_set['entries']: match_ = acl_entry['match'] ipv4 = Ipv4( dscp=match_["dscp"], source_ipv4_network=match_["src_address"], destination_ipv4_network=match_["dst_address"] dscp=match_['dscp'], source_ipv4_network=match_['src_address'], destination_ipv4_network=match_['dst_address'], ) tcp = None if match_['tcp_flags']: tcp = Tcp( flags=match_["tcp_flags"], source_port=Port(port=match_["src_port"]), destination_port=Port(port=match_["dst_port"]) flags=match_['tcp_flags'], source_port=Port(port=match_['src_port']), destination_port=Port(port=match_['dst_port']), ) matches = Matches(ipvr=ipv4, tcp=tcp) aces = Aces(ace=[ matches = Matches(ipv4=ipv4, tcp=tcp) ace.append( Ace( name=acl_entry['description'], matches=matches, actions=Action( forwarding=TFS_IETF_FORWARDING_ACTION_MAPPING[acl_entry["action"]["forward_action"]] ) ) ]) acl = Acl( name=rule_set["name"], type=TFS_IETF_RULE_TYPE_MAPPING[rule_set["type"]], aces=aces ) acl_sets = AclSets( acl_sets=AclSet( acl_set=[ Name(name=rule_set["name"]) forwarding=TFS_IETF_FORWARDING_ACTION_MAPPING[ acl_entry['action']['forward_action'] ] ), ) ) ingress = Ingress(ingress=acl_sets) interfaces = Interfaces(interface=[ aces = Aces(ace=ace) acl = Acl(name=rule_set['name'], type=TFS_IETF_RULE_TYPE_MAPPING[rule_set['type']], aces=aces) acl_sets = AclSets(acl_sets=AclSet(acl_set=[Name(name=rule_set['name'])])) interfaces = Interfaces( interface=[ Interface( interface_id=config_rule_rv["interface"], ingress=ingress ) ]) acls = Acls( acl=[acl], attachment_points=AttachmentPoints( attachment_points=interfaces interface_id=config_rule_rv['endpoint_id']['endpoint_uuid']['uuid'], ingress=acl_sets, ) ] ) acls = Acls(acl=[acl], attachment_points=interfaces) ietf_acl = IETF_ACL(acls=acls) return ietf_acl.model_dump(by_alias=True) return ietf_acl.model_dump(by_alias=True, exclude_none=True)