diff options
-rw-r--r-- | interface-definitions/interfaces-bridge.xml | 76 | ||||
-rw-r--r-- | python/vyos/configinterface.py | 8 | ||||
-rwxr-xr-x | src/conf_mode/interface-bridge.py | 86 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/0-to-1 (renamed from src/migration-scripts/interface/0-to-1) | 0 |
4 files changed, 125 insertions, 45 deletions
diff --git a/interface-definitions/interfaces-bridge.xml b/interface-definitions/interfaces-bridge.xml index a5f2df5b5..af19d9438 100644 --- a/interface-definitions/interfaces-bridge.xml +++ b/interface-definitions/interfaces-bridge.xml @@ -51,7 +51,8 @@ <description>Address aging time for bridge seconds (default 300)</description> </valueHelp> <constraint> - <validator name="numeric" argument="--range 0-1000000"/> + <validator name="numeric" argument="--range 0-0"/> + <validator name="numeric" argument="--range 10-1000000"/> </constraint> </properties> </leafNode> @@ -146,20 +147,7 @@ <leafNode name="querier"> <properties> <help>Enable or disable IGMP querier</help> - <completionHelp> - <list>enable disable</list> - </completionHelp> - <valueHelp> - <format>enable</format> - <description>Enable IGMP querier</description> - </valueHelp> - <valueHelp> - <format>disable</format> - <description>Disable IGMP querier</description> - </valueHelp> - <constraint> - <regex>(enable|disable)</regex> - </constraint> + <valueless/> </properties> </leafNode> </children> @@ -206,6 +194,49 @@ <constraintErrorMessage>Bridge max aging value must be between 1 and 40 seconds</constraintErrorMessage> </properties> </leafNode> + <node name="member"> + <properties> + <help>Bridge member interfaces</help> + </properties> + <children> + <tagNode name="interface"> + <properties> + <help>Member interface name</help> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py --bridgeable</script> + </completionHelp> + </properties> + <children> + <leafNode name="cost"> + <properties> + <help>Bridge port cost</help> + <valueHelp> + <format>1-65535</format> + <description>Path cost value for Spanning Tree Protocol</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-65535"/> + </constraint> + <constraintErrorMessage>Path cost value must be between 1 and 65535</constraintErrorMessage> + </properties> + </leafNode> + <leafNode name="priority"> + <properties> + <help>Bridge port priority</help> + <valueHelp> + <format>0-63</format> + <description>Bridge port priority</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-63"/> + </constraint> + <constraintErrorMessage>Port priority value must be between 0 and 63</constraintErrorMessage> + </properties> + </leafNode> + </children> + </tagNode> + </children> + </node> <leafNode name="priority"> <properties> <help>Priority for this bridge</help> @@ -222,20 +253,7 @@ <leafNode name="stp"> <properties> <help>Enable spanning tree protocol</help> - <completionHelp> - <list>true false</list> - </completionHelp> - <valueHelp> - <format>true</format> - <description>Enable Spanning Tree Protocol</description> - </valueHelp> - <valueHelp> - <format>false</format> - <description>Disable Spanning Tree Protocol</description> - </valueHelp> - <constraint> - <regex>(true|false)</regex> - </constraint> + <valueless/> </properties> </leafNode> </children> diff --git a/python/vyos/configinterface.py b/python/vyos/configinterface.py index b0d766b9c..37b6b92c1 100644 --- a/python/vyos/configinterface.py +++ b/python/vyos/configinterface.py @@ -15,6 +15,14 @@ import os +def set_mac_address(intf, addr): + """ + Configure interface mac address using iproute2 command + + NOTE: mac address should be validated here??? + """ + os.system('ip link set {} address {}'.format(intf, addr)) + def set_description(intf, desc): """ Sets the interface secription reported usually by SNMP diff --git a/src/conf_mode/interface-bridge.py b/src/conf_mode/interface-bridge.py index f7f70b15d..637c58a5e 100755 --- a/src/conf_mode/interface-bridge.py +++ b/src/conf_mode/interface-bridge.py @@ -44,6 +44,8 @@ default_config_data = { 'arp_cache_timeout_ms': '30000', 'mac' : '', 'max_age': '20', + 'member': [], + 'member_remove': [], 'priority': '32768', 'stp': 'off' } @@ -53,6 +55,10 @@ def subprocess_cmd(command): proc_stdout = process.communicate()[0].strip() print(proc_stdout) +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) conf = Config() @@ -60,7 +66,6 @@ def get_config(): # determine tagNode instance try: bridge['br_name'] = os.environ['VYOS_TAGNODE_VALUE'] - print("Executing script for interface: " + bridge['br_name']) except KeyError as E: print("Interface not specified") @@ -118,9 +123,7 @@ def get_config(): # Enable or disable IGMP querier if conf.exists('igmp-snooping querier'): - tmp = conf.return_value('igmp-snooping querier') - if tmp == "enable": - bridge['igmp_querier'] = 1 + bridge['igmp_querier'] = 1 # ARP cache entry timeout in seconds if conf.exists('ip arp-cache-timeout'): @@ -135,15 +138,35 @@ def get_config(): if conf.exists('max-age'): bridge['max_age'] = conf.return_value('max-age') + # Determine bridge member interface (currently configured) + for intf in conf.list_nodes('member interface'): + iface = { + 'name': intf, + 'cost': '', + 'priority': '' + } + + if conf.exists('member interface {} cost'.format(intf)): + iface['cost'] = 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)) + + bridge['member'].append(iface) + + # Determine bridge member interface (currently effective) - to determine which interfaces + # need to be removed from the bridge + eff_intf = conf.list_effective_nodes('member interface') + act_intf = conf.list_nodes('member interface') + bridge['member_remove'] = diff(eff_intf, act_intf) + # Priority for this bridge if conf.exists('priority'): bridge['priority'] = conf.return_value('priority') # Enable spanning tree protocol if conf.exists('stp'): - tmp = conf.return_value('stp') - if tmp == "true": - bridge['stp'] = 'on' + bridge['stp'] = 'on' return bridge @@ -151,6 +174,9 @@ def verify(bridge): if bridge is None: return None + # validate agains other bridge interfaces that the interface is not assigned + # to another bridge + return None def generate(bridge): @@ -165,43 +191,71 @@ def apply(bridge): if bridge['deleted']: # bridges need to be shutdown first - os.system("ip link set dev {0} down".format(bridge['br_name'])) + os.system("ip link set dev {} down".format(bridge['br_name'])) # delete bridge - os.system("brctl delbr {0}".format(bridge['br_name'])) + os.system("brctl delbr {}".format(bridge['br_name'])) else: # create bridge if it does not exist if not os.path.exists("/sys/class/net/" + bridge['br_name']): - os.system("brctl addbr {0}".format(bridge['br_name'])) + os.system("brctl addbr {}".format(bridge['br_name'])) # assemble bridge configuration # configuration is passed via subprocess to brctl cmd = '' # set ageing time - cmd += 'brctl setageing {0} {1}'.format(bridge['br_name'], bridge['aging']) + cmd += 'brctl setageing {} {}'.format(bridge['br_name'], bridge['aging']) cmd += ' && ' # set bridge forward delay - cmd += 'brctl setfd {0} {1}'.format(bridge['br_name'], bridge['forwarding_delay']) + cmd += 'brctl setfd {} {}'.format(bridge['br_name'], bridge['forwarding_delay']) cmd += ' && ' # set hello time - cmd += 'brctl sethello {0} {1}'.format(bridge['br_name'], bridge['hello_time']) + cmd += 'brctl sethello {} {}'.format(bridge['br_name'], bridge['hello_time']) cmd += ' && ' # set max message age - cmd += 'brctl setmaxage {0} {1}'.format(bridge['br_name'], bridge['max_age']) + cmd += 'brctl setmaxage {} {}'.format(bridge['br_name'], bridge['max_age']) cmd += ' && ' # set bridge priority - cmd += 'brctl setbridgeprio {0} {1}'.format(bridge['br_name'], bridge['priority']) + cmd += 'brctl setbridgeprio {} {}'.format(bridge['br_name'], bridge['priority']) cmd += ' && ' # turn stp on/off - cmd += 'brctl stp {0} {1}'.format(bridge['br_name'], bridge['stp']) + cmd += 'brctl stp {} {}'.format(bridge['br_name'], bridge['stp']) + + for intf in bridge['member_remove']: + # remove interface from bridge + cmd += ' && ' + cmd += 'brctl delif {} {}'.format(bridge['br_name'], 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['br_name'] + '/brif/' + intf['name']): + cmd += ' && ' + cmd += 'brctl addif {} {}'.format(bridge['br_name'], intf['name']) + + # set bridge port cost + if intf['cost']: + cmd += ' && ' + cmd += 'brctl setpathcost {} {} {}'.format(bridge['br_name'], intf['name'], intf['cost']) + + # set bridge port priority + if intf['priority']: + cmd += ' && ' + cmd += 'brctl setportprio {} {} {}'.format(bridge['br_name'], intf['name'], intf['priority']) subprocess_cmd(cmd) + # Change interface MAC address + if bridge['mac']: + VyIfconfig.set_mac_address(bridge['br_name'], bridge['mac']) + else: + print("TODO: change mac mac address to the autoselected one based on member interfaces" + # update interface description used e.g. within SNMP VyIfconfig.set_description(bridge['br_name'], bridge['description']) diff --git a/src/migration-scripts/interface/0-to-1 b/src/migration-scripts/interfaces/0-to-1 index 1c6119d86..1c6119d86 100755 --- a/src/migration-scripts/interface/0-to-1 +++ b/src/migration-scripts/interfaces/0-to-1 |