From de5540e49a0e66805204c424686556451592de45 Mon Sep 17 00:00:00 2001 From: DmitriyEshenko Date: Mon, 4 May 2020 12:30:31 +0000 Subject: ipoe: T2294: Fix nodes path --- src/conf_mode/service_ipoe-server.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/service_ipoe-server.py b/src/conf_mode/service_ipoe-server.py index b53692d37..84443ade3 100755 --- a/src/conf_mode/service_ipoe-server.py +++ b/src/conf_mode/service_ipoe-server.py @@ -112,28 +112,30 @@ def get_config(): 'name': interface, 'mac': [] } - for client in conf.list_nodes(base_path + ['authentication', 'interface', interface, 'mac-address']): - mac = { + for mac in conf.list_nodes(['authentication', 'interface', interface, 'mac-address']): + client = { 'address': mac, 'rate_download': '', 'rate_upload': '', 'vlan_id': '' } - conf.set_level(base_path + ['authentication', 'interface', interface, 'mac-address', client]) + conf.set_level(base_path + ['authentication', 'interface', interface, 'mac-address', mac]) if conf.exists(['rate-limit', 'download']): - mac['rate_download'] = conf.return_value(['rate-limit', 'download']) + client['rate_download'] = conf.return_value(['rate-limit', 'download']) if conf.exists(['rate-limit', 'upload']): - mac['rate_upload'] = conf.return_value(['rate-limit', 'upload']) + client['rate_upload'] = conf.return_value(['rate-limit', 'upload']) if conf.exists(['vlan-id']): - mac['vlan'] = conf.return_value(['vlan-id']) + client['vlan'] = conf.return_value(['vlan-id']) - tmp['mac'].append(mac) + tmp['mac'].append(client) ipoe['auth_interfaces'].append(tmp) + conf.set_level(base_path) + # # authentication mode radius servers and settings if conf.exists(['authentication', 'mode', 'radius']): -- cgit v1.2.3 From c1ad2a6461fc2e767d69567be9647150c3310569 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Sun, 3 May 2020 13:28:11 +0200 Subject: configdict: T2241: get interface name in intf/vlan_from_dict This is needed as later functions depend on it --- python/vyos/configdict.py | 2 ++ src/conf_mode/interfaces-bonding.py | 1 - src/conf_mode/interfaces-ethernet.py | 1 - src/conf_mode/interfaces-pseudo-ethernet.py | 1 - 4 files changed, 2 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py index 943092ceb..cd3364c94 100644 --- a/python/vyos/configdict.py +++ b/python/vyos/configdict.py @@ -23,6 +23,7 @@ from copy import deepcopy from vyos import ConfigError from vyos.ifconfig import Interface +from vyos.util import ifname_from_config def retrieve_config(path_hash, base_path, config): @@ -197,6 +198,7 @@ def intf_to_dict(conf, default): """ intf = deepcopy(default) + intf['intf'] = ifname_from_config(conf) # retrieve configured interface addresses if conf.exists('address'): diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py index a174e33e4..76caefabe 100755 --- a/src/conf_mode/interfaces-bonding.py +++ b/src/conf_mode/interfaces-bonding.py @@ -119,7 +119,6 @@ def get_config(): conf.set_level(cfg_base) bond, disabled = intf_to_dict(conf, default_config_data) - bond['intf'] = ifname # ARP link monitoring frequency in milliseconds if conf.exists('arp-monitor interval'): diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py index 3ddd394d7..c7f935ca6 100755 --- a/src/conf_mode/interfaces-ethernet.py +++ b/src/conf_mode/interfaces-ethernet.py @@ -92,7 +92,6 @@ def get_config(): conf.set_level(cfg_base) eth, disabled = intf_to_dict(conf, default_config_data) - eth['intf'] = ifname # disable ethernet flow control (pause frames) if conf.exists('disable-flow-control'): diff --git a/src/conf_mode/interfaces-pseudo-ethernet.py b/src/conf_mode/interfaces-pseudo-ethernet.py index f0f893b44..67250ec9f 100755 --- a/src/conf_mode/interfaces-pseudo-ethernet.py +++ b/src/conf_mode/interfaces-pseudo-ethernet.py @@ -85,7 +85,6 @@ def get_config(): conf.set_level(cfg_base) peth, disabled = intf_to_dict(conf, default_config_data) - peth['intf'] = ifname # ARP cache entry timeout in seconds if conf.exists(['ip', 'arp-cache-timeout']): -- cgit v1.2.3 From 900e75e387939a1d1d4d5b0b79809b8bb2305b91 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Sun, 3 May 2020 13:46:47 +0200 Subject: validate: T2241: rewrite is_bridge_member to generic is_member - rewrite the function to support both bridge and bonding interface types, if the type is passed it searches only that type, otherwise it searches both - move is_member check out of the deleted condition - move is_member check to intf_from_dict for interfaces that use it --- python/vyos/configdict.py | 3 ++ python/vyos/validate.py | 44 ++++++++++++++++++++--------- src/conf_mode/interfaces-bonding.py | 3 -- src/conf_mode/interfaces-dummy.py | 7 +++-- src/conf_mode/interfaces-geneve.py | 7 +++-- src/conf_mode/interfaces-openvpn.py | 7 +++-- src/conf_mode/interfaces-pseudo-ethernet.py | 5 +--- src/conf_mode/interfaces-tunnel.py | 4 +-- src/conf_mode/interfaces-vxlan.py | 7 +++-- src/conf_mode/interfaces-wireguard.py | 7 +++-- src/conf_mode/interfaces-wireless.py | 7 +++-- src/conf_mode/interfaces-wirelessmodem.py | 7 +++-- 12 files changed, 65 insertions(+), 43 deletions(-) (limited to 'src/conf_mode') diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py index cd3364c94..ab72aac6c 100644 --- a/python/vyos/configdict.py +++ b/python/vyos/configdict.py @@ -23,6 +23,7 @@ from copy import deepcopy from vyos import ConfigError from vyos.ifconfig import Interface +from vyos.validate import is_member from vyos.util import ifname_from_config @@ -268,6 +269,8 @@ def intf_to_dict(conf, default): # Media Access Control (MAC) address if conf.exists('mac'): intf['mac'] = conf.return_value('mac') + # check if interface is member of a bridge + intf['is_bridge_member'] = is_member(conf, intf['intf'], 'bridge') # IPv6 Duplicate Address Detection (DAD) tries if conf.exists('ipv6 dup-addr-detect-transmits'): diff --git a/python/vyos/validate.py b/python/vyos/validate.py index 446f6e4ca..eb3f8bf52 100644 --- a/python/vyos/validate.py +++ b/python/vyos/validate.py @@ -241,25 +241,43 @@ def assert_mac(m): if octets[:5] == (0, 0, 94, 0, 1): raise ValueError(f'{m} is a VRRP MAC address') -def is_bridge_member(conf, interface): +def is_member(conf, interface, intftype=None): """ - Checks if passed interfaces is part of a bridge device or not. - - Returns a tuple: - None -> Interface not a bridge member - Bridge -> Interface is a member of this bridge + Checks if passed interface is member of other interface of specified type. + intftype is optional, if not passed it will search all known types + (currently bridge and bonding) + + Returns: + None -> Interface is not a member + interface name -> Interface is a member of this interface + False -> interface type cannot have members """ ret_val = None - old_level = conf.get_level() + + if intftype not in ['bonding', 'bridge', None]: + raise ValueError(( + f'unknown interface type "{intftype}" or it cannot ' + f'have member interfaces')) + + intftype = ['bonding', 'bridge'] if intftype == None else [intftype] # set config level to root + old_level = conf.get_level() conf.set_level([]) - base = ['interfaces', 'bridge'] - for bridge in conf.list_nodes(base): - members = conf.list_nodes(base + [bridge, 'member', 'interface']) - if interface in members: - ret_val = bridge - break + + for it in intftype: + base = 'interfaces ' + it + for intf in conf.list_nodes(base): + memberintf = f'{base} {intf} member interface' + if conf.is_tag(memberintf): + if interface in conf.list_nodes(memberintf): + ret_val = intf + break + elif conf.is_leaf(memberintf): + if ( conf.exists(memberintf) and + interface in conf.return_values(memberintf) ): + ret_val = intf + break old_level = conf.set_level(old_level) return ret_val diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py index 76caefabe..0fc8cfa6c 100755 --- a/src/conf_mode/interfaces-bonding.py +++ b/src/conf_mode/interfaces-bonding.py @@ -25,7 +25,6 @@ from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config from vyos.configdict import list_diff, intf_to_dict, add_to_dict from vyos.config import Config from vyos.util import call, cmd -from vyos.validate import is_bridge_member from vyos import ConfigError default_config_data = { @@ -111,8 +110,6 @@ def get_config(): bond = deepcopy(default_config_data) bond['intf'] = ifname bond['deleted'] = True - # check if interface is member if a bridge - bond['is_bridge_member'] = is_bridge_member(conf, ifname) return bond # set new configuration level diff --git a/src/conf_mode/interfaces-dummy.py b/src/conf_mode/interfaces-dummy.py index 23eaa4ecb..7bc834be5 100755 --- a/src/conf_mode/interfaces-dummy.py +++ b/src/conf_mode/interfaces-dummy.py @@ -23,7 +23,7 @@ from netifaces import interfaces from vyos.ifconfig import DummyIf from vyos.configdict import list_diff from vyos.config import Config -from vyos.validate import is_bridge_member +from vyos.validate import is_member from vyos import ConfigError default_config_data = { @@ -47,11 +47,12 @@ def get_config(): dummy['intf'] = os.environ['VYOS_TAGNODE_VALUE'] + # check if we are a member of any bridge + dummy['is_bridge_member'] = is_member(conf, dummy['intf'], 'bridge') + # Check if interface has been removed if not conf.exists('interfaces dummy ' + dummy['intf']): dummy['deleted'] = True - # check if interface is member if a bridge - dummy['is_bridge_member'] = is_bridge_member(conf, dummy['intf']) return dummy # set new configuration level diff --git a/src/conf_mode/interfaces-geneve.py b/src/conf_mode/interfaces-geneve.py index 708a64474..98f0672c5 100755 --- a/src/conf_mode/interfaces-geneve.py +++ b/src/conf_mode/interfaces-geneve.py @@ -22,7 +22,7 @@ from netifaces import interfaces from vyos.config import Config from vyos.ifconfig import GeneveIf -from vyos.validate import is_bridge_member +from vyos.validate import is_member from vyos import ConfigError default_config_data = { @@ -49,11 +49,12 @@ def get_config(): geneve['intf'] = os.environ['VYOS_TAGNODE_VALUE'] + # check if interface is member if a bridge + geneve['is_bridge_member'] = is_member(conf, geneve['intf'], 'bridge') + # Check if interface has been removed if not conf.exists('interfaces geneve ' + geneve['intf']): geneve['deleted'] = True - # check if interface is member if a bridge - geneve['is_bridge_member'] = is_bridge_member(conf, geneve['intf']) return geneve # set new configuration level diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index 029bc1d69..23a690bf2 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.py @@ -29,7 +29,7 @@ from vyos.configdict import list_diff from vyos.ifconfig import VTunIf from vyos.template import render from vyos.util import call, chown, chmod_600, chmod_755 -from vyos.validate import is_addr_assigned, is_bridge_member, is_ipv4 +from vyos.validate import is_addr_assigned, is_member, is_ipv4 from vyos import ConfigError user = 'openvpn' @@ -199,11 +199,12 @@ def get_config(): openvpn['intf'] = os.environ['VYOS_TAGNODE_VALUE'] openvpn['auth_user_pass_file'] = f"/run/openvpn/{openvpn['intf']}.pw" + # check if interface is member of a bridge + openvpn['is_bridge_member'] = is_member(conf, openvpn['intf'], 'bridge') + # Check if interface instance has been removed if not conf.exists('interfaces openvpn ' + openvpn['intf']): openvpn['deleted'] = True - # check if interface is member if a bridge - openvpn['is_bridge_member'] = is_bridge_member(conf, openvpn['intf']) return openvpn # Check if we belong to any bridge interface diff --git a/src/conf_mode/interfaces-pseudo-ethernet.py b/src/conf_mode/interfaces-pseudo-ethernet.py index 67250ec9f..f9523ca8b 100755 --- a/src/conf_mode/interfaces-pseudo-ethernet.py +++ b/src/conf_mode/interfaces-pseudo-ethernet.py @@ -21,10 +21,9 @@ from sys import exit from netifaces import interfaces from vyos.config import Config -from vyos.configdict import list_diff, vlan_to_dict, intf_to_dict, add_to_dict +from vyos.configdict import list_diff, intf_to_dict, add_to_dict from vyos.ifconfig import MACVLANIf, Section from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config -from vyos.validate import is_bridge_member from vyos import ConfigError default_config_data = { @@ -77,8 +76,6 @@ def get_config(): if not conf.exists(cfg_base): peth = deepcopy(default_config_data) peth['deleted'] = True - # check if interface is member if a bridge - peth['is_bridge_member'] = is_bridge_member(conf, ifname) return peth # set new configuration level diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py index fc084814a..1916d2de2 100755 --- a/src/conf_mode/interfaces-tunnel.py +++ b/src/conf_mode/interfaces-tunnel.py @@ -25,7 +25,7 @@ from vyos.config import Config from vyos.ifconfig import Interface, GREIf, GRETapIf, IPIPIf, IP6GREIf, IPIP6If, IP6IP6If, SitIf, Sit6RDIf from vyos.ifconfig.afi import IP4, IP6 from vyos.configdict import list_diff -from vyos.validate import is_ipv4, is_ipv6, is_bridge_member +from vyos.validate import is_ipv4, is_ipv6, is_member from vyos import ConfigError from vyos.dicts import FixedDict @@ -410,7 +410,7 @@ def get_config(): options['tunnel'] = {} # check for bridges - options['bridge'] = is_bridge_member(conf, ifname) + options['bridge'] = is_member(conf, ifname, 'bridge') options['interfaces'] = interfaces() for name in ct: diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py index 74eae4281..334e418ab 100755 --- a/src/conf_mode/interfaces-vxlan.py +++ b/src/conf_mode/interfaces-vxlan.py @@ -22,7 +22,7 @@ from netifaces import interfaces from vyos.config import Config from vyos.ifconfig import VXLANIf, Interface -from vyos.validate import is_bridge_member +from vyos.validate import is_member from vyos import ConfigError default_config_data = { @@ -62,11 +62,12 @@ def get_config(): vxlan['intf'] = os.environ['VYOS_TAGNODE_VALUE'] + # check if interface is member if a bridge + vxlan['is_bridge_member'] = is_member(conf, vxlan['intf'], 'bridge') + # Check if interface has been removed if not conf.exists('interfaces vxlan ' + vxlan['intf']): vxlan['deleted'] = True - # check if interface is member if a bridge - vxlan['is_bridge_member'] = is_bridge_member(conf, vxlan['intf']) return vxlan # set new configuration level diff --git a/src/conf_mode/interfaces-wireguard.py b/src/conf_mode/interfaces-wireguard.py index 01f84260d..98d5fcb27 100755 --- a/src/conf_mode/interfaces-wireguard.py +++ b/src/conf_mode/interfaces-wireguard.py @@ -25,7 +25,7 @@ from vyos.config import Config from vyos.configdict import list_diff from vyos.ifconfig import WireGuardIf from vyos.util import chown, chmod_750, call -from vyos.validate import is_bridge_member +from vyos.validate import is_member from vyos import ConfigError kdir = r'/config/auth/wireguard' @@ -78,11 +78,12 @@ def get_config(): wg = deepcopy(default_config_data) wg['intf'] = os.environ['VYOS_TAGNODE_VALUE'] + # check if interface is member if a bridge + wg['is_bridge_member'] = is_member(conf, wg['intf'], 'bridge') + # Check if interface has been removed if not conf.exists(base + [wg['intf']]): wg['deleted'] = True - # check if interface is member if a bridge - wg['is_bridge_member'] = is_bridge_member(conf, wg['intf']) return wg conf.set_level(base + [wg['intf']]) diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py index 148a7f6e0..04125ff31 100755 --- a/src/conf_mode/interfaces-wireless.py +++ b/src/conf_mode/interfaces-wireless.py @@ -29,7 +29,7 @@ from vyos.ifconfig import WiFiIf, Section from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config from vyos.template import render from vyos.util import chown, call -from vyos.validate import is_bridge_member +from vyos.validate import is_member from vyos import ConfigError default_config_data = { @@ -134,12 +134,13 @@ def get_config(): wifi['intf'] = os.environ['VYOS_TAGNODE_VALUE'] + # check if interface is member if a bridge + wifi['is_bridge_member'] = is_member(conf, wifi['intf'], 'bridge') + # check if wireless interface has been removed cfg_base = 'interfaces wireless ' + wifi['intf'] if not conf.exists(cfg_base): wifi['deleted'] = True - # check if interface is member if a bridge - wifi['is_bridge_member'] = is_bridge_member(conf, wifi['intf']) # we can not bail out early as wireless interface can not be removed # Kernel will complain with: RTNETLINK answers: Operation not supported. # Thus we need to remove individual settings diff --git a/src/conf_mode/interfaces-wirelessmodem.py b/src/conf_mode/interfaces-wirelessmodem.py index a3a2a2648..03832f345 100755 --- a/src/conf_mode/interfaces-wirelessmodem.py +++ b/src/conf_mode/interfaces-wirelessmodem.py @@ -23,7 +23,7 @@ from netifaces import interfaces from vyos.config import Config from vyos.template import render from vyos.util import chown, chmod_755, cmd, call -from vyos.validate import is_bridge_member +from vyos.validate import is_member from vyos import ConfigError default_config_data = { @@ -64,11 +64,12 @@ def get_config(): wwan['logfile'] = f"/var/log/vyatta/ppp_{wwan['intf']}.log" wwan['chat_script'] = f"/etc/ppp/peers/chat.{wwan['intf']}" + # check if interface is member if a bridge + wwan['is_bridge_member'] = is_member(conf, wwan['intf'], 'bridge') + # Check if interface has been removed if not conf.exists('interfaces wirelessmodem ' + wwan['intf']): wwan['deleted'] = True - # check if interface is member if a bridge - wwan['is_bridge_member'] = is_bridge_member(conf, wwan['intf']) return wwan # set new configuration level -- cgit v1.2.3 From 66e150056ad2cfecb302ab7f42d06096395b7517 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 13:38:51 +0200 Subject: openvpn: T2241: remove redundant bridge_member variable --- data/templates/openvpn/server.conf.tmpl | 2 +- src/conf_mode/interfaces-openvpn.py | 34 ++++++++++----------------------- 2 files changed, 11 insertions(+), 25 deletions(-) (limited to 'src/conf_mode') diff --git a/data/templates/openvpn/server.conf.tmpl b/data/templates/openvpn/server.conf.tmpl index 75ab602f8..401f8e04b 100644 --- a/data/templates/openvpn/server.conf.tmpl +++ b/data/templates/openvpn/server.conf.tmpl @@ -74,7 +74,7 @@ nobind topology {% if server_topology == 'point-to-point' %}p2p{% else %}{{ server_topology }}{% endif %} {%- endif %} -{%- if bridge_member %} +{%- if is_bridge_member %} mode server tls-server {%- else %} diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index 23a690bf2..c0678764f 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.py @@ -41,7 +41,6 @@ default_config_data = { 'auth_pass': '', 'auth_user_pass_file': '', 'auth': False, - 'bridge_member': [], 'compress_lzo': False, 'deleted': False, 'description': '', @@ -207,14 +206,8 @@ def get_config(): openvpn['deleted'] = True return openvpn - # Check if we belong to any bridge interface - for bridge in conf.list_nodes('interfaces bridge'): - for intf in conf.list_nodes('interfaces bridge {} member interface'.format(bridge)): - if intf == openvpn['intf']: - openvpn['bridge_member'].append(intf) - # bridged server should not have a pool by default (but can be specified manually) - if openvpn['bridge_member']: + if openvpn['is_bridge_member']: openvpn['server_pool'] = False openvpn['server_ipv6_pool'] = False @@ -598,7 +591,7 @@ def get_config(): default_server = getDefaultServer(server_network_v4, openvpn['server_topology'], openvpn['type']) if default_server: # server-bridge doesn't require a pool so don't set defaults for it - if openvpn['server_pool'] and not openvpn['bridge_member']: + if openvpn['server_pool'] and not openvpn['is_bridge_member']: if not openvpn['server_pool_start']: openvpn['server_pool_start'] = default_server['pool_start'] @@ -636,22 +629,15 @@ def get_config(): def verify(openvpn): if openvpn['deleted']: if openvpn['is_bridge_member']: - interface = openvpn['intf'] - bridge = openvpn['is_bridge_member'] - raise ConfigError(f'Interface "{interface}" can not be deleted as it belongs to bridge "{bridge}"!') - - return None + raise ConfigError(( + f'Cannot delete interface "{openvpn["intf"]}" as it is a ' + f'member of bridge "{openvpn["is_bridge_menber"]}"!')) + return None if not openvpn['mode']: raise ConfigError('Must specify OpenVPN operation mode') - # Checks which need to be performed on interface rmeoval - if openvpn['deleted']: - # OpenVPN interface can not be deleted if it's still member of a bridge - if openvpn['bridge_member']: - raise ConfigError('Can not delete {} as it is a member interface of bridge {}!'.format(openvpn['intf'], bridge)) - # Check if we have disabled ncp and at the same time specified ncp-ciphers if openvpn['disable_ncp'] and openvpn['ncp_ciphers']: raise ConfigError('Cannot specify both "encryption disable-ncp" and "encryption ncp-ciphers"') @@ -681,9 +667,9 @@ def verify(openvpn): if openvpn['ncp_ciphers']: raise ConfigError('encryption ncp-ciphers cannot be specified in site-to-site mode, only server or client') - if openvpn['mode'] == 'site-to-site' and not openvpn['bridge_member']: + if openvpn['mode'] == 'site-to-site' and not openvpn['is_bridge_member']: if not (openvpn['local_address'] or openvpn['ipv6_local_address']): - raise ConfigError('Must specify "local-address" or "bridge member interface"') + raise ConfigError('Must specify "local-address" or add interface to bridge') if len(openvpn['local_address']) > 1 or len(openvpn['ipv6_local_address']) > 1: raise ConfigError('Cannot specify more than 1 IPv4 and 1 IPv6 "local-address"') @@ -762,8 +748,8 @@ def verify(openvpn): raise ConfigError(f'Client "{client["name"]}" IP {client["ip"][0]} not in server subnet {subnet}') else: - if not openvpn['bridge_member']: - raise ConfigError('Must specify "server subnet" or "bridge member interface" in server mode') + if not openvpn['is_bridge_member']: + raise ConfigError('Must specify "server subnet" or add interface to bridge in server mode') if openvpn['server_pool']: if not (openvpn['server_pool_start'] and openvpn['server_pool_stop']): -- cgit v1.2.3 From 347347c68687849822912e5e26febc5f92955b8b Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Sun, 3 May 2020 15:43:16 +0200 Subject: bridge: T2241: use vyos.util get_bridge_member_config function Was previously moved out of this script. --- src/conf_mode/interfaces-bridge.py | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-bridge.py b/src/conf_mode/interfaces-bridge.py index 9d638653c..d46b625d8 100755 --- a/src/conf_mode/interfaces-bridge.py +++ b/src/conf_mode/interfaces-bridge.py @@ -24,7 +24,7 @@ from vyos.ifconfig import BridgeIf, Section from vyos.ifconfig.stp import STP from vyos.configdict import list_diff from vyos.config import Config -from vyos.util import cmd +from vyos.util import cmd, get_bridge_member_config from vyos import ConfigError default_config_data = { @@ -202,22 +202,12 @@ def get_config(): # Determine bridge member interface (currently configured) for intf in conf.list_nodes('member interface'): - # cost and priority initialized with linux defaults - # by reading /sys/devices/virtual/net/br0/brif/eth2/{path_cost,priority} - # after adding interface to bridge after reboot - iface = { - 'name': intf, - 'cost': 100, - 'priority': 32 - } - - if conf.exists('member interface {} cost'.format(intf)): - iface['cost'] = int(conf.return_value('member interface {} cost'.format(intf))) - - if conf.exists('member interface {} priority'.format(intf)): - iface['priority'] = int(conf.return_value('member interface {} priority'.format(intf))) - - bridge['member'].append(iface) + # defaults are stored in util.py (they can't be here as all interface + # scripts use the function) + memberconf = get_bridge_member_config(conf, bridge['intf'], intf) + if memberconf: + memberconf['name'] = intf + bridge['member'].append(memberconf) # Determine bridge member interface (currently effective) - to determine which # interfaces is no longer assigend to the bridge and thus can be removed @@ -382,9 +372,9 @@ def apply(bridge): for member in bridge['member']: i = STPBridgeIf(member['name']) # configure ARP cache timeout - i.set_arp_cache_tmo(bridge['arp_cache_tmo']) + i.set_arp_cache_tmo(member['arp_cache_tmo']) # ignore link state changes - i.set_link_detect(bridge['disable_link_detect']) + i.set_link_detect(member['disable_link_detect']) # set bridge port path cost i.set_path_cost(member['cost']) # set bridge port path priority -- cgit v1.2.3 From 5ac80802197e1b5c17db96580b004391bde47bf2 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 16:26:50 +0200 Subject: bonding: T2241: make VRF and bridge membership mutually exclusive --- src/conf_mode/interfaces-bonding.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py index 0fc8cfa6c..7681a8c71 100755 --- a/src/conf_mode/interfaces-bonding.py +++ b/src/conf_mode/interfaces-bonding.py @@ -184,9 +184,15 @@ def verify(bond): raise ConfigError('Mode dependency failed, primary not supported ' \ 'in mode "{}"!'.format(bond['mode'])) - vrf_name = bond['vrf'] - if vrf_name and vrf_name not in interfaces(): - raise ConfigError(f'VRF "{vrf_name}" does not exist') + if bond['vrf']: + if bond['vrf'] not in interfaces(): + raise ConfigError(f'VRF "{bond["vrf"]}" does not exist') + + if bond['is_bridge_member']: + raise ConfigError(( + f'Interface "{bond["intf"]}" cannot be member of VRF ' + f'"{bond["vrf"]}" and bridge {bond["is_bridge_member"]} ' + f'at the same time!')) # use common function to verify VLAN configuration verify_vlan_config(bond) -- cgit v1.2.3 From d3ac208e936caa172c575c953d3e8582286f70ef Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Sun, 3 May 2020 21:01:50 +0200 Subject: bonding: T2241: disallow adding interfaces with addresses to bond --- src/conf_mode/interfaces-bonding.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py index 7681a8c71..ec9e0bb11 100755 --- a/src/conf_mode/interfaces-bonding.py +++ b/src/conf_mode/interfaces-bonding.py @@ -25,6 +25,7 @@ from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config from vyos.configdict import list_diff, intf_to_dict, add_to_dict from vyos.config import Config from vyos.util import call, cmd +from vyos.validate import has_address_configured from vyos import ConfigError default_config_data = { @@ -213,9 +214,10 @@ def verify(bond): 'belongs to {}'.format(intf, tmp)) # can not add interfaces with an assigned address to a bond - if conf.exists('interfaces ethernet ' + intf + ' address'): - raise ConfigError('can not enslave interface {} which has an address ' \ - 'assigned'.format(intf)) + if has_address_configured(conf, intf): + raise ConfigError(( + f'Cannot add interface "{intf}" to bond "{bond["intf"]}", ' + f'it has an address assigned!')) # bond members are not allowed to be bridge members, too for tmp in conf.list_nodes('interfaces bridge'): -- cgit v1.2.3 From 9998768f0c8edb3e72566f1d26bee67d42adc133 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Sun, 3 May 2020 21:02:10 +0200 Subject: bonding: T2241: make address and bridge membership mutually exclusive Bridge members should not have addresses assigned. --- src/conf_mode/interfaces-bonding.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py index ec9e0bb11..e5626ef6c 100755 --- a/src/conf_mode/interfaces-bonding.py +++ b/src/conf_mode/interfaces-bonding.py @@ -185,6 +185,14 @@ def verify(bond): raise ConfigError('Mode dependency failed, primary not supported ' \ 'in mode "{}"!'.format(bond['mode'])) + if ( bond['is_bridge_member'] + and ( bond['address'] + or bond['ipv6_eui64_prefix'] + or bond['ipv6_autoconf'] ) ): + raise ConfigError(( + f'Cannot assign address to interface "{bond["intf"]}" ' + f'as it is a member of bridge "{bond["is_bridge_member"]}"!')) + if bond['vrf']: if bond['vrf'] not in interfaces(): raise ConfigError(f'VRF "{bond["vrf"]}" does not exist') -- cgit v1.2.3 From 512510b887408d8263865197fc936501ee453064 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 16:31:35 +0200 Subject: bonding: T2241: cleanup verify section - use is_member function instead of checking config directly - make error output more user friendly - replace .format with f-strings - split into lines less than ~80 characters long --- src/conf_mode/interfaces-bonding.py | 66 ++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 31 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py index e5626ef6c..235b24439 100755 --- a/src/conf_mode/interfaces-bonding.py +++ b/src/conf_mode/interfaces-bonding.py @@ -25,7 +25,7 @@ from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config from vyos.configdict import list_diff, intf_to_dict, add_to_dict from vyos.config import Config from vyos.util import call, cmd -from vyos.validate import has_address_configured +from vyos.validate import is_member, has_address_configured from vyos import ConfigError default_config_data = { @@ -172,18 +172,20 @@ def get_config(): def verify(bond): if bond['deleted']: if bond['is_bridge_member']: - interface = bond['intf'] - bridge = bond['is_bridge_member'] - raise ConfigError(f'Interface "{interface}" can not be deleted as it belongs to bridge "{bridge}"!') + raise ConfigError(( + f'Cannot delete interface "{bond["intf"]}" as it is a ' + f'member of bridge "{bond["is_bridge_member"]}"!')) + return None - if len (bond['arp_mon_tgt']) > 16: - raise ConfigError('The maximum number of targets that can be specified is 16') + if len(bond['arp_mon_tgt']) > 16: + raise ConfigError('The maximum number of arp-monitor targets is 16') if bond['primary']: if bond['mode'] not in ['active-backup', 'balance-tlb', 'balance-alb']: - raise ConfigError('Mode dependency failed, primary not supported ' \ - 'in mode "{}"!'.format(bond['mode'])) + raise ConfigError(( + 'Mode dependency failed, primary not supported in mode ' + f'"{bond["mode"]}"!')) if ( bond['is_bridge_member'] and ( bond['address'] @@ -210,16 +212,17 @@ def verify(bond): for intf in bond['member']: # check if member interface is "real" if intf not in interfaces(): - raise ConfigError('interface {} does not exist!'.format(intf)) + raise ConfigError(f'Interface {intf} does not exist!') # a bonding member interface is only allowed to be assigned to one bond! all_bonds = conf.list_nodes('interfaces bonding') # We do not need to check our own bond all_bonds.remove(bond['intf']) for tmp in all_bonds: - if conf.exists('interfaces bonding ' + tmp + ' member interface ' + intf): - raise ConfigError('can not enslave interface {} which already ' \ - 'belongs to {}'.format(intf, tmp)) + if conf.exists('interfaces bonding {tmp} member interface {intf}'): + raise ConfigError(( + f'Cannot add interface "{intf}" to bond "{bond["intf"]}", ' + f'it is already a member of bond "{tmp}"!')) # can not add interfaces with an assigned address to a bond if has_address_configured(conf, intf): @@ -227,35 +230,37 @@ def verify(bond): f'Cannot add interface "{intf}" to bond "{bond["intf"]}", ' f'it has an address assigned!')) - # bond members are not allowed to be bridge members, too - for tmp in conf.list_nodes('interfaces bridge'): - if conf.exists('interfaces bridge ' + tmp + ' member interface ' + intf): - raise ConfigError('can not enslave interface {} which belongs to ' \ - 'bridge {}'.format(intf, tmp)) + # bond members are not allowed to be bridge members + tmp = is_member(conf, intf, 'bridge') + if tmp: + raise ConfigError(( + f'Cannot add interface "{intf}" to bond "{bond["intf"]}", ' + f'it is already a member of bridge "{tmp}"!')) - # bond members are not allowed to be vrrp members, too + # bond members are not allowed to be vrrp members for tmp in conf.list_nodes('high-availability vrrp group'): - if conf.exists('high-availability vrrp group ' + tmp + ' interface ' + intf): - raise ConfigError('can not enslave interface {} which belongs to ' \ - 'VRRP group {}'.format(intf, tmp)) + if conf.exists('high-availability vrrp group {tmp} interface {intf}'): + raise ConfigError(( + f'Cannot add interface "{intf}" to bond "{bond["intf"]}", ' + f'it is already a member of VRRP group "{tmp}"!')) # bond members are not allowed to be underlaying psuedo-ethernet devices for tmp in conf.list_nodes('interfaces pseudo-ethernet'): - if conf.exists('interfaces pseudo-ethernet ' + tmp + ' link ' + intf): - raise ConfigError('can not enslave interface {} which belongs to ' \ - 'pseudo-ethernet {}'.format(intf, tmp)) + if conf.exists('interfaces pseudo-ethernet {tmp} link {intf}'): + raise ConfigError(( + f'Cannot add interface "{intf}" to bond "{bond["intf"]}", ' + f'it is already the link of pseudo-ethernet "{tmp}"!')) # bond members are not allowed to be underlaying vxlan devices for tmp in conf.list_nodes('interfaces vxlan'): - if conf.exists('interfaces vxlan ' + tmp + ' link ' + intf): - raise ConfigError('can not enslave interface {} which belongs to ' \ - 'vxlan {}'.format(intf, tmp)) - + if conf.exists('interfaces vxlan {tmp} link {intf}'): + raise ConfigError(( + f'Cannot add interface "{intf}" to bond "{bond["intf"]}", ' + f'it is already the link of VXLAN "{tmp}"!')) if bond['primary']: if bond['primary'] not in bond['member']: - raise ConfigError('primary interface must be a member interface of {}' \ - .format(bond['intf'])) + raise ConfigError(f'Bond "{bond["intf"]}" primary interface must be a member') if bond['mode'] not in ['active-backup', 'balance-tlb', 'balance-alb']: raise ConfigError('primary interface only works for mode active-backup, ' \ @@ -268,7 +273,6 @@ def verify(bond): return None - def generate(bond): return None -- cgit v1.2.3 From 600b3bc874355237d24bbe38660478a43ce6c946 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 16:33:31 +0200 Subject: bonding: T2241: fix falling out of bridge when changing settings Previously, set_vrf was always called, which uses the same master and nomaster commands as bridge, so it removed the interface from the bridge. - add checks to make VRF and bridge membership mutually exclusive - always re-add the interface back to any bridge it is part of in case it is deleted and recreated --- src/conf_mode/interfaces-bonding.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py index 235b24439..a8900ac76 100755 --- a/src/conf_mode/interfaces-bonding.py +++ b/src/conf_mode/interfaces-bonding.py @@ -405,8 +405,14 @@ def apply(bond): for addr in bond['address']: b.add_addr(addr) - # assign/remove VRF - b.set_vrf(bond['vrf']) + # assign/remove VRF (ONLY when not a member of a bridge, + # otherwise 'nomaster' removes it from it) + if not bond['is_bridge_member']: + b.set_vrf(bond['vrf']) + + # re-add ourselves to any bridge we might have fallen out of + if bond['is_bridge_member']: + b.add_to_bridge(bond['is_bridge_member']) # remove no longer required service VLAN interfaces (vif-s) for vif_s in bond['vif_s_remove']: -- cgit v1.2.3 From 6369d56ed5bd5a36c4ae3de21e0e316989f0da8e Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 16:37:59 +0200 Subject: bridge: T2241: cleanup verify section - use is_member function instead of checking config directly - rearrange to join 2 for loops into one - make error output more user friendly - replace .format with f-strings - split into lines less than ~80 characters long --- src/conf_mode/interfaces-bridge.py | 41 +++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 18 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-bridge.py b/src/conf_mode/interfaces-bridge.py index d46b625d8..3f54e0dc3 100755 --- a/src/conf_mode/interfaces-bridge.py +++ b/src/conf_mode/interfaces-bridge.py @@ -23,6 +23,7 @@ from netifaces import interfaces from vyos.ifconfig import BridgeIf, Section from vyos.ifconfig.stp import STP from vyos.configdict import list_diff +from vyos.validate import is_member from vyos.config import Config from vyos.util import cmd, get_bridge_member_config from vyos import ConfigError @@ -238,30 +239,34 @@ def verify(bridge): raise ConfigError(f'VRF "{vrf_name}" does not exist') conf = Config() - for br in conf.list_nodes('interfaces bridge'): - # it makes no sense to verify ourself in this case - if br == bridge['intf']: - continue - - for intf in bridge['member']: - tmp = conf.list_nodes('interfaces bridge {} member interface'.format(br)) - if intf['name'] in tmp: - raise ConfigError('Interface "{}" belongs to bridge "{}" and can not be enslaved.'.format(intf['name'], bridge['intf'])) - - # the interface must exist prior adding it to a bridge for intf in bridge['member']: + # the interface must exist prior adding it to a bridge if intf['name'] not in interfaces(): - raise ConfigError('Can not add non existing interface "{}" to bridge "{}"'.format(intf['name'], bridge['intf'])) + raise ConfigError(( + f'Cannot add nonexistent interface "{intf["name"]}" ' + f'to bridge "{bridge["intf"]}"')) if intf['name'] == 'lo': raise ConfigError('Loopback interface "lo" can not be added to a bridge') - # bridge members are not allowed to be bond members, too - for intf in bridge['member']: - for bond in conf.list_nodes('interfaces bonding'): - if conf.exists('interfaces bonding ' + bond + ' member interface'): - if intf['name'] in conf.return_values('interfaces bonding ' + bond + ' member interface'): - raise ConfigError('Interface {} belongs to bond {}, can not add it to {}'.format(intf['name'], bond, bridge['intf'])) + # bridge members aren't allowed to be members of another bridge + for br in conf.list_nodes('interfaces bridge'): + # it makes no sense to verify ourself in this case + if br == bridge['intf']: + continue + + tmp = conf.list_nodes(f'interfaces bridge {br} member interface') + if intf['name'] in tmp: + raise ConfigError(( + f'Cannot add interface "{intf["name"]}" to bridge ' + f'"{bridge["intf"]}", it is already a member of bridge "{br}"!')) + + # bridge members are not allowed to be bond members + tmp = is_member(conf, intf['name'], 'bonding') + if tmp: + raise ConfigError(( + f'Cannot add interface "{intf["name"]}" to bridge ' + f'"{bridge["intf"]}", it is already a member of bond "{tmp}"!')) return None -- cgit v1.2.3 From f81ca22c1988495943531cba11add7cfc9441033 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 17:45:20 +0200 Subject: bridge: T2241: disallow adding interfaces with addresses to bridge --- src/conf_mode/interfaces-bridge.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-bridge.py b/src/conf_mode/interfaces-bridge.py index 3f54e0dc3..fe3675190 100755 --- a/src/conf_mode/interfaces-bridge.py +++ b/src/conf_mode/interfaces-bridge.py @@ -23,7 +23,7 @@ from netifaces import interfaces from vyos.ifconfig import BridgeIf, Section from vyos.ifconfig.stp import STP from vyos.configdict import list_diff -from vyos.validate import is_member +from vyos.validate import is_member, has_address_configured from vyos.config import Config from vyos.util import cmd, get_bridge_member_config from vyos import ConfigError @@ -268,6 +268,12 @@ def verify(bridge): f'Cannot add interface "{intf["name"]}" to bridge ' f'"{bridge["intf"]}", it is already a member of bond "{tmp}"!')) + # bridge members must not have an assigned address + if has_address_configured(conf, intf['name']): + raise ConfigError(( + f'Cannot add interface "{intf["name"]}" to bridge ' + f'"{bridge["intf"]}", it has an address assigned!')) + return None def generate(bridge): -- cgit v1.2.3 From 0ea1abae11dfa5d376f4aff80cd87486370211ed Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 18:00:28 +0200 Subject: dummy: T2241: make VRF and bridge membership mutually exclusive --- src/conf_mode/interfaces-dummy.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-dummy.py b/src/conf_mode/interfaces-dummy.py index 7bc834be5..712f867e1 100755 --- a/src/conf_mode/interfaces-dummy.py +++ b/src/conf_mode/interfaces-dummy.py @@ -91,9 +91,15 @@ def verify(dummy): return None - vrf_name = dummy['vrf'] - if vrf_name and vrf_name not in interfaces(): - raise ConfigError(f'VRF "{vrf_name}" does not exist') + if dummy['vrf']: + if dummy['vrf'] not in interfaces(): + raise ConfigError(f'VRF "{dummy["vrf"]}" does not exist') + + if dummy['is_bridge_member']: + raise ConfigError(( + f'Interface "{dummy["intf"]}" cannot be member of VRF ' + f'"{dummy["vrf"]}" and bridge "{dummy["is_bridge_member"]}" ' + f'at the same time!')) return None -- cgit v1.2.3 From 571b162345aa18f440ccd3f02f8b9f4b62a16c8a Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 18:01:14 +0200 Subject: dummy: T2241: make address and bridge membership mutually exclusive Bridge members should not have any addresses assigned. --- src/conf_mode/interfaces-dummy.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-dummy.py b/src/conf_mode/interfaces-dummy.py index 712f867e1..7d266e693 100755 --- a/src/conf_mode/interfaces-dummy.py +++ b/src/conf_mode/interfaces-dummy.py @@ -101,6 +101,11 @@ def verify(dummy): f'"{dummy["vrf"]}" and bridge "{dummy["is_bridge_member"]}" ' f'at the same time!')) + if dummy['is_bridge_member'] and dummy['address']: + raise ConfigError(( + f'Cannot assign address to interface "{dummy["intf"]}" ' + f'as it is a member of bridge "{dummy["is_bridge_member"]}"!')) + return None def generate(dummy): -- cgit v1.2.3 From ea7ba8a636189bb8e2d87f0de995484be55a016e Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 18:02:05 +0200 Subject: dummy: T2241: fix falling out of bridge when changing settings Previously, set_vrf was always called, which uses the same master and nomaster commands as bridge, so it removed the interface from the bridge. - add checks to make VRF and bridge membership mutually exclusive --- src/conf_mode/interfaces-dummy.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-dummy.py b/src/conf_mode/interfaces-dummy.py index 7d266e693..0049442cd 100755 --- a/src/conf_mode/interfaces-dummy.py +++ b/src/conf_mode/interfaces-dummy.py @@ -129,8 +129,10 @@ def apply(dummy): for addr in dummy['address']: d.add_addr(addr) - # assign/remove VRF - d.set_vrf(dummy['vrf']) + # assign/remove VRF (ONLY when not a member of a bridge, + # otherwise 'nomaster' removes it from it) + if not dummy['is_bridge_member']: + d.set_vrf(dummy['vrf']) # disable interface on demand if dummy['disable']: -- cgit v1.2.3 From c6914e2595172a24d376c0b65c6a2c520a2aaf80 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 18:04:11 +0200 Subject: dummy: T2241: cleanup verify section - make error output more user friendly - replace .format with f-strings - split into lines less than ~80 characters long --- src/conf_mode/interfaces-dummy.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-dummy.py b/src/conf_mode/interfaces-dummy.py index 0049442cd..4a77b0c1a 100755 --- a/src/conf_mode/interfaces-dummy.py +++ b/src/conf_mode/interfaces-dummy.py @@ -85,9 +85,9 @@ def get_config(): def verify(dummy): if dummy['deleted']: if dummy['is_bridge_member']: - interface = dummy['intf'] - bridge = dummy['is_bridge_member'] - raise ConfigError(f'Interface "{interface}" can not be deleted as it belongs to bridge "{bridge}"!') + raise ConfigError(( + f'Interface "{dummy["intf"]}" cannot be deleted as it is a ' + f'member of bridge "{dummy["is_bridge_member"]}"!')) return None -- cgit v1.2.3 From be55968dfbe66477bbef4492abc0875c5da5b797 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 18:08:14 +0200 Subject: ethernet: T2241: add checks for bridge and bond membership --- src/conf_mode/interfaces-ethernet.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py index c7f935ca6..cc6a824dc 100755 --- a/src/conf_mode/interfaces-ethernet.py +++ b/src/conf_mode/interfaces-ethernet.py @@ -23,6 +23,7 @@ from netifaces import interfaces from vyos.ifconfig import EthernetIf, Section from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config from vyos.configdict import list_diff, intf_to_dict, add_to_dict +from vyos.validate import is_member from vyos.config import Config from vyos import ConfigError @@ -53,6 +54,8 @@ default_config_data = { 'ipv6_eui64_prefix_remove': [], 'ipv6_forwarding': 1, 'ipv6_dup_addr_detect': 1, + 'is_bridge_member': False, + 'is_bond_member': False, 'intf': '', 'mac': '', 'mtu': 1500, @@ -113,6 +116,9 @@ def get_config(): if conf.exists('ip proxy-arp-pvlan'): eth['ip_proxy_arp_pvlan'] = 1 + # check if we are a member of any bond + eth['is_bond_member'] = is_member(conf, eth['intf'], 'bonding') + # GRO (generic receive offload) if conf.exists('offload-options generic-receive'): eth['offload_gro'] = conf.return_value('offload-options generic-receive') -- cgit v1.2.3 From 2b002b2b2309942f3ee137e5c2e8427c44038935 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 18:11:13 +0200 Subject: ethernet: T2241: make VRF and bond/bridge membership mutually exclusive --- src/conf_mode/interfaces-ethernet.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py index cc6a824dc..468a9040a 100755 --- a/src/conf_mode/interfaces-ethernet.py +++ b/src/conf_mode/interfaces-ethernet.py @@ -167,9 +167,7 @@ def verify(eth): if eth['dhcpv6_prm_only'] and eth['dhcpv6_temporary']: raise ConfigError('DHCPv6 temporary and parameters-only options are mutually exclusive!') - vrf_name = eth['vrf'] - if vrf_name and vrf_name not in interfaces(): - raise ConfigError(f'VRF "{vrf_name}" does not exist') + memberof = eth['is_bridge_member'] if eth['is_bridge_member'] else eth['is_bond_member'] conf = Config() # some options can not be changed when interface is enslaved to a bond @@ -180,6 +178,15 @@ def verify(eth): if eth['address']: raise ConfigError(f"Can not assign address to interface {eth['intf']} which is a member of {bond}") + if eth['vrf']: + if eth['vrf'] not in interfaces(): + raise ConfigError(f'VRF "{eth["vrf"]}" does not exist') + + if memberof: + raise ConfigError(( + f'Interface "{eth["intf"]}" cannot be member of VRF "{eth["vrf"]}" ' + f'and "{memberof}" at the same time!')) + # use common function to verify VLAN configuration verify_vlan_config(eth) return None -- cgit v1.2.3 From 41a2e2f7de7bf281b4233d82d3b43d6039019bc7 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 18:12:29 +0200 Subject: ethernet: T2241: make address and bond membership exclusive Bond members should not have any addresses assigned. --- src/conf_mode/interfaces-ethernet.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py index 468a9040a..314e696ca 100755 --- a/src/conf_mode/interfaces-ethernet.py +++ b/src/conf_mode/interfaces-ethernet.py @@ -143,6 +143,11 @@ def get_config(): if conf.exists('speed'): eth['speed'] = conf.return_value('speed') + # remove default IPv6 link-local address if member of a bond + if eth['is_bond_member'] and 'fe80::/64' in eth['ipv6_eui64_prefix']: + eth['ipv6_eui64_prefix'].remove('fe80::/64') + eth['ipv6_eui64_prefix_remove'].append('fe80::/64') + add_to_dict(conf, disabled, eth, 'vif', 'vif') add_to_dict(conf, disabled, eth, 'vif-s', 'vif_s') @@ -169,14 +174,13 @@ def verify(eth): memberof = eth['is_bridge_member'] if eth['is_bridge_member'] else eth['is_bond_member'] - conf = Config() - # some options can not be changed when interface is enslaved to a bond - for bond in conf.list_nodes('interfaces bonding'): - if conf.exists('interfaces bonding ' + bond + ' member interface'): - bond_member = conf.return_values('interfaces bonding ' + bond + ' member interface') - if eth['intf'] in bond_member: - if eth['address']: - raise ConfigError(f"Can not assign address to interface {eth['intf']} which is a member of {bond}") + if ( memberof + and ( eth['address'] + or eth['ipv6_eui64_prefix'] + or eth['ipv6_autoconf'] ) ): + raise ConfigError(( + f'Cannot assign address to interface "{eth["intf"]}" ' + f'as it is a member of "{memberof}"!')) if eth['vrf']: if eth['vrf'] not in interfaces(): -- cgit v1.2.3 From ad0448e6e213dd964d44fac450c4a428d035f635 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 18:13:59 +0200 Subject: ethernet: T2241: fix falling out of bridge when changing settings Previously, set_vrf was always called, which uses the same master and nomaster commands as bridge, so it removed the interface from the bridge. - add checks to make VRF and bridge membership mutually exclusive - always re-add the interface back to any bridge it is part of --- src/conf_mode/interfaces-ethernet.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py index 314e696ca..9b9ae931c 100755 --- a/src/conf_mode/interfaces-ethernet.py +++ b/src/conf_mode/interfaces-ethernet.py @@ -20,7 +20,7 @@ from sys import exit from copy import deepcopy from netifaces import interfaces -from vyos.ifconfig import EthernetIf, Section +from vyos.ifconfig import EthernetIf from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config from vyos.configdict import list_diff, intf_to_dict, add_to_dict from vyos.validate import is_member @@ -297,8 +297,14 @@ def apply(eth): for addr in eth['address']: e.add_addr(addr) - # assign/remove VRF - e.set_vrf(eth['vrf']) + # assign/remove VRF (ONLY when not a member of a bridge or bond, + # otherwise 'nomaster' removes it from it) + if not ( eth['is_bridge_member'] or eth['is_bond_member'] ): + e.set_vrf(eth['vrf']) + + # re-add ourselves to any bridge we might have fallen out of + if eth['is_bridge_member']: + e.add_to_bridge(eth['is_bridge_member']) # remove no longer required service VLAN interfaces (vif-s) for vif_s in eth['vif_s_remove']: -- cgit v1.2.3 From 5a0101bdd4b117001e0b0f77acae09b96865c815 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 18:16:47 +0200 Subject: geneve: T2241: make address and bridge membership mutually exclusive Bridge members should not have any addresses assigned. --- src/conf_mode/interfaces-geneve.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-geneve.py b/src/conf_mode/interfaces-geneve.py index 98f0672c5..ab1bd7d7b 100755 --- a/src/conf_mode/interfaces-geneve.py +++ b/src/conf_mode/interfaces-geneve.py @@ -104,6 +104,11 @@ def verify(geneve): return None + if geneve['is_bridge_member'] and geneve['address']: + raise ConfigError(( + f'Cannot assign address to interface "{geneve["intf"]}" ' + f'as it is a member of bridge "{geneve["is_bridge_member"]}"!')) + if not geneve['remote']: raise ConfigError('GENEVE remote must be configured') -- cgit v1.2.3 From 9979a6ef4f45ffc6f3686e6c63e50818ea32b610 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 18:17:47 +0200 Subject: geneve: T2241: fix falling out of bridge when changing settings Previously, the interface was always deleted and recreated, which removed it from the bridge. - always re-add the interface back to any bridge it is part of in case it is deleted and recreated --- src/conf_mode/interfaces-geneve.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-geneve.py b/src/conf_mode/interfaces-geneve.py index ab1bd7d7b..11d6cc2f1 100755 --- a/src/conf_mode/interfaces-geneve.py +++ b/src/conf_mode/interfaces-geneve.py @@ -164,6 +164,10 @@ def apply(geneve): if not geneve['disable']: g.set_admin_state('up') + # re-add ourselves to any bridge we might have fallen out of + if geneve['is_bridge_member']: + g.add_to_bridge(geneve['is_bridge_member']) + return None -- cgit v1.2.3 From 65d4d4c669650ccf727541306330a43da7dceb6f Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 18:19:29 +0200 Subject: geneve: T2241: cleanup verify section - make error output more user friendly - replace .format with f-strings - split into lines less than ~80 characters long --- src/conf_mode/interfaces-geneve.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-geneve.py b/src/conf_mode/interfaces-geneve.py index 11d6cc2f1..e4109a221 100755 --- a/src/conf_mode/interfaces-geneve.py +++ b/src/conf_mode/interfaces-geneve.py @@ -98,9 +98,9 @@ def get_config(): def verify(geneve): if geneve['deleted']: if geneve['is_bridge_member']: - interface = geneve['intf'] - bridge = geneve['is_bridge_member'] - raise ConfigError(f'Interface "{interface}" can not be deleted as it belongs to bridge "{bridge}"!') + raise ConfigError(( + f'Cannot delete interface "{geneve["intf"]}" as it is a ' + f'member of bridge "{geneve["is_bridge_member"]}"!')) return None -- cgit v1.2.3 From f25f65e38ecde122409534bdc648b768e89b8c8f Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 18:44:12 +0200 Subject: l2tpv3: T2241: add check for bridge membership --- src/conf_mode/interfaces-l2tpv3.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-l2tpv3.py b/src/conf_mode/interfaces-l2tpv3.py index 33cf62f70..1f249c5d0 100755 --- a/src/conf_mode/interfaces-l2tpv3.py +++ b/src/conf_mode/interfaces-l2tpv3.py @@ -24,7 +24,7 @@ from vyos.config import Config from vyos.ifconfig import L2TPv3If, Interface from vyos import ConfigError from vyos.util import call -from vyos.validate import is_bridge_member, is_addr_assigned +from vyos.validate import is_member, is_addr_assigned default_config_data = { 'address': [], @@ -66,12 +66,13 @@ def get_config(): l2tpv3['intf'] = os.environ['VYOS_TAGNODE_VALUE'] + # check if interface is member of a bridge + l2tpv3['is_bridge_member'] = is_member(conf, l2tpv3['intf'], 'bridge') + # Check if interface has been removed if not conf.exists('interfaces l2tpv3 ' + l2tpv3['intf']): l2tpv3['deleted'] = True interface = l2tpv3['intf'] - # check if interface is member if a bridge - l2tpv3['is_bridge_member'] = is_bridge_member(conf, interface) # to delete the l2tpv3 interface we need the current tunnel_id and session_id if conf.exists_effective(f'interfaces l2tpv3 {interface} tunnel-id'): -- cgit v1.2.3 From c63ee72e797d29a756c413174ada98d301631bac Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 18:45:33 +0200 Subject: l2tpv3: T2241: make address and bridge membership mutually exclusive Bridge members should not have any addresses assigned. --- src/conf_mode/interfaces-l2tpv3.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-l2tpv3.py b/src/conf_mode/interfaces-l2tpv3.py index 1f249c5d0..90a7ecdc8 100755 --- a/src/conf_mode/interfaces-l2tpv3.py +++ b/src/conf_mode/interfaces-l2tpv3.py @@ -119,7 +119,8 @@ def get_config(): l2tpv3['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64') # Remove the default link-local address if set. - if not conf.exists('ipv6 address no-default-link-local'): + if not ( conf.exists('ipv6 address no-default-link-local') or + l2tpv3['is_bridge_member'] ): # add the link-local by default to make IPv6 work l2tpv3['ipv6_eui64_prefix'].append('fe80::/64') @@ -194,6 +195,14 @@ def verify(l2tpv3): if not l2tpv3['peer_session_id']: raise ConfigError(f'Must configure the l2tpv3 peer-session-id for {interface}') + if ( l2tpv3['is_bridge_member'] + and ( l2tpv3['address'] + or l2tpv3['ipv6_eui64_prefix'] + or l2tpv3['ipv6_autoconf'] ) ): + raise ConfigError(( + f'Cannot assign address to interface "{l2tpv3["intf"]}" ' + f'as it is a member of bridge "{l2tpv3["is_bridge_member"]}"!')) + return None -- cgit v1.2.3 From ea6fd38d526f95a4e8524dfb3fc3ccc4460276e0 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 18:49:57 +0200 Subject: l2tpv3: T2241: fix falling out of bridge when changing settings Previously, the interface was always deleted and recreated, which removed it from the bridge. - always re-add the interface back to any bridge it is part of in case it is deleted and recreated --- src/conf_mode/interfaces-l2tpv3.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-l2tpv3.py b/src/conf_mode/interfaces-l2tpv3.py index 90a7ecdc8..fe5de3431 100755 --- a/src/conf_mode/interfaces-l2tpv3.py +++ b/src/conf_mode/interfaces-l2tpv3.py @@ -264,6 +264,10 @@ def apply(l2tpv3): if not l2tpv3['disable']: l.set_admin_state('up') + # re-add ourselves to any bridge we might have fallen out of + if l2tpv3['is_bridge_member']: + l.add_to_bridge(l2tpv3['is_bridge_member']) + return None if __name__ == '__main__': -- cgit v1.2.3 From 141d45d39d83fbd1eab025bcd00dabcadd6f4e61 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 18:53:27 +0200 Subject: l2tpv3: T2241: cleanup verify section - make error output more user friendly - replace .format with f-strings - split into lines less than ~80 characters long --- src/conf_mode/interfaces-l2tpv3.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-l2tpv3.py b/src/conf_mode/interfaces-l2tpv3.py index fe5de3431..26bb537e5 100755 --- a/src/conf_mode/interfaces-l2tpv3.py +++ b/src/conf_mode/interfaces-l2tpv3.py @@ -168,9 +168,9 @@ def verify(l2tpv3): if l2tpv3['deleted']: if l2tpv3['is_bridge_member']: - interface = l2tpv3['intf'] - bridge = l2tpv3['is_bridge_member'] - raise ConfigError(f'Interface "{interface}" can not be deleted as it belongs to bridge "{bridge}"!') + raise ConfigError(( + f'Interface "{l2tpv3["intf"]}" cannot be deleted as it is a ' + f'member of bridge "{l2tpv3["is_bridge_member"]}"!')) return None -- cgit v1.2.3 From f11ce49a670507f814183e27c4f3e50e29e54e6e Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 19:41:42 +0200 Subject: pseudo-ethernet: T2241: make VRF and bridge membership mutually exclusive --- src/conf_mode/interfaces-pseudo-ethernet.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-pseudo-ethernet.py b/src/conf_mode/interfaces-pseudo-ethernet.py index f9523ca8b..9f01cf0c1 100755 --- a/src/conf_mode/interfaces-pseudo-ethernet.py +++ b/src/conf_mode/interfaces-pseudo-ethernet.py @@ -122,9 +122,15 @@ def verify(peth): if not peth['source_interface'] in interfaces(): raise ConfigError('Pseudo-ethernet source-interface does not exist') - vrf_name = peth['vrf'] - if vrf_name and vrf_name not in interfaces(): - raise ConfigError(f'VRF "{vrf_name}" does not exist') + if peth['vrf']: + if peth['vrf'] not in interfaces(): + raise ConfigError(f'VRF "{peth["vrf"]}" does not exist') + + if peth['is_bridge_member']: + raise ConfigError(( + f'Interface "{peth["intf"]}" cannot be member of VRF ' + f'"{peth["vrf"]}" and bridge {peth["is_bridge_member"]} ' + f'at the same time!')) # use common function to verify VLAN configuration verify_vlan_config(peth) -- cgit v1.2.3 From 50ca89433c2a29367a36f5f049821a9bedb39d24 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 19:44:17 +0200 Subject: pseudo-ethernet: T2241: make address and bridge membership mutually exclusive Bridge members should not have any addresses assigned. --- src/conf_mode/interfaces-pseudo-ethernet.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-pseudo-ethernet.py b/src/conf_mode/interfaces-pseudo-ethernet.py index 9f01cf0c1..e06f14a95 100755 --- a/src/conf_mode/interfaces-pseudo-ethernet.py +++ b/src/conf_mode/interfaces-pseudo-ethernet.py @@ -122,6 +122,14 @@ def verify(peth): if not peth['source_interface'] in interfaces(): raise ConfigError('Pseudo-ethernet source-interface does not exist') + if ( peth['is_bridge_member'] + and ( peth['address'] + or peth['ipv6_eui64_prefix'] + or peth['ipv6_autoconf'] ) ): + raise ConfigError(( + f'Cannot assign address to interface "{peth["intf"]}" ' + f'as it is a member of bridge "{peth["is_bridge_member"]}"!')) + if peth['vrf']: if peth['vrf'] not in interfaces(): raise ConfigError(f'VRF "{peth["vrf"]}" does not exist') -- cgit v1.2.3 From f45c165ca53d4c9e8017d36940de768d7419e097 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 19:45:11 +0200 Subject: pseudo-ethernet: T2241: fix falling out of bridge when changing settings Previously, the interface was always deleted and recreated, which removed it from the bridge. - add checks to make VRF and bridge membership mutually exclusive - always re-add the interface back to any bridge it is part of --- src/conf_mode/interfaces-pseudo-ethernet.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-pseudo-ethernet.py b/src/conf_mode/interfaces-pseudo-ethernet.py index e06f14a95..bd0942fd8 100755 --- a/src/conf_mode/interfaces-pseudo-ethernet.py +++ b/src/conf_mode/interfaces-pseudo-ethernet.py @@ -213,8 +213,10 @@ def apply(peth): # IPv6 Duplicate Address Detection (DAD) tries p.set_ipv6_dad_messages(peth['ipv6_dup_addr_detect']) - # assign/remove VRF - p.set_vrf(peth['vrf']) + # assign/remove VRF (ONLY when not a member of a bridge, + # otherwise 'nomaster' removes it from it) + if not peth['is_bridge_member']: + p.set_vrf(peth['vrf']) # Delete old IPv6 EUI64 addresses before changing MAC for addr in peth['ipv6_eui64_prefix_remove']: @@ -245,6 +247,10 @@ def apply(peth): for addr in peth['address']: p.add_addr(addr) + # re-add ourselves to any bridge we might have fallen out of + if peth['is_bridge_member']: + p.add_to_bridge(peth['is_bridge_member']) + # remove no longer required service VLAN interfaces (vif-s) for vif_s in peth['vif_s_remove']: p.del_vlan(vif_s) -- cgit v1.2.3 From ee58d8ef363d989ab7c63441b84489a6c45cfc31 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 19:48:48 +0200 Subject: pseudo-ethernet: T2241: cleanup verify section - make error output more user friendly - replace .format with f-strings - split into lines less than ~80 characters long --- src/conf_mode/interfaces-pseudo-ethernet.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-pseudo-ethernet.py b/src/conf_mode/interfaces-pseudo-ethernet.py index bd0942fd8..1d04d6dbe 100755 --- a/src/conf_mode/interfaces-pseudo-ethernet.py +++ b/src/conf_mode/interfaces-pseudo-ethernet.py @@ -110,17 +110,19 @@ def get_config(): def verify(peth): if peth['deleted']: if peth['is_bridge_member']: - interface = peth['intf'] - bridge = peth['is_bridge_member'] - raise ConfigError(f'Interface "{interface}" can not be deleted as it belongs to bridge "{bridge}"!') + raise ConfigError(( + f'Cannot delete interface "{peth["intf"]}" as it is a ' + f'member of bridge "{peth["is_bridge_member"]}"!')) return None if not peth['source_interface']: - raise ConfigError('source-interface must be set for virtual ethernet {}'.format(peth['intf'])) + raise ConfigError(( + f'Link device must be set for pseudo-ethernet "{peth["intf"]}"')) if not peth['source_interface'] in interfaces(): - raise ConfigError('Pseudo-ethernet source-interface does not exist') + raise ConfigError(( + f'Pseudo-ethernet "{peth["intf"]}" link device does not exist') if ( peth['is_bridge_member'] and ( peth['address'] -- cgit v1.2.3 From f5ebaaa3ea3091f3228c509991c06300269883ef Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 19:50:21 +0200 Subject: tunnel: T2241: make VRF and bridge membership mutually exclusive --- src/conf_mode/interfaces-tunnel.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py index 1916d2de2..363daaf4f 100755 --- a/src/conf_mode/interfaces-tunnel.py +++ b/src/conf_mode/interfaces-tunnel.py @@ -525,10 +525,15 @@ def verify(conf): print(f'Should not use IPv6 addresses on tunnel {iftype} {ifname}') # vrf check - - vrf = options['vrf'] - if vrf and vrf not in options['interfaces']: - raise ConfigError(f'VRF "{vrf}" does not exist') + if options['vrf']: + if options['vrf'] not in options['interfaces']: + raise ConfigError(f'VRF "{options["vrf"]}" does not exist') + + if options['bridge']: + raise ConfigError(( + f'Interface "{options["ifname"]}" cannot be member of VRF ' + f'"{options["vrf"]}" and bridge {options["bridge"]} ' + f'at the same time!')) # source-interface check -- cgit v1.2.3 From c6fba800f088ca389bd73386793b5444ef185c22 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 19:51:09 +0200 Subject: tunnel: T2241: make address and bridge membership mutually exclusive Bridge members should not have any addresses assigned. --- src/conf_mode/interfaces-tunnel.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py index 363daaf4f..2ef1017c9 100755 --- a/src/conf_mode/interfaces-tunnel.py +++ b/src/conf_mode/interfaces-tunnel.py @@ -535,6 +535,14 @@ def verify(conf): f'"{options["vrf"]}" and bridge {options["bridge"]} ' f'at the same time!')) + # bridge and address check + if ( options['bridge'] + and ( options['addresses-add'] + or options['ipv6_autoconf'] ) ): + raise ConfigError(( + f'Cannot assign address to interface "{options["name"]}" ' + f'as it is a member of bridge "{options["bridge"]}"!')) + # source-interface check if tun_dev and tun_dev not in options['interfaces']: -- cgit v1.2.3 From 6866efd1081c39b50a473b58aea61188f4eb6d6e Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 19:51:56 +0200 Subject: tunnel: T2241: fix falling out of bridge when changing settings Previously, set_vrf was always called, which uses the same master and nomaster commands as bridge, so it removed the interface from the bridge. - add checks to make VRF and bridge membership mutually exclusive --- src/conf_mode/interfaces-tunnel.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py index 2ef1017c9..57bc3b8e0 100755 --- a/src/conf_mode/interfaces-tunnel.py +++ b/src/conf_mode/interfaces-tunnel.py @@ -633,12 +633,17 @@ def apply(conf): # set other interface properties for option in ('alias', 'mtu', 'link_detect', 'multicast', 'allmulticast', - 'vrf', 'ipv6_autoconf', 'ipv6_forwarding', 'ipv6_dad_transmits'): + 'ipv6_autoconf', 'ipv6_forwarding', 'ipv6_dad_transmits'): if not options[option]: # should never happen but better safe continue tunnel.set_interface(option, options[option]) + # assign/remove VRF (ONLY when not a member of a bridge, + # otherwise 'nomaster' removes it from it) + if not options['bridge']: + tunnel.set_vrf(options['vrf']) + # Configure interface address(es) for addr in options['addresses-del']: tunnel.del_addr(addr) -- cgit v1.2.3 From dd50da5f22d18745adafb482ae19ac2455f86cba Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 19:53:41 +0200 Subject: tunnel: T2241: cleanup verify section - make error output more user friendly - replace .format with f-strings - split into lines less than ~80 characters long --- src/conf_mode/interfaces-tunnel.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py index 57bc3b8e0..f4cd53981 100755 --- a/src/conf_mode/interfaces-tunnel.py +++ b/src/conf_mode/interfaces-tunnel.py @@ -436,11 +436,14 @@ def verify(conf): if changes['section'] == 'delete': if ifname in options['nhrp']: - raise ConfigError(f'Can not delete interface tunnel {iftype} {ifname}, it is used by nhrp') + raise ConfigError(( + f'Cannot delete interface tunnel {iftype} {ifname}, ' + 'it is used by NHRP')) - bridge = options['bridge'] - if bridge: - raise ConfigError(f'Interface "{ifname}" can not be deleted as it belongs to bridge "{bridge}"!') + if options['bridge']: + raise ConfigError(( + f'Cannot delete interface "{options["ifname"]}" as it is a ' + f'member of bridge "{options["bridge"]}"!')) # done, bail out early return None -- cgit v1.2.3 From 1a170e9172eac154322c49d8c196e09f5804bc4a Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 19:54:53 +0200 Subject: vxlan: T2241: make address and bridge membership mutually exclusive Bridge members should not have any addresses assigned. --- src/conf_mode/interfaces-vxlan.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py index 334e418ab..5bf1f2fb6 100755 --- a/src/conf_mode/interfaces-vxlan.py +++ b/src/conf_mode/interfaces-vxlan.py @@ -122,7 +122,8 @@ def get_config(): vxlan['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64') # Remove the default link-local address if set. - if not conf.exists('ipv6 address no-default-link-local'): + if not ( conf.exists('ipv6 address no-default-link-local') + or vxlan['is_bridge_member'] ): # add the link-local by default to make IPv6 work vxlan['ipv6_eui64_prefix'].append('fe80::/64') @@ -194,6 +195,14 @@ def verify(vxlan): raise ConfigError('VXLAN has a 50 byte overhead, underlaying device ' \ 'MTU is to small ({})'.format(underlay_mtu)) + if ( vxlan['is_bridge_member'] + and ( vxlan['address'] + or vxlan['ipv6_eui64_prefix'] + or vxlan['ipv6_autoconf'] ) ): + raise ConfigError(( + f'Cannot assign address to interface "{vxlan["intf"]}" ' + f'as it is a member of bridge "{vxlan["is_bridge_member"]}"!')) + return None -- cgit v1.2.3 From 3a3b3c3ffaea0a6e77f6dbf5ee6a3de121b5b9a9 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 19:55:48 +0200 Subject: vxlan: T2241: fix falling out of bridge when changing settings Previously, the interface was always deleted and recreated, which removed it from the bridge. - always re-add the interface back to any bridge it is part of --- src/conf_mode/interfaces-vxlan.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py index 5bf1f2fb6..8abd2b46e 100755 --- a/src/conf_mode/interfaces-vxlan.py +++ b/src/conf_mode/interfaces-vxlan.py @@ -274,6 +274,10 @@ def apply(vxlan): if not vxlan['disable']: v.set_admin_state('up') + # re-add ourselves to any bridge we might have fallen out of + if vxlan['is_bridge_member']: + v.add_to_bridge(vxlan['is_bridge_member']) + return None -- cgit v1.2.3 From 08bb34e392989ccefa4706ac017449148e8f61fe Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 19:56:47 +0200 Subject: vxlan: T2241: cleanup verify section - make error output more user friendly - replace .format with f-strings - split into lines less than ~80 characters long --- src/conf_mode/interfaces-vxlan.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py index 8abd2b46e..fabfaa9df 100755 --- a/src/conf_mode/interfaces-vxlan.py +++ b/src/conf_mode/interfaces-vxlan.py @@ -165,9 +165,9 @@ def get_config(): def verify(vxlan): if vxlan['deleted']: if vxlan['is_bridge_member']: - interface = vxlan['intf'] - bridge = vxlan['is_bridge_member'] - raise ConfigError(f'Interface "{interface}" can not be deleted as it belongs to bridge "{bridge}"!') + raise ConfigError(( + f'Cannot delete interface "{vxlan["intf"]}" as it is a ' + f'member of bridge "{vxlan["is_bridge_member"]}"!') return None -- cgit v1.2.3 From 4efdaa11523d4fed36f2ea73bd1aed4c4186faa7 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 19:58:30 +0200 Subject: wireguard: T2241: make VRF and bridge membership mutually exclusive --- src/conf_mode/interfaces-wireguard.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-wireguard.py b/src/conf_mode/interfaces-wireguard.py index 98d5fcb27..3fb527401 100755 --- a/src/conf_mode/interfaces-wireguard.py +++ b/src/conf_mode/interfaces-wireguard.py @@ -38,8 +38,8 @@ default_config_data = { 'listen_port': '', 'deleted': False, 'disable': False, - 'is_bridge_member': False, 'fwmark': 0, + 'is_bridge_member': False, 'mtu': 1420, 'peer': [], 'peer_remove': [], # stores public keys of peers to remove @@ -200,9 +200,15 @@ def verify(wg): return None - vrf_name = wg['vrf'] - if vrf_name and vrf_name not in interfaces(): - raise ConfigError(f'VRF "{vrf_name}" does not exist') + if wg['vrf']: + if wg['vrf'] not in interfaces(): + raise ConfigError(f'VRF "{wg["vrf"]}" does not exist') + + if wg['is_bridge_member']: + raise ConfigError(( + f'Interface "{wg["intf"]}" cannot be member of VRF ' + f'"{wg["vrf"]}" and bridge {wg["is_bridge_member"]} ' + f'at the same time!')) if not os.path.exists(wg['pk']): raise ConfigError('No keys found, generate them by executing:\n' \ -- cgit v1.2.3 From 56caf9cc1e980f5b2e03b930a5411a94190fbba7 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 19:59:17 +0200 Subject: wireguard: T2241: make address and bridge membership mutually exclusive Bridge members should not have any addresses assigned. --- src/conf_mode/interfaces-wireguard.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-wireguard.py b/src/conf_mode/interfaces-wireguard.py index 3fb527401..3b18f8a15 100755 --- a/src/conf_mode/interfaces-wireguard.py +++ b/src/conf_mode/interfaces-wireguard.py @@ -200,6 +200,11 @@ def verify(wg): return None + if wg['is_bridge_member'] and wg['address']: + raise ConfigError(( + f'Cannot assign address to interface "{wg["intf"]}" ' + f'as it is a member of bridge "{wg["is_bridge_member"]}"!')) + if wg['vrf']: if wg['vrf'] not in interfaces(): raise ConfigError(f'VRF "{wg["vrf"]}" does not exist') -- cgit v1.2.3 From 5b628a395fca837f9e0b3fde180c11ce0eac16a5 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 19:59:53 +0200 Subject: wireguard: T2241: fix falling out of bridge when changing settings Previously, set_vrf was always called, which uses the same master and nomaster commands as bridge, so it removed the interface from the bridge. - add checks to make VRF and bridge membership mutually exclusive --- src/conf_mode/interfaces-wireguard.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-wireguard.py b/src/conf_mode/interfaces-wireguard.py index 3b18f8a15..2065278fd 100755 --- a/src/conf_mode/interfaces-wireguard.py +++ b/src/conf_mode/interfaces-wireguard.py @@ -264,8 +264,10 @@ def apply(wg): # update interface description used e.g. within SNMP w.set_alias(wg['description']) - # assign/remove VRF - w.set_vrf(wg['vrf']) + # assign/remove VRF (ONLY when not a member of a bridge, + # otherwise 'nomaster' removes it from it) + if not wg['is_bridge_member']: + w.set_vrf(wg['vrf']) # remove peers for pub_key in wg['peer_remove']: -- cgit v1.2.3 From 8bdbf5fa8bf4a0134d373412bfca0a562c615a5d Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 20:00:48 +0200 Subject: wireguard: T2241: cleanup verify section - make error output more user friendly - replace .format with f-strings - split into lines less than ~80 characters long --- src/conf_mode/interfaces-wireguard.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-wireguard.py b/src/conf_mode/interfaces-wireguard.py index 2065278fd..820b0a724 100755 --- a/src/conf_mode/interfaces-wireguard.py +++ b/src/conf_mode/interfaces-wireguard.py @@ -190,13 +190,11 @@ def get_config(): def verify(wg): - interface = wg['intf'] - if wg['deleted']: if wg['is_bridge_member']: - interface = wg['intf'] - bridge = wg['is_bridge_member'] - raise ConfigError(f'Interface "{interface}" can not be deleted as it belongs to bridge "{bridge}"!') + raise ConfigError(( + f'Cannot delete interface "{wg["intf"]}" as it is a member ' + f'of bridge "{wg["is_bridge_member"]}"!')) return None @@ -220,25 +218,24 @@ def verify(wg): '"run generate wireguard [keypair|named-keypairs]"') if not wg['address']: - raise ConfigError(f'IP address required for interface "{interface}"!') + raise ConfigError(f'IP address required for interface "{wg["intf"]}"!') if not wg['peer']: - raise ConfigError(f'Peer required for interface "{interface}"!') + raise ConfigError(f'Peer required for interface "{wg["intf"]}"!') # run checks on individual configured WireGuard peer for peer in wg['peer']: - peer_name = peer['name'] if not peer['allowed-ips']: - raise ConfigError(f'Peer allowed-ips required for peer "{peer_name}"!') + raise ConfigError(f'Peer allowed-ips required for peer "{peer["name"]}"!') if not peer['pubkey']: - raise ConfigError(f'Peer public-key required for peer "{peer_name}"!') + raise ConfigError(f'Peer public-key required for peer "{peer["name"]}"!') if peer['address'] and not peer['port']: - raise ConfigError(f'Peer "{peer_name}" port must be defined if address is defined!') + raise ConfigError(f'Peer "{peer["name"]}" port must be defined if address is defined!') if not peer['address'] and peer['port']: - raise ConfigError(f'Peer "{peer_name}" address must be defined if port is defined!') + raise ConfigError(f'Peer "{peer["name"]}" address must be defined if port is defined!') def apply(wg): -- cgit v1.2.3 From 366a53072f40f9ffbf05800787dc7faef5e489e2 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 20:01:54 +0200 Subject: wireless: T2241: make VRF and bridge membership mutually exclusive --- src/conf_mode/interfaces-wireless.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py index 04125ff31..319685fbd 100755 --- a/src/conf_mode/interfaces-wireless.py +++ b/src/conf_mode/interfaces-wireless.py @@ -599,9 +599,15 @@ def verify(wifi): if not radius['key']: raise ConfigError('Misssing RADIUS shared secret key for server: {}'.format(radius['server'])) - vrf_name = wifi['vrf'] - if vrf_name and vrf_name not in interfaces(): - raise ConfigError(f'VRF "{vrf_name}" does not exist') + if wifi['vrf']: + if wifi['vrf'] not in interfaces(): + raise ConfigError(f'VRF "{wifi["vrf"]}" does not exist') + + if wifi['is_bridge_member']: + raise ConfigError(( + f'Interface "{wifi["intf"]}" cannot be member of VRF ' + f'"{wifi["vrf"]}" and bridge {wifi["is_bridge_member"]} ' + f'at the same time!')) # use common function to verify VLAN configuration verify_vlan_config(wifi) -- cgit v1.2.3 From 91762a9c10d3cc047c5a0938fe9827688fcdd5c0 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 20:02:34 +0200 Subject: wireless: T2241: make address and bridge membership mutually exclusive Bridge members should not have any addresses assigned. --- src/conf_mode/interfaces-wireless.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py index 319685fbd..99f5323d6 100755 --- a/src/conf_mode/interfaces-wireless.py +++ b/src/conf_mode/interfaces-wireless.py @@ -379,8 +379,8 @@ def get_config(): eff_addr = conf.return_effective_values('ipv6 address eui64') wifi['ipv6_eui64_prefix_remove'] = list_diff(eff_addr, wifi['ipv6_eui64_prefix']) - # Remove the default link-local address if set. - if conf.exists('ipv6 address no-default-link-local'): + # Remove the default link-local address if set or if member of a bridge + if conf.exists('ipv6 address no-default-link-local') or wifi['is_bridge_member']: wifi['ipv6_eui64_prefix_remove'].append('fe80::/64') else: # add the link-local by default to make IPv6 work @@ -599,6 +599,14 @@ def verify(wifi): if not radius['key']: raise ConfigError('Misssing RADIUS shared secret key for server: {}'.format(radius['server'])) + if ( wifi['is_bridge_member'] + and ( wifi['address'] + or wifi['ipv6_eui64_prefix'] + or wifi['ipv6_autoconf'] ) ): + raise ConfigError(( + f'Cannot assign address to interface "{wifi["intf"]}" ' + f'as it is a member of bridge "{wifi["is_bridge_member"]}"!')) + if wifi['vrf']: if wifi['vrf'] not in interfaces(): raise ConfigError(f'VRF "{wifi["vrf"]}" does not exist') -- cgit v1.2.3 From 0e369db49f7b51c175a458dbc32215fbed4ad5a0 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 20:03:02 +0200 Subject: wireless: T2241: fix falling out of bridge when changing settings Previously, set_vrf was always called, which uses the same master and nomaster commands as bridge, so it removed the interface from the bridge. - add checks to make VRF and bridge membership mutually exclusive --- src/conf_mode/interfaces-wireless.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py index 99f5323d6..962238273 100755 --- a/src/conf_mode/interfaces-wireless.py +++ b/src/conf_mode/interfaces-wireless.py @@ -706,8 +706,10 @@ def apply(wifi): # Finally create the new interface w = WiFiIf(interface, **conf) - # assign/remove VRF - w.set_vrf(wifi['vrf']) + # assign/remove VRF (ONLY when not a member of a bridge, + # otherwise 'nomaster' removes it from it) + if not wifi['is_bridge_member']: + w.set_vrf(wifi['vrf']) # update interface description used e.g. within SNMP w.set_alias(wifi['description']) -- cgit v1.2.3 From ab478417b027ca650563552c11af97742930a451 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 20:04:28 +0200 Subject: wireless: T2241: cleanup verify section - make error output more user friendly - replace .format with f-strings - split into lines less than ~80 characters long --- src/conf_mode/interfaces-wireless.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py index 962238273..4d61dc303 100755 --- a/src/conf_mode/interfaces-wireless.py +++ b/src/conf_mode/interfaces-wireless.py @@ -552,9 +552,9 @@ def get_config(): def verify(wifi): if wifi['deleted']: if wifi['is_bridge_member']: - interface = wifi['intf'] - bridge = wifi['is_bridge_member'] - raise ConfigError(f'Interface "{interface}" can not be deleted as it belongs to bridge "{bridge}"!') + raise ConfigError(( + f'Cannot delete interface "{wifi["intf"]}" as it is a ' + f'member of bridge "{wifi["is_bridge_member"]}"!')) return None -- cgit v1.2.3 From 2cb8062719280b9695b3e50c6cfa7c6997309bbc Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 20:05:17 +0200 Subject: wirelessmodem: T2241: make VRF and bond/bridge membership mutually exclusive --- src/conf_mode/interfaces-wirelessmodem.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-wirelessmodem.py b/src/conf_mode/interfaces-wirelessmodem.py index 03832f345..2e25c33a9 100755 --- a/src/conf_mode/interfaces-wirelessmodem.py +++ b/src/conf_mode/interfaces-wirelessmodem.py @@ -134,9 +134,15 @@ def verify(wwan): if not os.path.exists(f"/dev/{wwan['device']}"): raise ConfigError(f"Device {wwan['device']} does not exist") - vrf_name = wwan['vrf'] - if vrf_name and vrf_name not in interfaces(): - raise ConfigError(f'VRF {vrf_name} does not exist') + if wwan['vrf']: + if wwan['vrf'] not in interfaces(): + raise ConfigError(f'VRF "{wwan["vrf"]}" does not exist') + + if wwan['is_bridge_member']: + raise ConfigError(( + f'Interface "{wwan["intf"]}" cannot be member of VRF ' + f'"{wwan["vrf"]}" and bridge {wwan["is_bridge_member"]} ' + f'at the same time!')) return None -- cgit v1.2.3 From 9282b705afa350c49bfef4bdd46bf96c19aef5a0 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 20:06:42 +0200 Subject: wirelessmodem: T2241: make address and bridge membership mutually exclusive Bridge members should not have any addresses assigned. --- src/conf_mode/interfaces-wirelessmodem.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-wirelessmodem.py b/src/conf_mode/interfaces-wirelessmodem.py index 2e25c33a9..313d19470 100755 --- a/src/conf_mode/interfaces-wirelessmodem.py +++ b/src/conf_mode/interfaces-wirelessmodem.py @@ -134,6 +134,11 @@ def verify(wwan): if not os.path.exists(f"/dev/{wwan['device']}"): raise ConfigError(f"Device {wwan['device']} does not exist") + if wwan['is_bridge_member'] and wwan['address']: + raise ConfigError(( + f'Cannot assign address to interface "{wwan["intf"]}" ' + f'as it is a member of bridge "{wwan["is_bridge_member"]}"!')) + if wwan['vrf']: if wwan['vrf'] not in interfaces(): raise ConfigError(f'VRF "{wwan["vrf"]}" does not exist') -- cgit v1.2.3 From bca5864a1b1182b9c2b2949cddfb715f51535ffb Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 20:07:25 +0200 Subject: wirelessmodem: T2241: fix falling out of bridge when changing settings Previously, the interface was always deleted and recreated, which removed it from the bridge. - always re-add the interface back to any bridge it is part of --- src/conf_mode/interfaces-wirelessmodem.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-wirelessmodem.py b/src/conf_mode/interfaces-wirelessmodem.py index 313d19470..cf2945593 100755 --- a/src/conf_mode/interfaces-wirelessmodem.py +++ b/src/conf_mode/interfaces-wirelessmodem.py @@ -21,6 +21,7 @@ from copy import deepcopy from netifaces import interfaces from vyos.config import Config +from vyos.ifconfig import BridgeIf, Section from vyos.template import render from vyos.util import chown, chmod_755, cmd, call from vyos.validate import is_member @@ -205,6 +206,12 @@ def apply(wwan): # make logfile owned by root / vyattacfg chown(wwan['logfile'], 'root', 'vyattacfg') + # re-add ourselves to any bridge we might have fallen out of + # FIXME: wwan isn't under vyos.ifconfig so we can't call + # Interfaces.add_to_bridge() so STP settings won't get applied + if wwan['is_bridge_member'] in Section.interfaces('bridge'): + BridgeIf(wwan['is_bridge_member'], create=False).add_port(wwan['intf']) + return None if __name__ == '__main__': -- cgit v1.2.3 From 6c8c129c78d084dd3e3b4dfeb7e7aa1b386370b8 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Fri, 1 May 2020 20:08:06 +0200 Subject: wirelessmodem: T2241: cleanup verify section - make error output more user friendly - replace .format with f-strings - split into lines less than ~80 characters long --- src/conf_mode/interfaces-wirelessmodem.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-wirelessmodem.py b/src/conf_mode/interfaces-wirelessmodem.py index cf2945593..975e21d9f 100755 --- a/src/conf_mode/interfaces-wirelessmodem.py +++ b/src/conf_mode/interfaces-wirelessmodem.py @@ -121,9 +121,9 @@ def get_config(): def verify(wwan): if wwan['deleted']: if wwan['is_bridge_member']: - interface = wwan['intf'] - bridge = wwan['is_bridge_member'] - raise ConfigError(f'Interface "{interface}" can not be deleted as it belongs to bridge "{bridge}"!') + raise ConfigError(( + f'Cannot delete interface "{wwan["intf"]}" as it is a ' + f'member of bridge "{wwan["is_bridge_member"]}"!')) return None -- cgit v1.2.3 From b38326721ce6448a865100a7da200a291388c029 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Sat, 2 May 2020 15:11:48 +0200 Subject: bonding: T2367: use simple 'ip addr flush' to flush member addresses We've already verified that all member interfaces don't have any addresses configured, so it should be safe to simply call 'ip addr flush' on them to flush the remaining addresses (e.g. IPv6 link-local) --- src/conf_mode/interfaces-bonding.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py index a8900ac76..82b7c0f2a 100755 --- a/src/conf_mode/interfaces-bonding.py +++ b/src/conf_mode/interfaces-bonding.py @@ -20,7 +20,7 @@ from copy import deepcopy from sys import exit from netifaces import interfaces -from vyos.ifconfig import BondIf, Section +from vyos.ifconfig import BondIf from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config from vyos.configdict import list_diff, intf_to_dict, add_to_dict from vyos.config import Config @@ -381,12 +381,9 @@ def apply(bond): # Add (enslave) interfaces to bond for intf in bond['member']: - # flushes only children of Interfaces class (e.g. vlan are not) - if intf in Section.interfaces(): - klass = Section.klass(intf, vlan=False) - klass(intf, create=False).flush_addrs() - # flushes also vlan interfaces - call(f'ip addr flush dev "{intf}"') + # if we've come here we already verified the interface doesn't + # have addresses configured so just flush any remaining ones + cmd(f'ip addr flush dev "{intf}"') b.add_port(intf) # As the bond interface is always disabled first when changing -- cgit v1.2.3 From b16dc5044eb9735c51ea211ea00fa35297d921f3 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Sat, 2 May 2020 15:54:42 +0200 Subject: bridge: T2367: use simple 'ip addr flush' to flush member addresses We've already verified that all member interfaces don't have any addresses configured, so it should be safe to simply call 'ip addr flush' on them to flush the remaining addresses (e.g. IPv6 link-local) --- src/conf_mode/interfaces-bridge.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-bridge.py b/src/conf_mode/interfaces-bridge.py index fe3675190..c43fae78b 100755 --- a/src/conf_mode/interfaces-bridge.py +++ b/src/conf_mode/interfaces-bridge.py @@ -348,12 +348,8 @@ def apply(bridge): # add interfaces to bridge for member in bridge['member']: - # flushes address of only children of Interfaces class - # (e.g. vlan are not) - if member['name'] in Section.interfaces(): - klass = Section.klass(member['name'], vlan=False) - klass(member['name'], create=False).flush_addrs() - # flushes all interfaces + # if we've come here we already verified the interface doesn't + # have addresses configured so just flush any remaining ones cmd(f'ip addr flush dev "{member["name"]}"') br.add_port(member['name']) -- cgit v1.2.3 From d637a1cd2af0bc6bb2d47b8b661da262892046a2 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Tue, 5 May 2020 16:07:24 +0200 Subject: bonding: T2427: move VLAN adding to common function --- src/conf_mode/interfaces-bonding.py | 36 +++++------------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py index 82b7c0f2a..5a2ff9eef 100755 --- a/src/conf_mode/interfaces-bonding.py +++ b/src/conf_mode/interfaces-bonding.py @@ -21,7 +21,7 @@ from sys import exit from netifaces import interfaces from vyos.ifconfig import BondIf -from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config +from vyos.ifconfig_vlan import apply_all_vlans, verify_vlan_config from vyos.configdict import list_diff, intf_to_dict, add_to_dict from vyos.config import Config from vyos.util import call, cmd @@ -63,9 +63,9 @@ default_config_data = { 'shutdown_required': False, 'mtu': 1500, 'primary': '', - 'vif_s': [], + 'vif_s': {}, 'vif_s_remove': [], - 'vif': [], + 'vif': {}, 'vif_remove': [], 'vrf': '' } @@ -411,34 +411,8 @@ def apply(bond): if bond['is_bridge_member']: b.add_to_bridge(bond['is_bridge_member']) - # remove no longer required service VLAN interfaces (vif-s) - for vif_s in bond['vif_s_remove']: - b.del_vlan(vif_s) - - # create service VLAN interfaces (vif-s) - for vif_s in bond['vif_s']: - s_vlan = b.add_vlan(vif_s['id'], ethertype=vif_s['ethertype']) - apply_vlan_config(s_vlan, vif_s) - - # remove no longer required client VLAN interfaces (vif-c) - # on lower service VLAN interface - for vif_c in vif_s['vif_c_remove']: - s_vlan.del_vlan(vif_c) - - # create client VLAN interfaces (vif-c) - # on lower service VLAN interface - for vif_c in vif_s['vif_c']: - c_vlan = s_vlan.add_vlan(vif_c['id']) - apply_vlan_config(c_vlan, vif_c) - - # remove no longer required VLAN interfaces (vif) - for vif in bond['vif_remove']: - b.del_vlan(vif) - - # create VLAN interfaces (vif) - for vif in bond['vif']: - vlan = b.add_vlan(vif['id']) - apply_vlan_config(vlan, vif) + # apply all vlans to interface + apply_all_vlans(b, bond) return None -- cgit v1.2.3 From 8abba78e5571d3fbcb2c51a1165b0e879a5dbd02 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Tue, 5 May 2020 16:08:28 +0200 Subject: ethernet: T2427: move VLAN adding to common function --- src/conf_mode/interfaces-ethernet.py | 46 ++++-------------------------------- 1 file changed, 5 insertions(+), 41 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py index 9b9ae931c..955022042 100755 --- a/src/conf_mode/interfaces-ethernet.py +++ b/src/conf_mode/interfaces-ethernet.py @@ -21,7 +21,7 @@ from copy import deepcopy from netifaces import interfaces from vyos.ifconfig import EthernetIf -from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config +from vyos.ifconfig_vlan import apply_all_vlans, verify_vlan_config from vyos.configdict import list_diff, intf_to_dict, add_to_dict from vyos.validate import is_member from vyos.config import Config @@ -65,9 +65,9 @@ default_config_data = { 'offload_tso': 'off', 'offload_ufo': 'off', 'speed': 'auto', - 'vif_s': [], + 'vif_s': {}, 'vif_s_remove': [], - 'vif': [], + 'vif': {}, 'vif_remove': [], 'vrf': '' } @@ -306,44 +306,8 @@ def apply(eth): if eth['is_bridge_member']: e.add_to_bridge(eth['is_bridge_member']) - # remove no longer required service VLAN interfaces (vif-s) - for vif_s in eth['vif_s_remove']: - e.del_vlan(vif_s) - - # create service VLAN interfaces (vif-s) - for vif_s in eth['vif_s']: - s_vlan = e.add_vlan(vif_s['id'], ethertype=vif_s['ethertype']) - apply_vlan_config(s_vlan, vif_s) - - # remove no longer required client VLAN interfaces (vif-c) - # on lower service VLAN interface - for vif_c in vif_s['vif_c_remove']: - s_vlan.del_vlan(vif_c) - - # create client VLAN interfaces (vif-c) - # on lower service VLAN interface - for vif_c in vif_s['vif_c']: - c_vlan = s_vlan.add_vlan(vif_c['id']) - apply_vlan_config(c_vlan, vif_c) - - # remove no longer required VLAN interfaces (vif) - for vif in eth['vif_remove']: - e.del_vlan(vif) - - # create VLAN interfaces (vif) - for vif in eth['vif']: - # QoS priority mapping can only be set during interface creation - # so we delete the interface first if required. - if vif['egress_qos_changed'] or vif['ingress_qos_changed']: - try: - # on system bootup the above condition is true but the interface - # does not exists, which throws an exception, but that's legal - e.del_vlan(vif['id']) - except: - pass - - vlan = e.add_vlan(vif['id'], ingress_qos=vif['ingress_qos'], egress_qos=vif['egress_qos']) - apply_vlan_config(vlan, vif) + # apply all vlans to interface + apply_all_vlans(e, eth) return None -- cgit v1.2.3 From d6a93991d1a3a5e4575ccd3d586e9f8f48234544 Mon Sep 17 00:00:00 2001 From: Jernej Jakob Date: Tue, 5 May 2020 16:09:42 +0200 Subject: pseudo-ethernet: T2427: move VLAN adding to common function --- src/conf_mode/interfaces-pseudo-ethernet.py | 36 ++++------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-pseudo-ethernet.py b/src/conf_mode/interfaces-pseudo-ethernet.py index 1d04d6dbe..4063b85b0 100755 --- a/src/conf_mode/interfaces-pseudo-ethernet.py +++ b/src/conf_mode/interfaces-pseudo-ethernet.py @@ -23,7 +23,7 @@ from netifaces import interfaces from vyos.config import Config from vyos.configdict import list_diff, intf_to_dict, add_to_dict from vyos.ifconfig import MACVLANIf, Section -from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config +from vyos.ifconfig_vlan import apply_all_vlans, verify_vlan_config from vyos import ConfigError default_config_data = { @@ -56,9 +56,9 @@ default_config_data = { 'source_interface_changed': False, 'mac': '', 'mode': 'private', - 'vif_s': [], + 'vif_s': {}, 'vif_s_remove': [], - 'vif': [], + 'vif': {}, 'vif_remove': [], 'vrf': '' } @@ -253,34 +253,8 @@ def apply(peth): if peth['is_bridge_member']: p.add_to_bridge(peth['is_bridge_member']) - # remove no longer required service VLAN interfaces (vif-s) - for vif_s in peth['vif_s_remove']: - p.del_vlan(vif_s) - - # create service VLAN interfaces (vif-s) - for vif_s in peth['vif_s']: - s_vlan = p.add_vlan(vif_s['id'], ethertype=vif_s['ethertype']) - apply_vlan_config(s_vlan, vif_s) - - # remove no longer required client VLAN interfaces (vif-c) - # on lower service VLAN interface - for vif_c in vif_s['vif_c_remove']: - s_vlan.del_vlan(vif_c) - - # create client VLAN interfaces (vif-c) - # on lower service VLAN interface - for vif_c in vif_s['vif_c']: - c_vlan = s_vlan.add_vlan(vif_c['id']) - apply_vlan_config(c_vlan, vif_c) - - # remove no longer required VLAN interfaces (vif) - for vif in peth['vif_remove']: - p.del_vlan(vif) - - # create VLAN interfaces (vif) - for vif in peth['vif']: - vlan = p.add_vlan(vif['id']) - apply_vlan_config(vlan, vif) + # apply all vlans to interface + apply_all_vlans(b, bond) return None -- cgit v1.2.3 From d55050dcb8806a982b0394dcde00c1814499d9f3 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 6 May 2020 21:41:15 +0200 Subject: sstp: T2392: add initial IPv6 support New commands added: * set vpn sstp network-settings client-ipv6-pool prefix 2001:db8::/64 mask 112 * set vpn sstp network-settings client-ipv6-pool delegate 2001:db8:100::/48 delegation-prefix 64 --- data/templates/accel-ppp/sstp.config.tmpl | 21 +++++++++++++++ interface-definitions/vpn_sstp.xml.in | 1 + src/conf_mode/vpn_sstp.py | 43 ++++++++++++++++++++++++++++--- 3 files changed, 62 insertions(+), 3 deletions(-) (limited to 'src/conf_mode') diff --git a/data/templates/accel-ppp/sstp.config.tmpl b/data/templates/accel-ppp/sstp.config.tmpl index c3dc83429..e0a48a44e 100644 --- a/data/templates/accel-ppp/sstp.config.tmpl +++ b/data/templates/accel-ppp/sstp.config.tmpl @@ -9,6 +9,9 @@ chap-secrets radius {% endif -%} ippool +ipv6pool +ipv6_nd +ipv6_dhcp {% for proto in auth_proto %} {{proto}} @@ -87,6 +90,9 @@ check-ip=1 {% if mtu %} mtu={{ mtu }} {% endif -%} +{% if client_ipv6_pool %} +ipv6=allow +{% endif %} {% if ppp_mppe %} mppe={{ ppp_mppe }} @@ -101,6 +107,21 @@ lcp-echo-failure={{ ppp_echo_failure }} lcp-echo-timeout={{ ppp_echo_timeout }} {% endif %} +{% if client_ipv6_pool %} +[ipv6-pool] +{% for p in client_ipv6_pool %} +{{ p.prefix }},{{ p.mask }} +{% endfor %} +{% for p in client_ipv6_delegate_prefix %} +delegate={{ p.prefix }},{{ p.mask }} +{% endfor %} +{% endif %} + +{% if client_ipv6_delegate_prefix %} +[ipv6-dhcp] +verbose=1 +{% endif %} + {% if radius_shaper_attr %} [shaper] verbose=1 diff --git a/interface-definitions/vpn_sstp.xml.in b/interface-definitions/vpn_sstp.xml.in index 7e4471015..4ce231e0f 100644 --- a/interface-definitions/vpn_sstp.xml.in +++ b/interface-definitions/vpn_sstp.xml.in @@ -220,6 +220,7 @@ + #include #include diff --git a/src/conf_mode/vpn_sstp.py b/src/conf_mode/vpn_sstp.py index d250cd3b0..6d9496012 100755 --- a/src/conf_mode/vpn_sstp.py +++ b/src/conf_mode/vpn_sstp.py @@ -35,7 +35,11 @@ default_config_data = { 'auth_mode' : 'local', 'auth_proto' : ['auth_mschap_v2'], 'chap_secrets_file': sstp_chap_secrets, # used in Jinja2 template + 'client_ip_pool' : [], + 'client_ipv6_pool': [], + 'client_ipv6_delegate_prefix': [], 'client_gateway': '', + 'dnsv4' : [], 'radius_server' : [], 'radius_acct_tmo' : '3', 'radius_max_try' : '3', @@ -49,8 +53,6 @@ default_config_data = { 'ssl_ca' : '', 'ssl_cert' : '', 'ssl_key' : '', - 'client_ip_pool' : [], - 'dnsv4' : [], 'mtu' : '', 'ppp_mppe' : 'prefer', 'ppp_echo_failure' : '', @@ -210,7 +212,7 @@ def get_config(): # - # read in client ip pool settings + # read in client IPv4 pool conf.set_level(base_path + ['network-settings', 'client-ip-settings']) if conf.exists(['subnet']): sstp['client_ip_pool'] = conf.return_values(['subnet']) @@ -218,6 +220,33 @@ def get_config(): if conf.exists(['gateway-address']): sstp['client_gateway'] = conf.return_value(['gateway-address']) + # + # read in client IPv6 pool + conf.set_level(base_path + ['network-settings', 'client-ipv6-pool']) + if conf.exists(['prefix']): + for prefix in conf.list_nodes(['prefix']): + tmp = { + 'prefix': prefix, + 'mask': '64' + } + + if conf.exists(['prefix', prefix, 'mask']): + tmp['mask'] = conf.return_value(['prefix', prefix, 'mask']) + + sstp['client_ipv6_pool'].append(tmp) + + if conf.exists(['delegate']): + for prefix in conf.list_nodes(['delegate']): + tmp = { + 'prefix': prefix, + 'mask': '' + } + + if conf.exists(['delegate', prefix, 'delegation-prefix']): + tmp['mask'] = conf.return_value(['delegate', prefix, 'delegation-prefix']) + + sstp['client_ipv6_delegate_prefix'].append(tmp) + # # read in network settings conf.set_level(base_path + ['network-settings']) @@ -275,6 +304,14 @@ def verify(sstp): if len(sstp['dnsv4']) > 2: raise ConfigError('Not more then two IPv4 DNS name-servers can be configured') + # check ipv6 + if sstp['client_ipv6_delegate_prefix'] and not sstp['client_ipv6_pool']: + raise ConfigError('IPv6 prefix delegation requires client-ipv6-pool prefix') + + for prefix in sstp['client_ipv6_delegate_prefix']: + if not prefix['mask']: + raise ConfigError('Delegation-prefix required for individual delegated networks') + if not sstp['ssl_ca'] or not sstp['ssl_cert'] or not sstp['ssl_key']: raise ConfigError('One or more SSL certificates missing') -- cgit v1.2.3 From ed22334321d3b6f27b5d695a4f984257b909f78b Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 6 May 2020 21:44:07 +0200 Subject: sstp: T2392: add IPv6 DNS support New command added: * set vpn sstp network-settings name-server 2001:db8::1111 --- data/templates/accel-ppp/sstp.config.tmpl | 8 ++++++++ interface-definitions/vpn_sstp.xml.in | 14 +------------- src/conf_mode/vpn_sstp.py | 13 +++++++++---- 3 files changed, 18 insertions(+), 17 deletions(-) (limited to 'src/conf_mode') diff --git a/data/templates/accel-ppp/sstp.config.tmpl b/data/templates/accel-ppp/sstp.config.tmpl index e0a48a44e..411fca489 100644 --- a/data/templates/accel-ppp/sstp.config.tmpl +++ b/data/templates/accel-ppp/sstp.config.tmpl @@ -54,6 +54,14 @@ dns{{ loop.index }}={{ dns }} {% endfor -%} {% endif %} +{% if dnsv6 %} +[ipv6-dns] +{% for dns in dnsv6 -%} +{{ dns }} +{% endfor -%} +{% endif %} + + {% if auth_mode == 'local' %} [chap-secrets] chap-secrets={{ chap_secrets_file }} diff --git a/interface-definitions/vpn_sstp.xml.in b/interface-definitions/vpn_sstp.xml.in index 4ce231e0f..f0c93b882 100644 --- a/interface-definitions/vpn_sstp.xml.in +++ b/interface-definitions/vpn_sstp.xml.in @@ -207,20 +207,8 @@ - - - DNS servers propagated to clients - - ipv4 - IPv4 address - - - - - - - #include + #include #include diff --git a/src/conf_mode/vpn_sstp.py b/src/conf_mode/vpn_sstp.py index 6d9496012..7c3e3f515 100755 --- a/src/conf_mode/vpn_sstp.py +++ b/src/conf_mode/vpn_sstp.py @@ -22,10 +22,10 @@ from copy import deepcopy from stat import S_IRUSR, S_IWUSR, S_IRGRP from vyos.config import Config -from vyos import ConfigError -from vyos.util import call, run, get_half_cpus from vyos.template import render - +from vyos.util import call, run, get_half_cpus +from vyos.validate import is_ipv4 +from vyos import ConfigError sstp_conf = '/run/accel-pppd/sstp.conf' sstp_chap_secrets = '/run/accel-pppd/sstp.chap-secrets' @@ -40,6 +40,7 @@ default_config_data = { 'client_ipv6_delegate_prefix': [], 'client_gateway': '', 'dnsv4' : [], + 'dnsv6' : [], 'radius_server' : [], 'radius_acct_tmo' : '3', 'radius_max_try' : '3', @@ -251,7 +252,11 @@ def get_config(): # read in network settings conf.set_level(base_path + ['network-settings']) if conf.exists(['name-server']): - sstp['dnsv4'] = conf.return_values(['name-server']) + for name_server in conf.return_values(['name-server']): + if is_ipv4(name_server): + sstp['dnsv4'].append(name_server) + else: + sstp['dnsv6'].append(name_server) if conf.exists(['mtu']): sstp['mtu'] = conf.return_value(['mtu']) -- cgit v1.2.3