diff options
Diffstat (limited to 'python/vyos/ifconfig')
-rw-r--r-- | python/vyos/ifconfig/__init__.py | 1 | ||||
-rw-r--r-- | python/vyos/ifconfig/bond.py | 3 | ||||
-rw-r--r-- | python/vyos/ifconfig/bridge.py | 3 | ||||
-rw-r--r-- | python/vyos/ifconfig/control.py | 13 | ||||
-rw-r--r-- | python/vyos/ifconfig/dhcp.py | 194 | ||||
-rw-r--r-- | python/vyos/ifconfig/ethernet.py | 2 | ||||
-rw-r--r-- | python/vyos/ifconfig/input.py | 31 | ||||
-rw-r--r-- | python/vyos/ifconfig/interface.py | 46 | ||||
-rw-r--r-- | python/vyos/ifconfig/macvlan.py | 11 | ||||
-rw-r--r-- | python/vyos/ifconfig/section.py (renamed from python/vyos/ifconfig/register.py) | 72 | ||||
-rw-r--r-- | python/vyos/ifconfig/stp.py | 2 | ||||
-rw-r--r-- | python/vyos/ifconfig/tunnel.py | 16 | ||||
-rw-r--r-- | python/vyos/ifconfig/vti.py | 31 | ||||
-rw-r--r-- | python/vyos/ifconfig/vxlan.py | 25 |
14 files changed, 255 insertions, 195 deletions
diff --git a/python/vyos/ifconfig/__init__.py b/python/vyos/ifconfig/__init__.py index 1f9956af0..cd1696ca1 100644 --- a/python/vyos/ifconfig/__init__.py +++ b/python/vyos/ifconfig/__init__.py @@ -14,6 +14,7 @@ # License along with this library. If not, see <http://www.gnu.org/licenses/>. +from vyos.ifconfig.section import Section from vyos.ifconfig.interface import Interface from vyos.ifconfig.bond import BondIf diff --git a/python/vyos/ifconfig/bond.py b/python/vyos/ifconfig/bond.py index e2ff71490..47dd4ff34 100644 --- a/python/vyos/ifconfig/bond.py +++ b/python/vyos/ifconfig/bond.py @@ -18,7 +18,8 @@ import os from vyos.ifconfig.interface import Interface from vyos.ifconfig.vlan import VLAN -from vyos.validate import * +from vyos.validate import assert_list +from vyos.validate import assert_positive @Interface.register diff --git a/python/vyos/ifconfig/bridge.py b/python/vyos/ifconfig/bridge.py index 94b0075d8..44b92c1db 100644 --- a/python/vyos/ifconfig/bridge.py +++ b/python/vyos/ifconfig/bridge.py @@ -16,7 +16,8 @@ from vyos.ifconfig.interface import Interface -from vyos.validate import * +from vyos.validate import assert_boolean +from vyos.validate import assert_positive @Interface.register diff --git a/python/vyos/ifconfig/control.py b/python/vyos/ifconfig/control.py index c7a2fa2d6..7bb63beed 100644 --- a/python/vyos/ifconfig/control.py +++ b/python/vyos/ifconfig/control.py @@ -16,12 +16,13 @@ import os -from vyos.util import debug, debug_msg -from vyos.util import popen, cmd -from vyos.ifconfig.register import Register +from vyos import debug +from vyos.util import popen +from vyos.util import cmd +from vyos.ifconfig.section import Section -class Control(Register): +class Control(Section): _command_get = {} _command_set = {} @@ -35,10 +36,10 @@ class Control(Register): # if debug is not explicitely disabled the the config, enable it self.debug = '' if kargs.get('debug', True): - self.debug = debug('ifconfig') + self.debug = debug.enabled('ifconfig') def _debug_msg (self, message): - return debug_msg(message, self.debug) + return debug.message(message, self.debug) def _popen(self, command): return popen(command, self.debug) diff --git a/python/vyos/ifconfig/dhcp.py b/python/vyos/ifconfig/dhcp.py index 8ec8263b5..d4ff9c2cd 100644 --- a/python/vyos/ifconfig/dhcp.py +++ b/python/vyos/ifconfig/dhcp.py @@ -14,105 +14,37 @@ # License along with this library. If not, see <http://www.gnu.org/licenses/>. import os -import jinja2 +from vyos.dicts import FixedDict from vyos.ifconfig.control import Control +from vyos.template import render -template_v4 = """ -# generated by ifconfig.py -option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; -timeout 60; -retry 300; - -interface "{{ intf }}" { - send host-name "{{ hostname }}"; - {% if client_id -%} - send dhcp-client-identifier "{{ client_id }}"; - {% endif -%} - {% if vendor_class_id -%} - send vendor-class-identifier "{{ vendor_class_id }}"; - {% endif -%} - request subnet-mask, broadcast-address, routers, domain-name-servers, - rfc3442-classless-static-routes, domain-name, interface-mtu; - require subnet-mask; -} - -""" - -template_v6 = """ -# generated by ifconfig.py -interface "{{ intf }}" { - request routers, domain-name-servers, domain-name; -} - -""" - -class DHCP (Control): + +class _DHCP (Control): client_base = r'/var/lib/dhcp/dhclient_' - def __init__ (self, ifname, **kargs): + def __init__(self, ifname, version, **kargs): super().__init__(**kargs) - - # per interface DHCP config files - self._dhcp = { - 4: { - 'ifname': ifname, - 'conf': self.client_base + ifname + '.conf', - 'pid': self.client_base + ifname + '.pid', - 'lease': self.client_base + ifname + '.leases', - 'options': { - 'intf': ifname, - 'hostname': '', - 'client_id': '', - 'vendor_class_id': '' - }, - }, - 6: { - 'ifname': ifname, - 'conf': self.client_base + ifname + '.v6conf', - 'pid': self.client_base + ifname + '.v6pid', - 'lease': self.client_base + ifname + '.v6leases', - 'accept_ra': f'/proc/sys/net/ipv6/conf/{ifname}/accept_ra', - 'options': { - 'intf': ifname, - 'dhcpv6_prm_only': False, - 'dhcpv6_temporary': False - }, - }, + 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', } - def get_dhcp_options(self): - """ - Return dictionary with supported DHCP options. - - Dictionary should be altered and send back via set_dhcp_options() - so those options are applied when DHCP is run. - """ - return self._dhcp[4]['options'] - - def set_dhcp_options(self, options): - """ - Store new DHCP options used by next run of DHCP client. - """ - self._dhcp[4]['options'] = options - - def get_dhcpv6_options(self): - """ - Return dictionary with supported DHCPv6 options. - - Dictionary should be altered and send back via set_dhcp_options() - so those options are applied when DHCP is run. - """ - return self._dhcp[6]['options'] - - def set_dhcpv6_options(self, options): - """ - Store new DHCP options used by next run of DHCP client. - """ - self._dhcp[6]['options'] = options +class _DHCPv4 (_DHCP): + def __init__(self, ifname): + super().__init__(ifname, '') + self.options = FixedDict(**{ + 'ifname': ifname, + 'hostname': '', + 'client_id': '', + 'vendor_class_id': '' + }) # replace dhcpv4/v6 with systemd.networkd? - def _set_dhcp(self): + def set(self): """ Configure interface as DHCP client. The dhclient binary is automatically started in background! @@ -121,21 +53,16 @@ class DHCP (Control): >>> from vyos.ifconfig import Interface >>> j = Interface('eth0') - >>> j.set_dhcp() + >>> j.dhcp.v4.set() """ - dhcp = self.get_dhcp_options() - if not dhcp['hostname']: + if not self.options['hostname']: # read configured system hostname. # maybe change to vyos hostd client ??? with open('/etc/hostname', 'r') as f: - dhcp['hostname'] = f.read().rstrip('\n') + self.options['hostname'] = f.read().rstrip('\n') - # render DHCP configuration - tmpl = jinja2.Template(template_v4) - dhcp_text = tmpl.render(dhcp) - with open(self._dhcp[4]['conf'], 'w') as f: - f.write(dhcp_text) + render(self.file['conf'], 'dhcp-client/ipv4.tmpl' ,self.options) cmd = 'start-stop-daemon' cmd += ' --start' @@ -146,9 +73,9 @@ class DHCP (Control): cmd += ' --' # now pass arguments to dhclient binary cmd += ' -4 -nw -cf {conf} -pf {pid} -lf {lease} {ifname}' - return self._cmd(cmd.format(**self._dhcp[4])) + return self._cmd(cmd.format(**self.file)) - def _del_dhcp(self): + def delete(self): """ De-configure interface as DHCP clinet. All auto generated files like pid, config and lease will be removed. @@ -157,14 +84,14 @@ class DHCP (Control): >>> from vyos.ifconfig import Interface >>> j = Interface('eth0') - >>> j.del_dhcp() + >>> j.dhcp.v4.delete() """ - if not os.path.isfile(self._dhcp[4]['pid']): + if not os.path.isfile(self.file['pid']): self._debug_msg('No DHCP client PID found') return None - # with open(self._dhcp[4]['pid'], 'r') as f: - # pid = int(f.read()) + # 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: @@ -178,14 +105,27 @@ class DHCP (Control): # Hostname Option 12, length 10: "vyos" # cmd = '/sbin/dhclient -cf {conf} -pf {pid} -lf {lease} -r {ifname}' - self._cmd(cmd.format(**self._dhcp[4])) + self._cmd(cmd.format(**self.file)) # cleanup old config files for name in ('conf', 'pid', 'lease'): - if os.path.isfile(self._dhcp[4][name]): - os.remove(self._dhcp[4][name]) + if os.path.isfile(self.file[name]): + os.remove(self.file[name]) + - def _set_dhcpv6(self): +class _DHCPv6 (_DHCP): + def __init__(self, ifname): + super().__init__(ifname, 'v6') + self.options = FixedDict(**{ + 'ifname': ifname, + 'dhcpv6_prm_only': False, + 'dhcpv6_temporary': False, + }) + self.file.update({ + 'accept_ra': f'/proc/sys/net/ipv6/conf/{ifname}/accept_ra', + }) + + def set(self): """ Configure interface as DHCPv6 client. The dhclient binary is automatically started in background! @@ -196,22 +136,17 @@ class DHCP (Control): >>> j = Interface('eth0') >>> j.set_dhcpv6() """ - dhcpv6 = self.get_dhcpv6_options() # better save then sorry .. should be checked in interface script # but if you missed it we are safe! - if dhcpv6['dhcpv6_prm_only'] and dhcpv6['dhcpv6_temporary']: + if self.options['dhcpv6_prm_only'] and self.options['dhcpv6_temporary']: raise Exception( 'DHCPv6 temporary and parameters-only options are mutually exclusive!') - # render DHCP configuration - tmpl = jinja2.Template(template_v6) - dhcpv6_text = tmpl.render(dhcpv6) - with open(self._dhcp[6]['conf'], 'w') as f: - f.write(dhcpv6_text) + render(self.file['conf'], 'dhcp-client/ipv6.tmpl', self.options) # no longer accept router announcements on this interface - self._write_sysfs(self._dhcp[6]['accept_ra'], 0) + self._write_sysfs(self.file['accept_ra'], 0) # assemble command-line to start DHCPv6 client (dhclient) cmd = 'start-stop-daemon' @@ -224,15 +159,15 @@ class DHCP (Control): # now pass arguments to dhclient binary cmd += ' -6 -nw -cf {conf} -pf {pid} -lf {lease}' # add optional arguments - if dhcpv6['dhcpv6_prm_only']: + if self.options['dhcpv6_prm_only']: cmd += ' -S' - if dhcpv6['dhcpv6_temporary']: + if self.options['dhcpv6_temporary']: cmd += ' -T' cmd += ' {ifname}' - return self._cmd(cmd.format(**self._dhcp[6])) + return self._cmd(cmd.format(**self.file)) - def _del_dhcpv6(self): + def delete(self): """ De-configure interface as DHCPv6 clinet. All auto generated files like pid, config and lease will be removed. @@ -243,12 +178,12 @@ class DHCP (Control): >>> j = Interface('eth0') >>> j.del_dhcpv6() """ - if not os.path.isfile(self._dhcp[6]['pid']): + if not os.path.isfile(self.file['pid']): self._debug_msg('No DHCPv6 client PID found') return None - # with open(self._dhcp[6]['pid'], 'r') as f: - # pid = int(f.read()) + # with open(self.file['pid'], 'r') as f: + # pid = int(f.read()) # stop dhclient cmd = 'start-stop-daemon' @@ -256,13 +191,18 @@ class DHCP (Control): cmd += ' --oknodo' cmd += ' --quiet' cmd += ' --pidfile {pid}' - self._cmd(cmd.format(**self._dhcp[6])) + self._cmd(cmd.format(**self.file)) # accept router announcements on this interface - self._write_sysfs(self._dhcp[6]['accept_ra'], 1) + self._write_sysfs(self.options['accept_ra'], 1) # cleanup old config files for name in ('conf', 'pid', 'lease'): - if os.path.isfile(self._dhcp[6][name]): - os.remove(self._dhcp[6][name]) + if os.path.isfile(self.file[name]): + os.remove(self.file[name]) + +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 291b326bf..542de4f59 100644 --- a/python/vyos/ifconfig/ethernet.py +++ b/python/vyos/ifconfig/ethernet.py @@ -18,8 +18,8 @@ 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.validate import * @Interface.register diff --git a/python/vyos/ifconfig/input.py b/python/vyos/ifconfig/input.py new file mode 100644 index 000000000..bfab36335 --- /dev/null +++ b/python/vyos/ifconfig/input.py @@ -0,0 +1,31 @@ +# Copyright 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 +# 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/>. + + +from vyos.ifconfig.interface import Interface + + +@Interface.register +class InputIf(Interface): + default = { + 'type': '', + } + definition = { + **Interface.definition, + **{ + 'section': 'input', + 'prefixes': ['ifb', ], + }, + } diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 96057a943..43f823eca 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -18,23 +18,33 @@ import re import json import glob import time +from time import sleep +from os.path import isfile from copy import deepcopy +from datetime import timedelta -from vyos.validate import * # should not * include -from vyos.util import mac2eui64 -from vyos import ConfigError - +from hurry.filesize import size, alternative from ipaddress import IPv4Network, IPv6Address, IPv6Network from netifaces import ifaddresses, AF_INET, AF_INET6 -from time import sleep -from os.path import isfile from tabulate import tabulate -from hurry.filesize import size,alternative -from datetime import timedelta +from vyos.util import mac2eui64 +from vyos import ConfigError from vyos.ifconfig.dhcp import DHCP +from vyos.validate import is_ipv4 +from vyos.validate import is_ipv6 +from vyos.validate import is_intf_addr_assigned +from vyos.validate import assert_boolean +from vyos.validate import assert_list +from vyos.validate import assert_mac +from vyos.validate import assert_mtu +from vyos.validate import assert_positive +from vyos.validate import assert_range + +from vyos.ifconfig.control import Control + -class Interface(DHCP): +class Interface(Control): options = [] required = [] default = { @@ -173,7 +183,8 @@ class Interface(DHCP): self.config['ifname'] = ifname # we must have updated config before initialising the Interface - super().__init__(ifname, **kargs) + super().__init__(**kargs) + self.dhcp = DHCP(ifname) if not os.path.exists('/sys/class/net/{}'.format(self.config['ifname'])): # Any instance of Interface, such as Interface('eth0') @@ -216,8 +227,8 @@ class Interface(DHCP): >>> i.remove() """ # stop DHCP(v6) if running - self._del_dhcp() - self._del_dhcpv6() + 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 @@ -660,12 +671,13 @@ class Interface(DHCP): # 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") + raise ConfigError( + "Can't configure both static IPv4 and DHCP address on the same interface") if addr == 'dhcp': - self._set_dhcp() + self.dhcp.v4.set() elif addr == 'dhcpv6': - self._set_dhcpv6() + 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']) @@ -694,9 +706,9 @@ class Interface(DHCP): ['2001:db8::ffff/64'] """ if addr == 'dhcp': - self._del_dhcp() + self.dhcp.v4.delete() elif addr == 'dhcpv6': - self._del_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']) diff --git a/python/vyos/ifconfig/macvlan.py b/python/vyos/ifconfig/macvlan.py index 4e4b563a1..55b1a3e91 100644 --- a/python/vyos/ifconfig/macvlan.py +++ b/python/vyos/ifconfig/macvlan.py @@ -35,10 +35,10 @@ class MACVLANIf(Interface): 'prefixes': ['peth', ], }, } - options = Interface.options + ['link', 'mode'] + options = Interface.options + ['source_interface', 'mode'] def _create(self): - cmd = 'ip link add {ifname} link {link} type macvlan mode {mode}'.format( + cmd = 'ip link add {ifname} link {source_interface} type macvlan mode {mode}'.format( **self.config) self._cmd(cmd) @@ -54,7 +54,7 @@ class MACVLANIf(Interface): """ config = { 'address': '', - 'link': 0, + 'source_interface': '', 'mode': '' } return config @@ -62,7 +62,6 @@ class MACVLANIf(Interface): def set_mode(self, mode): """ """ - - cmd = 'ip link set dev {} type macvlan mode {}'.format( - self.config['ifname'], mode) + ifname = self.config['ifname'] + cmd = f'ip link set dev {ifname} type macvlan mode {mode}' return self._cmd(cmd) diff --git a/python/vyos/ifconfig/register.py b/python/vyos/ifconfig/section.py index c90782b70..ab340d247 100644 --- a/python/vyos/ifconfig/register.py +++ b/python/vyos/ifconfig/section.py @@ -16,9 +16,10 @@ import netifaces -class Register: +class Section: # the known interface prefixes _prefixes = {} + _classes = [] # class need to define: definition['prefixes'] # the interface prefixes declared by a class used to name interface with @@ -26,9 +27,16 @@ class Register: @classmethod def register(cls, klass): + """ + A function to use as decorator the interfaces classes + It register the prefix for the interface (eth, dum, vxlan, ...) + with the class which can handle it (EthernetIf, DummyIf,VXLANIf, ...) + """ if not klass.definition.get('prefixes',[]): raise RuntimeError(f'valid interface prefixes not defined for {klass.__name__}') + cls._classes.append(klass) + for ifprefix in klass.definition['prefixes']: if ifprefix in cls._prefixes: raise RuntimeError(f'only one class can be registered for prefix "{ifprefix}" type') @@ -38,7 +46,11 @@ class Register: @classmethod def _basename (cls, name, vlan): - # remove number from interface name + """ + remove the number at the end of interface name + name: name of the interface + vlan: if vlan is True, do not stop at the vlan number + """ name = name.rstrip('0123456789') name = name.rstrip('.') if vlan: @@ -47,15 +59,13 @@ class Register: @classmethod def section(cls, name, vlan=True): - # return the name of a section an interface should be under + """ + return the name of a section an interface should be under + name: name of the interface (eth0, dum1, ...) + vlan: should we try try to remove the VLAN from the number + """ name = cls._basename(name, vlan) - # XXX: To leave as long as vti and input are not moved to vyos - if name == 'vti': - return 'vti' - if name == 'ifb': - return 'input' - if name in cls._prefixes: return cls._prefixes[name].definition['section'] return '' @@ -68,15 +78,13 @@ class Register: raise ValueError(f'No type found for interface name: {name}') @classmethod - def _listing (cls,section=''): + def _intf_under_section (cls,section=''): + """ + return a generator with the name of the interface which are under a section + """ interfaces = netifaces.interfaces() for ifname in interfaces: - # XXX: Temporary hack as vti and input are not yet moved from vyatta to vyos - if ifname.startswith('vti') or ifname.startswith('input'): - yield ifname - continue - ifsection = cls.section(ifname) if not ifsection: continue @@ -87,9 +95,37 @@ class Register: yield ifname @classmethod - def listing(cls, section=''): - return list(cls._listing(section)) + def interfaces(cls, section=''): + """ + return a list of the name of the interface which are under a section + if no section is provided, then it returns all configured interfaces + """ + return list(cls._intf_under_section(section)) + @classmethod + def _intf_with_feature(cls, feature=''): + """ + return a generator with the name of the interface which have + a particular feature set in their definition such as: + bondable, broadcast, bridgeable, ... + """ + for klass in cls._classes: + if klass.definition[feature]: + yield klass.definition['section'] -# XXX: TODO - limit name for VRF interfaces + @classmethod + def feature(cls, feature=''): + """ + return list with the name of the interface which have + a particular feature set in their definition such as: + bondable, broadcast, bridgeable, ... + """ + return list(cls._intf_with_feature(feature)) + @classmethod + def reserved(cls): + """ + return list with the interface name prefixes + eth, lo, vxlan, dum, ... + """ + return list(cls._prefixes.keys()) diff --git a/python/vyos/ifconfig/stp.py b/python/vyos/ifconfig/stp.py index 97a3c1ff3..5e83206c2 100644 --- a/python/vyos/ifconfig/stp.py +++ b/python/vyos/ifconfig/stp.py @@ -16,7 +16,7 @@ from vyos.ifconfig.interface import Interface -from vyos.validate import * +from vyos.validate import assert_positive class STP: diff --git a/python/vyos/ifconfig/tunnel.py b/python/vyos/ifconfig/tunnel.py index 1bbb9eb6a..009a53a82 100644 --- a/python/vyos/ifconfig/tunnel.py +++ b/python/vyos/ifconfig/tunnel.py @@ -31,7 +31,7 @@ def enable_to_on(value): raise ValueError(f'expect enable or disable but got "{value}"') - +@Interface.register class _Tunnel(Interface): """ _Tunnel: private base class for tunnels @@ -143,7 +143,7 @@ class GREIf(_Tunnel): options = ['local', 'remote', 'ttl', 'tos', 'key'] updates = ['local', 'remote', 'ttl', 'tos', - 'multicast', 'allmulticast'] + 'mtu', 'multicast', 'allmulticast'] create = 'ip tunnel add {ifname} mode {type}' change = 'ip tunnel cha {ifname}' @@ -167,7 +167,7 @@ class GRETapIf(_Tunnel): required = ['local', ] options = ['local', 'remote', ] - updates = [] + updates = ['mtu', ] create = 'ip link add {ifname} type {type}' change = '' @@ -193,7 +193,7 @@ class IP6GREIf(_Tunnel): 'hoplimit', 'tclass', 'flowlabel'] updates = ['local', 'remote', 'encaplimit', 'hoplimit', 'tclass', 'flowlabel', - 'multicast', 'allmulticast'] + 'mtu', 'multicast', 'allmulticast'] create = 'ip tunnel add {ifname} mode {type}' change = 'ip tunnel cha {ifname} mode {type}' @@ -227,7 +227,7 @@ class IPIPIf(_Tunnel): options = ['local', 'remote', 'ttl', 'tos', 'key'] updates = ['local', 'remote', 'ttl', 'tos', - 'multicast', 'allmulticast'] + 'mtu', 'multicast', 'allmulticast'] create = 'ip tunnel add {ifname} mode {type}' change = 'ip tunnel cha {ifname}' @@ -252,7 +252,7 @@ class IPIP6If(_Tunnel): 'hoplimit', 'tclass', 'flowlabel'] updates = ['local', 'remote', 'encaplimit', 'hoplimit', 'tclass', 'flowlabel', - 'multicast', 'allmulticast'] + 'mtu', 'multicast', 'allmulticast'] create = 'ip -6 tunnel add {ifname} mode {type}' change = 'ip -6 tunnel cha {ifname}' @@ -288,7 +288,7 @@ class SitIf(_Tunnel): options = ['local', 'remote', 'ttl', 'tos', 'key'] updates = ['local', 'remote', 'ttl', 'tos', - 'multicast', 'allmulticast'] + 'mtu', 'multicast', 'allmulticast'] create = 'ip tunnel add {ifname} mode {type}' change = 'ip tunnel cha {ifname}' @@ -309,7 +309,7 @@ class Sit6RDIf(SitIf): # TODO: check if key can really be used with 6RD options = ['remote', 'ttl', 'tos', 'key', '6rd-prefix', '6rd-relay-prefix'] updates = ['remote', 'ttl', 'tos', - 'multicast', 'allmulticast'] + 'mtu', 'multicast', 'allmulticast'] def _create(self): # do not call _Tunnel.create, building fully here diff --git a/python/vyos/ifconfig/vti.py b/python/vyos/ifconfig/vti.py new file mode 100644 index 000000000..56ebe01d1 --- /dev/null +++ b/python/vyos/ifconfig/vti.py @@ -0,0 +1,31 @@ +# Copyright 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 +# 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/>. + + +from vyos.ifconfig.interface import Interface + + +@Interface.register +class VTIIf(Interface): + default = { + 'type': 'vti', + } + definition = { + **Interface.definition, + **{ + 'section': 'vti', + 'prefixes': ['vti', ], + }, + } diff --git a/python/vyos/ifconfig/vxlan.py b/python/vyos/ifconfig/vxlan.py index 5678ad62e..f47ae17cc 100644 --- a/python/vyos/ifconfig/vxlan.py +++ b/python/vyos/ifconfig/vxlan.py @@ -43,12 +43,13 @@ class VXLANIf(Interface): default = { 'type': 'vxlan', - 'vni': 0, - 'dev': '', 'group': '', - 'remote': '', 'port': 8472, # The Linux implementation of VXLAN pre-dates # the IANA's selection of a standard destination port + 'remote': '', + 'src_address': '', + 'src_interface': '', + 'vni': 0 } definition = { **Interface.definition, @@ -58,24 +59,30 @@ class VXLANIf(Interface): 'bridgeable': True, } } - options = ['group', 'remote', 'dev', 'port', 'vni'] + options = ['group', 'remote', 'src_interface', 'port', 'vni', 'src_address'] mapping = { 'ifname': 'add', 'vni': 'id', 'port': 'dstport', + 'src_address': 'nolearning local', } def _create(self): cmdline = set() if self.config['remote']: - cmdline = ('ifname', 'type', 'remote', 'dev', 'vni', 'port') - elif self.config['group'] and self.config['dev']: - cmdline = ('ifname', 'type', 'group', 'dev', 'vni', 'port') + cmdline = ('ifname', 'type', 'remote', 'src_interface', 'vni', 'port') + + elif self.config['src_address']: + cmdline = ('ifname', 'type', 'src_address', 'vni', 'port') + + elif self.config['group'] and self.config['src_interface']: + cmdline = ('ifname', 'type', 'group', 'src_interface', 'vni', 'port') + else: - intf = self.config['intf'] + ifname = self.config['ifname'] raise ConfigError( - f'VXLAN "{intf}" is missing mandatory underlay interface for a multicast network.') + f'VXLAN "{ifname}" is missing mandatory underlay interface for a multicast network.') cmd = 'ip link' for key in cmdline: |