Commit c5b2c7e6 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Device component - gNMI OpenConfig:

- Support for ICMP protocol
- Directionality of ACL rules
- Manage cleanup of ACL rules while composing OpenConfig messages
parent f239617f
Loading
Loading
Loading
Loading
+57 −15
Original line number Diff line number Diff line
@@ -12,12 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import json
import logging
import json, libyang, logging
from typing import Any, Dict, List, Tuple

import libyang

from common.proto.context_pb2 import AclDirectionEnum
from ._Handler import _Handler
from .YangHandler import YangHandler

@@ -41,6 +38,20 @@ _OC_TFS_FWD_ACTION = {v: k for k, v in _TFS_OC_FWD_ACTION.items()}

# ─────────────────────────────────────────────────────────────────────────

DIRECTION_INGRESS = {
    AclDirectionEnum.ACLDIRECTION_BOTH,
    AclDirectionEnum.Name(AclDirectionEnum.ACLDIRECTION_BOTH),
    AclDirectionEnum.ACLDIRECTION_INGRESS,
    AclDirectionEnum.Name(AclDirectionEnum.ACLDIRECTION_INGRESS),
}

DIRECTION_EGRESS = {
    AclDirectionEnum.ACLDIRECTION_BOTH,
    AclDirectionEnum.Name(AclDirectionEnum.ACLDIRECTION_BOTH),
    AclDirectionEnum.ACLDIRECTION_EGRESS,
    AclDirectionEnum.Name(AclDirectionEnum.ACLDIRECTION_EGRESS),
}


class AclHandler(_Handler):
    def get_resource_key(self) -> str:
@@ -59,8 +70,9 @@ class AclHandler(_Handler):
        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']
        #device = resource_value['endpoint_id']['device_id']['device_uuid']['uuid']
        iface = resource_value['endpoint_id']['endpoint_uuid']['uuid']
        direction = resource_value['direction']

        if delete:
            path = f'/acl/acl-sets/acl-set[name={rs_name}][type={oc_type}]'
@@ -77,11 +89,11 @@ class AclHandler(_Handler):
        y_entries = y_set.create_path('acl-entries')
        for entry in rs.get('entries', []):
            seq = int(entry['sequence_id'])
            m_ = entry["match"]
            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")
            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}"]')
@@ -91,9 +103,12 @@ class AclHandler(_Handler):
            y_ipv4.create_path('config/source-address', src_address)
            y_ipv4.create_path('config/destination-address', dst_address)

            proto = m_.get('protocol')
            if proto is not None:
                y_ipv4.create_path('config/protocol', int(proto))

            if src_port or dst_port:
                proto = m_.get("protocol")
                y_trans = y_e.create_path("transport")
                y_trans = y_e.create_path('transport')
                if src_port:
                    y_trans.create_path("config/source-port", int(src_port))
                if dst_port:
@@ -106,14 +121,41 @@ class AclHandler(_Handler):
        # 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)

        if direction in DIRECTION_INGRESS:
            y_ingress = y_intf.create_path('ingress-acl-sets')
            y_ingress_set = y_ingress.create_path(f'ingress-acl-set[set-name="{rs_name}"][type="{oc_type}"]')
            y_ingress_set.create_path('config/set-name', rs_name)
            y_ingress_set.create_path('config/type', oc_type)

        if direction in DIRECTION_EGRESS:
            y_egress = y_intf.create_path('egress-acl-sets')
            y_egress_set = y_egress.create_path(f'egress-acl-set[set-name="{rs_name}"][type="{oc_type}"]')
            y_egress_set.create_path('config/set-name', rs_name)
            y_egress_set.create_path('config/type', oc_type)

        json_data = yang_acl.print_mem('json')
        #json_data = str(node.print_mem(
        #    fmt='json', with_siblings=True, pretty=True,
        #    keep_empty_containers=True, include_implicit_defaults=True
        #))
        LOGGER.debug('JSON data: %s', json_data)
        json_obj = json.loads(json_data)['openconfig-acl:acl']

        # release generated nodes to prevent side effects
        node_ifs : libyang.DNode = yang_acl.find_path('/openconfig-acl:acl/interfaces')
        #if node is None: return None
        LOGGER.info('node_ifs = {:s}'.format(str(node_ifs)))
        node_ifs.unlink()
        node_ifs.free()

        # release generated nodes to prevent side effects
        node_acls : libyang.DNode = yang_acl.find_path('/openconfig-acl:acl/acl-sets')
        #if node is None: return None
        LOGGER.info('node_acls = {:s}'.format(str(node_acls)))
        node_acls.unlink()
        node_acls.free()

        return '/acl', json.dumps(json_obj)

    def parse(  # pylint: disable=too-many-locals