summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorMarcus Hoff <marcus.hoff@ring2.dk>2020-09-20 11:59:32 +0200
committerMarcus Hoff <marcus.hoff@ring2.dk>2020-09-20 11:59:32 +0200
commit45b30adfaaec7065f768d04085138a75a76ed376 (patch)
treea9cd47236468077141eee56068ba23027b0d4c7d /python
parent46fb580fa0131f6815bbcfc95631654f6fe999a8 (diff)
parente0797331774a02ca23e8363fbcfe5a49fb3ca2bd (diff)
downloadvyos-1x-45b30adfaaec7065f768d04085138a75a76ed376.tar.gz
vyos-1x-45b30adfaaec7065f768d04085138a75a76ed376.zip
Merge remote-tracking branch 'upstream/current' into current
Diffstat (limited to 'python')
-rw-r--r--python/vyos/configdict.py6
-rw-r--r--python/vyos/ifconfig/bond.py56
-rw-r--r--python/vyos/ifconfig/control.py6
-rw-r--r--python/vyos/ifconfig/dummy.py2
-rw-r--r--python/vyos/ifconfig/ethernet.py23
-rw-r--r--python/vyos/ifconfig/geneve.py2
-rw-r--r--python/vyos/ifconfig/input.py2
-rw-r--r--python/vyos/ifconfig/interface.py200
-rw-r--r--python/vyos/ifconfig/l2tpv3.py3
-rw-r--r--python/vyos/ifconfig/loopback.py2
-rw-r--r--python/vyos/ifconfig/macvlan.py4
-rw-r--r--python/vyos/ifconfig/operational.py5
-rw-r--r--python/vyos/ifconfig/tunnel.py1
-rw-r--r--python/vyos/ifconfig/vlan.py142
-rw-r--r--python/vyos/ifconfig/vrrp.py4
-rw-r--r--python/vyos/ifconfig/vti.py2
-rw-r--r--python/vyos/ifconfig/vtun.py2
-rw-r--r--python/vyos/ifconfig/vxlan.py1
-rw-r--r--python/vyos/ifconfig/wireguard.py2
-rw-r--r--python/vyos/ifconfig/wireless.py18
-rw-r--r--python/vyos/util.py1
21 files changed, 241 insertions, 243 deletions
diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py
index e8c0aa5b3..bfc70b772 100644
--- a/python/vyos/configdict.py
+++ b/python/vyos/configdict.py
@@ -148,8 +148,8 @@ def T2665_default_dict_cleanup(dict):
def leaf_node_changed(conf, path):
"""
Check if a leaf node was altered. If it has been altered - values has been
- changed, or it was added/removed, we will return the old value. If nothing
- has been changed, None is returned
+ changed, or it was added/removed, we will return a list containing the old
+ value(s). If nothing has been changed, None is returned
"""
from vyos.configdiff import get_config_diff
D = get_config_diff(conf, key_mangling=('-', '_'))
@@ -157,7 +157,7 @@ def leaf_node_changed(conf, path):
(new, old) = D.get_value_diff(path)
if new != old:
if isinstance(old, str):
- return old
+ return [old]
elif isinstance(old, list):
if isinstance(new, str):
new = [new]
diff --git a/python/vyos/ifconfig/bond.py b/python/vyos/ifconfig/bond.py
index 64407401b..9108fc180 100644
--- a/python/vyos/ifconfig/bond.py
+++ b/python/vyos/ifconfig/bond.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
@@ -16,15 +16,12 @@
import os
from vyos.ifconfig.interface import Interface
-from vyos.ifconfig.vlan import VLAN
-
from vyos.util import cmd
from vyos.util import vyos_dict_search
from vyos.validate import assert_list
from vyos.validate import assert_positive
@Interface.register
-@VLAN.enable
class BondIf(Interface):
"""
The Linux bonding driver provides a method for aggregating multiple network
@@ -52,6 +49,10 @@ class BondIf(Interface):
'validate': lambda v: assert_list(v, ['layer2', 'layer2+3', 'layer3+4', 'encap2+3', 'encap3+4']),
'location': '/sys/class/net/{ifname}/bonding/xmit_hash_policy',
},
+ 'bond_min_links': {
+ 'validate': assert_positive,
+ 'location': '/sys/class/net/{ifname}/bonding/min_links',
+ },
'bond_miimon': {
'validate': assert_positive,
'location': '/sys/class/net/{ifname}/bonding/miimon'
@@ -130,6 +131,29 @@ class BondIf(Interface):
"""
self.set_interface('bond_hash_policy', mode)
+ def set_min_links(self, number):
+ """
+ Specifies the minimum number of links that must be active before
+ asserting carrier. It is similar to the Cisco EtherChannel min-links
+ feature. This allows setting the minimum number of member ports that
+ must be up (link-up state) before marking the bond device as up
+ (carrier on). This is useful for situations where higher level services
+ such as clustering want to ensure a minimum number of low bandwidth
+ links are active before switchover. This option only affect 802.3ad
+ mode.
+
+ The default value is 0. This will cause carrier to be asserted (for
+ 802.3ad mode) whenever there is an active aggregator, regardless of the
+ number of available links in that aggregator. Note that, because an
+ aggregator cannot be active without at least one available link,
+ setting this option to 0 or to 1 has the exact same effect.
+
+ Example:
+ >>> from vyos.ifconfig import BondIf
+ >>> BondIf('bond0').set_min_links('0')
+ """
+ self.set_interface('bond_min_links', number)
+
def set_arp_interval(self, interval):
"""
Specifies the ARP link monitoring frequency in milliseconds.
@@ -347,12 +371,21 @@ class BondIf(Interface):
value = config.get('hash_policy')
if value: self.set_hash_policy(value)
+ # Minimum number of member interfaces
+ value = config.get('min_links')
+ if value: self.set_min_links(value)
+
# Some interface options can only be changed if the interface is
# administratively down
if self.get_admin_state() == 'down':
- # Delete bond member port(s)
+ # Remove ALL bond member interfaces
for interface in self.get_slaves():
self.del_port(interface)
+ # Removing an interface from a bond will always place the underlaying
+ # physical interface in admin-down state! If physical interface is
+ # not disabled, re-enable it.
+ if not vyos_dict_search(f'member.interface_remove.{interface}.disable', config):
+ Interface(interface).set_admin_state('up')
# Bonding policy/mode
value = config.get('mode')
@@ -360,13 +393,12 @@ class BondIf(Interface):
# Add (enslave) interfaces to bond
value = vyos_dict_search('member.interface', config)
- if value:
- for interface in value:
- # if we've come here we already verified the interface
- # does not have an addresses configured so just flush
- # any remaining ones
- Interface(interface).flush_addrs()
- self.add_port(interface)
+ for interface in (value or []):
+ # if we've come here we already verified the interface
+ # does not have an addresses configured so just flush
+ # any remaining ones
+ Interface(interface).flush_addrs()
+ self.add_port(interface)
# Primary device interface - must be set after 'mode'
value = config.get('primary')
diff --git a/python/vyos/ifconfig/control.py b/python/vyos/ifconfig/control.py
index a6fc8ac6c..43136f361 100644
--- a/python/vyos/ifconfig/control.py
+++ b/python/vyos/ifconfig/control.py
@@ -13,8 +13,8 @@
# 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 os
+
from inspect import signature
from inspect import _empty
@@ -30,9 +30,9 @@ class Control(Section):
_signature = {}
def __init__(self, **kargs):
- # some commands (such as operation comands - show interfaces, etc.)
+ # some commands (such as operation comands - show interfaces, etc.)
# need to query the interface statistics. If the interface
- # code is used and the debugging is enabled, the screen output
+ # code is used and the debugging is enabled, the screen output
# will include both the command but also the debugging for that command
# to prevent this, debugging can be explicitely disabled
diff --git a/python/vyos/ifconfig/dummy.py b/python/vyos/ifconfig/dummy.py
index 43614cd1c..19ef9d304 100644
--- a/python/vyos/ifconfig/dummy.py
+++ b/python/vyos/ifconfig/dummy.py
@@ -13,10 +13,8 @@
# 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 vyos.ifconfig.interface import Interface
-
@Interface.register
class DummyIf(Interface):
"""
diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py
index 17c1bd64d..1d48941f9 100644
--- a/python/vyos/ifconfig/ethernet.py
+++ b/python/vyos/ifconfig/ethernet.py
@@ -17,13 +17,11 @@ import os
import re
from vyos.ifconfig.interface import Interface
-from vyos.ifconfig.vlan import VLAN
from vyos.validate import assert_list
from vyos.util import run
from vyos.util import vyos_dict_search
@Interface.register
-@VLAN.enable
class EthernetIf(Interface):
"""
Abstraction of a Linux Ethernet Interface
@@ -253,6 +251,22 @@ class EthernetIf(Interface):
"""
return self.set_interface('ufo', state)
+ def set_ring_buffer(self, b_type, b_size):
+ """
+ Example:
+ >>> from vyos.ifconfig import EthernetIf
+ >>> i = EthernetIf('eth0')
+ >>> i.set_ring_buffer('rx', '4096')
+ """
+ cmd = '/sbin/ethtool -G {0} {1} {2}'.format(self.config['ifname'], b_type, b_size)
+ output, code = self._popen(cmd)
+ # ethtool error codes:
+ # 80 - value already setted
+ # 81 - does not possible to set value
+ if code and code != 80:
+ print('could not set {0} ring-buffer for {1}'.format(b_type, self.config['ifname']))
+ return output
+
def update(self, config):
""" General helper function which works on a dictionary retrived by
@@ -298,6 +312,11 @@ class EthernetIf(Interface):
duplex = config.get('duplex')
self.set_speed_duplex(speed, duplex)
+ # Set interface ring buffer
+ if 'ring_buffer' in config:
+ for b_type in config['ring_buffer']:
+ self.set_ring_buffer(b_type, config['ring_buffer'][b_type])
+
# Enable/Disable of an interface must always be done at the end of the
# derived class to make use of the ref-counting set_admin_state()
# function. We will only enable the interface if 'up' was called as
diff --git a/python/vyos/ifconfig/geneve.py b/python/vyos/ifconfig/geneve.py
index dd0658668..0a13043cc 100644
--- a/python/vyos/ifconfig/geneve.py
+++ b/python/vyos/ifconfig/geneve.py
@@ -14,10 +14,8 @@
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
from copy import deepcopy
-
from vyos.ifconfig.interface import Interface
-
@Interface.register
class GeneveIf(Interface):
"""
diff --git a/python/vyos/ifconfig/input.py b/python/vyos/ifconfig/input.py
index bfab36335..a6e566d87 100644
--- a/python/vyos/ifconfig/input.py
+++ b/python/vyos/ifconfig/input.py
@@ -13,10 +13,8 @@
# 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 vyos.ifconfig.interface import Interface
-
@Interface.register
class InputIf(Interface):
default = {
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index ef2336c17..be97b411b 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -86,10 +86,6 @@ class Interface(Control):
'shellcmd': 'ip -json link show dev {ifname}',
'format': lambda j: 'up' if 'UP' in jmespath.search('[*].flags | [0]', json.loads(j)) else 'down',
},
- 'vlan_protocol': {
- 'shellcmd': 'ip -json -details link show dev {ifname}',
- 'format': lambda j: jmespath.search('[*].linkinfo.info_data.protocol | [0]', json.loads(j)),
- },
}
_command_set = {
@@ -464,10 +460,13 @@ class Interface(Control):
Calculate the EUI64 from the interface's MAC, then assign it
with the given prefix to the interface.
"""
-
- eui64 = mac2eui64(self.get_mac(), prefix)
- prefixlen = prefix.split('/')[1]
- self.add_addr(f'{eui64}/{prefixlen}')
+ # T2863: only add a link-local IPv6 address if the interface returns
+ # a MAC address. This is not the case on e.g. WireGuard interfaces.
+ mac = self.get_mac()
+ if mac:
+ eui64 = mac2eui64(mac, prefix)
+ prefixlen = prefix.split('/')[1]
+ self.add_addr(f'{eui64}/{prefixlen}')
def del_ipv6_eui64_address(self, prefix):
"""
@@ -559,17 +558,6 @@ class Interface(Control):
"""
self.set_interface('alias', ifalias)
- def get_vlan_protocol(self):
- """
- Retrieve VLAN protocol in use, this can be 802.1Q, 802.1ad or None
-
- Example:
- >>> from vyos.ifconfig import Interface
- >>> Interface('eth0.10').get_vlan_protocol()
- '802.1Q'
- """
- return self.get_interface('vlan_protocol')
-
def get_admin_state(self):
"""
Get interface administrative state. Function will return 'up' or 'down'
@@ -591,17 +579,6 @@ class Interface(Control):
>>> Interface('eth0').get_admin_state()
'down'
"""
- # A VLAN interface can only be placed in admin up state when
- # the lower interface is up, too
- if self.get_vlan_protocol():
- lower_interface = glob(f'/sys/class/net/{self.ifname}/lower*/flags')[0]
- with open(lower_interface, 'r') as f:
- flags = f.read()
- # If parent is not up - bail out as we can not bring up the VLAN.
- # Flags are defined in kernel source include/uapi/linux/if.h
- if not int(flags, 16) & 1:
- return None
-
if state == 'up':
self._admin_state_down_cnt -= 1
if self._admin_state_down_cnt < 1:
@@ -1028,33 +1005,160 @@ class Interface(Control):
self.add_to_bridge(bridge)
# remove no longer required 802.1ad (Q-in-Q VLANs)
+ ifname = config['ifname']
for vif_s_id in config.get('vif_s_remove', {}):
- self.del_vlan(vif_s_id)
+ vif_s_ifname = f'{ifname}.{vif_s_id}'
+ VLANIf(vif_s_ifname).remove()
# create/update 802.1ad (Q-in-Q VLANs)
- ifname = config['ifname']
- for vif_s_id, vif_s in config.get('vif_s', {}).items():
- tmp=get_ethertype(vif_s.get('ethertype', '0x88A8'))
- s_vlan = self.add_vlan(vif_s_id, ethertype=tmp)
- vif_s['ifname'] = f'{ifname}.{vif_s_id}'
- s_vlan.update(vif_s)
+ for vif_s_id, vif_s_config in config.get('vif_s', {}).items():
+ tmp = deepcopy(VLANIf.get_config())
+ tmp['ethertype'] = get_ethertype(vif_s_config.get('ethertype', '0x88A8'))
+ tmp['source_interface'] = ifname
+ tmp['vlan_id'] = vif_s_id
+
+ vif_s_ifname = f'{ifname}.{vif_s_id}'
+ vif_s_config['ifname'] = vif_s_ifname
+ s_vlan = VLANIf(vif_s_ifname, **tmp)
+ s_vlan.update(vif_s_config)
# remove no longer required client VLAN (vif-c)
- for vif_c_id in vif_s.get('vif_c_remove', {}):
- s_vlan.del_vlan(vif_c_id)
+ for vif_c_id in vif_s_config.get('vif_c_remove', {}):
+ vif_c_ifname = f'{vif_s_ifname}.{vif_c_id}'
+ VLANIf(vif_c_ifname).remove()
# create/update client VLAN (vif-c) interface
- for vif_c_id, vif_c in vif_s.get('vif_c', {}).items():
- c_vlan = s_vlan.add_vlan(vif_c_id)
- vif_c['ifname'] = f'{ifname}.{vif_s_id}.{vif_c_id}'
- c_vlan.update(vif_c)
+ for vif_c_id, vif_c_config in vif_s_config.get('vif_c', {}).items():
+ tmp = deepcopy(VLANIf.get_config())
+ tmp['source_interface'] = vif_s_ifname
+ tmp['vlan_id'] = vif_c_id
+
+ vif_c_ifname = f'{vif_s_ifname}.{vif_c_id}'
+ vif_c_config['ifname'] = vif_c_ifname
+ c_vlan = VLANIf(vif_c_ifname, **tmp)
+ c_vlan.update(vif_c_config)
# remove no longer required 802.1q VLAN interfaces
for vif_id in config.get('vif_remove', {}):
- self.del_vlan(vif_id)
+ vif_ifname = f'{ifname}.{vif_id}'
+ VLANIf(vif_ifname).remove()
# create/update 802.1q VLAN interfaces
- for vif_id, vif in config.get('vif', {}).items():
- vlan = self.add_vlan(vif_id)
- vif['ifname'] = f'{ifname}.{vif_id}'
- vlan.update(vif)
+ for vif_id, vif_config in config.get('vif', {}).items():
+ tmp = deepcopy(VLANIf.get_config())
+ tmp['source_interface'] = ifname
+ tmp['vlan_id'] = vif_id
+
+ vif_ifname = f'{ifname}.{vif_id}'
+ vif_config['ifname'] = vif_ifname
+ vlan = VLANIf(vif_ifname, **tmp)
+ vlan.update(vif_config)
+
+
+class VLANIf(Interface):
+ """ Specific class which abstracts 802.1q and 802.1ad (Q-in-Q) VLAN interfaces """
+ default = {
+ 'type': 'vlan',
+ 'source_interface': '',
+ 'vlan_id': '',
+ 'ethertype': '',
+ 'ingress_qos': '',
+ 'egress_qos': '',
+ }
+
+ options = Interface.options + \
+ ['source_interface', 'vlan_id', 'ethertype', 'ingress_qos', 'egress_qos']
+
+ def remove(self):
+ """
+ Remove interface from operating system. Removing the interface
+ deconfigures all assigned IP addresses and clear possible DHCP(v6)
+ client processes.
+
+ Example:
+ >>> from vyos.ifconfig import Interface
+ >>> VLANIf('eth0.10').remove
+ """
+ # Do we have sub interfaces (VLANs)? As interfaces need to be deleted
+ # "in order" starting from Q-in-Q we delete them first.
+ for upper in glob(f'/sys/class/net/{self.ifname}/upper*'):
+ # an upper interface could be named: upper_bond0.1000.1100, thus
+ # we need top drop the upper_ prefix
+ vif_c = os.path.basename(upper)
+ vif_c = vif_c.replace('upper_', '')
+ VLANIf(vif_c).remove()
+
+ super().remove()
+
+ def _create(self):
+ # bail out early if interface already exists
+ if os.path.exists(f'/sys/class/net/{self.ifname}'):
+ return
+
+ cmd = 'ip link add link {source_interface} name {ifname} type vlan id {vlan_id}'
+ if self.config['ethertype']:
+ cmd += ' proto {ethertype}'
+ if self.config['ingress_qos']:
+ cmd += ' ingress-qos-map {ingress_qos}'
+ if self.config['egress_qos']:
+ cmd += ' egress-qos-map {egress_qos}'
+
+ self._cmd(cmd.format(**self.config))
+
+ # interface is always A/D down. It needs to be enabled explicitly
+ self.set_admin_state('down')
+
+ @staticmethod
+ def get_config():
+ """
+ MACsec interfaces require a configuration when they are added using
+ iproute2. This static method will provide the configuration dictionary
+ used by this class.
+
+ Example:
+ >> dict = VLANIf().get_config()
+ """
+ config = deepcopy(__class__.default)
+ del config['type']
+ return config
+
+ def set_admin_state(self, state):
+ """
+ Set interface administrative state to be 'up' or 'down'
+
+ Example:
+ >>> from vyos.ifconfig import Interface
+ >>> Interface('eth0.10').set_admin_state('down')
+ >>> Interface('eth0.10').get_admin_state()
+ 'down'
+ """
+ # A VLAN interface can only be placed in admin up state when
+ # the lower interface is up, too
+ lower_interface = glob(f'/sys/class/net/{self.ifname}/lower*/flags')[0]
+ with open(lower_interface, 'r') as f:
+ flags = f.read()
+ # If parent is not up - bail out as we can not bring up the VLAN.
+ # Flags are defined in kernel source include/uapi/linux/if.h
+ if not int(flags, 16) & 1:
+ return None
+
+ return super().set_admin_state(state)
+
+ 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 first
+ super().update(config)
+
+ # Enable/Disable of an interface must always be done at the end of the
+ # derived class to make use of the ref-counting set_admin_state()
+ # function. We will only enable the interface if 'up' was called as
+ # often as 'down'. This is required by some interface implementations
+ # as certain parameters can only be changed when the interface is
+ # in admin-down state. This ensures the link does not flap during
+ # reconfiguration.
+ state = 'down' if 'disable' in config else 'up'
+ self.set_admin_state(state)
diff --git a/python/vyos/ifconfig/l2tpv3.py b/python/vyos/ifconfig/l2tpv3.py
index 34147eb38..33740921e 100644
--- a/python/vyos/ifconfig/l2tpv3.py
+++ b/python/vyos/ifconfig/l2tpv3.py
@@ -13,12 +13,9 @@
# 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 os
-
from vyos.ifconfig.interface import Interface
-
@Interface.register
class L2TPv3If(Interface):
"""
diff --git a/python/vyos/ifconfig/loopback.py b/python/vyos/ifconfig/loopback.py
index c70e1773f..0e632d826 100644
--- a/python/vyos/ifconfig/loopback.py
+++ b/python/vyos/ifconfig/loopback.py
@@ -13,10 +13,8 @@
# 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 vyos.ifconfig.interface import Interface
-
@Interface.register
class LoopbackIf(Interface):
"""
diff --git a/python/vyos/ifconfig/macvlan.py b/python/vyos/ifconfig/macvlan.py
index b068ce873..9c1d09c1c 100644
--- a/python/vyos/ifconfig/macvlan.py
+++ b/python/vyos/ifconfig/macvlan.py
@@ -14,13 +14,9 @@
# 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
-
@Interface.register
-@VLAN.enable
class MACVLANIf(Interface):
"""
Abstraction of a Linux MACvlan interface
diff --git a/python/vyos/ifconfig/operational.py b/python/vyos/ifconfig/operational.py
index d585c1873..33e8614f0 100644
--- a/python/vyos/ifconfig/operational.py
+++ b/python/vyos/ifconfig/operational.py
@@ -14,20 +14,19 @@
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
import os
+
from time import time
from datetime import datetime
from functools import reduce
-
from tabulate import tabulate
from vyos.ifconfig import Control
-
class Operational(Control):
"""
A class able to load Interface statistics
"""
-
+
cache_magic = 'XYZZYX'
_stat_names = {
diff --git a/python/vyos/ifconfig/tunnel.py b/python/vyos/ifconfig/tunnel.py
index 85c22b5b4..964ffe383 100644
--- a/python/vyos/ifconfig/tunnel.py
+++ b/python/vyos/ifconfig/tunnel.py
@@ -16,7 +16,6 @@
# https://developers.redhat.com/blog/2019/05/17/an-introduction-to-linux-virtual-interfaces-tunnels/
# https://community.hetzner.com/tutorials/linux-setup-gre-tunnel
-
from copy import deepcopy
from vyos.ifconfig.interface import Interface
diff --git a/python/vyos/ifconfig/vlan.py b/python/vyos/ifconfig/vlan.py
deleted file mode 100644
index d68e8f6cd..000000000
--- a/python/vyos/ifconfig/vlan.py
+++ /dev/null
@@ -1,142 +0,0 @@
-# Copyright 2019 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 os
-import re
-
-from vyos.ifconfig.interface import Interface
-
-
-# This is an internal implementation class
-class VLAN:
- """
- This class handels the creation and removal of a VLAN interface. It serves
- as base class for BondIf and EthernetIf.
- """
-
- _novlan_remove = lambda : None
-
- @classmethod
- def enable (cls,adaptee):
- adaptee._novlan_remove = adaptee.remove
- adaptee.remove = cls.remove
- adaptee.add_vlan = cls.add_vlan
- adaptee.del_vlan = cls.del_vlan
- adaptee.definition['vlan'] = True
- return adaptee
-
- def remove(self):
- """
- Remove interface from operating system. Removing the interface
- deconfigures all assigned IP addresses and clear possible DHCP(v6)
- client processes.
-
- Example:
- >>> from vyos.ifconfig import Interface
- >>> i = Interface('eth0')
- >>> i.remove()
- """
- ifname = self.config['ifname']
-
- # Do we have sub interfaces (VLANs)? We apply a regex matching
- # subinterfaces (indicated by a .) of a parent interface.
- #
- # As interfaces need to be deleted "in order" starting from Q-in-Q
- # we delete them first.
- vlan_ifs = [f for f in os.listdir(r'/sys/class/net')
- if re.match(ifname + r'(?:\.\d+)(?:\.\d+)', f)]
-
- for vlan in vlan_ifs:
- Interface(vlan).remove()
-
- # After deleting all Q-in-Q interfaces delete other VLAN interfaces
- # which probably acted as parent to Q-in-Q or have been regular 802.1q
- # interface.
- vlan_ifs = [f for f in os.listdir(r'/sys/class/net')
- if re.match(ifname + r'(?:\.\d+)', f)]
-
- for vlan in vlan_ifs:
- # self.__class__ is already VLAN.enabled
- self.__class__(vlan)._novlan_remove()
-
- # All subinterfaces are now removed, continue on the physical interface
- self._novlan_remove()
-
- def add_vlan(self, vlan_id, ethertype='', ingress_qos='', egress_qos=''):
- """
- A virtual LAN (VLAN) is any broadcast domain that is partitioned and
- isolated in a computer network at the data link layer (OSI layer 2).
- Use this function to create a new VLAN interface on a given physical
- interface.
-
- This function creates both 802.1q and 802.1ad (Q-in-Q) interfaces. Proto
- parameter is used to indicate VLAN type.
-
- A new object of type VLANIf is returned once the interface has been
- created.
-
- @param ethertype: If specified, create 802.1ad or 802.1q Q-in-Q VLAN
- interface
- @param ingress_qos: Defines a mapping of VLAN header prio field to the
- Linux internal packet priority on incoming frames.
- @param ingress_qos: Defines a mapping of Linux internal packet priority
- to VLAN header prio field but for outgoing frames.
-
- Example:
- >>> from vyos.ifconfig import MACVLANIf
- >>> i = MACVLANIf('eth0')
- >>> i.add_vlan(10)
- """
- vlan_ifname = self.config['ifname'] + '.' + str(vlan_id)
- 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
- # or interface description and so on
- return self.__class__(vlan_ifname)
-
- def del_vlan(self, vlan_id):
- """
- Remove VLAN interface from operating system. Removing the interface
- deconfigures all assigned IP addresses and clear possible DHCP(v6)
- client processes.
-
- Example:
- >>> from vyos.ifconfig import MACVLANIf
- >>> i = MACVLANIf('eth0.10')
- >>> i.del_vlan()
- """
- ifname = self.config['ifname']
- self.__class__(f'{ifname}.{vlan_id}')._novlan_remove()
diff --git a/python/vyos/ifconfig/vrrp.py b/python/vyos/ifconfig/vrrp.py
index 01a7cc7ab..d3e9d5df2 100644
--- a/python/vyos/ifconfig/vrrp.py
+++ b/python/vyos/ifconfig/vrrp.py
@@ -16,15 +16,13 @@
import os
import json
import signal
+
from time import time
from time import sleep
-
from tabulate import tabulate
-from vyos import airbag
from vyos import util
-
class VRRPError(Exception):
pass
diff --git a/python/vyos/ifconfig/vti.py b/python/vyos/ifconfig/vti.py
index 56ebe01d1..d0745898c 100644
--- a/python/vyos/ifconfig/vti.py
+++ b/python/vyos/ifconfig/vti.py
@@ -13,10 +13,8 @@
# 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 vyos.ifconfig.interface import Interface
-
@Interface.register
class VTIIf(Interface):
default = {
diff --git a/python/vyos/ifconfig/vtun.py b/python/vyos/ifconfig/vtun.py
index 60c178b9a..b25e32d63 100644
--- a/python/vyos/ifconfig/vtun.py
+++ b/python/vyos/ifconfig/vtun.py
@@ -13,10 +13,8 @@
# 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 vyos.ifconfig.interface import Interface
-
@Interface.register
class VTunIf(Interface):
default = {
diff --git a/python/vyos/ifconfig/vxlan.py b/python/vyos/ifconfig/vxlan.py
index 18a500336..dba62b61a 100644
--- a/python/vyos/ifconfig/vxlan.py
+++ b/python/vyos/ifconfig/vxlan.py
@@ -18,7 +18,6 @@ from copy import deepcopy
from vyos import ConfigError
from vyos.ifconfig.interface import Interface
-
@Interface.register
class VXLANIf(Interface):
"""
diff --git a/python/vyos/ifconfig/wireguard.py b/python/vyos/ifconfig/wireguard.py
index fad4ef282..d8e89229d 100644
--- a/python/vyos/ifconfig/wireguard.py
+++ b/python/vyos/ifconfig/wireguard.py
@@ -13,9 +13,9 @@
# 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 os
import time
+
from datetime import timedelta
from hurry.filesize import size
diff --git a/python/vyos/ifconfig/wireless.py b/python/vyos/ifconfig/wireless.py
index a50346ffa..346577119 100644
--- a/python/vyos/ifconfig/wireless.py
+++ b/python/vyos/ifconfig/wireless.py
@@ -13,14 +13,9 @@
# 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 os
-
from vyos.ifconfig.interface import Interface
-from vyos.ifconfig.vlan import VLAN
-
@Interface.register
-@VLAN.enable
class WiFiIf(Interface):
"""
Handle WIFI/WLAN interfaces.
@@ -77,9 +72,22 @@ class WiFiIf(Interface):
interface setup code and provide a single point of entry when workin
on any interface. """
+ # We can not call add_to_bridge() until wpa_supplicant is running, thus
+ # we will remove the key from the config dict and react to this specal
+ # case in thie derived class.
+ # re-add ourselves to any bridge we might have fallen out of
+ bridge_member = ''
+ if 'is_bridge_member' in config:
+ bridge_member = config['is_bridge_member']
+ del config['is_bridge_member']
+
# call base class first
super().update(config)
+ # re-add ourselves to any bridge we might have fallen out of
+ if bridge_member:
+ self.add_to_bridge(bridge_member)
+
# Enable/Disable of an interface must always be done at the end of the
# derived class to make use of the ref-counting set_admin_state()
# function. We will only enable the interface if 'up' was called as
diff --git a/python/vyos/util.py b/python/vyos/util.py
index 84aa16791..79e11a86d 100644
--- a/python/vyos/util.py
+++ b/python/vyos/util.py
@@ -654,6 +654,7 @@ def get_bridge_member_config(conf, br, intf):
def check_kmod(k_mod):
""" Common utility function to load required kernel modules on demand """
+ from vyos import ConfigError
if isinstance(k_mod, str):
k_mod = k_mod.split()
for module in k_mod: