From fba3e4b624529576cbfe59f10dfc1bb3df80634f Mon Sep 17 00:00:00 2001 From: Thomas Mangin Date: Tue, 23 Jun 2020 18:24:29 +0100 Subject: validation: T2630: bound to interface mtu if available --- python/vyos/ifconfig/control.py | 34 ++++++++++++++++++++++++++++++++-- python/vyos/validate.py | 31 ++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 5 deletions(-) (limited to 'python/vyos') diff --git a/python/vyos/ifconfig/control.py b/python/vyos/ifconfig/control.py index 0958be642..a6fc8ac6c 100644 --- a/python/vyos/ifconfig/control.py +++ b/python/vyos/ifconfig/control.py @@ -15,6 +15,8 @@ import os +from inspect import signature +from inspect import _empty from vyos import debug from vyos.util import popen @@ -25,6 +27,7 @@ from vyos.ifconfig.section import Section class Control(Section): _command_get = {} _command_set = {} + _signature = {} def __init__(self, **kargs): # some commands (such as operation comands - show interfaces, etc.) @@ -54,6 +57,30 @@ class Control(Section): cmd = self._command_get[name]['shellcmd'].format(**config) return self._command_get[name].get('format', lambda _: _)(self._cmd(cmd)) + def _values(self, name, validate, value): + """ + looks at the validation function "validate" + for the interface sysfs or command and + returns a dict with the right options to call it + """ + if name not in self._signature: + self._signature[name] = signature(validate) + + values = {} + + for k in self._signature[name].parameters: + default = self._signature[name].parameters[k].default + if default is not _empty: + continue + if k == 'self': + values[k] = self + elif k == 'ifname': + values[k] = self.ifname + else: + values[k] = value + + return values + def _set_command(self, config, name, value): """ Using the defined names, set data write to sysfs. @@ -64,7 +91,7 @@ class Control(Section): validate = self._command_set[name].get('validate', None) if validate: try: - validate(value) + validate(**self._values(name, validate, value)) except Exception as e: raise e.__class__(f'Could not set {name}. {e}') @@ -124,7 +151,10 @@ class Control(Section): validate = self._sysfs_set[name].get('validate', None) if validate: - validate(value) + try: + validate(**self._values(name, validate, value)) + except Exception as e: + raise e.__class__(f'Could not set {name}. {e}') config = {**config, **{'value': value}} diff --git a/python/vyos/validate.py b/python/vyos/validate.py index 6304fa8de..9072c5817 100644 --- a/python/vyos/validate.py +++ b/python/vyos/validate.py @@ -13,10 +13,23 @@ # You should have received a copy of the GNU Lesser General Public # License along with this library. If not, see . +import json import socket import netifaces import ipaddress +from vyos.util import cmd + +# Important note when you are adding new validation functions: +# +# The Control class will analyse the signature of the function in this file +# and will build the parameters to be passed to it. +# +# The parameter names "ifname" and "self" will get the Interface name and class +# parameters with default will be left unset +# all other paramters will receive the value to check + + def is_ip(addr): """ Check addr if it is an IPv4 or IPv6 address @@ -208,10 +221,21 @@ def assert_positive(n, smaller=0): raise ValueError(f'{n} is smaller than {smaller}') -def assert_mtu(mtu, min=68, max=9000): +def assert_mtu(mtu, ifname): assert_number(mtu) - if int(mtu) < min or int(mtu) > max: - raise ValueError(f'Invalid MTU size: "{mtu}"') + + out = cmd(f'ip -j -d link show dev {ifname}') + # [{"ifindex":2,"ifname":"eth0","flags":["BROADCAST","MULTICAST","UP","LOWER_UP"],"mtu":1500,"qdisc":"pfifo_fast","operstate":"UP","linkmode":"DEFAULT","group":"default","txqlen":1000,"link_type":"ether","address":"08:00:27:d9:5b:04","broadcast":"ff:ff:ff:ff:ff:ff","promiscuity":0,"min_mtu":46,"max_mtu":16110,"inet6_addr_gen_mode":"none","num_tx_queues":1,"num_rx_queues":1,"gso_max_size":65536,"gso_max_segs":65535}] + parsed = json.loads(out)[0] + min_mtu = int(parsed.get('min_mtu', '0')) + # cur_mtu = parsed.get('mtu',0), + max_mtu = int(parsed.get('max_mtu', '0')) + cur_mtu = int(mtu) + + if (min_mtu and cur_mtu < min_mtu) or cur_mtu < 68: + raise ValueError(f'MTU is too small for interface "{ifname}": {mtu} < {min_mtu}') + if (max_mtu and cur_mtu > max_mtu) or cur_mtu > 65536: + raise ValueError(f'MTU is too small for interface "{ifname}": {mtu} > {max_mtu}') def assert_mac(m): @@ -241,6 +265,7 @@ def assert_mac(m): if octets[:5] == (0, 0, 94, 0, 1): raise ValueError(f'{m} is a VRRP MAC address') + def is_member(conf, interface, intftype=None): """ Checks if passed interface is member of other interface of specified type. -- cgit v1.2.3