diff options
Diffstat (limited to 'python')
-rw-r--r-- | python/vyos/ifconfig/bond.py | 4 | ||||
-rw-r--r-- | python/vyos/ifconfig/bridge.py | 4 | ||||
-rw-r--r-- | python/vyos/ifconfig/dummy.py | 5 | ||||
-rw-r--r-- | python/vyos/ifconfig/ethernet.py | 6 | ||||
-rw-r--r-- | python/vyos/ifconfig/geneve.py | 3 | ||||
-rw-r--r-- | python/vyos/ifconfig/input.py | 5 | ||||
-rw-r--r-- | python/vyos/ifconfig/interface.py | 23 | ||||
-rw-r--r-- | python/vyos/ifconfig/l2tpv3.py | 1 | ||||
-rw-r--r-- | python/vyos/ifconfig/loopback.py | 6 | ||||
-rw-r--r-- | python/vyos/ifconfig/macsec.py | 3 | ||||
-rw-r--r-- | python/vyos/ifconfig/macvlan.py | 5 | ||||
-rw-r--r-- | python/vyos/ifconfig/pppoe.py | 1 | ||||
-rw-r--r-- | python/vyos/ifconfig/sstpc.py | 1 | ||||
-rw-r--r-- | python/vyos/ifconfig/tunnel.py | 9 | ||||
-rw-r--r-- | python/vyos/ifconfig/veth.py | 3 | ||||
-rw-r--r-- | python/vyos/ifconfig/vrrp.py | 3 | ||||
-rw-r--r-- | python/vyos/ifconfig/vti.py | 1 | ||||
-rw-r--r-- | python/vyos/ifconfig/vtun.py | 1 | ||||
-rw-r--r-- | python/vyos/ifconfig/vxlan.py | 4 | ||||
-rw-r--r-- | python/vyos/ifconfig/wireguard.py | 9 | ||||
-rw-r--r-- | python/vyos/ifconfig/wireless.py | 1 | ||||
-rw-r--r-- | python/vyos/ifconfig/wwan.py | 1 | ||||
-rw-r--r-- | python/vyos/utils/process.py | 52 |
23 files changed, 84 insertions, 67 deletions
diff --git a/python/vyos/ifconfig/bond.py b/python/vyos/ifconfig/bond.py index 8ba481728..a659b9bd2 100644 --- a/python/vyos/ifconfig/bond.py +++ b/python/vyos/ifconfig/bond.py @@ -31,7 +31,6 @@ class BondIf(Interface): monitoring may be performed. """ - iftype = 'bond' definition = { **Interface.definition, ** { @@ -109,6 +108,9 @@ class BondIf(Interface): ] return options + def _create(self): + super()._create('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 917f962b7..d534dade7 100644 --- a/python/vyos/ifconfig/bridge.py +++ b/python/vyos/ifconfig/bridge.py @@ -32,7 +32,6 @@ class BridgeIf(Interface): The Linux bridge code implements a subset of the ANSI/IEEE 802.1d standard. """ - iftype = 'bridge' definition = { **Interface.definition, **{ @@ -107,6 +106,9 @@ class BridgeIf(Interface): }, }} + def _create(self): + super()._create('bridge') + def get_vlan_filter(self): """ Get the status of the bridge VLAN filter diff --git a/python/vyos/ifconfig/dummy.py b/python/vyos/ifconfig/dummy.py index d45769931..29a1965a3 100644 --- a/python/vyos/ifconfig/dummy.py +++ b/python/vyos/ifconfig/dummy.py @@ -22,8 +22,6 @@ class DummyIf(Interface): interface. The purpose of a dummy interface is to provide a device to route packets through without actually transmitting them. """ - - iftype = 'dummy' definition = { **Interface.definition, **{ @@ -31,3 +29,6 @@ class DummyIf(Interface): 'prefixes': ['dum', ], }, } + + def _create(self): + super()._create('dummy') diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py index d0c03dbe0..93727bdf6 100644 --- a/python/vyos/ifconfig/ethernet.py +++ b/python/vyos/ifconfig/ethernet.py @@ -33,7 +33,6 @@ class EthernetIf(Interface): Abstraction of a Linux Ethernet Interface """ - iftype = 'ethernet' definition = { **Interface.definition, **{ @@ -119,6 +118,9 @@ class EthernetIf(Interface): super().__init__(ifname, **kargs) self.ethtool = Ethtool(ifname) + def _create(self): + pass + def remove(self): """ Remove interface from config. Removing the interface deconfigures all @@ -137,7 +139,7 @@ class EthernetIf(Interface): # Remove all VLAN subinterfaces - filter with the VLAN dot for vlan in [ x - for x in Section.interfaces(self.iftype) + for x in Section.interfaces('ethernet') if x.startswith(f'{self.ifname}.') ]: Interface(vlan).remove() diff --git a/python/vyos/ifconfig/geneve.py b/python/vyos/ifconfig/geneve.py index fbb261a35..f7fddb812 100644 --- a/python/vyos/ifconfig/geneve.py +++ b/python/vyos/ifconfig/geneve.py @@ -27,7 +27,6 @@ class GeneveIf(Interface): https://developers.redhat.com/blog/2019/05/17/an-introduction-to-linux-virtual-interfaces-tunnels/#geneve https://lwn.net/Articles/644938/ """ - iftype = 'geneve' definition = { **Interface.definition, **{ @@ -49,7 +48,7 @@ class GeneveIf(Interface): 'parameters.ipv6.flowlabel' : 'flowlabel', } - cmd = 'ip link add name {ifname} type {type} id {vni} remote {remote}' + cmd = 'ip link add name {ifname} type geneve id {vni} remote {remote}' for vyos_key, iproute2_key in mapping.items(): # dict_search will return an empty dict "{}" for valueless nodes like # "parameters.nolearning" - thus we need to test the nodes existence diff --git a/python/vyos/ifconfig/input.py b/python/vyos/ifconfig/input.py index 3e5f5790d..201d3cacb 100644 --- a/python/vyos/ifconfig/input.py +++ b/python/vyos/ifconfig/input.py @@ -25,8 +25,6 @@ class InputIf(Interface): a single stack of qdiscs, classes and filters can be shared between multiple interfaces. """ - - iftype = 'ifb' definition = { **Interface.definition, **{ @@ -34,3 +32,6 @@ class InputIf(Interface): 'prefixes': ['ifb', ], }, } + + def _create(self): + super()._create('ifb') diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index a58ee0bbd..cb73e2597 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -29,7 +29,6 @@ from netifaces import AF_INET6 from netaddr import EUI from netaddr import mac_unix_expanded -from vyos.base import ConfigError from vyos.configdict import list_diff from vyos.configdict import dict_merge from vyos.configdict import get_vlan_ids @@ -74,7 +73,6 @@ class Interface(Control): OperationalClass = Operational options = ['debug', 'create'] - required = [] default = { 'debug': True, 'create': True, @@ -336,22 +334,10 @@ class Interface(Control): super().__init__(**kargs) if not self.exists(ifname): - # Any instance of Interface, such as Interface('eth0') can be used - # safely to access the generic function in this class as 'type' is - # unset, the class can not be created - if not hasattr(self, 'iftype'): - raise ConfigError(f'Interface "{ifname}" has no "iftype" attribute defined!') - self.config['type'] = self.iftype - # Should an Instance of a child class (EthernetIf, DummyIf, ..) # be required, then create should be set to False to not accidentally create it. # In case a subclass does not define it, we use get to set the default to True - if self.config.get('create',True): - for k in self.required: - if k not in kargs: - name = self.default['type'] - raise ConfigError(f'missing required option {k} for {name} {ifname} creation') - + if self.config.get('create', True): self._create() # If we can not connect to the interface then let the caller know # as the class could not be correctly initialised @@ -364,13 +350,14 @@ class Interface(Control): self.operational = self.OperationalClass(ifname) self.vrrp = VRRP(ifname) - def _create(self): + def _create(self, type: str=''): # Do not create interface that already exist or exists in netns netns = self.config.get('netns', None) if self.exists(f'{self.ifname}', netns=netns): return - cmd = 'ip link add dev {ifname} type {type}'.format(**self.config) + cmd = f'ip link add dev {self.ifname}' + if type: cmd += f' type {type}' if 'netns' in self.config: cmd = f'ip netns exec {netns} {cmd}' self._cmd(cmd) @@ -1952,8 +1939,6 @@ class Interface(Control): class VLANIf(Interface): """ Specific class which abstracts 802.1q and 802.1ad (Q-in-Q) VLAN interfaces """ - iftype = 'vlan' - def _create(self): # bail out early if interface already exists if self.exists(f'{self.ifname}'): diff --git a/python/vyos/ifconfig/l2tpv3.py b/python/vyos/ifconfig/l2tpv3.py index c1f2803ee..dfaa006aa 100644 --- a/python/vyos/ifconfig/l2tpv3.py +++ b/python/vyos/ifconfig/l2tpv3.py @@ -45,7 +45,6 @@ class L2TPv3If(Interface): either hot standby or load balancing services. Additionally, link integrity monitoring may be performed. """ - iftype = 'l2tp' definition = { **Interface.definition, **{ diff --git a/python/vyos/ifconfig/loopback.py b/python/vyos/ifconfig/loopback.py index e1d041839..13e8a2c50 100644 --- a/python/vyos/ifconfig/loopback.py +++ b/python/vyos/ifconfig/loopback.py @@ -22,16 +22,20 @@ class LoopbackIf(Interface): uses to communicate with itself. """ _persistent_addresses = ['127.0.0.1/8', '::1/128'] - iftype = 'loopback' definition = { **Interface.definition, **{ 'section': 'loopback', 'prefixes': ['lo', ], 'bridgeable': True, + 'eternal': 'lo$', } } + def _create(self): + # we can not create this interface as it is managed by the Kernel + pass + def remove(self): """ Loopback interface can not be deleted from operating system. We can diff --git a/python/vyos/ifconfig/macsec.py b/python/vyos/ifconfig/macsec.py index 383905814..3b4dc223f 100644 --- a/python/vyos/ifconfig/macsec.py +++ b/python/vyos/ifconfig/macsec.py @@ -27,7 +27,6 @@ class MACsecIf(Interface): other security solutions such as IPsec (layer 3) or TLS (layer 4), as all those solutions are used for their own specific use cases. """ - iftype = 'macsec' definition = { **Interface.definition, **{ @@ -43,7 +42,7 @@ class MACsecIf(Interface): """ # create tunnel interface - cmd = 'ip link add link {source_interface} {ifname} type {type}'.format(**self.config) + cmd = 'ip link add link {source_interface} {ifname} type macsec'.format(**self.config) cmd += f' cipher {self.config["security"]["cipher"]}' if 'encrypt' in self.config["security"]: diff --git a/python/vyos/ifconfig/macvlan.py b/python/vyos/ifconfig/macvlan.py index fb7f1d298..fe948b920 100644 --- a/python/vyos/ifconfig/macvlan.py +++ b/python/vyos/ifconfig/macvlan.py @@ -20,7 +20,6 @@ class MACVLANIf(Interface): """ Abstraction of a Linux MACvlan interface """ - iftype = 'macvlan' definition = { **Interface.definition, **{ @@ -35,12 +34,12 @@ class MACVLANIf(Interface): down by default. """ # please do not change the order when assembling the command - cmd = 'ip link add {ifname} link {source_interface} type {type} mode {mode}' + cmd = 'ip link add {ifname} link {source_interface} type macvlan mode {mode}' self._cmd(cmd.format(**self.config)) # interface is always A/D down. It needs to be enabled explicitly self.set_admin_state('down') def set_mode(self, mode): - cmd = f'ip link set dev {self.ifname} type {self.iftype} mode {mode}' + cmd = f'ip link set dev {self.ifname} type macvlan mode {mode}' return self._cmd(cmd) diff --git a/python/vyos/ifconfig/pppoe.py b/python/vyos/ifconfig/pppoe.py index f80a68d4f..85ca3877e 100644 --- a/python/vyos/ifconfig/pppoe.py +++ b/python/vyos/ifconfig/pppoe.py @@ -19,7 +19,6 @@ from vyos.utils.network import get_interface_config @Interface.register class PPPoEIf(Interface): - iftype = 'pppoe' definition = { **Interface.definition, **{ diff --git a/python/vyos/ifconfig/sstpc.py b/python/vyos/ifconfig/sstpc.py index 50fc6ee6b..d92ef23dc 100644 --- a/python/vyos/ifconfig/sstpc.py +++ b/python/vyos/ifconfig/sstpc.py @@ -17,7 +17,6 @@ from vyos.ifconfig.interface import Interface @Interface.register class SSTPCIf(Interface): - iftype = 'sstpc' definition = { **Interface.definition, **{ diff --git a/python/vyos/ifconfig/tunnel.py b/python/vyos/ifconfig/tunnel.py index 9ba7b31a6..df904f7d5 100644 --- a/python/vyos/ifconfig/tunnel.py +++ b/python/vyos/ifconfig/tunnel.py @@ -90,9 +90,8 @@ class TunnelIf(Interface): # T3357: we do not have the 'encapsulation' in kargs when calling this # class from op-mode like "show interfaces tunnel" if 'encapsulation' in kargs: - self.iftype = kargs['encapsulation'] # The gretap interface has the possibility to act as L2 bridge - if self.iftype in ['gretap', 'ip6gretap']: + if kargs['encapsulation'] in ['gretap', 'ip6gretap']: # no multicast, ttl or tos for gretap self.definition = { **TunnelIf.definition, @@ -110,10 +109,10 @@ class TunnelIf(Interface): mapping = { **self.mapping, **self.mapping_ipv4 } cmd = 'ip tunnel add {ifname} mode {encapsulation}' - if self.iftype in ['gretap', 'ip6gretap', 'erspan', 'ip6erspan']: + if self.config['encapsulation'] in ['gretap', 'ip6gretap', 'erspan', 'ip6erspan']: cmd = 'ip link add name {ifname} type {encapsulation}' # ERSPAN requires the serialisation of packets - if self.iftype in ['erspan', 'ip6erspan']: + if self.config['encapsulation'] in ['erspan', 'ip6erspan']: cmd += ' seq' for vyos_key, iproute2_key in mapping.items(): @@ -132,7 +131,7 @@ class TunnelIf(Interface): def _change_options(self): # gretap interfaces do not support changing any parameter - if self.iftype in ['gretap', 'ip6gretap', 'erspan', 'ip6erspan']: + if self.config['encapsulation'] in ['gretap', 'ip6gretap', 'erspan', 'ip6erspan']: return if self.config['encapsulation'] in ['ipip6', 'ip6ip6', 'ip6gre']: diff --git a/python/vyos/ifconfig/veth.py b/python/vyos/ifconfig/veth.py index aafbf226a..2c8709d20 100644 --- a/python/vyos/ifconfig/veth.py +++ b/python/vyos/ifconfig/veth.py @@ -21,7 +21,6 @@ class VethIf(Interface): """ Abstraction of a Linux veth interface """ - iftype = 'veth' definition = { **Interface.definition, **{ @@ -46,7 +45,7 @@ class VethIf(Interface): return # create virtual-ethernet interface - cmd = 'ip link add {ifname} type {type}'.format(**self.config) + cmd = f'ip link add {self.ifname} type veth' cmd += f' peer name {self.config["peer_name"]}' self._cmd(cmd) diff --git a/python/vyos/ifconfig/vrrp.py b/python/vyos/ifconfig/vrrp.py index a3657370f..3ee22706c 100644 --- a/python/vyos/ifconfig/vrrp.py +++ b/python/vyos/ifconfig/vrrp.py @@ -26,15 +26,12 @@ from vyos.utils.file import read_file from vyos.utils.file import wait_for_file_write_complete from vyos.utils.process import process_running - class VRRPError(Exception): pass - class VRRPNoData(VRRPError): pass - class VRRP(object): _vrrp_prefix = '00:00:5E:00:01:' location = { diff --git a/python/vyos/ifconfig/vti.py b/python/vyos/ifconfig/vti.py index 251cbeb36..78f5895f8 100644 --- a/python/vyos/ifconfig/vti.py +++ b/python/vyos/ifconfig/vti.py @@ -19,7 +19,6 @@ from vyos.utils.vti_updown_db import vti_updown_db_exists, open_vti_updown_db_re @Interface.register class VTIIf(Interface): - iftype = 'vti' definition = { **Interface.definition, **{ diff --git a/python/vyos/ifconfig/vtun.py b/python/vyos/ifconfig/vtun.py index 6fb414e56..ee790f275 100644 --- a/python/vyos/ifconfig/vtun.py +++ b/python/vyos/ifconfig/vtun.py @@ -17,7 +17,6 @@ from vyos.ifconfig.interface import Interface @Interface.register class VTunIf(Interface): - iftype = 'vtun' definition = { **Interface.definition, **{ diff --git a/python/vyos/ifconfig/vxlan.py b/python/vyos/ifconfig/vxlan.py index 1023c58d1..58844885b 100644 --- a/python/vyos/ifconfig/vxlan.py +++ b/python/vyos/ifconfig/vxlan.py @@ -42,8 +42,6 @@ class VXLANIf(Interface): For more information please refer to: https://www.kernel.org/doc/Documentation/networking/vxlan.txt """ - - iftype = 'vxlan' definition = { **Interface.definition, **{ @@ -94,7 +92,7 @@ class VXLANIf(Interface): remote_list = self.config['remote'][1:] self.config['remote'] = self.config['remote'][0] - cmd = 'ip link add {ifname} type {type} dstport {port}' + cmd = 'ip link add {ifname} type vxlan dstport {port}' for vyos_key, iproute2_key in mapping.items(): # dict_search will return an empty dict "{}" for valueless nodes like # "parameters.nolearning" - thus we need to test the nodes existence diff --git a/python/vyos/ifconfig/wireguard.py b/python/vyos/ifconfig/wireguard.py index cccac361d..519012625 100644 --- a/python/vyos/ifconfig/wireguard.py +++ b/python/vyos/ifconfig/wireguard.py @@ -26,7 +26,6 @@ from vyos.ifconfig import Interface from vyos.ifconfig import Operational from vyos.template import is_ipv6 - class WireGuardOperational(Operational): def _dump(self): """Dump wireguard data in a python friendly way.""" @@ -160,18 +159,18 @@ class WireGuardOperational(Operational): @Interface.register class WireGuardIf(Interface): OperationalClass = WireGuardOperational - iftype = 'wireguard' definition = { **Interface.definition, **{ 'section': 'wireguard', - 'prefixes': [ - 'wg', - ], + 'prefixes': ['wg', ], 'bridgeable': False, }, } + def _create(self): + super()._create('wireguard') + def get_mac(self): """Get a synthetic MAC address.""" return self.get_mac_synthetic() diff --git a/python/vyos/ifconfig/wireless.py b/python/vyos/ifconfig/wireless.py index 88eaa772b..121f56bd5 100644 --- a/python/vyos/ifconfig/wireless.py +++ b/python/vyos/ifconfig/wireless.py @@ -20,7 +20,6 @@ class WiFiIf(Interface): """ Handle WIFI/WLAN interfaces. """ - iftype = 'wifi' definition = { **Interface.definition, **{ diff --git a/python/vyos/ifconfig/wwan.py b/python/vyos/ifconfig/wwan.py index 845c9bef9..004a64b39 100644 --- a/python/vyos/ifconfig/wwan.py +++ b/python/vyos/ifconfig/wwan.py @@ -17,7 +17,6 @@ from vyos.ifconfig.interface import Interface @Interface.register class WWANIf(Interface): - iftype = 'wwan' definition = { **Interface.definition, **{ diff --git a/python/vyos/utils/process.py b/python/vyos/utils/process.py index d8aabb822..054088325 100644 --- a/python/vyos/utils/process.py +++ b/python/vyos/utils/process.py @@ -20,10 +20,23 @@ from subprocess import PIPE from subprocess import STDOUT from subprocess import DEVNULL + +def get_wrapper(vrf, netns, auth): + wrapper = '' + if vrf: + wrapper = f'ip vrf exec {vrf} ' + elif netns: + wrapper = f'ip netns exec {netns} ' + if auth: + wrapper = f'{auth} {wrapper}' + return wrapper + + def popen(command, flag='', shell=None, input=None, timeout=None, env=None, - stdout=PIPE, stderr=PIPE, decode='utf-8'): + stdout=PIPE, stderr=PIPE, decode='utf-8', auth='', vrf=None, + netns=None): """ - popen is a wrapper helper aound subprocess.Popen + popen is a wrapper helper around subprocess.Popen with it default setting it will return a tuple (out, err) out: the output of the program run err: the error code returned by the program @@ -45,6 +58,8 @@ def popen(command, flag='', shell=None, input=None, timeout=None, env=None, - DEVNULL, discard the output decode: specify the expected text encoding (utf-8, ascii, ...) the default is explicitely utf-8 which is python's own default + vrf: run command in a VRF context + netns: run command in the named network namespace usage: get both stdout and stderr: popen('command', stdout=PIPE, stderr=STDOUT) @@ -60,6 +75,16 @@ def popen(command, flag='', shell=None, input=None, timeout=None, env=None, if not debug.enabled(flag): flag = 'command' + # Must be run as root to execute command in VRF or network namespace + if vrf or netns: + if os.getuid() != 0: + raise OSError( + 'Permission denied: cannot execute commands in VRF and netns contexts as an unprivileged user' + ) + + wrapper = get_wrapper(vrf, netns, auth) + command = f'{wrapper} {command}' + cmd_msg = f"cmd '{command}'" debug.message(cmd_msg, flag) @@ -111,7 +136,7 @@ def popen(command, flag='', shell=None, input=None, timeout=None, env=None, def run(command, flag='', shell=None, input=None, timeout=None, env=None, - stdout=DEVNULL, stderr=PIPE, decode='utf-8'): + stdout=DEVNULL, stderr=PIPE, decode='utf-8', vrf=None, netns=None): """ A wrapper around popen, which discard the stdout and will return the error code of a command @@ -122,13 +147,15 @@ def run(command, flag='', shell=None, input=None, timeout=None, env=None, input=input, timeout=timeout, env=env, shell=shell, decode=decode, + vrf=vrf, + netns=netns, ) return code def cmd(command, flag='', shell=None, input=None, timeout=None, env=None, stdout=PIPE, stderr=PIPE, decode='utf-8', raising=None, message='', - expect=[0], auth=''): + expect=[0], auth='', vrf=None, netns=None): """ A wrapper around popen, which returns the stdout and will raise the error code of a command @@ -139,13 +166,18 @@ 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( - f'{auth} {command}'.strip(), flag, + command, flag, stdout=stdout, stderr=stderr, input=input, timeout=timeout, env=env, shell=shell, decode=decode, + auth=auth, + vrf=vrf, + netns=netns, ) if code not in expect: + wrapper = get_wrapper(vrf, netns, auth='') + command = f'{wrapper} {command}' feedback = message + '\n' if message else '' feedback += f'failed to run command: {command}\n' feedback += f'returned: {decoded}\n' @@ -159,7 +191,7 @@ def cmd(command, flag='', shell=None, input=None, timeout=None, env=None, def rc_cmd(command, flag='', shell=None, input=None, timeout=None, env=None, - stdout=PIPE, stderr=STDOUT, decode='utf-8'): + stdout=PIPE, stderr=STDOUT, decode='utf-8', vrf=None, netns=None): """ A wrapper around popen, which returns the return code of a command and stdout @@ -175,11 +207,14 @@ def rc_cmd(command, flag='', shell=None, input=None, timeout=None, env=None, input=input, timeout=timeout, env=env, shell=shell, decode=decode, + vrf=vrf, + netns=netns, ) return code, out + def call(command, flag='', shell=None, input=None, timeout=None, env=None, - stdout=None, stderr=None, decode='utf-8'): + stdout=None, stderr=None, decode='utf-8', vrf=None, netns=None): """ A wrapper around popen, which print the stdout and will return the error code of a command @@ -190,11 +225,14 @@ def call(command, flag='', shell=None, input=None, timeout=None, env=None, input=input, timeout=timeout, env=env, shell=shell, decode=decode, + vrf=vrf, + netns=netns, ) if out: print(out) return code + def process_running(pid_file): """ Checks if a process with PID in pid_file is running """ from psutil import pid_exists |