diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/vyos/ifconfig/vxlan.py | 66 | ||||
| -rw-r--r-- | python/vyos/utils/network.py | 45 | ||||
| -rw-r--r-- | python/vyos/utils/process.py | 2 | 
3 files changed, 110 insertions, 3 deletions
| diff --git a/python/vyos/ifconfig/vxlan.py b/python/vyos/ifconfig/vxlan.py index 6a9911588..1fe5db7cd 100644 --- a/python/vyos/ifconfig/vxlan.py +++ b/python/vyos/ifconfig/vxlan.py @@ -1,4 +1,4 @@ -# Copyright 2019-2022 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2019-2023 VyOS maintainers and contributors <maintainers@vyos.io>  #  # This library is free software; you can redistribute it and/or  # modify it under the terms of the GNU Lesser General Public @@ -13,9 +13,15 @@  # You should have received a copy of the GNU Lesser General Public  # License along with this library.  If not, see <http://www.gnu.org/licenses/>. +from json import loads +  from vyos import ConfigError +from vyos.configdict import list_diff  from vyos.ifconfig import Interface +from vyos.utils.assertion import assert_list  from vyos.utils.dict import dict_search +from vyos.utils.network import get_interface_config +from vyos.utils.network import get_vxlan_vlan_tunnels  @Interface.register  class VXLANIf(Interface): @@ -49,6 +55,13 @@ class VXLANIf(Interface):          }      } +    _command_set = {**Interface._command_set, **{ +        'vlan_tunnel': { +            'validate': lambda v: assert_list(v, ['on', 'off']), +            'shellcmd': 'bridge link set dev {ifname} vlan_tunnel {value}', +        }, +    }} +      def _create(self):          # This table represents a mapping from VyOS internal config dict to          # arguments used by iproute2. For more information please refer to: @@ -99,3 +112,54 @@ class VXLANIf(Interface):                  cmd = f'bridge fdb append to 00:00:00:00:00:00 dst {remote} ' \                         'port {port} dev {ifname}'                  self._cmd(cmd.format(**self.config)) + +    def set_vlan_vni_mapping(self, state): +        """ +        Controls whether vlan to tunnel mapping is enabled on the port. +        By default this flag is off. +        """ +        if not isinstance(state, bool): +            raise ValueError('Value out of range') + +        cur_vlan_ids = [] +        if 'vlan_to_vni_removed' in self.config: +            cur_vlan_ids = self.config['vlan_to_vni_removed'] +            for vlan in cur_vlan_ids: +                self._cmd(f'bridge vlan del dev {self.ifname} vid {vlan}') + +        # Determine current OS Kernel vlan_tunnel setting - only adjust when needed +        tmp = get_interface_config(self.ifname) +        cur_state = 'on' if dict_search(f'linkinfo.info_slave_data.vlan_tunnel', tmp) == True else 'off' +        new_state = 'on' if state else 'off' +        if cur_state != new_state: +            self.set_interface('vlan_tunnel', new_state) + +        # Determine current OS Kernel configured VLANs +        os_configured_vlan_ids = get_vxlan_vlan_tunnels(self.ifname) + +        if 'vlan_to_vni' in self.config: +            add_vlan = list_diff(list(self.config['vlan_to_vni'].keys()), os_configured_vlan_ids) + +            for vlan, vlan_config in self.config['vlan_to_vni'].items(): +                # VLAN mapping already exists - skip +                if vlan not in add_vlan: +                    continue + +                vni = vlan_config['vni'] +                # The following commands must be run one after another, +                # they can not be combined with linux 6.1 and iproute2 6.1 +                self._cmd(f'bridge vlan add dev {self.ifname} vid {vlan}') +                self._cmd(f'bridge vlan add dev {self.ifname} vid {vlan} tunnel_info id {vni}') + +    def update(self, config): +        """ General helper function which works on a dictionary retrived by +        get_config_dict(). It's main intention is to consolidate the scattered +        interface setup code and provide a single point of entry when workin +        on any interface. """ + +        # call base class last +        super().update(config) + +        # Enable/Disable VLAN tunnel mapping +        # This is only possible after the interface was assigned to the bridge +        self.set_vlan_vni_mapping(dict_search('vlan_to_vni', config) != None) diff --git a/python/vyos/utils/network.py b/python/vyos/utils/network.py index 55ff29f0c..4c579c760 100644 --- a/python/vyos/utils/network.py +++ b/python/vyos/utils/network.py @@ -408,7 +408,7 @@ def is_subnet_connected(subnet, primary=False):      return False -def is_afi_configured(interface, afi): +def is_afi_configured(interface: str, afi):      """ Check if given address family is configured, or in other words - an IP      address is assigned to the interface. """      from netifaces import ifaddresses @@ -425,3 +425,46 @@ def is_afi_configured(interface, afi):          return False      return afi in addresses + +def get_vxlan_vlan_tunnels(interface: str) -> list: +    """ Return a list of strings with VLAN IDs configured in the Kernel """ +    from json import loads +    from vyos.utils.process import cmd + +    if not interface.startswith('vxlan'): +        raise ValueError('Only applicable for VXLAN interfaces!') + +    # Determine current OS Kernel configured VLANs +    # +    # $ bridge -j -p vlan tunnelshow dev vxlan0 +    # [ { +    #         "ifname": "vxlan0", +    #         "tunnels": [ { +    #                 "vlan": 10, +    #                 "vlanEnd": 11, +    #                 "tunid": 10010, +    #                 "tunidEnd": 10011 +    #             },{ +    #                 "vlan": 20, +    #                 "tunid": 10020 +    #             } ] +    #     } ] +    # +    os_configured_vlan_ids = [] +    tmp = loads(cmd(f'bridge --json vlan tunnelshow dev {interface}')) +    if tmp: +        for tunnel in tmp[0].get('tunnels', {}): +            vlanStart = tunnel['vlan'] +            if 'vlanEnd' in tunnel: +                vlanEnd = tunnel['vlanEnd'] +                # Build a real list for user VLAN IDs +                vlan_list = list(range(vlanStart, vlanEnd +1)) +                # Convert list of integers to list or strings +                os_configured_vlan_ids.extend(map(str, vlan_list)) +                # Proceed with next tunnel - this one is complete +                continue + +            # Add single tunel id - not part of a range +            os_configured_vlan_ids.append(str(vlanStart)) + +    return os_configured_vlan_ids diff --git a/python/vyos/utils/process.py b/python/vyos/utils/process.py index c2ef98140..9ecdddf09 100644 --- a/python/vyos/utils/process.py +++ b/python/vyos/utils/process.py @@ -139,7 +139,7 @@ def cmd(command, flag='', shell=None, input=None, timeout=None, env=None,      expect:  a list of error codes to consider as normal      """      decoded, code = popen( -        command, flag, +        command.lstrip(), flag,          stdout=stdout, stderr=stderr,          input=input, timeout=timeout,          env=env, shell=shell, | 
