diff options
Diffstat (limited to 'python/vyos')
-rw-r--r-- | python/vyos/ifconfig/control.py | 30 | ||||
-rw-r--r-- | python/vyos/ifconfig/ethernet.py | 27 | ||||
-rw-r--r-- | python/vyos/ifconfig/interface.py | 25 | ||||
-rw-r--r-- | python/vyos/ifconfig/l2tpv3.py | 16 | ||||
-rw-r--r-- | python/vyos/util.py | 50 |
5 files changed, 103 insertions, 45 deletions
diff --git a/python/vyos/ifconfig/control.py b/python/vyos/ifconfig/control.py index c1a073aef..c7a2fa2d6 100644 --- a/python/vyos/ifconfig/control.py +++ b/python/vyos/ifconfig/control.py @@ -15,8 +15,9 @@ import os -from subprocess import Popen, PIPE, STDOUT +from vyos.util import debug, debug_msg +from vyos.util import popen, cmd from vyos.ifconfig.register import Register @@ -32,27 +33,18 @@ class Control(Register): # to prevent this, debugging can be explicitely disabled # if debug is not explicitely disabled the the config, enable it - self.debug = kargs.get('debug', True) + self.debug = '' + if kargs.get('debug', True): + self.debug = debug('ifconfig') - def _debug_msg(self, msg): - if os.path.isfile('/tmp/vyos.ifconfig.debug') and self.debug: - print('DEBUG/{:<6} {}'.format(self.config['ifname'], msg)) + def _debug_msg (self, message): + return debug_msg(message, self.debug) def _popen(self, command): - p = Popen(command, stdout=PIPE, stderr=STDOUT, shell=True) - tmp = p.communicate()[0].strip() - self._debug_msg(f"cmd '{command}'") - decoded = tmp.decode() - if decoded: - self._debug_msg(f"returned:\n{decoded}") - return decoded, p.returncode + return popen(command, self.debug) def _cmd(self, command): - decoded, code = self._popen(command) - if code != 0: - # error code can be recovered with .errno - raise OSError(code, f'{command}\nreturned: {decoded}') - return decoded + return cmd(command, self.debug) def _get_command(self, config, name): """ @@ -79,6 +71,10 @@ class Control(Register): if convert: value = convert(value) + possible = self._command_set[name].get('possible', None) + if possible and not possible(config['ifname'], value): + return False + config = {**config, **{'value': value}} cmd = self._command_set[name]['shellcmd'].format(**config) diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py index 50552dc71..c18d2e72f 100644 --- a/python/vyos/ifconfig/ethernet.py +++ b/python/vyos/ifconfig/ethernet.py @@ -18,7 +18,7 @@ import re from vyos.ifconfig.interface import Interface from vyos.ifconfig.vlan import VLAN - +from vyos.util import popen from vyos.validate import * @@ -43,27 +43,36 @@ class EthernetIf(Interface): } } + @staticmethod + def feature(ifname, option, value): + out, code = popen(f'/sbin/ethtool -K {ifname} {option} {value}','ifconfig') + return False _command_set = {**Interface._command_set, **{ 'gro': { 'validate': lambda v: assert_list(v, ['on', 'off']), - 'shellcmd': '/sbin/ethtool -K {ifname} gro {value}', + 'possible': lambda i, v: EthernetIf.feature(i, 'gro', v), + # 'shellcmd': '/sbin/ethtool -K {ifname} gro {value}', }, 'gso': { 'validate': lambda v: assert_list(v, ['on', 'off']), - 'shellcmd': '/sbin/ethtool -K {ifname} gso {value}', + 'possible': lambda i, v: EthernetIf.feature(i, 'gso', v), + # 'shellcmd': '/sbin/ethtool -K {ifname} gso {value}', }, 'sg': { 'validate': lambda v: assert_list(v, ['on', 'off']), - 'shellcmd': '/sbin/ethtool -K {ifname} sg {value}', + 'possible': lambda i, v: EthernetIf.feature(i, 'sg', v), + # 'shellcmd': '/sbin/ethtool -K {ifname} sg {value}', }, 'tso': { 'validate': lambda v: assert_list(v, ['on', 'off']), - 'shellcmd': '/sbin/ethtool -K {ifname} tso {value}', + 'possible': lambda i, v: EthernetIf.feature(i, 'tso', v), + # 'shellcmd': '/sbin/ethtool -K {ifname} tso {value}', }, 'ufo': { 'validate': lambda v: assert_list(v, ['on', 'off']), - 'shellcmd': '/sbin/ethtool -K {ifname} ufo {value}', + 'possible': lambda i, v: EthernetIf.feature(i, 'ufo', v), + # 'shellcmd': '/sbin/ethtool -K {ifname} ufo {value}', }, }} @@ -245,8 +254,4 @@ class EthernetIf(Interface): >>> i = EthernetIf('eth0') >>> i.set_udp_offload('on') """ - if state not in ['on', 'off']: - raise ValueError('state must be "on" or "off"') - - cmd = '/sbin/ethtool -K {} ufo {}'.format(self.config['ifname'], state) - return self._cmd(cmd) + return self.set_interface('ufo', state) diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 4a34f96d6..96057a943 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -39,6 +39,8 @@ class Interface(DHCP): required = [] default = { 'type': '', + 'debug': True, + 'create': True, } definition = { 'section': '', @@ -174,15 +176,26 @@ class Interface(DHCP): super().__init__(ifname, **kargs) if not os.path.exists('/sys/class/net/{}'.format(self.config['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 self.config['type']: raise Exception('interface "{}" not found'.format(self.config['ifname'])) - 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') - - self._create() + # 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') + + self._create() + # If we can not connect to the interface then let the caller know + # as the class could not be correctly initialised + else: + raise Exception('interface "{}" not found'.format(self.config['ifname'])) # list of assigned IP addresses self._addr = [] diff --git a/python/vyos/ifconfig/l2tpv3.py b/python/vyos/ifconfig/l2tpv3.py index f0d64a53d..34147eb38 100644 --- a/python/vyos/ifconfig/l2tpv3.py +++ b/python/vyos/ifconfig/l2tpv3.py @@ -80,16 +80,14 @@ class L2TPv3If(Interface): # interface is always A/D down. It needs to be enabled explicitly self.set_admin_state('down') - if self._config['tunnel_id'] and self._config['session_id']: - cmd = 'ip l2tp del session tunnel_id {} '.format( - self._config['tunnel_id']) - cmd += 'session_id {} '.format(self._config['session_id']) - self._cmd(cmd) + if self.config['tunnel_id'] and self.config['session_id']: + cmd = 'ip l2tp del session tunnel_id {tunnel_id}' + cmd += ' session_id {session_id}' + self._cmd(cmd.format(**self.config)) - if self._config['tunnel_id']: - cmd = 'ip l2tp del tunnel tunnel_id {} '.format( - self._config['tunnel_id']) - self._cmd(cmd) + if self.config['tunnel_id']: + cmd = 'ip l2tp del tunnel tunnel_id {tunnel_id}' + self._cmd(cmd.format(**self.config)) @staticmethod def get_config(): diff --git a/python/vyos/util.py b/python/vyos/util.py index 3970b8bf1..c8ab43c11 100644 --- a/python/vyos/util.py +++ b/python/vyos/util.py @@ -16,6 +16,52 @@ import os import re import sys +from subprocess import Popen, PIPE, STDOUT + + +# debugging + + +def debug(flag): + return flag if os.path.isfile(f'/tmp/vyos.{flag}.debug') else '' + + +def debug_msg(message, section=''): + if section: + print(f'DEBUG/{section:<6} {message}') + + +# commands + + +def popen(command, section=''): + p = Popen(command, stdout=PIPE, stderr=STDOUT, shell=True) + tmp = p.communicate()[0].strip() + debug_msg(f"cmd '{command}'", section) + decoded = tmp.decode() + if decoded: + debug_msg(f"returned:\n{decoded}", section) + return decoded, p.returncode + + +def cmd(command, section=''): + decoded, code = popen(command, section) + if code != 0: + # error code can be recovered with .errno + raise OSError(code, f'{command}\nreturned: {decoded}') + return decoded + + +# file manipulation + + + +def subprocess_cmd(command): + """ execute arbitrary command via Popen """ + from subprocess import Popen, PIPE + p = Popen(command, stdout=PIPE, shell=True) + p.communicate() + def read_file(path): """ Read a file to string """ @@ -35,11 +81,11 @@ def chown_file(path, user, group): os.chown(path, uid, gid) -def chmod_x_file(path): +def chmod_x(path): """ make file executable """ from stat import S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IXGRP, S_IROTH, S_IXOTH - if os.path.isfile(path): + if os.path.exists(path): bitmask = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | \ S_IROTH | S_IXOTH os.chmod(path, bitmask) |