Commit 469138e4 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Service component - L3NM gNMI OpenConfig:

- Fix rule composer to do not remove (sub-)interfaces not in VLANs and preserve MTUs
parent 0d56613c
Loading
Loading
Loading
Loading
+36 −14
Original line number Diff line number Diff line
@@ -54,15 +54,16 @@ def _safe_bool(value: Optional[object]) -> Optional[bool]:
def _interface(
    interface : str, if_type : Optional[str] = 'l3ipvlan', index : int = 0, vlan_id : Optional[int] = None,
    address_ip : Optional[str] = None, address_prefix : Optional[int] = None, mtu : Optional[int] = None,
    enabled : bool = True
    enabled : Optional[bool] = True
) -> Tuple[str, Dict]:
    path = '/interface[{:s}]/subinterface[{:d}]'.format(interface, index)
    data = {'name': interface, 'type': if_type, 'index': index, 'enabled': enabled}
    data = {'name': interface, 'type': if_type, 'index': index}
    if if_type is not None: data['type'] = if_type
    if vlan_id is not None: data['vlan_id'] = vlan_id
    if address_ip is not None: data['address_ip'] = address_ip
    if address_prefix is not None: data['address_prefix'] = address_prefix
    if mtu is not None: data['mtu'] = mtu
    if enabled is not None: data['enabled'] = enabled
    return path, data

def _network_instance(ni_name : str, ni_type : str) -> Tuple[str, Dict]:
@@ -114,6 +115,7 @@ class EndpointComposer:
        self.ipv4_prefix_len = None
        self.explicit_vlan_ids : Set[int] = set()
        self.force_trunk = False
        self.mtu : Optional[int] = None

    def _add_vlan_id(self, vlan_id : Optional[int]) -> None:
        if vlan_id is not None:
@@ -124,6 +126,9 @@ class EndpointComposer:
            return
        vlan_id = _safe_int(json_settings.get('vlan_id', json_settings.get('vlan-id')))
        self._add_vlan_id(vlan_id)
        mtu = _safe_int(json_settings.get('mtu'))
        if mtu is not None:
            self.mtu = mtu

    def configure(self, endpoint_obj : Optional[EndPoint], settings : Optional[TreeNode]) -> None:
        if endpoint_obj is not None:
@@ -185,17 +190,25 @@ class EndpointComposer:
            )))

        if delete:
            if sub_interface_index == 0:
                config_rules.extend([
                    json_config_rule(*_interface(
                        self.objekt.name, index=sub_interface_index, address_ip=self.ipv4_address,
                        address_prefix=self.ipv4_prefix_len, enabled=None, vlan_id=vlan_id, mtu=None
                    )),
                ])
            else:
                config_rules.extend([
                    json_config_rule(*_interface(
                        self.objekt.name, index=sub_interface_index, address_ip=None,
                    address_prefix=None, enabled=False, vlan_id=vlan_id
                        address_prefix=None, enabled=None, vlan_id=vlan_id, mtu=None
                    )),
                ])
        else:
            config_rules.extend([
                json_config_rule(*_interface(
                    self.objekt.name, index=sub_interface_index, address_ip=self.ipv4_address,
                    address_prefix=self.ipv4_prefix_len, enabled=True, vlan_id=vlan_id
                    address_prefix=self.ipv4_prefix_len, enabled=True, vlan_id=vlan_id, mtu=self.mtu
                )),
            ])
        return config_rules
@@ -207,6 +220,7 @@ class EndpointComposer:
            'address_prefix': self.ipv4_prefix_len,
            'explicit_vlan_ids': list(self.explicit_vlan_ids),
            'force_trunk' : self.force_trunk,
            'mtu' : self.mtu,
        }
    
    def __str__(self):
@@ -226,6 +240,7 @@ class DeviceComposer:
        self.service_vlan_id : Optional[int] = None
        self.access_vlan_tagged = False
        self.vlan_ids : Set[int] = set()
        self.interface_mtu : Dict[str, int] = dict()

    def set_endpoint_alias(self, endpoint_name : str, endpoint_uuid : str) -> None:
        self.aliases[endpoint_name] = endpoint_uuid
@@ -238,6 +253,7 @@ class DeviceComposer:

    def configure(self, device_obj : Device, settings : Optional[TreeNode]) -> None:
        self.objekt = device_obj
        self.interface_mtu = dict()
        for endpoint_obj in device_obj.device_endpoints:
            endpoint_uuid = endpoint_obj.endpoint_id.endpoint_uuid.uuid
            self.set_endpoint_alias(endpoint_obj.name, endpoint_uuid)
@@ -255,6 +271,8 @@ class DeviceComposer:
            resource_value = json.loads(config_rule_custom.resource_value)
            management = resource_value.get('management', False)
            if management: mgmt_ifaces.add(if_name)
            mtu = _safe_int(resource_value.get('mtu'))
            if mtu is not None: self.interface_mtu[if_name] = mtu

        # Find data plane interfaces
        for config_rule in device_obj.device_config.config_rules:
@@ -287,6 +305,13 @@ class DeviceComposer:
                next_hop = resource_value['next_hop']
                self.static_routes.setdefault(prefix, dict())[metric] = next_hop

        for if_name, mtu in self.interface_mtu.items():
            if if_name in mgmt_ifaces: continue
            if if_name not in self.aliases: continue
            endpoint = self.get_endpoint(if_name)
            if endpoint.mtu is None:
                endpoint.mtu = mtu

        if settings is None: return
        json_settings : Dict = settings.value
        static_routes : List[Dict] = json_settings.get('static_routes', [])
@@ -325,7 +350,8 @@ class DeviceComposer:
            parent_interfaces.add(endpoint.objekt.name)
            if not delete and endpoint.objekt.name not in configured_parents:
                config_rules.append(json_config_rule_set(*_interface(
                    endpoint.objekt.name, index=0, address_ip=None, address_prefix=None, enabled=True
                    endpoint.objekt.name, index=0, address_ip=None, address_prefix=None,
                    enabled=True, mtu=endpoint.mtu
                )))
                configured_parents.add(endpoint.objekt.name)
            config_rules.extend(endpoint.get_config_rules(
@@ -334,10 +360,6 @@ class DeviceComposer:
            ))
            self.vlan_ids.update(endpoint.explicit_vlan_ids)

        if delete:
            for if_name in sorted(parent_interfaces):
                config_rules.append(json_config_rule_delete(*_interface_switched_vlan(if_name)))

        for vlan_id in sorted(self.vlan_ids):
            vlan_name = 'tfs-vlan-{:s}'.format(str(vlan_id))
            config_rules.append(json_config_rule(*_network_instance_vlan(