diff options
| -rw-r--r-- | data/templates/frr/isisd.frr.j2 | 42 | ||||
| -rw-r--r-- | interface-definitions/include/isis/level-1-2-leaf.xml.i | 13 | ||||
| -rw-r--r-- | interface-definitions/include/isis/lfa-local.xml.i | 128 | ||||
| -rw-r--r-- | interface-definitions/include/isis/lfa-protocol.xml.i | 11 | ||||
| -rw-r--r-- | interface-definitions/include/isis/lfa-remote.xml.i | 28 | ||||
| -rw-r--r-- | interface-definitions/include/isis/protocol-common-config.xml.i | 8 | ||||
| -rw-r--r-- | op-mode-definitions/include/isis-common.xml.i | 27 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_protocols_isis.py | 62 | ||||
| -rwxr-xr-x | src/conf_mode/protocols_isis.py | 37 | 
9 files changed, 353 insertions, 3 deletions
| diff --git a/data/templates/frr/isisd.frr.j2 b/data/templates/frr/isisd.frr.j2 index 3c37e28b9..e1041f01e 100644 --- a/data/templates/frr/isisd.frr.j2 +++ b/data/templates/frr/isisd.frr.j2 @@ -159,6 +159,48 @@ router isis VyOS {{ 'vrf ' + vrf if vrf is vyos_defined }}  {%         endfor %}  {%     endfor %}  {% endif %} +{% if fast_reroute.lfa is vyos_defined %} +{%     if fast_reroute.lfa.local is vyos_defined %} +{%         if fast_reroute.lfa.local.load_sharing.disable.level_1 is vyos_defined %} + fast-reroute load-sharing disable level-1 +{%         elif fast_reroute.lfa.local.load_sharing.disable.level_2 is vyos_defined %} + fast-reroute load-sharing disable level-2 +{%         elif fast_reroute.lfa.local.load_sharing.disable is vyos_defined %} + fast-reroute load-sharing disable +{%         endif %} +{%         if fast_reroute.lfa.local.priority_limit is vyos_defined %} +{%             for priority, priority_limit_options in fast_reroute.lfa.local.priority_limit.items() %} +{%                 for level in priority_limit_options %} + fast-reroute priority-limit {{ priority }} {{ level | replace('_', '-') }} +{%                 endfor %}                    +{%             endfor %} +{%         endif %} +{%         if fast_reroute.lfa.local.tiebreaker is vyos_defined %} +{%             for tiebreaker, tiebreaker_options in fast_reroute.lfa.local.tiebreaker.items() %} +{%                 for index, index_options in tiebreaker_options.items() %} +{%                     for index_value, index_value_options in index_options.items() %} +{%                         for level in index_value_options %} + fast-reroute lfa tiebreaker {{ tiebreaker | replace('_', '-') }} index {{ index_value }} {{ level | replace('_', '-') }} +{%                         endfor %} +{%                     endfor %} +{%                 endfor %} +{%             endfor %} +{%         endif %} +{%     endif %} +{%     if fast_reroute.lfa.remote.prefix_list is vyos_defined %} +{%         for prefix_list, prefix_list_options in fast_reroute.lfa.remote.prefix_list.items() %} +{%             if prefix_list_options.level_1 is vyos_defined %} +fast-reroute remote-lfa prefix-list {{ prefix_list }} level-1 +{%             endif %} +{%             if prefix_list_options.level_2 is vyos_defined %} +fast-reroute remote-lfa prefix-list {{ prefix_list }} level-2 +{%             endif %} +{%             if prefix_list is vyos_defined and prefix_list_options.level_1 is not vyos_defined and prefix_list_options.level_2 is not vyos_defined %} +fast-reroute remote-lfa prefix-list {{ prefix_list }} +{%             endif %} +{%         endfor %} +{%     endif %} +{% endif %}  {% if redistribute.ipv4 is vyos_defined %}  {%     for protocol, protocol_options in redistribute.ipv4.items() %}  {%         for level, level_config in protocol_options.items() %} diff --git a/interface-definitions/include/isis/level-1-2-leaf.xml.i b/interface-definitions/include/isis/level-1-2-leaf.xml.i new file mode 100644 index 000000000..3703da1ed --- /dev/null +++ b/interface-definitions/include/isis/level-1-2-leaf.xml.i @@ -0,0 +1,13 @@ +<!-- include start from isis/level-1-2-leaf.xml.i --> +<leafNode name="level-1"> +  <properties> +    <help>Match on IS-IS level-1 routes</help> +    <valueless/> +  </properties> +</leafNode> +<leafNode name="level-2"> +  <properties> +    <help>Match on IS-IS level-2 routes</help> +    <valueless/> +  </properties> +</leafNode>
\ No newline at end of file diff --git a/interface-definitions/include/isis/lfa-local.xml.i b/interface-definitions/include/isis/lfa-local.xml.i new file mode 100644 index 000000000..c5bf6a3eb --- /dev/null +++ b/interface-definitions/include/isis/lfa-local.xml.i @@ -0,0 +1,128 @@ +<!-- include start from isis/lfa-local.xml.i --> +<node name="local"> +  <properties> +    <help>Local loop free alternate options</help> +  </properties> +  <children> +    <node name="load-sharing"> +      <properties> +        <help>Load share prefixes across multiple backups</help> +      </properties> +      <children> +        <node name="disable"> +          <properties> +            <help>Disable load sharing</help> +          </properties> +          <children> +            #include <include/isis/level-1-2-leaf.xml.i> +          </children> +        </node> +      </children> +    </node> +    <node name="priority-limit"> +      <properties> +        <help>Limit backup computation up to the prefix priority</help> +      </properties> +      <children> +        <node name="medium"> +          <properties> +            <help>Compute for critical, high, and medium priority prefixes</help> +          </properties> +          <children> +            #include <include/isis/level-1-2-leaf.xml.i> +          </children> +        </node> +        <node name="high"> +          <properties> +            <help>Compute for critical, and high priority prefixes</help> +          </properties> +          <children> +            #include <include/isis/level-1-2-leaf.xml.i> +          </children> +        </node> +        <node name="critical"> +          <properties> +            <help>Compute for critical priority prefixes only</help> +          </properties> +          <children> +            #include <include/isis/level-1-2-leaf.xml.i> +          </children> +        </node> +      </children> +    </node> +    <node name="tiebreaker"> +      <properties> +        <help>Configure tiebreaker for multiple backups</help> +      </properties> +      <children> +        <node name="downstream"> +          <properties> +            <help>Prefer backup path via downstream node</help> +          </properties> +          <children> +            <tagNode name="index"> +              <properties> +                <help>Set preference order among tiebreakers</help> +                <valueHelp> +                  <format>u32:1-255</format> +                    <description>The index integer value</description> +                </valueHelp> +                <constraint> +                  <validator name="numeric" argument="--range 1-255"/> +                </constraint> +              </properties> +              <children> +                #include <include/isis/level-1-2-leaf.xml.i> +              </children> +            </tagNode> +          </children> +        </node> +        <node name="lowest-backup-metric"> +          <properties> +            <help>Prefer backup path with lowest total metric</help> +          </properties> +          <children> +            <tagNode name="index"> +              <properties> +                <help>Set preference order among tiebreakers</help> +                <valueHelp> +                  <format>u32:1-255</format> +                    <description>The index integer value</description> +                </valueHelp> +                <constraint> +                  <validator name="numeric" argument="--range 1-255"/> +                </constraint> +              </properties> +              <children> +                #include <include/isis/level-1-2-leaf.xml.i> +              </children> +            </tagNode> +          </children> +        </node> +        <node name="node-protecting"> +          <properties> +            <help>Prefer node protecting backup path</help> +          </properties> +          <children> +            <tagNode name="index"> +              <properties> +                <help>Set preference order among tiebreakers</help> +                <valueHelp> +                  <format>u32:1-255</format> +                    <description>The index integer value</description> +                </valueHelp> +                <constraint> +                  <validator name="numeric" argument="--range 1-255"/> +                </constraint> +              </properties> +              <children> +                #include <include/isis/level-1-2-leaf.xml.i> +              </children> +            </tagNode> +          </children> +        </node> +      </children> +    </node> +  </children> +</node> +<!-- include end -->
\ No newline at end of file diff --git a/interface-definitions/include/isis/lfa-protocol.xml.i b/interface-definitions/include/isis/lfa-protocol.xml.i new file mode 100644 index 000000000..cfb1a6dc1 --- /dev/null +++ b/interface-definitions/include/isis/lfa-protocol.xml.i @@ -0,0 +1,11 @@ +<!-- include start from isis/lfa-protocol.xml.i --> +<node name="lfa"> +  <properties> +    <help>Loop free alternate functionality</help> +  </properties> +  <children> +    #include <include/isis/lfa-remote.xml.i> +    #include <include/isis/lfa-local.xml.i> +  </children> +</node> +<!-- include end -->
\ No newline at end of file diff --git a/interface-definitions/include/isis/lfa-remote.xml.i b/interface-definitions/include/isis/lfa-remote.xml.i new file mode 100644 index 000000000..8434e35bf --- /dev/null +++ b/interface-definitions/include/isis/lfa-remote.xml.i @@ -0,0 +1,28 @@ +<!-- include start from isis/lfa-remote.xml.i --> +<node name="remote"> +  <properties> +    <help>Remote loop free alternate options</help> +  </properties> +  <children> +    <tagNode name="prefix-list"> +      <properties> +        <help>Filter PQ node router ID based on prefix list</help> +        <completionHelp> +          <path>policy prefix-list</path> +        </completionHelp> +        <valueHelp> +          <format>txt</format> +          <description>Name of IPv4/IPv6 prefix-list</description> +        </valueHelp> +        <constraint> +          #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i> +        </constraint> +        <constraintErrorMessage>Name of prefix-list can only contain alpha-numeric letters, hyphen and underscores</constraintErrorMessage> +      </properties> +      <children> +        #include <include/isis/level-1-2-leaf.xml.i> +      </children> +    </tagNode> +  </children> +</node> +<!-- include end -->
\ No newline at end of file diff --git a/interface-definitions/include/isis/protocol-common-config.xml.i b/interface-definitions/include/isis/protocol-common-config.xml.i index 4ca7061db..87b9d552f 100644 --- a/interface-definitions/include/isis/protocol-common-config.xml.i +++ b/interface-definitions/include/isis/protocol-common-config.xml.i @@ -153,6 +153,14 @@    </properties>  </leafNode>  #include <include/isis/ldp-sync-protocol.xml.i> +<node name="fast-reroute"> +  <properties> +    <help>IS-IS fast reroute configuration</help> +  </properties> +  <children> +    #include <include/isis/lfa-protocol.xml.i> +  </children> +</node>  <leafNode name="net">    <properties>      <help>A Network Entity Title for this process (ISO only)</help> diff --git a/op-mode-definitions/include/isis-common.xml.i b/op-mode-definitions/include/isis-common.xml.i index e94d868e8..493a56633 100644 --- a/op-mode-definitions/include/isis-common.xml.i +++ b/op-mode-definitions/include/isis-common.xml.i @@ -17,6 +17,33 @@    </properties>    <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>  </tagNode> +<node name="fast-reroute"> +  <properties> +    <help>Show IS-IS fast reroute/loop free alternate (lfa) information</help> +  </properties> +  <children> +    <node name="summary"> +      <properties> +        <help>Show summary of fast reroute/loop free alternate (lfa) information</help> +      </properties> +      <children> +        <leafNode name="level-1"> +          <properties> +            <help>Show level-1 specific fast reroute/loop free alternate (lfa) information</help> +          </properties> +          <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +        </leafNode> +        <leafNode name="level-2"> +          <properties> +            <help>Show level-2 specific fast reroute/loop free alternate (lfa) information</help> +          </properties> +          <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +        </leafNode> +      </children> +      <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +    </node> +  </children> +</node>  <leafNode name="hostname">    <properties>      <help>Show IS-IS dynamic hostname mapping</help> diff --git a/smoketest/scripts/cli/test_protocols_isis.py b/smoketest/scripts/cli/test_protocols_isis.py index 5ab7fae14..af171c8b2 100755 --- a/smoketest/scripts/cli/test_protocols_isis.py +++ b/smoketest/scripts/cli/test_protocols_isis.py @@ -320,5 +320,65 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):              self.assertIn(f' ipv6 router isis {domain}', tmp)              self.assertIn(f' no isis mpls ldp-sync', tmp) +    def test_isis_09_lfa(self): +        prefix_list = 'lfa-prefix-list-test-1' +        prefix_list_address = '192.168.255.255/32' +        interface = 'lo' + +        self.cli_set(base_path + ['net', net]) +        self.cli_set(base_path + ['interface', interface]) +        self.cli_set(['policy', 'prefix-list', prefix_list, 'rule', '1', 'action', 'permit']) +        self.cli_set(['policy', 'prefix-list', prefix_list, 'rule', '1', 'prefix', prefix_list_address]) +         +        # Commit main ISIS changes +        self.cli_commit() + +        # Add remote portion of LFA with prefix list with validation +        for level in ['level-1', 'level-2']: +            self.cli_set(base_path + ['fast-reroute', 'lfa', 'remote', 'prefix-list', prefix_list, level]) +            self.cli_commit() +            tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') +            self.assertIn(f' net {net}', tmp) +            self.assertIn(f' fast-reroute remote-lfa prefix-list {prefix_list} {level}', tmp) +            self.cli_delete(base_path + ['fast-reroute']) +            self.cli_commit() + +        # Add local portion of LFA load-sharing portion with validation +        for level in ['level-1', 'level-2']: +            self.cli_set(base_path + ['fast-reroute', 'lfa', 'local', 'load-sharing', 'disable', level]) +            self.cli_commit() +            tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') +            self.assertIn(f' net {net}', tmp) +            self.assertIn(f' fast-reroute load-sharing disable {level}', tmp) +            self.cli_delete(base_path + ['fast-reroute']) +            self.cli_commit() + +        # Add local portion of LFA priority-limit portion with validation +        for priority in ['critical', 'high', 'medium']: +            for level in ['level-1', 'level-2']: +                self.cli_set(base_path + ['fast-reroute', 'lfa', 'local', 'priority-limit', priority, level]) +                self.cli_commit() +                tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') +                self.assertIn(f' net {net}', tmp) +                self.assertIn(f' fast-reroute priority-limit {priority} {level}', tmp) +                self.cli_delete(base_path + ['fast-reroute']) +                self.cli_commit() + +        # Add local portion of LFA tiebreaker portion with validation +        index = '100' +        for tiebreaker in ['downstream','lowest-backup-metric','node-protecting']: +            for level in ['level-1', 'level-2']: +                self.cli_set(base_path + ['fast-reroute', 'lfa', 'local', 'tiebreaker', tiebreaker, 'index', index, level]) +                self.cli_commit() +                tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd') +                self.assertIn(f' net {net}', tmp) +                self.assertIn(f' fast-reroute lfa tiebreaker {tiebreaker} index {index} {level}', tmp) +                self.cli_delete(base_path + ['fast-reroute']) +                self.cli_commit() + +        # Clean up and remove prefix list +        self.cli_delete(['policy', 'prefix-list', prefix_list]) +        self.cli_commit() +  if __name__ == '__main__': -    unittest.main(verbosity=2) +    unittest.main(verbosity=2)
\ No newline at end of file diff --git a/src/conf_mode/protocols_isis.py b/src/conf_mode/protocols_isis.py index e00c58ee4..ce67ccff7 100755 --- a/src/conf_mode/protocols_isis.py +++ b/src/conf_mode/protocols_isis.py @@ -48,7 +48,8 @@ def get_config(config=None):      # eqivalent of the C foo ? 'a' : 'b' statement      base = vrf and ['vrf', 'name', vrf, 'protocols', 'isis'] or base_path      isis = conf.get_config_dict(base, key_mangling=('-', '_'), -                                get_first_key=True) +                                get_first_key=True, +                                no_tag_node_value_mangle=True)      # Assign the name of our VRF context. This MUST be done before the return      # statement below, else on deletion we will delete the default instance @@ -219,6 +220,38 @@ def verify(isis):                  if ("explicit_null" in prefix_config['index']) and ("no_php_flag" in prefix_config['index']):                      raise ConfigError(f'Segment routing prefix {prefix} cannot have both explicit-null '\                                        f'and no-php-flag configured at the same time.') +                 +    # Check for LFA tiebreaker index duplication +    if dict_search('fast_reroute.lfa.local.tiebreaker', isis): +        comparison_dictionary = {} +        for item, item_options in isis['fast_reroute']['lfa']['local']['tiebreaker'].items(): +            for index, index_options in item_options.items(): +                for index_value, index_value_options in index_options.items(): +                    if index_value not in comparison_dictionary.keys(): +                        comparison_dictionary[index_value] = [item] +                    else: +                        comparison_dictionary[index_value].append(item) +        for index, index_length in comparison_dictionary.items(): +            if int(len(index_length)) > 1: +                raise ConfigError(f'LFA index {index} cannot have more than one tiebreaker configured.') + +    # Check for LFA priority-limit configured multiple times per level +    if dict_search('fast_reroute.lfa.local.priority_limit', isis): +        comparison_dictionary = {} +        for priority, priority_options in isis['fast_reroute']['lfa']['local']['priority_limit'].items(): +            for level, level_options in priority_options.items(): +                if level not in comparison_dictionary.keys(): +                    comparison_dictionary[level] = [priority] +                else: +                    comparison_dictionary[level].append(priority) +            for level, level_length in comparison_dictionary.items(): +                if int(len(level_length)) > 1: +                    raise ConfigError(f'LFA priority-limit on {level.replace("_", "-")} cannot have more than one priority configured.') + +    # Check for LFA remote prefix list configured with more than one list +    if dict_search('fast_reroute.lfa.remote.prefix_list', isis): +        if int(len(isis['fast_reroute']['lfa']['remote']['prefix_list'].items())) > 1: +            raise ConfigError(f'LFA remote prefix-list has more than one configured. Cannot have more than one configured.')      return None @@ -265,4 +298,4 @@ if __name__ == '__main__':          apply(c)      except ConfigError as e:          print(e) -        exit(1) +        exit(1)
\ No newline at end of file | 
