diff options
| -rw-r--r-- | python/vyos/ifconfig/bond.py | 18 | ||||
| -rw-r--r-- | python/vyos/ifconfig/bridge.py | 17 | ||||
| -rw-r--r-- | python/vyos/ifconfig/control.py | 4 | ||||
| -rw-r--r-- | python/vyos/ifconfig/dummy.py | 8 | ||||
| -rw-r--r-- | python/vyos/ifconfig/ethernet.py | 20 | ||||
| -rw-r--r-- | python/vyos/ifconfig/geneve.py | 9 | ||||
| -rw-r--r-- | python/vyos/ifconfig/interface.py | 8 | ||||
| -rw-r--r-- | python/vyos/ifconfig/l2tpv3.py | 14 | ||||
| -rw-r--r-- | python/vyos/ifconfig/loopback.py | 11 | ||||
| -rw-r--r-- | python/vyos/ifconfig/macvlan.py | 11 | ||||
| -rw-r--r-- | python/vyos/ifconfig/register.py | 96 | ||||
| -rw-r--r-- | python/vyos/ifconfig/tunnel.py | 8 | ||||
| -rw-r--r-- | python/vyos/ifconfig/vxlan.py | 24 | ||||
| -rw-r--r-- | python/vyos/ifconfig/wireguard.py | 14 | ||||
| -rw-r--r-- | python/vyos/ifconfig/wireless.py | 26 | ||||
| -rw-r--r-- | python/vyos/ifconfig_vlan.py | 2 | 
16 files changed, 260 insertions, 30 deletions
| diff --git a/python/vyos/ifconfig/bond.py b/python/vyos/ifconfig/bond.py index c9dac891f..af4082f8f 100644 --- a/python/vyos/ifconfig/bond.py +++ b/python/vyos/ifconfig/bond.py @@ -21,6 +21,7 @@ from vyos.ifconfig.vlan import VLANIf  from vyos.validate import * +@Interface.register  class BondIf(VLANIf):      """      The Linux bonding driver provides a method for aggregating multiple network @@ -30,6 +31,19 @@ class BondIf(VLANIf):      monitoring may be performed.      """ +    default = { +        'type': 'bond', +    } +    definition = { +        **Interface.definition, +        ** { +            'section': 'bonding', +            'prefixes': ['bond', ], +            'broadcast': True, +            'bridgeable': True, +        }, +    } +      _sysfs_set = {**VLANIf._sysfs_set, **{          'bond_hash_policy': {              'validate': lambda v: assert_list(v, ['layer2', 'layer2+3', 'layer3+4', 'encap2+3', 'encap3+4']), @@ -69,10 +83,6 @@ class BondIf(VLANIf):          }      }} -    default = { -        'type': 'bond', -    } -      def remove(self):          """          Remove interface from operating system. Removing the interface diff --git a/python/vyos/ifconfig/bridge.py b/python/vyos/ifconfig/bridge.py index 90c44af13..94b0075d8 100644 --- a/python/vyos/ifconfig/bridge.py +++ b/python/vyos/ifconfig/bridge.py @@ -18,6 +18,8 @@ from vyos.ifconfig.interface import Interface  from vyos.validate import * + +@Interface.register  class BridgeIf(Interface):      """      A bridge is a way to connect two Ethernet segments together in a protocol @@ -28,6 +30,18 @@ class BridgeIf(Interface):      The Linux bridge code implements a subset of the ANSI/IEEE 802.1d standard.      """ +    default = { +        'type': 'bridge', +    } +    definition = { +        **Interface.definition, +        **{ +            'section': 'bridge', +            'prefixes': ['br', ], +            'broadcast': True, +        }, +    } +      _sysfs_set = {**Interface._sysfs_set, **{          'ageing_time': {              'validate': assert_positive, @@ -72,9 +86,6 @@ class BridgeIf(Interface):          },      }} -    default = { -        'type': 'bridge', -    }      def set_ageing_time(self, time):          """ diff --git a/python/vyos/ifconfig/control.py b/python/vyos/ifconfig/control.py index 89deba40a..28adc80d1 100644 --- a/python/vyos/ifconfig/control.py +++ b/python/vyos/ifconfig/control.py @@ -17,8 +17,10 @@  import os  from subprocess import Popen, PIPE, STDOUT +from vyos.ifconfig.register import Register -class Control: + +class Control(Register):      _command_get = {}      _command_set = {} diff --git a/python/vyos/ifconfig/dummy.py b/python/vyos/ifconfig/dummy.py index 58b89fe68..404c490c7 100644 --- a/python/vyos/ifconfig/dummy.py +++ b/python/vyos/ifconfig/dummy.py @@ -17,6 +17,7 @@  from vyos.ifconfig.interface import Interface +@Interface.register  class DummyIf(Interface):      """      A dummy interface is entirely virtual like, for example, the loopback @@ -27,3 +28,10 @@ class DummyIf(Interface):      default = {          'type': 'dummy',      } +    definition = { +        **Interface.definition, +        **{ +            'section': 'dummy', +            'prefixes': ['dum', ], +        }, +    } diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py index 30e3a3bef..606161121 100644 --- a/python/vyos/ifconfig/ethernet.py +++ b/python/vyos/ifconfig/ethernet.py @@ -17,15 +17,31 @@ import os  import re  from vyos.ifconfig.vlan import VLANIf +from vyos.ifconfig.interface import Interface  from vyos.validate import * +@Interface.register  class EthernetIf(VLANIf):      """      Abstraction of a Linux Ethernet Interface      """ +    default = { +        'type': 'ethernet', +    } +    definition = { +        **Interface.definition, +        **{ +            'section': 'ethernet', +            'prefixes': ['lan', 'eth', 'eno', 'ens', 'enp', 'enx'], +            'bondable': True, +            'broadcast': True, +            'bridgeable': True, +        } +    } +      _command_set = {**VLANIf._command_set, **{          'gro': {              'validate': lambda v: assert_list(v, ['on', 'off']), @@ -49,10 +65,6 @@ class EthernetIf(VLANIf):          },      }} -    default = { -        'type': 'ethernet', -    } -      def _delete(self):          # Ethernet interfaces can not be removed          pass diff --git a/python/vyos/ifconfig/geneve.py b/python/vyos/ifconfig/geneve.py index a3b3a4c4a..f27786417 100644 --- a/python/vyos/ifconfig/geneve.py +++ b/python/vyos/ifconfig/geneve.py @@ -18,6 +18,7 @@ from copy import deepcopy  from vyos.ifconfig.interface import Interface +@Interface.register  class GeneveIf(Interface):      """      Geneve: Generic Network Virtualization Encapsulation @@ -34,6 +35,14 @@ class GeneveIf(Interface):          'vni': 0,          'remote': '',      } +    definition = { +        **Interface.definition, +        **{ +            'section': 'geneve', +            'prefixes': ['gnv', ], +            'bridgeable': True, +        } +    }      def _create(self):          cmd = 'ip link add name {ifname} type geneve id {vni} remote {remote}'.format(**self.config) diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index a1f8198c7..1759e3545 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -42,6 +42,14 @@ class Interface(DHCP):      default = {          'type': '',      } +    definition = { +        'section': '', +        'prefixes': [], +        'vlan': False, +        'bondable': False, +        'broadcast': False, +        'bridgeable':  False, +    }      _command_set = {          'state': { diff --git a/python/vyos/ifconfig/l2tpv3.py b/python/vyos/ifconfig/l2tpv3.py index a87535277..fbfab4c6e 100644 --- a/python/vyos/ifconfig/l2tpv3.py +++ b/python/vyos/ifconfig/l2tpv3.py @@ -19,6 +19,7 @@ import os  from vyos.ifconfig.interface import Interface +@Interface.register  class L2TPv3If(Interface):      """      The Linux bonding driver provides a method for aggregating multiple network @@ -28,12 +29,19 @@ class L2TPv3If(Interface):      monitoring may be performed.      """ -    options = Interface.options + \ -        ['tunnel_id', 'peer_tunnel_id', 'local_port', 'remote_port', -            'encapsulation', 'local_address', 'remote_address']      default = {          'type': 'l2tp',      } +    definition = { +        **Interface.definition, +        **{ +            'section': 'l2tpeth', +            'prefixes': ['l2tpeth', ], +            'bridgeable': True, +        } +    } +    options = Interface.options + \ +        ['tunnel_id', 'peer_tunnel_id', 'local_port', 'remote_port', 'encapsulation', 'local_address', 'remote_address']      def _create(self):          # create tunnel interface diff --git a/python/vyos/ifconfig/loopback.py b/python/vyos/ifconfig/loopback.py index 37b8e9e3b..8e4438662 100644 --- a/python/vyos/ifconfig/loopback.py +++ b/python/vyos/ifconfig/loopback.py @@ -17,6 +17,7 @@  from vyos.ifconfig.interface import Interface +@Interface.register  class LoopbackIf(Interface):      """      The loopback device is a special, virtual network interface that your router @@ -26,6 +27,16 @@ class LoopbackIf(Interface):      default = {          'type': 'loopback',      } +    definition = { +        **Interface.definition, +        **{ +            'section': 'loopback', +            'prefixes': ['lo', ], +            'bridgeable': True, +        } +    } + +    name = 'loopback'      def remove(self):          """ diff --git a/python/vyos/ifconfig/macvlan.py b/python/vyos/ifconfig/macvlan.py index da3beea8b..a1dca5e41 100644 --- a/python/vyos/ifconfig/macvlan.py +++ b/python/vyos/ifconfig/macvlan.py @@ -14,18 +14,27 @@  # License along with this library.  If not, see <http://www.gnu.org/licenses/>. +from vyos.ifconfig.interface import Interface  from vyos.ifconfig.vlan import VLANIf +@Interface.register  class MACVLANIf(VLANIf):      """      Abstraction of a Linux MACvlan interface      """ -    options = VLANIf.options + ['link', 'mode']      default = {          'type': 'macvlan',      } +    definition = { +        **Interface.definition, +        **{ +            'section': 'pseudo-ethernet', +            'prefixes': ['peth', ], +        }, +    } +    options = Interface.options + ['link', 'mode']      def _create(self):          cmd = 'ip link add {ifname} link {link} type macvlan mode {mode}'.format( diff --git a/python/vyos/ifconfig/register.py b/python/vyos/ifconfig/register.py new file mode 100644 index 000000000..2d4b0d4c0 --- /dev/null +++ b/python/vyos/ifconfig/register.py @@ -0,0 +1,96 @@ +# Copyright 2020 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 +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +# Lesser General Public License for more details. +# +# 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/>. + +import netifaces + + +class Register: +    # the known interface prefixes +    _prefixes = {} + +    # class need to define: definition['prefixes'] +    # the interface prefixes declared by a class used to name interface with +    # prefix[0-9]*(\.[0-9]+)?(\.[0-9]+)?, such as lo, eth0 or eth0.1.2 + +    @classmethod +    def register(cls, klass): +        if not klass.definition.get('prefixes',[]): +            raise RuntimeError(f'valid interface prefixes not defined for {klass.__name__}') + +        for ifprefix in klass.definition['prefixes']: +            if ifprefix in cls._prefixes: +                raise RuntimeError(f'only one class can be registered for prefix "{ifprefix}" type') +            cls._prefixes[ifprefix] = klass + +        return klass + +    @classmethod +    def _basename (cls, name, vlan): +        # remove number from interface name +        name = name.rstrip('0123456789') +        name = name.rstrip('.') +        if vlan: +            name = name.rstrip('0123456789') +        return name + +    @classmethod +    def section(cls, name, vlan=True): +        # return the name of a section an interface should be under +        name = cls._basename(name, vlan) + +        # XXX: To leave as long as vti and input are not moved to vyos +        if name == 'vti': +            return 'vti' +        if name == 'ifb': +            return 'input' + +        if name in cls._prefixes: +            return cls._prefixes[name].defintion['section'] +        return '' +  +    @classmethod +    def klass(cls, name, vlan=True): +        name = cls._basename(name, vlan) +        if name in cls._prefixes: +            return cls._prefixes[name] +        raise ValueError(f'No type found for interface name: {name}') + +    @classmethod +    def _listing (cls): +        interfaces = netifaces.interfaces() + +        for ifname in interfaces: +            if '@' in ifname: +                # Tunnels: sit0@NONE, gre0@NONE, gretap0@NONE, erspan0@NONE, tunl0@NONE, ip6tnl0@NONE, ip6gre0@NONE +                continue + +            # XXX: Temporary hack as vti and input are not yet moved from vyatta to vyos +            if ifname.startswith('vti') or ifname.startswith('input'): +                yield ifname +                continue + +            if not cls.section(ifname): +                continue +            yield ifname + +    @classmethod +    def listing(cls, section=''): +        if not section: +            return list(cls._listing()) +        return [_ for _ in cls._listing() if cls._basename(_,False) in self.prefixes] + + +# XXX: TODO - limit name for VRF interfaces + diff --git a/python/vyos/ifconfig/tunnel.py b/python/vyos/ifconfig/tunnel.py index c82727eee..a49bdd51c 100644 --- a/python/vyos/ifconfig/tunnel.py +++ b/python/vyos/ifconfig/tunnel.py @@ -38,6 +38,14 @@ class _Tunnel(Interface):      https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/ip/tunnel.c      https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/ip/ip6tunnel.c      """ +    definition = { +        **Interface.definition, +        **{ +            'section': 'tunnel', +            'prefixes': ['tun',], +            'bridgeable': True, +        }, +    }      # TODO: This is surely used for more than tunnels      # TODO: could be refactored elsewhere diff --git a/python/vyos/ifconfig/vxlan.py b/python/vyos/ifconfig/vxlan.py index 75cdf8957..5678ad62e 100644 --- a/python/vyos/ifconfig/vxlan.py +++ b/python/vyos/ifconfig/vxlan.py @@ -19,6 +19,7 @@ from vyos import ConfigError  from vyos.ifconfig.interface import Interface +@Interface.register  class VXLANIf(Interface):      """      The VXLAN protocol is a tunnelling protocol designed to solve the @@ -40,14 +41,6 @@ class VXLANIf(Interface):      https://www.kernel.org/doc/Documentation/networking/vxlan.txt      """ -    options = ['group', 'remote', 'dev', 'port', 'vni'] - -    mapping = { -        'ifname': 'add', -        'vni':    'id', -        'port':   'dstport', -    } -      default = {          'type': 'vxlan',          'vni': 0, @@ -57,6 +50,21 @@ class VXLANIf(Interface):          'port': 8472,   # The Linux implementation of VXLAN pre-dates                          # the IANA's selection of a standard destination port      } +    definition = { +        **Interface.definition, +        **{ +            'section': 'vxlan', +            'prefixes': ['vxlan', ], +            'bridgeable': True, +        } +    } +    options = ['group', 'remote', 'dev', 'port', 'vni'] + +    mapping = { +        'ifname': 'add', +        'vni':    'id', +        'port':   'dstport', +    }      def _create(self):          cmdline = set() diff --git a/python/vyos/ifconfig/wireguard.py b/python/vyos/ifconfig/wireguard.py index 71ee67c98..8cf1ff58c 100644 --- a/python/vyos/ifconfig/wireguard.py +++ b/python/vyos/ifconfig/wireguard.py @@ -22,10 +22,8 @@ from datetime import timedelta  import time  from hurry.filesize import size,alternative +@Interface.register  class WireGuardIf(Interface): -    options = ['port', 'private-key', 'pubkey', 'psk', -               'allowed-ips', 'fwmark', 'endpoint', 'keepalive'] -      default = {          'type': 'wireguard',          'port': 0, @@ -37,6 +35,16 @@ class WireGuardIf(Interface):          'endpoint': None,          'keepalive': 0      } +    definition = { +        **Interface.definition, +        **{ +            'section': 'wireguard', +            'prefixes': ['wg', ], +            'bridgeable': True, +        } +    } +    options = ['port', 'private-key', 'pubkey', 'psk', +               'allowed-ips', 'fwmark', 'endpoint', 'keepalive']      """      Wireguard interface class, contains a comnfig dictionary since diff --git a/python/vyos/ifconfig/wireless.py b/python/vyos/ifconfig/wireless.py index 7f507ff6e..f94509c80 100644 --- a/python/vyos/ifconfig/wireless.py +++ b/python/vyos/ifconfig/wireless.py @@ -15,19 +15,29 @@  import os +from vyos.ifconfig.interface import Interface  from vyos.ifconfig.vlan import VLANIf + +@Interface.register  class WiFiIf(VLANIf):      """      Handle WIFI/WLAN interfaces.      """ -    options = ['phy', 'op_mode'] -      default = {          'type': 'wifi',          'phy': 'phy0'      } +    definition = { +        **Interface.definition, +        **{ +            'section': 'wireless', +            'prefixes': ['wlan', ], +            'bridgeable': True, +        } +    } +    options = ['phy', 'op_mode']      def _create(self):          # all interfaces will be added in monitor mode @@ -54,3 +64,15 @@ class WiFiIf(VLANIf):              'phy': 'phy0'          }          return config + + + +@Interface.register +class WiFiModemIf(WiFiIf): +    definition = { +        **WiFiIf.definition, +        **{ +            'section': 'wirelessmodem', +            'prefixes': ['wlm', ], +        } +    } diff --git a/python/vyos/ifconfig_vlan.py b/python/vyos/ifconfig_vlan.py index fe94a5af4..245453307 100644 --- a/python/vyos/ifconfig_vlan.py +++ b/python/vyos/ifconfig_vlan.py @@ -23,7 +23,7 @@ def apply_vlan_config(vlan, config):      to a VLAN interface      """ -    if vlan.__class__ != VLANIf: +    if not vlan.definition['vlan']:          raise TypeError()      # get DHCP config dictionary and update values | 
