From 0e19d622a04100f7b6e53b3fe601873412609057 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 19 Apr 2020 11:55:09 +0200 Subject: bridge: T2232: move helper to vyos.validate --- python/vyos/util.py | 18 ---------------- python/vyos/validate.py | 29 +++++++++++++++++++++++-- src/conf_mode/interfaces-bonding.py | 18 ++++++++-------- src/conf_mode/interfaces-dummy.py | 17 ++++++++------- src/conf_mode/interfaces-geneve.py | 17 ++++++++------- src/conf_mode/interfaces-l2tpv3.py | 33 +++++++++++++++-------------- src/conf_mode/interfaces-openvpn.py | 22 +++++++++---------- src/conf_mode/interfaces-pseudo-ethernet.py | 23 ++++++++++---------- src/conf_mode/interfaces-vxlan.py | 19 +++++++++-------- src/conf_mode/interfaces-wireguard.py | 18 +++++++++------- src/conf_mode/interfaces-wireless.py | 22 +++++++++---------- src/conf_mode/interfaces-wirelessmodem.py | 25 ++++++++++------------ 12 files changed, 136 insertions(+), 125 deletions(-) diff --git a/python/vyos/util.py b/python/vyos/util.py index c70bff091..b1d95fbbf 100644 --- a/python/vyos/util.py +++ b/python/vyos/util.py @@ -429,24 +429,6 @@ def mac2eui64(mac, prefix=None): except: # pylint: disable=bare-except return -def is_bridge_member(interface): - """ - Checks if passed interfaces is part of a bridge device or not. - - Returns a tuple: - False, None -> Not part of a bridge - True, bridge-name -> If it is assigned to a bridge - """ - from vyos.config import Config - c = Config() - base = ['interfaces', 'bridge'] - for bridge in c.list_nodes(base): - members = c.list_nodes(base + [bridge, 'member', 'interface']) - if interface in members: - return (True, bridge) - - return False, None - def get_half_cpus(): """ return 1/2 of the numbers of available CPUs """ cpu = os.cpu_count() diff --git a/python/vyos/validate.py b/python/vyos/validate.py index 9d413ffab..15716ada4 100644 --- a/python/vyos/validate.py +++ b/python/vyos/validate.py @@ -86,8 +86,8 @@ def _is_intf_addr_assigned(intf, address, netmask=''): # check if the requested address type is configured at all # { - # 17: [{'addr': '08:00:27:d9:5b:04', 'broadcast': 'ff:ff:ff:ff:ff:ff'}], - # 2: [{'addr': '10.0.2.15', 'netmask': '255.255.255.0', 'broadcast': '10.0.2.255'}], + # 17: [{'addr': '08:00:27:d9:5b:04', 'broadcast': 'ff:ff:ff:ff:ff:ff'}], + # 2: [{'addr': '10.0.2.15', 'netmask': '255.255.255.0', 'broadcast': '10.0.2.255'}], # 10: [{'addr': 'fe80::a00:27ff:fed9:5b04%eth0', 'netmask': 'ffff:ffff:ffff:ffff::'}] # } try: @@ -240,3 +240,28 @@ 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): + """ + 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 + """ + ret_val = None + old_level = conf.get_level() + + # set config level to root + conf.set_level([]) + base = ['interfaces', 'bridge'] + for bridge in conf.list_nodes(base): + members = conf.list_nodes(base + [bridge, 'member', 'interface']) + print(members) + if interface in members: + ret_val = bridge + 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 fd1f218d1..380457772 100755 --- a/src/conf_mode/interfaces-bonding.py +++ b/src/conf_mode/interfaces-bonding.py @@ -24,8 +24,8 @@ from vyos.ifconfig import BondIf from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config from vyos.configdict import list_diff, vlan_to_dict from vyos.config import Config -from vyos.util import is_bridge_member from vyos.util import call +from vyos.validate import is_bridge_member from vyos import ConfigError default_config_data = { @@ -43,6 +43,7 @@ default_config_data = { 'disable': False, 'disable_link_detect': 1, 'hash_policy': 'layer2', + 'intf': '', 'ip_arp_cache_tmo': 30, 'ip_disable_arp_filter': 1, 'ip_enable_arp_accept': 0, @@ -54,7 +55,7 @@ default_config_data = { 'ipv6_eui64_prefix': '', 'ipv6_forwarding': 1, 'ipv6_dup_addr_detect': 1, - 'intf': '', + 'is_bridge_member': False, 'mac': '', 'mode': '802.3ad', 'member': [], @@ -109,6 +110,8 @@ def get_config(): cfg_base = 'interfaces bonding ' + bond['intf'] if not conf.exists(cfg_base): bond['deleted'] = True + # check if interface is member if a bridge + bond['is_bridge_member'] = is_bridge_member(conf, bond['intf']) return bond # set new configuration level @@ -279,13 +282,10 @@ def get_config(): def verify(bond): if bond['deleted']: - interface = bond['intf'] - is_member, bridge = is_bridge_member(interface) - if is_member: - # can not use a f'' formatted-string here as bridge would not get - # expanded in the print statement - raise ConfigError('Can not delete interface "{0}" as it ' \ - 'is a member of bridge "{1}"!'.format(interface, bridge)) + 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}"!') return None if len (bond['arp_mon_tgt']) > 16: diff --git a/src/conf_mode/interfaces-dummy.py b/src/conf_mode/interfaces-dummy.py index a256103af..2cc60fb16 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.util import is_bridge_member +from vyos.validate import is_bridge_member from vyos import ConfigError default_config_data = { @@ -33,6 +33,7 @@ default_config_data = { 'description': '', 'disable': False, 'intf': '', + 'is_bridge_member': False, 'vrf': '' } @@ -49,6 +50,8 @@ def get_config(): # 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 @@ -80,13 +83,11 @@ def get_config(): def verify(dummy): if dummy['deleted']: - interface = dummy['intf'] - is_member, bridge = is_bridge_member(interface) - if is_member: - # can not use a f'' formatted-string here as bridge would not get - # expanded in the print statement - raise ConfigError('Can not delete interface "{0}" as it ' \ - 'is a member of bridge "{1}"!'.format(interface, bridge)) + 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}"!') + return None vrf_name = dummy['vrf'] diff --git a/src/conf_mode/interfaces-geneve.py b/src/conf_mode/interfaces-geneve.py index e47473d76..708a64474 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.util import is_bridge_member +from vyos.validate import is_bridge_member from vyos import ConfigError default_config_data = { @@ -33,6 +33,7 @@ default_config_data = { 'intf': '', 'ip_arp_cache_tmo': 30, 'ip_proxy_arp': 0, + 'is_bridge_member': False, 'mtu': 1500, 'remote': '', 'vni': '' @@ -51,6 +52,8 @@ def get_config(): # 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 @@ -93,13 +96,11 @@ def get_config(): def verify(geneve): if geneve['deleted']: - interface = geneve['intf'] - is_member, bridge = is_bridge_member(interface) - if is_member: - # can not use a f'' formatted-string here as bridge would not get - # expanded in the print statement - raise ConfigError('Can not delete interface "{0}" as it ' \ - 'is a member of bridge "{1}"!'.format(interface, bridge)) + 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}"!') + return None if not geneve['remote']: diff --git a/src/conf_mode/interfaces-l2tpv3.py b/src/conf_mode/interfaces-l2tpv3.py index 11ba9acdd..c7c9f6aca 100755 --- a/src/conf_mode/interfaces-l2tpv3.py +++ b/src/conf_mode/interfaces-l2tpv3.py @@ -18,13 +18,13 @@ import os from sys import exit from copy import deepcopy +from netifaces import interfaces from vyos.config import Config from vyos.ifconfig import L2TPv3If, Interface from vyos import ConfigError from vyos.util import call -from vyos.util import is_bridge_member -from netifaces import interfaces +from vyos.validate import is_bridge_member default_config_data = { 'address': [], @@ -39,6 +39,7 @@ default_config_data = { 'ipv6_eui64_prefix': '', 'ipv6_forwarding': 1, 'ipv6_dup_addr_detect': 1, + 'is_bridge_member': False 'mtu': 1488, 'peer_session_id': '', 'peer_tunnel_id': '', @@ -68,15 +69,16 @@ def get_config(): # Check if interface has been removed if not conf.exists('interfaces l2tpv3 ' + l2tpv3['intf']): l2tpv3['deleted'] = True - # to delete the l2tpv3 interface we need to current - # tunnel_id and session_id - if conf.exists_effective('interfaces l2tpv3 {} tunnel-id'.format(l2tpv3['intf'])): - l2tpv3['tunnel_id'] = conf.return_effective_value( - 'interfaces l2tpv3 {} tunnel-id'.format(l2tpv3['intf'])) + interface = l2tpv3['intf'] + # check if interface is member if a bridge + l2tpv3['is_bridge_member'] = is_bridge_member(conf, interface) - if conf.exists_effective('interfaces l2tpv3 {} session-id'.format(l2tpv3['intf'])): - l2tpv3['session_id'] = conf.return_effective_value( - 'interfaces l2tpv3 {} session-id'.format(l2tpv3['intf'])) + # to delete the l2tpv3 interface we need the current tunnel_id and session_id + if conf.exists_effective(f'interfaces l2tpv3 {interface} tunnel-id'): + l2tpv3['tunnel_id'] = conf.return_effective_value(f'interfaces l2tpv3 {interface} tunnel-id') + + if conf.exists_effective(f'interfaces l2tpv3 {interface} session-id'): + l2tpv3['session_id'] = conf.return_effective_value(f'interfaces l2tpv3 {interface} session-id') return l2tpv3 @@ -158,12 +160,11 @@ def verify(l2tpv3): interface = l2tpv3['intf'] if l2tpv3['deleted']: - is_member, bridge = is_bridge_member(interface) - if is_member: - # can not use a f'' formatted-string here as bridge would not get - # expanded in the print statement - raise ConfigError('Can not delete interface "{0}" as it ' \ - 'is a member of bridge "{1}"!'.format(interface, bridge)) + 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}"!') + return None if not l2tpv3['local_address']: diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index 836deb64b..9cea07a61 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.py @@ -26,11 +26,10 @@ from shutil import rmtree from vyos.config import Config from vyos.ifconfig import VTunIf -from vyos.util import call, is_bridge_member, chown, chmod_600, chmod_755 -from vyos.validate import is_addr_assigned -from vyos import ConfigError 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 +from vyos import ConfigError user = 'openvpn' group = 'openvpn' @@ -55,6 +54,7 @@ default_config_data = { 'ipv6_dup_addr_detect': 1, 'ipv6_local_address': [], 'ipv6_remote_address': [], + 'is_bridge_member': False, 'ping_restart': '60', 'ping_interval': '10', 'local_address': [], @@ -197,6 +197,8 @@ def get_config(): # 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 @@ -598,13 +600,11 @@ def get_config(): def verify(openvpn): if openvpn['deleted']: - interface = openvpn['intf'] - is_member, bridge = is_bridge_member(interface) - if is_member: - # can not use a f'' formatted-string here as bridge would not get - # expanded in the print statement - raise ConfigError('Can not delete interface "{0}" as it ' \ - 'is a member of bridge "{1}"!'.format(interface, bridge)) + 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 diff --git a/src/conf_mode/interfaces-pseudo-ethernet.py b/src/conf_mode/interfaces-pseudo-ethernet.py index 655006146..3e5b7be5b 100755 --- a/src/conf_mode/interfaces-pseudo-ethernet.py +++ b/src/conf_mode/interfaces-pseudo-ethernet.py @@ -20,11 +20,11 @@ from copy import deepcopy from sys import exit from netifaces import interfaces +from vyos.config import Config +from vyos.configdict import list_diff, vlan_to_dict from vyos.ifconfig import MACVLANIf from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config -from vyos.configdict import list_diff, vlan_to_dict -from vyos.config import Config -from vyos.util import is_bridge_member +from vyos.validate import is_bridge_member from vyos import ConfigError default_config_data = { @@ -39,6 +39,7 @@ default_config_data = { 'dhcpv6_temporary': False, 'disable': False, 'disable_link_detect': 1, + 'intf': '', 'ip_arp_cache_tmo': 30, 'ip_disable_arp_filter': 1, 'ip_enable_arp_accept': 0, @@ -50,7 +51,7 @@ default_config_data = { 'ipv6_eui64_prefix': '', 'ipv6_forwarding': 1, 'ipv6_dup_addr_detect': 1, - 'intf': '', + 'is_bridge_member': False, 'source_interface': '', 'source_interface_changed': False, 'mac': '', @@ -76,6 +77,8 @@ def get_config(): # Check if interface has been removed if not conf.exists(cfg_base): peth['deleted'] = True + # check if interface is member if a bridge + peth['is_bridge_member'] = is_bridge_member(conf, peth['intf']) return peth # set new configuration level @@ -218,13 +221,11 @@ def get_config(): def verify(peth): if peth['deleted']: - interface = peth['intf'] - is_member, bridge = is_bridge_member(interface) - if is_member: - # can not use a f'' formatted-string here as bridge would not get - # expanded in the print statement - raise ConfigError('Can not delete interface "{0}" as it ' \ - 'is a member of bridge "{1}"!'.format(interface, bridge)) + 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}"!') + return None if not peth['source_interface']: diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py index 6639a9b0d..d238ddb57 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.util import is_bridge_member +from vyos.validate import is_bridge_member from vyos import ConfigError default_config_data = { @@ -42,6 +42,7 @@ default_config_data = { 'ipv6_eui64_prefix': '', 'ipv6_forwarding': 1, 'ipv6_dup_addr_detect': 1, + 'is_bridge_member': False, 'source_address': '', 'source_interface': '', 'mtu': 1450, @@ -64,6 +65,8 @@ def get_config(): # 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 @@ -154,13 +157,11 @@ def get_config(): def verify(vxlan): if vxlan['deleted']: - interface = vxlan['intf'] - is_member, bridge = is_bridge_member(interface) - if is_member: - # can not use a f'' formatted-string here as bridge would not get - # expanded in the print statement - raise ConfigError('Can not delete interface "{0}" as it ' \ - 'is a member of bridge "{1}"!'.format(interface, bridge)) + 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}"!') + return None if vxlan['mtu'] < 1500: @@ -250,7 +251,7 @@ def apply(vxlan): for addr in vxlan['address']: v.add_addr(addr) - # As the bond interface is always disabled first when changing + # As the VXLAN interface is always disabled first when changing # parameters we will only re-enable the interface if it is not # administratively disabled if not vxlan['disable']: diff --git a/src/conf_mode/interfaces-wireguard.py b/src/conf_mode/interfaces-wireguard.py index 8bf81c747..423700370 100755 --- a/src/conf_mode/interfaces-wireguard.py +++ b/src/conf_mode/interfaces-wireguard.py @@ -24,8 +24,8 @@ from netifaces import interfaces from vyos.config import Config from vyos.configdict import list_diff from vyos.ifconfig import WireGuardIf -from vyos.util import chown, is_bridge_member, chmod_750 -from vyos.util import call +from vyos.util import chown, chmod_750, call +from vyos.validate import is_bridge_member from vyos import ConfigError kdir = r'/config/auth/wireguard' @@ -38,6 +38,7 @@ default_config_data = { 'lport': None, 'deleted': False, 'disable': False, + 'is_bridge_member': False, 'fwmark': 0x00, 'mtu': 1420, 'peer': [], @@ -80,6 +81,8 @@ def get_config(): # 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']]) @@ -189,12 +192,11 @@ def verify(wg): interface = wg['intf'] if wg['deleted']: - is_member, bridge = is_bridge_member(interface) - if is_member: - # can not use a f'' formatted-string here as bridge would not get - # expanded in the print statement - raise ConfigError('Can not delete interface "{0}" as it ' \ - 'is a member of bridge "{1}"!'.format(interface, bridge)) + 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}"!') + return None vrf_name = wg['vrf'] diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py index 1964af6e1..42842f9bd 100755 --- a/src/conf_mode/interfaces-wireless.py +++ b/src/conf_mode/interfaces-wireless.py @@ -27,10 +27,10 @@ from vyos.config import Config from vyos.configdict import list_diff, vlan_to_dict from vyos.ifconfig import WiFiIf from vyos.ifconfig_vlan import apply_vlan_config, verify_vlan_config -from vyos.util import chown, is_bridge_member, call -from vyos import ConfigError from vyos.template import render - +from vyos.util import chown, call +from vyos.validate import is_bridge_member +from vyos import ConfigError default_config_data = { 'address': [], @@ -91,6 +91,7 @@ default_config_data = { 'ipv6_eui64_prefix': '', 'ipv6_forwarding': 1, 'ipv6_dup_addr_detect': 1, + 'is_bridge_member': False, 'mac' : '', 'max_stations' : '', 'mgmt_frame_protection' : 'disabled', @@ -136,6 +137,8 @@ def get_config(): 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 @@ -528,15 +531,12 @@ def get_config(): def verify(wifi): if wifi['deleted']: - interface = wifi['intf'] - is_member, bridge = is_bridge_member(interface) - if is_member: - # can not use a f'' formatted-string here as bridge would not get - # expanded in the print statement - raise ConfigError('Can not delete interface "{0}" as it ' \ - 'is a member of bridge "{1}"!'.format(interface, bridge)) - return None + 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}"!') + return None if wifi['op_mode'] != 'monitor' and not wifi['ssid']: raise ConfigError('SSID must be set for {}'.format(wifi['intf'])) diff --git a/src/conf_mode/interfaces-wirelessmodem.py b/src/conf_mode/interfaces-wirelessmodem.py index da1855cd9..40bd1bbaf 100755 --- a/src/conf_mode/interfaces-wirelessmodem.py +++ b/src/conf_mode/interfaces-wirelessmodem.py @@ -21,14 +21,10 @@ from copy import deepcopy from netifaces import interfaces from vyos.config import Config -from vyos.util import chown -from vyos.util import chmod_755 -from vyos.util import is_bridge_member -from vyos.util import cmd -from vyos.util import call -from vyos import ConfigError from vyos.template import render - +from vyos.util import chown, chmod_755, cmd, call +from vyos.validate import is_bridge_member +from vyos import ConfigError default_config_data = { 'address': [], @@ -44,6 +40,7 @@ default_config_data = { 'metric': '10', 'mtu': '1500', 'name_server': True, + 'is_bridge_member': False, 'intf': '', 'vrf': '' } @@ -70,6 +67,8 @@ def get_config(): # 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 @@ -119,13 +118,11 @@ def get_config(): def verify(wwan): if wwan['deleted']: - interface = wwan['intf'] - is_member, bridge = is_bridge_member(interface) - if is_member: - # can not use a f'' formatted-string here as bridge would not get - # expanded in the print statement - raise ConfigError('Can not delete interface "{0}" as it ' \ - 'is a member of bridge "{1}"!'.format(interface, bridge)) + 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}"!') + return None if not wwan['apn']: -- cgit v1.2.3