diff options
Diffstat (limited to 'src/conf_mode/interface-bridge.py')
-rwxr-xr-x | src/conf_mode/interface-bridge.py | 234 |
1 files changed, 92 insertions, 142 deletions
diff --git a/src/conf_mode/interface-bridge.py b/src/conf_mode/interface-bridge.py index 543349e7b..401182a0d 100755 --- a/src/conf_mode/interface-bridge.py +++ b/src/conf_mode/interface-bridge.py @@ -17,51 +17,39 @@ # import os -import sys -import copy -import subprocess -import vyos.configinterface as VyIfconfig +from copy import deepcopy +from sys import exit +from netifaces import interfaces +from vyos.ifconfig import BridgeIf, Interface +from vyos.configdict import list_diff from vyos.config import Config from vyos import ConfigError default_config_data = { 'address': [], 'address_remove': [], - 'aging': '300', - 'arp_cache_timeout_ms': '30000', + 'aging': 300, + 'arp_cache_tmo': 30, 'description': '', 'deleted': False, - 'dhcp_client_id': '', - 'dhcp_hostname': '', - 'dhcpv6_parameters_only': False, - 'dhcpv6_temporary': False, 'disable': False, - 'disable_link_detect': False, - 'forwarding_delay': '15', - 'hello_time': '2', + 'disable_link_detect': 1, + 'forwarding_delay': 14, + 'hello_time': 2, 'igmp_querier': 0, 'intf': '', 'mac' : '', - 'max_age': '20', + 'max_age': 20, 'member': [], 'member_remove': [], - 'priority': '32768', - 'stp': 'off' + 'priority': 32768, + 'stp': 0 } -def subprocess_cmd(command): - process = subprocess.Popen(command,stdout=subprocess.PIPE, shell=True) - proc_stdout = process.communicate()[0].strip() - pass - -def diff(first, second): - second = set(second) - return [item for item in first if item not in second] - def get_config(): - bridge = copy.deepcopy(default_config_data) + bridge = deepcopy(default_config_data) conf = Config() # determine tagNode instance @@ -82,45 +70,34 @@ def get_config(): if conf.exists('address'): bridge['address'] = conf.return_values('address') + # Determine interface addresses (currently effective) - to determine which + # address is no longer valid and needs to be removed + eff_addr = conf.return_effective_values('address') + bridge['address_remove'] = list_diff(eff_addr, bridge['address']) + # retrieve aging - how long addresses are retained if conf.exists('aging'): - bridge['aging'] = conf.return_value('aging') + bridge['aging'] = int(conf.return_value('aging')) # retrieve interface description if conf.exists('description'): bridge['description'] = conf.return_value('description') - # DHCP client identifier - if conf.exists('dhcp-options client-id'): - bridge['dhcp_client_id'] = conf.return_value('dhcp-options client-id') - - # DHCP client hostname - if conf.exists('dhcp-options host-name'): - bridge['dhcp_hostname'] = conf.return_value('dhcp-options host-name') - - # DHCPv6 acquire only config parameters, no address - if conf.exists('dhcpv6-options parameters-only'): - bridge['dhcpv6_parameters_only'] = True - - # DHCPv6 IPv6 "temporary" address - if conf.exists('dhcpv6-options temporary'): - bridge['dhcpv6_temporary'] = True - # Disable this bridge interface if conf.exists('disable'): bridge['disable'] = True # Ignore link state changes if conf.exists('disable-link-detect'): - bridge['disable_link_detect'] = True + bridge['disable_link_detect'] = 2 # Forwarding delay if conf.exists('forwarding-delay'): - bridge['forwarding_delay'] = conf.return_value('forwarding-delay') + bridge['forwarding_delay'] = int(conf.return_value('forwarding-delay')) # Hello packet advertisment interval if conf.exists('hello-time'): - bridge['hello_time'] = conf.return_value('hello-time') + bridge['hello_time'] = int(conf.return_value('hello-time')) # Enable Internet Group Management Protocol (IGMP) querier if conf.exists('igmp querier'): @@ -128,8 +105,7 @@ def get_config(): # ARP cache entry timeout in seconds if conf.exists('ip arp-cache-timeout'): - tmp = 1000 * int(conf.return_value('ip arp-cache-timeout')) - bridge['arp_cache_timeout_ms'] = str(tmp) + bridge['arp_cache_tmo'] = int(conf.return_value('ip arp-cache-timeout')) # Media Access Control (MAC) address if conf.exists('mac'): @@ -137,21 +113,24 @@ def get_config(): # Interval at which neighbor bridges are removed if conf.exists('max-age'): - bridge['max_age'] = conf.return_value('max-age') + bridge['max_age'] = int(conf.return_value('max-age')) # 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': '', - 'priority': '' + 'cost': 100, + 'priority': 32 } if conf.exists('member interface {} cost'.format(intf)): - iface['cost'] = conf.return_value('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'] = conf.return_value('member interface {} priority'.format(intf)) + iface['priority'] = int(conf.return_value('member interface {} priority'.format(intf))) bridge['member'].append(iface) @@ -159,28 +138,19 @@ def get_config(): # interfaces is no longer assigend to the bridge and thus can be removed eff_intf = conf.list_effective_nodes('member interface') act_intf = conf.list_nodes('member interface') - bridge['member_remove'] = diff(eff_intf, act_intf) - - # Determine interface addresses (currently effective) - to determine which - # address is no longer valid and needs to be removed from the bridge - eff_addr = conf.return_effective_values('address') - act_addr = conf.return_values('address') - bridge['address_remove'] = diff(eff_addr, act_addr) + bridge['member_remove'] = list_diff(eff_intf, act_intf) # Priority for this bridge if conf.exists('priority'): - bridge['priority'] = conf.return_value('priority') + bridge['priority'] = int(conf.return_value('priority')) # Enable spanning tree protocol if conf.exists('stp'): - bridge['stp'] = 'on' + bridge['stp'] = 1 return bridge def verify(bridge): - if bridge is None: - return None - conf = Config() for br in conf.list_nodes('interfaces bridge'): # it makes no sense to verify ourself in this case @@ -190,108 +160,88 @@ def verify(bridge): for intf in bridge['member']: tmp = conf.list_nodes('interfaces bridge {} member interface'.format(br)) if intf['name'] in tmp: - raise ConfigError('{} can be assigned to any one bridge only'.format(intf['name'])) + 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']: + if intf['name'] not in interfaces(): + raise ConfigError('Can not add non existing interface "{}" to bridge "{}"'.format(intf['name'], bridge['intf'])) + + # 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'])) return None def generate(bridge): - if bridge is None: - return None - return None def apply(bridge): - if bridge is None: - return None + br = BridgeIf(bridge['intf']) - cmd = '' if bridge['deleted']: - # bridges need to be shutdown first - cmd += 'ip link set dev "{}" down'.format(bridge['intf']) - cmd += ' && ' - # delete bridge - cmd += 'brctl delbr "{}"'.format(bridge['intf']) - subprocess_cmd(cmd) - + # delete bridge interface + # DHCP is stopped inside remove() + br.remove() else: - # create bridge if it does not exist - if not os.path.exists("/sys/class/net/" + bridge['intf']): - # create bridge interface - cmd += 'brctl addbr "{}"'.format(bridge['intf']) - cmd += ' && ' - # activate "UP" the interface - cmd += 'ip link set dev "{}" up'.format(bridge['intf']) - cmd += ' && ' - + # enable interface + br.state = 'up' # set ageing time - cmd += 'brctl setageing "{}" "{}"'.format(bridge['intf'], bridge['aging']) - cmd += ' && ' - + br.ageing_time = bridge['aging'] # set bridge forward delay - cmd += 'brctl setfd "{}" "{}"'.format(bridge['intf'], bridge['forwarding_delay']) - cmd += ' && ' - + br.forward_delay = bridge['forwarding_delay'] # set hello time - cmd += 'brctl sethello "{}" "{}"'.format(bridge['intf'], bridge['hello_time']) - cmd += ' && ' - + br.hello_time = bridge['hello_time'] # set max message age - cmd += 'brctl setmaxage "{}" "{}"'.format(bridge['intf'], bridge['max_age']) - cmd += ' && ' - + br.max_age = bridge['max_age'] # set bridge priority - cmd += 'brctl setbridgeprio "{}" "{}"'.format(bridge['intf'], bridge['priority']) - cmd += ' && ' - + br.priority = bridge['priority'] # turn stp on/off - cmd += 'brctl stp "{}" "{}"'.format(bridge['intf'], bridge['stp']) - - for intf in bridge['member_remove']: - # remove interface from bridge - cmd += ' && ' - cmd += 'brctl delif "{}" "{}"'.format(bridge['intf'], intf) - - for intf in bridge['member']: - # add interface to bridge - # but only if it is not yet member of this bridge - if not os.path.exists('/sys/devices/virtual/net/' + bridge['intf'] + '/brif/' + intf['name']): - cmd += ' && ' - cmd += 'brctl addif "{}" "{}"'.format(bridge['intf'], intf['name']) - - # set bridge port cost - if intf['cost']: - cmd += ' && ' - cmd += 'brctl setpathcost "{}" "{}" "{}"'.format(bridge['intf'], intf['name'], intf['cost']) - - # set bridge port priority - if intf['priority']: - cmd += ' && ' - cmd += 'brctl setportprio "{}" "{}" "{}"'.format(bridge['intf'], intf['name'], intf['priority']) - - subprocess_cmd(cmd) + br.stp_state = bridge['stp'] + # enable or disable IGMP querier + br.multicast_querier = bridge['igmp_querier'] + # update interface description used e.g. within SNMP + br.ifalias = bridge['description'] # Change interface MAC address if bridge['mac']: - VyIfconfig.set_mac_address(bridge['intf'], bridge['mac']) - - # update interface description used e.g. within SNMP - VyIfconfig.set_description(bridge['intf'], bridge['description']) + br.mac = bridge['mac'] - # Ignore link state changes? - VyIfconfig.set_link_detect(bridge['intf'], bridge['disable_link_detect']) + # remove interface from bridge + for intf in bridge['member_remove']: + br.del_port( intf['name'] ) - # enable or disable IGMP querier - VyIfconfig.set_multicast_querier(bridge['intf'], bridge['igmp_querier']) + # add interfaces to bridge + for member in bridge['member']: + br.add_port(member['name']) - # ARP cache entry timeout in seconds - VyIfconfig.set_arp_cache_timeout(bridge['intf'], bridge['arp_cache_timeout_ms']) + # up/down interface + if bridge['disable']: + br.state = 'down' # Configure interface address(es) + # - not longer required addresses get removed first + # - newly addresses will be added second for addr in bridge['address_remove']: - VyIfconfig.remove_interface_address(bridge['intf'], addr) - + br.del_addr(addr) for addr in bridge['address']: - VyIfconfig.add_interface_address(bridge['intf'], addr) + br.add_addr(addr) + + # configure additional bridge member options + for member in bridge['member']: + # set bridge port cost + br.set_cost(member['name'], member['cost']) + # set bridge port priority + br.set_priority(member['name'], member['priority']) + + i = Interface(member['name']) + # configure ARP cache timeout + i.arp_cache_tmo = bridge['arp_cache_tmo'] + # ignore link state changes + i.link_detect = bridge['disable_link_detect'] return None @@ -303,4 +253,4 @@ if __name__ == '__main__': apply(c) except ConfigError as e: print(e) - sys.exit(1) + exit(1) |