diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/conf_mode/protocols_mpls.py | 411 |
1 files changed, 95 insertions, 316 deletions
diff --git a/src/conf_mode/protocols_mpls.py b/src/conf_mode/protocols_mpls.py index 84948baf4..6d3b98c47 100755 --- a/src/conf_mode/protocols_mpls.py +++ b/src/conf_mode/protocols_mpls.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019-2020 VyOS maintainers and contributors +# Copyright (C) 2017-2020 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -16,351 +16,130 @@ import os +from sys import exit + from vyos.config import Config +from vyos.configdict import node_changed from vyos import ConfigError from vyos.util import call from vyos.template import render - +from vyos.template import render_to_string +from vyos import frr from vyos import airbag airbag.enable() config_file = r'/tmp/ldpd.frr' -def sysctl(name, value): - call('sysctl -wq {}={}'.format(name, value)) - def get_config(config=None): if config: conf = config else: conf = Config() - mpls_conf = { - 'router_id' : None, - 'mpls_ldp' : False, - 'old_parameters' : { - 'no_ttl_propagation' : False, - 'maximum_ttl' : None - }, - 'parameters' : { - 'no_ttl_propagation' : False, - 'maximum_ttl' : None - }, - 'old_ldp' : { - 'interfaces' : [], - 'neighbors' : {}, - 'd_transp_ipv4' : None, - 'd_transp_ipv6' : None, - 'hello_ipv4_holdtime' : None, - 'hello_ipv4_interval' : None, - 'hello_ipv6_holdtime' : None, - 'hello_ipv6_interval' : None, - 'ses_ipv4_hold' : None, - 'ses_ipv6_hold' : None, - 'export_ipv4_exp' : False, - 'export_ipv6_exp' : False, - 'cisco_interop_tlv' : False, - 'transport_prefer_ipv4' : False, - 'target_ipv4_addresses' : [], - 'target_ipv6_addresses' : [], - 'target_ipv4_enable' : False, - 'target_ipv6_enable' : False, - 'target_ipv4_hello_int' : None, - 'target_ipv6_hello_int' : None, - 'target_ipv4_hello_hold' : None, - 'target_ipv6_hello_hold' : None - }, - 'ldp' : { - 'interfaces' : [], - 'neighbors' : {}, - 'd_transp_ipv4' : None, - 'd_transp_ipv6' : None, - 'hello_ipv4_holdtime' : None, - 'hello_ipv4_interval' : None, - 'hello_ipv6_holdtime' : None, - 'hello_ipv6_interval' : None, - 'ses_ipv4_hold' : None, - 'ses_ipv6_hold' : None, - 'export_ipv4_exp' : False, - 'export_ipv6_exp' : False, - 'cisco_interop_tlv' : False, - 'transport_prefer_ipv4' : False, - 'target_ipv4_addresses' : [], - 'target_ipv6_addresses' : [], - 'target_ipv4_enable' : False, - 'target_ipv6_enable' : False, - 'target_ipv4_hello_int' : None, - 'target_ipv6_hello_int' : None, - 'target_ipv4_hello_hold' : None, - 'target_ipv6_hello_hold' : None - } - } - if not (conf.exists('protocols mpls') or conf.exists_effective('protocols mpls')): - return None - - # If LDP is defined then enable LDP portion of code - if conf.exists('protocols mpls ldp'): - mpls_conf['mpls_ldp'] = True - - # Set to MPLS hierarchy configuration level - conf.set_level('protocols mpls') - - # Get no_ttl_propagation - if conf.exists_effective('parameters no-propagate-ttl'): - mpls_conf['old_parameters']['no_ttl_propagation'] = True - - if conf.exists('parameters no-propagate-ttl'): - mpls_conf['parameters']['no_ttl_propagation'] = True - - # Get maximum_ttl - if conf.exists_effective('parameters maximum-ttl'): - mpls_conf['old_parameters']['maximum_ttl'] = conf.return_effective_value('parameters maximum-ttl') - - if conf.exists('parameters maximum-ttl'): - mpls_conf['parameters']['maximum_ttl'] = conf.return_value('parameters maximum-ttl') - - # Set to LDP hierarchy configuration level - conf.set_level('protocols mpls ldp') - - # Get router-id - if conf.exists_effective('router-id'): - mpls_conf['old_router_id'] = conf.return_effective_value('router-id') - - if conf.exists('router-id'): - mpls_conf['router_id'] = conf.return_value('router-id') - - # Get hello-ipv4-holdtime - if conf.exists_effective('discovery hello-ipv4-holdtime'): - mpls_conf['old_ldp']['hello_ipv4_holdtime'] = conf.return_effective_value('discovery hello-ipv4-holdtime') - - if conf.exists('discovery hello-ipv4-holdtime'): - mpls_conf['ldp']['hello_ipv4_holdtime'] = conf.return_value('discovery hello-ipv4-holdtime') - - # Get hello-ipv4-interval - if conf.exists_effective('discovery hello-ipv4-interval'): - mpls_conf['old_ldp']['hello_ipv4_interval'] = conf.return_effective_value('discovery hello-ipv4-interval') - - if conf.exists('discovery hello-ipv4-interval'): - mpls_conf['ldp']['hello_ipv4_interval'] = conf.return_value('discovery hello-ipv4-interval') - - # Get hello-ipv6-holdtime - if conf.exists_effective('discovery hello-ipv6-holdtime'): - mpls_conf['old_ldp']['hello_ipv6_holdtime'] = conf.return_effective_value('discovery hello-ipv6-holdtime') - - if conf.exists('discovery hello-ipv6-holdtime'): - mpls_conf['ldp']['hello_ipv6_holdtime'] = conf.return_value('discovery hello-ipv6-holdtime') - - # Get hello-ipv6-interval - if conf.exists_effective('discovery hello-ipv6-interval'): - mpls_conf['old_ldp']['hello_ipv6_interval'] = conf.return_effective_value('discovery hello-ipv6-interval') - - if conf.exists('discovery hello-ipv6-interval'): - mpls_conf['ldp']['hello_ipv6_interval'] = conf.return_value('discovery hello-ipv6-interval') - - # Get session-ipv4-holdtime - if conf.exists_effective('discovery session-ipv4-holdtime'): - mpls_conf['old_ldp']['ses_ipv4_hold'] = conf.return_effective_value('discovery session-ipv4-holdtime') - - if conf.exists('discovery session-ipv4-holdtime'): - mpls_conf['ldp']['ses_ipv4_hold'] = conf.return_value('discovery session-ipv4-holdtime') - - # Get session-ipv6-holdtime - if conf.exists_effective('discovery session-ipv6-holdtime'): - mpls_conf['old_ldp']['ses_ipv6_hold'] = conf.return_effective_value('discovery session-ipv6-holdtime') - - if conf.exists('discovery session-ipv6-holdtime'): - mpls_conf['ldp']['ses_ipv6_hold'] = conf.return_value('discovery session-ipv6-holdtime') - - # Get discovery transport-ipv4-address - if conf.exists_effective('discovery transport-ipv4-address'): - mpls_conf['old_ldp']['d_transp_ipv4'] = conf.return_effective_value('discovery transport-ipv4-address') - - if conf.exists('discovery transport-ipv4-address'): - mpls_conf['ldp']['d_transp_ipv4'] = conf.return_value('discovery transport-ipv4-address') - - # Get discovery transport-ipv6-address - if conf.exists_effective('discovery transport-ipv6-address'): - mpls_conf['old_ldp']['d_transp_ipv6'] = conf.return_effective_value('discovery transport-ipv6-address') - - if conf.exists('discovery transport-ipv6-address'): - mpls_conf['ldp']['d_transp_ipv6'] = conf.return_value('discovery transport-ipv6-address') - - # Get export ipv4 explicit-null - if conf.exists_effective('export ipv4 explicit-null'): - mpls_conf['old_ldp']['export_ipv4_exp'] = True - - if conf.exists('export ipv4 explicit-null'): - mpls_conf['ldp']['export_ipv4_exp'] = True - - # Get export ipv6 explicit-null - if conf.exists_effective('export ipv6 explicit-null'): - mpls_conf['old_ldp']['export_ipv6_exp'] = True - - if conf.exists('export ipv6 explicit-null'): - mpls_conf['ldp']['export_ipv6_exp'] = True - - # Get target_ipv4_addresses - if conf.exists_effective('targeted-neighbor ipv4 address'): - mpls_conf['old_ldp']['target_ipv4_addresses'] = conf.return_effective_values('targeted-neighbor ipv4 address') - - if conf.exists('targeted-neighbor ipv4 address'): - mpls_conf['ldp']['target_ipv4_addresses'] = conf.return_values('targeted-neighbor ipv4 address') - - # Get target_ipv4_enable - if conf.exists_effective('targeted-neighbor ipv4 enable'): - mpls_conf['old_ldp']['target_ipv4_enable'] = True - - if conf.exists('targeted-neighbor ipv4 enable'): - mpls_conf['ldp']['target_ipv4_enable'] = True - - # Get target_ipv4_hello_int - if conf.exists_effective('targeted-neighbor ipv4 hello-interval'): - mpls_conf['old_ldp']['target_ipv4_hello_int'] = conf.return_effective_value('targeted-neighbor ipv4 hello-interval') - - if conf.exists('targeted-neighbor ipv4 hello-interval'): - mpls_conf['ldp']['target_ipv4_hello_int'] = conf.return_value('targeted-neighbor ipv4 hello-interval') - - # Get target_ipv4_hello_hold - if conf.exists_effective('targeted-neighbor ipv4 hello-holdtime'): - mpls_conf['old_ldp']['target_ipv4_hello_hold'] = conf.return_effective_value('targeted-neighbor ipv4 hello-holdtime') - - if conf.exists('targeted-neighbor ipv4 hello-holdtime'): - mpls_conf['ldp']['target_ipv4_hello_hold'] = conf.return_value('targeted-neighbor ipv4 hello-holdtime') - - # Get target_ipv6_addresses - if conf.exists_effective('targeted-neighbor ipv6 address'): - mpls_conf['old_ldp']['target_ipv6_addresses'] = conf.return_effective_values('targeted-neighbor ipv6 address') - - if conf.exists('targeted-neighbor ipv6 address'): - mpls_conf['ldp']['target_ipv6_addresses'] = conf.return_values('targeted-neighbor ipv6 address') - - # Get target_ipv6_enable - if conf.exists_effective('targeted-neighbor ipv6 enable'): - mpls_conf['old_ldp']['target_ipv6_enable'] = True - - if conf.exists('targeted-neighbor ipv6 enable'): - mpls_conf['ldp']['target_ipv6_enable'] = True - - # Get target_ipv6_hello_int - if conf.exists_effective('targeted-neighbor ipv6 hello-interval'): - mpls_conf['old_ldp']['target_ipv6_hello_int'] = conf.return_effective_value('targeted-neighbor ipv6 hello-interval') - - if conf.exists('targeted-neighbor ipv6 hello-interval'): - mpls_conf['ldp']['target_ipv6_hello_int'] = conf.return_value('targeted-neighbor ipv6 hello-interval') - - # Get target_ipv6_hello_hold - if conf.exists_effective('targeted-neighbor ipv6 hello-holdtime'): - mpls_conf['old_ldp']['target_ipv6_hello_hold'] = conf.return_effective_value('targeted-neighbor ipv6 hello-holdtime') - - if conf.exists('targeted-neighbor ipv6 hello-holdtime'): - mpls_conf['ldp']['target_ipv6_hello_hold'] = conf.return_value('targeted-neighbor ipv6 hello-holdtime') - - # Get parameters cisco-interop-tlv - if conf.exists_effective('parameters cisco-interop-tlv'): - mpls_conf['old_ldp']['cisco_interop_tlv'] = True - - if conf.exists('parameters cisco-interop-tlv'): - mpls_conf['ldp']['cisco_interop_tlv'] = True - - # Get parameters transport-prefer-ipv4 - if conf.exists_effective('parameters transport-prefer-ipv4'): - mpls_conf['old_ldp']['transport_prefer_ipv4'] = True - - if conf.exists('parameters transport-prefer-ipv4'): - mpls_conf['ldp']['transport_prefer_ipv4'] = True - - # Get interfaces - if conf.exists_effective('interface'): - mpls_conf['old_ldp']['interfaces'] = conf.return_effective_values('interface') - - if conf.exists('interface'): - mpls_conf['ldp']['interfaces'] = conf.return_values('interface') - - # Get neighbors - for neighbor in conf.list_effective_nodes('neighbor'): - mpls_conf['old_ldp']['neighbors'].update({ - neighbor : { - 'password' : conf.return_effective_value('neighbor {0} password'.format(neighbor), default=''), - 'ttl_security' : conf.return_effective_value('neighbor {0} ttl-security'.format(neighbor), default=''), - 'session_holdtime' : conf.return_effective_value('neighbor {0} session-holdtime'.format(neighbor), default='') - } - }) - - for neighbor in conf.list_nodes('neighbor'): - mpls_conf['ldp']['neighbors'].update({ - neighbor : { - 'password' : conf.return_value('neighbor {0} password'.format(neighbor), default=''), - 'ttl_security' : conf.return_value('neighbor {0} ttl-security'.format(neighbor), default=''), - 'session_holdtime' : conf.return_value('neighbor {0} session-holdtime'.format(neighbor), default='') - } - }) - - return mpls_conf - -def operate_mpls_on_intfc(interfaces, action): - rp_filter = 0 - if action == 1: - rp_filter = 2 - for iface in interfaces: - sysctl('net.mpls.conf.{0}.input'.format(iface), action) - # Operate rp filter - sysctl('net.ipv4.conf.{0}.rp_filter'.format(iface), rp_filter) + base = ['protocols', 'mpls'] + mpls = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + return mpls def verify(mpls): - if mpls is None: + # If no config, then just bail out early. + if not mpls: return None - if mpls['mpls_ldp']: - # Require router-id - if not mpls['router_id']: - raise ConfigError(f"MPLS ldp router-id is mandatory!") - - # Require discovery transport-address - if not mpls['ldp']['d_transp_ipv4'] and not mpls['ldp']['d_transp_ipv6']: - raise ConfigError(f"MPLS ldp discovery transport address is mandatory!") + # Checks to see if LDP is properly configured + if 'ldp' in mpls: + # If router ID not defined + if 'router_id' in mpls['ldp']: + pass + else: + raise ConfigError('Router ID missing. An LDP router id is mandatory!') + # If interface not set + if 'interface' in mpls['ldp']: + pass + else: + raise ConfigError('LDP interfaces are missing. An LDP interface is mandatory!') + # If transport addresses are not set + if 'discovery' in mpls['ldp']: + if 'transport_ipv4_address' in mpls['ldp']['discovery']: + pass + elif 'transport_ipv6_address' in mpls['ldp']['discovery']: + pass + else: + raise ConfigError('LDP transport address is missing. Add an LDP transport address!') + else: + raise ConfigError('LDP transport address is missing. Add an LDP transport address!') - # Require interface - if not mpls['ldp']['interfaces']: - raise ConfigError(f"MPLS ldp interface is mandatory!") + return None def generate(mpls): - if mpls is None: + # If there's no MPLS config generated, create dictionary key with no value. + if not mpls: + mpls['new_frr_config'] = '' return None - render(config_file, 'frr/ldpd.frr.tmpl', mpls) + mpls['new_frr_config'] = render_to_string('frr/ldpd.frr.tmpl', mpls, trim_blocks=True) return None def apply(mpls): - if mpls is None: - return None - - # Set number of entries in the platform label table - if mpls['mpls_ldp']: - sysctl('net.mpls.platform_labels', '1048575') + # Define dictionary that will load FRR config + frr_cfg = {} + # Save original configuration prior to starting any commit actions + frr_cfg['original_config'] = frr.get_configuration(daemon='ldpd') + frr_cfg['modified_config'] = frr.replace_section(frr_cfg['original_config'], mpls['new_frr_config'], from_re='mpls.*') + + # If FRR config is blank, rerun the blank commit three times due to frr-reload + # behavior/bug not properly clearing out on one commit. + if mpls['new_frr_config'] == '': + for x in range(3): + frr.reload_configuration(frr_cfg['modified_config'], daemon='ldpd') + elif not 'ldp' in mpls: + for x in range(3): + frr.reload_configuration(frr_cfg['modified_config'], daemon='ldpd') else: - sysctl('net.mpls.platform_labels', '0') + # FRR mark configuration will test for syntax errors and throws an + # exception if any syntax errors is detected + frr.mark_configuration(frr_cfg['modified_config']) + + # Commit resulting configuration to FRR, this will throw CommitError + # on failure + frr.reload_configuration(frr_cfg['modified_config'], daemon='ldpd') - # Choose whether to copy IP TTL to MPLS header TTL - if mpls['parameters']['no_ttl_propagation']: - sysctl('net.mpls.ip_ttl_propagate', '0') + # Set number of entries in the platform label tables + if 'interface' in mpls: + os.system('sysctl -wq net.mpls.platform_labels=1048575') else: - sysctl('net.mpls.ip_ttl_propagate', '1') - - # Choose whether to limit maximum MPLS header TTL - if mpls['parameters']['maximum_ttl']: - sysctl('net.mpls.default_ttl', '%s' %(mpls['parameters']['maximum_ttl'])) + os.system('sysctl -wq net.mpls.platform_labels=0') + + # Check for changes in global MPLS options + if 'parameters' in mpls: + # Choose whether to copy IP TTL to MPLS header TTL + if 'no_propagate_ttl' in mpls['parameters']: + os.system('sysctl -wq net.mpls.ip_ttl_propagate=0') + # Choose whether to limit maximum MPLS header TTL + if 'maximum_ttl' in mpls['parameters']: + os.system('sysctl -wq net.mpls.default_ttl=%s' %(mpls['parameters'].get('maximum_ttl'))) else: - sysctl('net.mpls.default_ttl', '255') - - # Allow mpls on interfaces - operate_mpls_on_intfc(mpls['ldp']['interfaces'], 1) - - # Disable mpls on deleted interfaces - diactive_ifaces = set(mpls['old_ldp']['interfaces']).difference(mpls['ldp']['interfaces']) - operate_mpls_on_intfc(diactive_ifaces, 0) - - if os.path.exists(config_file): - call(f'vtysh -d ldpd -f {config_file}') - os.remove(config_file) + # Set default global MPLS options if not defined. + os.system('sysctl -wq net.mpls.ip_ttl_propagate=1') + os.system('sysctl -wq net.mpls.default_ttl=255') + + # Enable and disable MPLS processing on interfaces per configuration + if 'interface' in mpls: + system_interfaces = [] + system_interfaces.append(((os.popen('sysctl net.mpls.conf').read()).split('\n'))) + del system_interfaces[0][-1] + for configured_interface in mpls['interface']: + for system_interface in system_interfaces[0]: + if configured_interface in system_interface: + os.system('sysctl -wq net.mpls.conf.%s.input=1' %(configured_interface)) + elif system_interface.endswith(' = 1'): + system_interface = system_interface.replace(' = 1', '=0') + os.system('sysctl -wq %s' %(system_interface)) + else: + # If MPLS interfaces are not configured, set MPLS processing disabled + system_interfaces = [] + system_interfaces.append(((os.popen('sysctl net.mpls.conf').read()).replace(" = 1", "=0")).split('\n')) + del system_interfaces[0][-1] + for interface in (system_interfaces[0]): + os.system('sysctl -wq %s' %(interface)) return None |