diff options
Diffstat (limited to 'python/vyos/ifconfig')
-rw-r--r-- | python/vyos/ifconfig/dhcp.py | 129 | ||||
-rw-r--r-- | python/vyos/ifconfig/ethernet.py | 5 | ||||
-rw-r--r-- | python/vyos/ifconfig/geneve.py | 2 | ||||
-rw-r--r-- | python/vyos/ifconfig/interface.py | 166 | ||||
-rw-r--r-- | python/vyos/ifconfig/macvlan.py | 47 | ||||
-rw-r--r-- | python/vyos/ifconfig/tunnel.py | 36 | ||||
-rw-r--r-- | python/vyos/ifconfig/vlan.py | 40 | ||||
-rw-r--r-- | python/vyos/ifconfig/vrrp.py | 2 | ||||
-rw-r--r-- | python/vyos/ifconfig/vxlan.py | 3 | ||||
-rw-r--r-- | python/vyos/ifconfig/wireguard.py | 5 | ||||
-rw-r--r-- | python/vyos/ifconfig/wireless.py | 3 |
11 files changed, 206 insertions, 232 deletions
diff --git a/python/vyos/ifconfig/dhcp.py b/python/vyos/ifconfig/dhcp.py index d4ff9c2cd..bf6566c07 100644 --- a/python/vyos/ifconfig/dhcp.py +++ b/python/vyos/ifconfig/dhcp.py @@ -19,28 +19,20 @@ from vyos.dicts import FixedDict from vyos.ifconfig.control import Control from vyos.template import render +config_base = r'/var/lib/dhcp/dhclient_' -class _DHCP (Control): - client_base = r'/var/lib/dhcp/dhclient_' - - def __init__(self, ifname, version, **kargs): - super().__init__(**kargs) - self.version = version - self.file = { - 'ifname': ifname, - 'conf': self.client_base + ifname + '.' + version + 'conf', - 'pid': self.client_base + ifname + '.' + version + 'pid', - 'lease': self.client_base + ifname + '.' + version + 'leases', - } - -class _DHCPv4 (_DHCP): +class _DHCPv4 (Control): def __init__(self, ifname): - super().__init__(ifname, '') + super().__init__() self.options = FixedDict(**{ 'ifname': ifname, 'hostname': '', 'client_id': '', - 'vendor_class_id': '' + 'vendor_class_id': '', + 'conf_file': config_base + f'{ifname}.conf', + 'options_file': config_base + f'{ifname}.options', + 'pid_file': config_base + f'{ifname}.pid', + 'lease_file': config_base + f'{ifname}.leases', }) # replace dhcpv4/v6 with systemd.networkd? @@ -55,25 +47,16 @@ class _DHCPv4 (_DHCP): >>> j = Interface('eth0') >>> j.dhcp.v4.set() """ - if not self.options['hostname']: # read configured system hostname. # maybe change to vyos hostd client ??? with open('/etc/hostname', 'r') as f: self.options['hostname'] = f.read().rstrip('\n') - render(self.file['conf'], 'dhcp-client/ipv4.tmpl' ,self.options) + render(self.options['options_file'], 'dhcp-client/daemon-options.tmpl', self.options) + render(self.options['conf_file'], 'dhcp-client/ipv4.tmpl', self.options) - cmd = 'start-stop-daemon' - cmd += ' --start' - cmd += ' --oknodo' - cmd += ' --quiet' - cmd += ' --pidfile {pid}' - cmd += ' --exec /sbin/dhclient' - cmd += ' --' - # now pass arguments to dhclient binary - cmd += ' -4 -nw -cf {conf} -pf {pid} -lf {lease} {ifname}' - return self._cmd(cmd.format(**self.file)) + return self._cmd('systemctl restart dhclient@{ifname}.service'.format(**self.options)) def delete(self): """ @@ -86,44 +69,29 @@ class _DHCPv4 (_DHCP): >>> j = Interface('eth0') >>> j.dhcp.v4.delete() """ - if not os.path.isfile(self.file['pid']): + if not os.path.isfile(self.options['pid_file']): self._debug_msg('No DHCP client PID found') return None - # with open(self.file['pid'], 'r') as f: - # pid = int(f.read()) - - # stop dhclient, we need to call dhclient and tell it should release the - # aquired IP address. tcpdump tells me: - # 172.16.35.103.68 > 172.16.35.254.67: [bad udp cksum 0xa0cb -> 0xb943!] BOOTP/DHCP, Request from 00:50:56:9d:11:df, length 300, xid 0x620e6946, Flags [none] (0x0000) - # Client-IP 172.16.35.103 - # Client-Ethernet-Address 00:50:56:9d:11:df - # Vendor-rfc1048 Extensions - # Magic Cookie 0x63825363 - # DHCP-Message Option 53, length 1: Release - # Server-ID Option 54, length 4: 172.16.35.254 - # Hostname Option 12, length 10: "vyos" - # - cmd = '/sbin/dhclient -cf {conf} -pf {pid} -lf {lease} -r {ifname}' - self._cmd(cmd.format(**self.file)) + self._cmd('systemctl stop dhclient@{ifname}.service'.format(**self.options)) # cleanup old config files - for name in ('conf', 'pid', 'lease'): - if os.path.isfile(self.file[name]): - os.remove(self.file[name]) + for name in ('conf_file', 'options_file', 'pid_file', 'lease_file'): + if os.path.isfile(self.options[name]): + os.remove(self.options[name]) - -class _DHCPv6 (_DHCP): +class _DHCPv6 (Control): def __init__(self, ifname): - super().__init__(ifname, 'v6') + super().__init__() self.options = FixedDict(**{ 'ifname': ifname, + 'conf_file': config_base + f'v6_{ifname}.conf', + 'options_file': config_base + f'v6_{ifname}.options', + 'pid_file': config_base + f'v6_{ifname}.pid', + 'lease_file': config_base + f'v6_{ifname}.leases', 'dhcpv6_prm_only': False, 'dhcpv6_temporary': False, }) - self.file.update({ - 'accept_ra': f'/proc/sys/net/ipv6/conf/{ifname}/accept_ra', - }) def set(self): """ @@ -134,7 +102,7 @@ class _DHCPv6 (_DHCP): >>> from vyos.ifconfig import Interface >>> j = Interface('eth0') - >>> j.set_dhcpv6() + >>> j.dhcp.v6.set() """ # better save then sorry .. should be checked in interface script @@ -143,29 +111,13 @@ class _DHCPv6 (_DHCP): raise Exception( 'DHCPv6 temporary and parameters-only options are mutually exclusive!') - render(self.file['conf'], 'dhcp-client/ipv6.tmpl', self.options) + render(self.options['options_file'], 'dhcp-client/daemon-options.tmpl', self.options) + render(self.options['conf_file'], 'dhcp-client/ipv6.tmpl', self.options) # no longer accept router announcements on this interface - self._write_sysfs(self.file['accept_ra'], 0) - - # assemble command-line to start DHCPv6 client (dhclient) - cmd = 'start-stop-daemon' - cmd += ' --start' - cmd += ' --oknodo' - cmd += ' --quiet' - cmd += ' --pidfile {pid}' - cmd += ' --exec /sbin/dhclient' - cmd += ' --' - # now pass arguments to dhclient binary - cmd += ' -6 -nw -cf {conf} -pf {pid} -lf {lease}' - # add optional arguments - if self.options['dhcpv6_prm_only']: - cmd += ' -S' - if self.options['dhcpv6_temporary']: - cmd += ' -T' - cmd += ' {ifname}' - - return self._cmd(cmd.format(**self.file)) + self._write_sysfs('/proc/sys/net/ipv6/conf/{ifname}/accept_ra'.format(**self.options), 0) + + return self._cmd('systemctl restart dhclient6@{ifname}.service'.format(**self.options)) def delete(self): """ @@ -176,33 +128,24 @@ class _DHCPv6 (_DHCP): >>> from vyos.ifconfig import Interface >>> j = Interface('eth0') - >>> j.del_dhcpv6() + >>> j.dhcp.v6.delete() """ - if not os.path.isfile(self.file['pid']): + if not os.path.isfile(self.options['pid_file']): self._debug_msg('No DHCPv6 client PID found') return None - # with open(self.file['pid'], 'r') as f: - # pid = int(f.read()) - - # stop dhclient - cmd = 'start-stop-daemon' - cmd += ' --start' - cmd += ' --oknodo' - cmd += ' --quiet' - cmd += ' --pidfile {pid}' - self._cmd(cmd.format(**self.file)) + self._cmd('systemctl stop dhclient6@{ifname}.service'.format(**self.options)) # accept router announcements on this interface - self._write_sysfs(self.options['accept_ra'], 1) + self._write_sysfs('/proc/sys/net/ipv6/conf/{ifname}/accept_ra'.format(**self.options), 1) # cleanup old config files - for name in ('conf', 'pid', 'lease'): - if os.path.isfile(self.file[name]): - os.remove(self.file[name]) + for name in ('conf_file', 'options_file', 'pid_file', 'lease_file'): + if os.path.isfile(self.options[name]): + os.remove(self.options[name]) -class DHCP (object): +class DHCP(object): def __init__(self, ifname): self.v4 = _DHCPv4(ifname) self.v6 = _DHCPv6(ifname) diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py index 542de4f59..5b18926c9 100644 --- a/python/vyos/ifconfig/ethernet.py +++ b/python/vyos/ifconfig/ethernet.py @@ -40,6 +40,7 @@ class EthernetIf(Interface): 'bondable': True, 'broadcast': True, 'bridgeable': True, + 'eternal': '(lan|eth|eno|ens|enp|enx)[0-9]+$', } } @@ -76,10 +77,6 @@ class EthernetIf(Interface): }, }} - def _delete(self): - # Ethernet interfaces can not be removed - pass - def get_driver_name(self): """ Return the driver name used by NIC. Some NICs don't support all diff --git a/python/vyos/ifconfig/geneve.py b/python/vyos/ifconfig/geneve.py index 0c1cdade9..145dc268c 100644 --- a/python/vyos/ifconfig/geneve.py +++ b/python/vyos/ifconfig/geneve.py @@ -35,6 +35,8 @@ class GeneveIf(Interface): 'vni': 0, 'remote': '', } + options = Interface.options + \ + ['vni', 'remote'] definition = { **Interface.definition, **{ diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 32ce1a80c..de5ca369f 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -1,4 +1,4 @@ -# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2019-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 @@ -14,6 +14,7 @@ # License along with this library. If not, see <http://www.gnu.org/licenses/>. import os +import re import json from copy import deepcopy @@ -49,7 +50,7 @@ class Interface(Control): # WireGuard to modify their display behaviour OperationalClass = Operational - options = [] + options = ['debug', 'create',] required = [] default = { 'type': '', @@ -63,6 +64,7 @@ class Interface(Control): 'bondable': False, 'broadcast': False, 'bridgeable': False, + 'eternal': '', } _command_get = { @@ -217,7 +219,7 @@ class Interface(Control): else: raise Exception('interface "{}" not found'.format(self.config['ifname'])) - # list of assigned IP addresses + # temporary list of assigned IP addresses self._addr = [] self.operational = self.OperationalClass(ifname) @@ -238,39 +240,21 @@ class Interface(Control): >>> i = Interface('eth0') >>> i.remove() """ - # stop DHCP(v6) if running - self.dhcp.v4.delete() - self.dhcp.v6.delete() # remove all assigned IP addresses from interface - this is a bit redundant # as the kernel will remove all addresses on interface deletion, but we # can not delete ALL interfaces, see below - for addr in self.get_addr(): - self.del_addr(addr) + self.flush_addrs() # --------------------------------------------------------------------- - # A code refactoring is required as this type check is present as - # Interface implement behaviour for one of it's sub-class. - - # It is required as the current pattern for vlan is: - # Interface('name').remove() to delete an interface - # The code should be modified to have a class method called connect and - # have Interface.connect('name').remove() + # Any class can define an eternal regex in its definition + # interface matching the regex will not be deleted - # each subclass should register within Interface the pattern for that - # interface ie: (ethX, etc.) and use this to create an instance of - # the right class (EthernetIf, ...) - - # Ethernet interfaces can not be removed - - # Commented out as nowhere in the code do we call Interface() - # This would also cause an import loop - # if self.__class__ == EthernetIf: - # return - - # --------------------------------------------------------------------- - - self._delete() + eternal = self.definition['eternal'] + if not eternal: + self._delete() + elif not re.match(eternal, self.ifname): + self._delete() def _delete(self): # NOTE (Improvement): @@ -431,39 +415,28 @@ class Interface(Control): """ return self.set_interface('ipv6_autoconf', autoconf) - def set_ipv6_eui64_address(self, prefix): + def add_ipv6_eui64_address(self, prefix): """ Extended Unique Identifier (EUI), as per RFC2373, allows a host to - assign iteslf a unique IPv6 address based on a given IPv6 prefix. + assign itself a unique IPv6 address based on a given IPv6 prefix. - If prefix is passed address is assigned, if prefix is '' address is - removed from interface. + Calculate the EUI64 from the interface's MAC, then assign it + with the given prefix to the interface. """ - # if prefix is an empty string convert it to None so mac2eui64 works - # as expected - if not prefix: - prefix = None eui64 = mac2eui64(self.get_mac(), prefix) + prefixlen = prefix.split('/')[1] + self.add_addr(f'{eui64}/{prefixlen}') - if not prefix: - # if prefix is empty - thus removed - we need to walk through all - # interface IPv6 addresses and find the one with the calculated - # EUI-64 identifier. The address is then removed - for addr in self.get_addr(): - addr_wo_prefix = addr.split('/')[0] - if is_ipv6(addr_wo_prefix): - if eui64 in IPv6Address(addr_wo_prefix).exploded: - self.del_addr(addr) - - return None + def del_ipv6_eui64_address(self, prefix): + """ + Delete the address based on the interface's MAC-based EUI64 + combined with the prefix address. + """ + eui64 = mac2eui64(self.get_mac(), prefix) + prefixlen = prefix.split('/')[1] + self.del_addr(f'{eui64}/{prefixlen}') - # calculate and add EUI-64 IPv6 address - if IPv6Network(prefix): - # we also need to take the subnet length into account - prefix = prefix.split('/')[1] - eui64 = f'{eui64}/{prefix}' - self.add_addr(eui64 ) def set_ipv6_forwarding(self, forwarding): """ @@ -644,7 +617,8 @@ class Interface(Control): def add_addr(self, addr): """ Add IP(v6) address to interface. Address is only added if it is not - already assigned to that interface. + already assigned to that interface. Address format must be validated + and compressed/normalized before calling this function. addr: can be an IPv4 address, IPv6 address, dhcp or dhcpv6! IPv4: add IPv4 address to interface @@ -652,6 +626,7 @@ class Interface(Control): dhcp: start dhclient (IPv4) on interface dhcpv6: start dhclient (IPv6) on interface + Returns False if address is already assigned and wasn't re-added. Example: >>> from vyos.ifconfig import Interface >>> j = Interface('eth0') @@ -660,32 +635,44 @@ class Interface(Control): >>> j.get_addr() ['192.0.2.1/24', '2001:db8::ffff/64'] """ + # XXX: normalize/compress with ipaddress if calling functions don't? + # is subnet mask always passed, and in the same way? - # cache new IP address which is assigned to interface - self._addr.append(addr) + # we can't have both DHCP and static IPv4 addresses assigned + for a in self._addr: + if ( ( addr == 'dhcp' and a != 'dhcpv6' and is_ipv4(a) ) or + ( a == 'dhcp' and addr != 'dhcpv6' and is_ipv4(addr) ) ): + raise ConfigError(( + "Can't configure both static IPv4 and DHCP address " + "on the same interface")) - # we can not have both DHCP and static IPv4 addresses assigned to an interface - if 'dhcp' in self._addr: - for addr in self._addr: - # do not change below 'if' ordering esle you will get an exception as: - # ValueError: 'dhcp' does not appear to be an IPv4 or IPv6 address - if addr != 'dhcp' and is_ipv4(addr): - raise ConfigError( - "Can't configure both static IPv4 and DHCP address on the same interface") + # do not add same address twice + if addr in self._addr: + return False + # add to interface if addr == 'dhcp': + self._addr.append(addr) self.dhcp.v4.set() - elif addr == 'dhcpv6': + return True + + if addr == 'dhcpv6': + self._addr.append(addr) self.dhcp.v6.set() - else: - if not is_intf_addr_assigned(self.config['ifname'], addr): - cmd = 'ip addr add "{}" dev "{}"'.format(addr, self.config['ifname']) - return self._cmd(cmd) + return True + + if not is_intf_addr_assigned(self.ifname, addr): + self._addr.append(addr) + self._cmd(f'ip addr add "{addr}" dev "{self.ifname}"') + return True + + return False def del_addr(self, addr): """ - Delete IP(v6) address to interface. Address is only added if it is - assigned to that interface. + Delete IP(v6) address from interface. Address is only deleted if it is + assigned to that interface. Address format must be exactly the same as + was used when adding the address. addr: can be an IPv4 address, IPv6 address, dhcp or dhcpv6! IPv4: delete IPv4 address from interface @@ -693,6 +680,7 @@ class Interface(Control): dhcp: stop dhclient (IPv4) on interface dhcpv6: stop dhclient (IPv6) on interface + Returns False if address isn't already assigned and wasn't deleted. Example: >>> from vyos.ifconfig import Interface >>> j = Interface('eth0') @@ -704,11 +692,35 @@ class Interface(Control): >>> j.get_addr() ['2001:db8::ffff/64'] """ + + # remove from cache (dhcp, and dhcpv6 can not be in it) + if addr in self._addr: + self._addr.remove(addr) + + # remove from interface if addr == 'dhcp': self.dhcp.v4.delete() - elif addr == 'dhcpv6': + return True + + if addr == 'dhcpv6': self.dhcp.v6.delete() - else: - if is_intf_addr_assigned(self.config['ifname'], addr): - cmd = 'ip addr del "{}" dev "{}"'.format(addr, self.config['ifname']) - return self._cmd(cmd) + return True + + if is_intf_addr_assigned(self.ifname, addr): + self._cmd(f'ip addr del "{addr}" dev "{self.ifname}"') + return True + + return False + + def flush_addrs(self): + """ + Flush all addresses from an interface, including DHCP. + + Will raise an exception on error. + """ + # stop DHCP(v6) if running + self.dhcp.v4.delete() + self.dhcp.v6.delete() + + # flush all addresses + self._cmd(f'ip addr flush dev "{self.ifname}"') diff --git a/python/vyos/ifconfig/macvlan.py b/python/vyos/ifconfig/macvlan.py index 55b1a3e91..b5481f4a7 100644 --- a/python/vyos/ifconfig/macvlan.py +++ b/python/vyos/ifconfig/macvlan.py @@ -13,6 +13,7 @@ # 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 copy import deepcopy from vyos.ifconfig.interface import Interface from vyos.ifconfig.vlan import VLAN @@ -27,6 +28,9 @@ class MACVLANIf(Interface): default = { 'type': 'macvlan', + 'address': '', + 'source_interface': '', + 'mode': '', } definition = { **Interface.definition, @@ -35,33 +39,32 @@ class MACVLANIf(Interface): 'prefixes': ['peth', ], }, } - options = Interface.options + ['source_interface', 'mode'] + options = Interface.options + \ + ['source_interface', 'mode'] def _create(self): - cmd = 'ip link add {ifname} link {source_interface} type macvlan mode {mode}'.format( - **self.config) - self._cmd(cmd) + # please do not change the order when assembling the command + cmd = 'ip link add {ifname}' + if self.config['source_interface']: + cmd += ' link {source_interface}' + cmd += ' type macvlan' + if self.config['mode']: + cmd += ' mode {mode}' + self._cmd(cmd.format(**self.config)) - @staticmethod - def get_config(): + def set_mode(self, mode): + ifname = self.config['ifname'] + cmd = f'ip link set dev {ifname} type macvlan mode {mode}' + return self._cmd(cmd) + + @classmethod + def get_config(cls): """ - VXLAN interfaces require a configuration when they are added using - iproute2. This static method will provide the configuration dictionary - used by this class. + MACVLAN interfaces require a configuration when they are added using + iproute2. This method will provide the configuration dictionary used + by this class. Example: >> dict = MACVLANIf().get_config() """ - config = { - 'address': '', - 'source_interface': '', - 'mode': '' - } - return config - - def set_mode(self, mode): - """ - """ - ifname = self.config['ifname'] - cmd = f'ip link set dev {ifname} type macvlan mode {mode}' - return self._cmd(cmd) + return deepcopy(cls.default) diff --git a/python/vyos/ifconfig/tunnel.py b/python/vyos/ifconfig/tunnel.py index 009a53a82..85c22b5b4 100644 --- a/python/vyos/ifconfig/tunnel.py +++ b/python/vyos/ifconfig/tunnel.py @@ -43,7 +43,7 @@ class _Tunnel(Interface): **{ 'section': 'tunnel', 'prefixes': ['tun',], - 'bridgeable': True, + 'bridgeable': False, }, } @@ -135,14 +135,21 @@ class GREIf(_Tunnel): https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/ip/link_gre.c """ + definition = { + **_Tunnel.definition, + **{ + 'bridgeable': True, + }, + } + ip = [IP4, IP6] tunnel = IP4 default = {'type': 'gre'} required = ['local', ] # mGRE is a GRE without remote endpoint - options = ['local', 'remote', 'ttl', 'tos', 'key'] - updates = ['local', 'remote', 'ttl', 'tos', + options = ['local', 'remote', 'dev', 'ttl', 'tos', 'key'] + updates = ['local', 'remote', 'dev', 'ttl', 'tos', 'mtu', 'multicast', 'allmulticast'] create = 'ip tunnel add {ifname} mode {type}' @@ -160,6 +167,13 @@ class GRETapIf(_Tunnel): # no multicast, ttl or tos for gretap + definition = { + **_Tunnel.definition, + **{ + 'bridgeable': True, + }, + } + ip = [IP4, ] tunnel = IP4 @@ -189,9 +203,9 @@ class IP6GREIf(_Tunnel): default = {'type': 'ip6gre'} required = ['local', 'remote'] - options = ['local', 'remote', 'encaplimit', + options = ['local', 'remote', 'dev', 'encaplimit', 'hoplimit', 'tclass', 'flowlabel'] - updates = ['local', 'remote', 'encaplimit', + updates = ['local', 'remote', 'dev', 'encaplimit', 'hoplimit', 'tclass', 'flowlabel', 'mtu', 'multicast', 'allmulticast'] @@ -225,8 +239,8 @@ class IPIPIf(_Tunnel): default = {'type': 'ipip'} required = ['local', 'remote'] - options = ['local', 'remote', 'ttl', 'tos', 'key'] - updates = ['local', 'remote', 'ttl', 'tos', + options = ['local', 'remote', 'dev', 'ttl', 'tos', 'key'] + updates = ['local', 'remote', 'dev', 'ttl', 'tos', 'mtu', 'multicast', 'allmulticast'] create = 'ip tunnel add {ifname} mode {type}' @@ -248,9 +262,9 @@ class IPIP6If(_Tunnel): default = {'type': 'ipip6'} required = ['local', 'remote'] - options = ['local', 'remote', 'encaplimit', + options = ['local', 'remote', 'dev', 'encaplimit', 'hoplimit', 'tclass', 'flowlabel'] - updates = ['local', 'remote', 'encaplimit', + updates = ['local', 'remote', 'dev', 'encaplimit', 'hoplimit', 'tclass', 'flowlabel', 'mtu', 'multicast', 'allmulticast'] @@ -286,8 +300,8 @@ class SitIf(_Tunnel): default = {'type': 'sit'} required = ['local', 'remote'] - options = ['local', 'remote', 'ttl', 'tos', 'key'] - updates = ['local', 'remote', 'ttl', 'tos', + options = ['local', 'remote', 'dev', 'ttl', 'tos', 'key'] + updates = ['local', 'remote', 'dev', 'ttl', 'tos', 'mtu', 'multicast', 'allmulticast'] create = 'ip tunnel add {ifname} mode {type}' diff --git a/python/vyos/ifconfig/vlan.py b/python/vyos/ifconfig/vlan.py index 7b1e00d87..d68e8f6cd 100644 --- a/python/vyos/ifconfig/vlan.py +++ b/python/vyos/ifconfig/vlan.py @@ -101,26 +101,26 @@ class VLAN: >>> i.add_vlan(10) """ vlan_ifname = self.config['ifname'] + '.' + str(vlan_id) - if not os.path.exists(f'/sys/class/net/{vlan_ifname}'): - self._vlan_id = int(vlan_id) - - if ethertype: - self._ethertype = ethertype - ethertype = 'proto {}'.format(ethertype) - - # Optional ingress QOS mapping - opt_i = '' - if ingress_qos: - opt_i = 'ingress-qos-map ' + ingress_qos - # Optional egress QOS mapping - opt_e = '' - if egress_qos: - opt_e = 'egress-qos-map ' + egress_qos - - # create interface in the system - cmd = 'ip link add link {ifname} name {ifname}.{vlan} type vlan {proto} id {vlan} {opt_e} {opt_i}' \ - .format(ifname=self.config['ifname'], vlan=self._vlan_id, proto=ethertype, opt_e=opt_e, opt_i=opt_i) - self._cmd(cmd) + if os.path.exists(f'/sys/class/net/{vlan_ifname}'): + return self.__class__(vlan_ifname) + + if ethertype: + self._ethertype = ethertype + ethertype = 'proto {}'.format(ethertype) + + # Optional ingress QOS mapping + opt_i = '' + if ingress_qos: + opt_i = 'ingress-qos-map ' + ingress_qos + # Optional egress QOS mapping + opt_e = '' + if egress_qos: + opt_e = 'egress-qos-map ' + egress_qos + + # create interface in the system + cmd = 'ip link add link {ifname} name {ifname}.{vlan} type vlan {proto} id {vlan} {opt_e} {opt_i}' \ + .format(ifname=self.ifname, vlan=vlan_id, proto=ethertype, opt_e=opt_e, opt_i=opt_i) + self._cmd(cmd) # return new object mapping to the newly created interface # we can now work on this object for e.g. IP address setting diff --git a/python/vyos/ifconfig/vrrp.py b/python/vyos/ifconfig/vrrp.py index 29b10dd9e..a872725b2 100644 --- a/python/vyos/ifconfig/vrrp.py +++ b/python/vyos/ifconfig/vrrp.py @@ -109,7 +109,7 @@ class VRRP(object): return [] disabled = [] - config = json.loads(util.readfile(cls.location['vyos'])) + config = json.loads(util.read_file(cls.location['vyos'])) # add disabled groups to the list for group in config['vrrp_groups']: diff --git a/python/vyos/ifconfig/vxlan.py b/python/vyos/ifconfig/vxlan.py index f47ae17cc..f9f2e38e9 100644 --- a/python/vyos/ifconfig/vxlan.py +++ b/python/vyos/ifconfig/vxlan.py @@ -59,7 +59,8 @@ class VXLANIf(Interface): 'bridgeable': True, } } - options = ['group', 'remote', 'src_interface', 'port', 'vni', 'src_address'] + options = Interface.options + \ + ['group', 'remote', 'src_interface', 'port', 'vni', 'src_address'] mapping = { 'ifname': 'add', diff --git a/python/vyos/ifconfig/wireguard.py b/python/vyos/ifconfig/wireguard.py index ff945c9d0..fdf5d9347 100644 --- a/python/vyos/ifconfig/wireguard.py +++ b/python/vyos/ifconfig/wireguard.py @@ -165,8 +165,9 @@ class WireGuardIf(Interface): 'bridgeable': True, } } - options = ['port', 'private-key', 'pubkey', 'psk', - 'allowed-ips', 'fwmark', 'endpoint', 'keepalive'] + options = Interface.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 946ae1642..3122ac0a3 100644 --- a/python/vyos/ifconfig/wireless.py +++ b/python/vyos/ifconfig/wireless.py @@ -38,7 +38,8 @@ class WiFiIf(Interface): 'bridgeable': True, } } - options = ['phy', 'op_mode'] + options = Interface.options + \ + ['phy', 'op_mode'] def _create(self): # all interfaces will be added in monitor mode |