From 3cb84afe3a6b9f22a35e0a887f7ca350644d6c8a Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 21 Mar 2021 11:35:21 +0100 Subject: isis: T3417: move from cli tagNode to node As there can only be one running IS-IS process (FRR limitation) there is no need in having a tagNode here. This adds artifical restrictions/limitations when moving on to support VRFs for IS-IS protocol. --- src/conf_mode/protocols_isis.py | 162 +++++++++++++++++----------------------- 1 file changed, 70 insertions(+), 92 deletions(-) (limited to 'src/conf_mode/protocols_isis.py') diff --git a/src/conf_mode/protocols_isis.py b/src/conf_mode/protocols_isis.py index b7afad473..24db52567 100755 --- a/src/conf_mode/protocols_isis.py +++ b/src/conf_mode/protocols_isis.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 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 @@ -23,7 +23,6 @@ from vyos.configdict import node_changed from vyos import ConfigError from vyos.util import call from vyos.util import dict_search -from vyos.template import render from vyos.template import render_to_string from vyos import frr from vyos import airbag @@ -35,9 +34,8 @@ def get_config(config=None): else: conf = Config() base = ['protocols', 'isis'] - - isis = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) - + isis = conf.get_config_dict(base, key_mangling=('-', '_'), + get_first_key=True) return isis def verify(isis): @@ -45,74 +43,70 @@ def verify(isis): if not isis: return None - for process, isis_config in isis.items(): - # If more then one isis process is defined (Frr only supports one) - # http://docs.frrouting.org/en/latest/isisd.html#isis-router - if len(isis) > 1: - raise ConfigError('Only one isis process can be defined') - - # If network entity title (net) not defined - if 'net' not in isis_config: - raise ConfigError('ISIS net format iso is mandatory!') - - # If interface not set - if 'interface' not in isis_config: - raise ConfigError('ISIS interface is mandatory!') - - # If md5 and plaintext-password set at the same time - if 'area_password' in isis_config: - if {'md5', 'plaintext_password'} <= set(isis_config['encryption']): - raise ConfigError('Can not use both md5 and plaintext-password for ISIS area-password!') - - # If one param from delay set, but not set others - if 'spf_delay_ietf' in isis_config: - required_timers = ['holddown', 'init_delay', 'long_delay', 'short_delay', 'time_to_learn'] - exist_timers = [] - for elm_timer in required_timers: - if elm_timer in isis_config['spf_delay_ietf']: - exist_timers.append(elm_timer) - - exist_timers = set(required_timers).difference(set(exist_timers)) - if len(exist_timers) > 0: - raise ConfigError('All types of delay must be specified: ' + ', '.join(exist_timers).replace('_', '-')) - - # If Redistribute set, but level don't set - if 'redistribute' in isis_config: - proc_level = isis_config.get('level','').replace('-','_') - for proto, proto_config in isis_config.get('redistribute', {}).get('ipv4', {}).items(): - if 'level_1' not in proto_config and 'level_2' not in proto_config: - raise ConfigError('Redistribute level-1 or level-2 should be specified in \"protocols isis {} redistribute ipv4 {}\"'.format(process, proto)) - for redistribute_level in proto_config.keys(): - if proc_level and proc_level != 'level_1_2' and proc_level != redistribute_level: - raise ConfigError('\"protocols isis {0} redistribute ipv4 {2} {3}\" cannot be used with \"protocols isis {0} level {1}\"'.format(process, proc_level, proto, redistribute_level)) - - # Segment routing checks - if dict_search('segment_routing', isis_config): - if dict_search('segment_routing.global_block', isis_config): - high_label_value = dict_search('segment_routing.global_block.high_label_value', isis_config) - low_label_value = dict_search('segment_routing.global_block.low_label_value', isis_config) - # If segment routing global block high value is blank, throw error - if low_label_value and not high_label_value: - raise ConfigError('Segment routing global block high value must not be left blank') - # If segment routing global block low value is blank, throw error - if high_label_value and not low_label_value: - raise ConfigError('Segment routing global block low value must not be left blank') - # If segment routing global block low value is higher than the high value, throw error - if int(low_label_value) > int(high_label_value): - raise ConfigError('Segment routing global block low value must be lower than high value') - - if dict_search('segment_routing.local_block', isis_config): - high_label_value = dict_search('segment_routing.local_block.high_label_value', isis_config) - low_label_value = dict_search('segment_routing.local_block.low_label_value', isis_config) - # If segment routing local block high value is blank, throw error - if low_label_value and not high_label_value: - raise ConfigError('Segment routing local block high value must not be left blank') - # If segment routing local block low value is blank, throw error - if high_label_value and not low_label_value: - raise ConfigError('Segment routing local block low value must not be left blank') - # If segment routing local block low value is higher than the high value, throw error - if int(low_label_value) > int(high_label_value): - raise ConfigError('Segment routing local block low value must be lower than high value') + if 'domain' not in isis: + raise ConfigError('Routing domain name/tag must be set!') + + if 'net' not in isis: + raise ConfigError('Network entity is mandatory!') + + # If interface not set + if 'interface' not in isis: + raise ConfigError('Interface used for routing updates is mandatory!') + + # If md5 and plaintext-password set at the same time + if 'area_password' in isis: + if {'md5', 'plaintext_password'} <= set(isis['encryption']): + raise ConfigError('Can not use both md5 and plaintext-password for ISIS area-password!') + + # If one param from delay set, but not set others + if 'spf_delay_ietf' in isis: + required_timers = ['holddown', 'init_delay', 'long_delay', 'short_delay', 'time_to_learn'] + exist_timers = [] + for elm_timer in required_timers: + if elm_timer in isis['spf_delay_ietf']: + exist_timers.append(elm_timer) + + exist_timers = set(required_timers).difference(set(exist_timers)) + if len(exist_timers) > 0: + raise ConfigError('All types of delay must be specified: ' + ', '.join(exist_timers).replace('_', '-')) + + # If Redistribute set, but level don't set + if 'redistribute' in isis: + proc_level = isis.get('level','').replace('-','_') + for proto, proto_config in isis.get('redistribute', {}).get('ipv4', {}).items(): + if 'level_1' not in proto_config and 'level_2' not in proto_config: + raise ConfigError('Redistribute level-1 or level-2 should be specified in \"protocols isis {} redistribute ipv4 {}\"'.format(process, proto)) + for redistribute_level in proto_config.keys(): + if proc_level and proc_level != 'level_1_2' and proc_level != redistribute_level: + raise ConfigError('\"protocols isis {0} redistribute ipv4 {2} {3}\" cannot be used with \"protocols isis {0} level {1}\"'.format(process, proc_level, proto, redistribute_level)) + + # Segment routing checks + if dict_search('segment_routing', isis): + if dict_search('segment_routing.global_block', isis): + high_label_value = dict_search('segment_routing.global_block.high_label_value', isis) + low_label_value = dict_search('segment_routing.global_block.low_label_value', isis) + # If segment routing global block high value is blank, throw error + if low_label_value and not high_label_value: + raise ConfigError('Segment routing global block high value must not be left blank') + # If segment routing global block low value is blank, throw error + if high_label_value and not low_label_value: + raise ConfigError('Segment routing global block low value must not be left blank') + # If segment routing global block low value is higher than the high value, throw error + if int(low_label_value) > int(high_label_value): + raise ConfigError('Segment routing global block low value must be lower than high value') + + if dict_search('segment_routing.local_block', isis): + high_label_value = dict_search('segment_routing.local_block.high_label_value', isis) + low_label_value = dict_search('segment_routing.local_block.low_label_value', isis) + # If segment routing local block high value is blank, throw error + if low_label_value and not high_label_value: + raise ConfigError('Segment routing local block high value must not be left blank') + # If segment routing local block low value is blank, throw error + if high_label_value and not low_label_value: + raise ConfigError('Segment routing local block low value must not be left blank') + # If segment routing local block low value is higher than the high value, throw error + if int(low_label_value) > int(high_label_value): + raise ConfigError('Segment routing local block low value must be lower than high value') return None @@ -121,22 +115,15 @@ def generate(isis): isis['new_frr_config'] = '' return None - # only one ISIS process is supported, so we can directly send the first key - # of the config dict - process = list(isis.keys())[0] - isis[process]['process'] = process - - isis['new_frr_config'] = render_to_string('frr/isis.frr.tmpl', - isis[process]) - + isis['new_frr_config'] = render_to_string('frr/isis.frr.tmpl', isis) return None def apply(isis): # Save original configuration prior to starting any commit actions frr_cfg = frr.FRRConfig() frr_cfg.load_configuration(daemon='isisd') - frr_cfg.modify_section(r'interface \S+', '') - frr_cfg.modify_section(f'router isis \S+', '') + frr_cfg.modify_section('^interface \S+$', '') + frr_cfg.modify_section('^router isis \S+$', '') frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', isis['new_frr_config']) frr_cfg.commit_configuration(daemon='isisd') @@ -146,15 +133,6 @@ def apply(isis): for a in range(5): frr_cfg.commit_configuration(daemon='isisd') - # Debugging - ''' - print('') - print('--------- DEBUGGING ----------') - print(f'Existing config:\n{frr_cfg["original_config"]}\n\n') - print(f'Replacement config:\n{isis["new_frr_config"]}\n\n') - print(f'Modified config:\n{frr_cfg["modified_config"]}\n\n') - ''' - return None if __name__ == '__main__': -- cgit v1.2.3