Skip to content

Commit

Permalink
IS-IS route import (Cumulus Linux, EOS, FRR, IOS) (#1305)
Browse files Browse the repository at this point in the history
  • Loading branch information
ipspace authored Sep 7, 2024
1 parent 7444e87 commit be101e3
Show file tree
Hide file tree
Showing 22 changed files with 240 additions and 263 deletions.
57 changes: 39 additions & 18 deletions docs/module/isis.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The module supports the following IS-IS features:
* Wide metrics (enabled by default, cannot be turned off)
* Unnumbered IPv4 interfaces
* Passive interfaces
* Route import (redistribution)
* BFD


Expand All @@ -25,19 +26,19 @@ The module supports the following IS-IS features:

The following table describes per-platform support of individual IS-IS features:

| Operating system | IS type | IPv6 AF | Multi<br>topology | Unnumbered<br />interfaces | IPv4<br />BFD | IPv6<br />BFD |
| ------------------ | :-: | :-: | :-: | :-: | :-: | :-: |
| Arista EOS |||||||
| Cisco ASAv |||| | | |
| Cisco IOSv/IOSvL2 |||||||
| Cisco IOS XE[^18v] |||||||
| Cisco IOS XRv |||||||
| Cisco Nexus OS ||||| | |
| FRR ||||| | |
| Junos[^Junos] ||||| | |
| Nokia SR Linux ||||| ||
| Nokia SR OS ||||| ||
| VyOS ||||| | |
| Operating system | IS type | IPv6 AF | Multi<br>topology | Unnumbered<br />interfaces | Route<br>import |
|------------------- | :-: | :-: | :-: | :-: | :-: |
| Arista EOS ||||||
| Cisco ASAv |||| | |
| Cisco IOSv/IOSvL2 ||||||
| Cisco IOS XE[^18v] ||||||
| Cisco IOS XRv ||||||
| Cisco Nexus OS ||||| |
| FRR ||||| |
| Junos[^Junos] ||||| |
| Nokia SR Linux ||| || |
| Nokia SR OS ||||| |
| VyOS ||| || |

[^18v]: Includes Cisco CSR 1000v and Cisco Catalyst 8000v

Expand All @@ -48,6 +49,19 @@ The following table describes per-platform support of individual IS-IS features:
* On VyOS, IPv6 is enabled on all interfaces as soon as one has an IPv6 address.
* Cisco ASA does not support P2P IS-IS links. You could add `isis.network_type: false` to point-to-point links connecting ASA to other devices.

Some platforms can use BFD to speed up IS-IS convergence:

| Operating system | IPv4<br />BFD | IPv6<br />BFD |
| ------------------ | :-: | :-: |
| Arista EOS |||
| Cisco IOSv/IOSvL2 |||
| Cisco IOS XE[^18v] |||
| Cisco Nexus OS |||
| Junos[^Junos] |||
| Nokia SR Linux |||
| Nokia SR OS |||
| VyOS |||

```{tip}
See [IS-IS Integration Tests Results](https://release.netlab.tools/_html/coverage.isis) for more details.
```
Expand All @@ -56,6 +70,7 @@ See [IS-IS Integration Tests Results](https://release.netlab.tools/_html/coverag

* **isis.area** -- CLNS area prefix. Router address (NET) is computed from area prefix, 6-byte system ID (using **id** node attribute), and NSAP selector (.00)
* **isis.type** -- IS-IS router type (**level-1**, **level-2** or **level-1-2**. Default: **level-2**)
* **isis.instance** -- The name of the IS-IS instance. Used on devices that want to have a name for an IS-IS instance. Default: **Gandalf**.
* **isis.bfd** -- enable BFD for IS-IS. This parameter could be a boolean value (*True*/*False*) or a dictionary of address families, for example:

```
Expand All @@ -67,24 +82,29 @@ isis:
```

```{warning}
Specify **‌isis.area** with a single dot (example: 49.0001) within quotes to tell the YAML parser it's not a floating-point number.
Specify an **‌isis.area** value that has a single dot (example: 49.0001) within quotes to tell the YAML parser it's not a floating-point number.
```

## Node Parameters

You can specify node parameters as global values (top-level topology elements) or within individual nodes. You can specify **isis.net** on individual nodes instead of using **isis.area** (see [example](#example) for details).
You can specify most node parameters as global values (top-level topology elements) or within individual nodes. You can also specify these node parameters:

* **isis.net**: Set specific NET on individual nodes instead of using **isis.area** to generate it (see [example](isis-example) for details).
* **isis.import** -- [import (redistribute) routes](routing_import) into the global IS-IS instance. By default, no routes are redistributed into the global IS-IS instance.

**Note:**
* When specifying **isis.net**, avoid values in range *area.0000.0000.0001.00* through *area.0000.0000.0099.00* as they are used for auto-generated NETs.

IS-IS is automatically started on all interfaces within an autonomous system (interfaces with no EBGP neighbors; see also [](routing_external)). To disable IS-IS on an intra-AS link, set the **isis** link parameter to *False* (see also [](routing_disable)).

```{tip}
The IS-IS configuration module is automatically removed from a node that does not run IS-IS on any non-loopback interface. In that case, _netlab_ generates a warning that can be turned off by setting **‌defaults.isis.warnings.inactive** to **‌False**.
```

## Link Parameters

IS-IS is automatically started on all interfaces within an autonomous system (interfaces with no EBGP neighbors; see also [](routing_external)). To disable IS-IS on an intra-AS link, set the **isis** link parameter to *False* (see also [](routing_disable)).

You can also set these parameters:

* **isis.type** -- Link type (**level-1**, **level-2** or **level-1-2**). Recognized as a valid attribute but not implemented. Please feel free to fix the configuration templates and submit a pull request.
* **isis.network_type** -- Set IS-IS network type. Valid values are **point-to-point** or *False* (do not set the network type). See also [Default Link Parameters](#default-link-parameters).
* **isis.metric** or **isis.cost** -- Interface cost. Both parameters are recognized to make IS-IS configuration similar to OSPF (*metric* takes precedence over *cost*)
Expand All @@ -104,7 +124,7 @@ links:

## Default Link Parameters

The number of neighbors on an interface is used to set IS-IS network type unless it's specified with **isis.network_type** link or interface attribute. Interfaces with exactly one non-host neighbor (point-to-point links) have **isis.network_type** set to **point-to-point**.
The number of neighbors on an interface is used to set the IS-IS network type unless it's specified with **isis.network_type** link or interface attribute. Interfaces with exactly one non-host neighbor (point-to-point links) have **isis.network_type** set to **point-to-point**.

When the **isis.passive** interface parameter is not set on a link or an interface, _netlab_ uses the link roles together with the link types to decide whether to include an interface in an IS-IS process and whether to make an interface passive:

Expand All @@ -117,6 +137,7 @@ When the **isis.passive** interface parameter is not set on a link or an interfa
* The BGP module could set link role. Links with devices from different AS numbers attached to them get a role specified in **defaults.bgp.ebgp_role** parameter. The system default value of that parameter is **external**, excluding inter-AS links from the IS-IS process.
* Management interfaces are never added to the IS-IS process. They are not in the set of device links and, thus, not considered in the IS-IS configuration template.

(isis-example)=
## Example

We want to create a three-router multi-area IS-IS network:
Expand Down
2 changes: 1 addition & 1 deletion docs/module/ospf.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ OSPF routing daemons support these interface-level features:
* **ospf.default** -- External default route origination ([more details](ospf-default))
* **ospf.reference_bandwidth** -- per-node OSPF auto-cost reference bandwidth (in Mbps).
* **ospf.bfd** -- enable BFD for OSPF (default: False)
* **ospf.import** -- [import (redistribute) routes](routing_import) into global OSPF instance. By default, no routes are redistributed into the global OSPF instance.
* **ospf.import** -- [import (redistribute) routes](routing_import) into the global OSPF instance. By default, no routes are redistributed into the global OSPF instance.
* **ospf.router_id** -- set [static router ID](routing_router_id).

You can specify most node parameters as global values (top-level topology elements) or within individual nodes (see [example](#example) for details).
Expand Down
2 changes: 1 addition & 1 deletion netsim/ansible/templates/bgp/ios.j2
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ router bgp {{ bgp.as }}
{% for af in ['ipv4','ipv6'] if bgp[af] is defined %}
address-family {{ af }}
bgp scan-time 5
{{ redistribute.config(bgp,af=af,ospf_pid=ospf_pid) }}
{{ redistribute.config(bgp,af=af,ospf_pid=ospf_pid)|indent(1,first=True) }}
!
{% if loopback[af] is defined and bgp.advertise_loopback %}
{{ bgpcfg.bgp_network(af,loopback[af]) }}
Expand Down
5 changes: 5 additions & 0 deletions netsim/ansible/templates/isis/eos.j2
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{% import "templates/routing/_redistribute.eos.j2" as redistribute with context %}
!
{% if 'ipv6' in isis.af %}
ipv6 unicast-routing
{% endif %}
Expand All @@ -11,6 +13,9 @@ router isis {{ isis.instance }}
{% elif isis.area is defined %}
net {{ "%s.0000.0000.%04d.00" % (isis.area,id) }}
{% endif %}
{% for afm in ['ipv4','ipv6'] if afm in isis.af %}
{{ redistribute.config(isis,af=afm,ospf_match=['internal','external']) }}
{% endfor %}
{% if isis.af.ipv4 is defined %}
address-family ipv4 unicast
{% endif %}
Expand Down
37 changes: 22 additions & 15 deletions netsim/ansible/templates/isis/frr.j2
Original file line number Diff line number Diff line change
@@ -1,47 +1,54 @@
{% import "templates/routing/_redistribute.frr.j2" as redistribute with context %}
!
{% if 'ipv6' in isis.af %}
ipv6 forwarding
{% endif %}
!
router isis {{ isis.instance }}
log-adjacency-changes
hostname dynamic
is-type {{ isis.type }}
metric-style wide
lsp-timers gen-interval 1 refresh-interval 900 max-lifetime 1800
log-adjacency-changes
hostname dynamic
is-type {{ isis.type }}
metric-style wide
lsp-timers gen-interval 1 refresh-interval 900 max-lifetime 1800
{% if isis.net is defined %}
net {{ isis.net }}
net {{ isis.net }}
{% elif isis.area is defined %}
net {{ "%s.0000.0000.%04d.00" % (isis.area,id) }}
net {{ "%s.0000.0000.%04d.00" % (isis.area,id) }}
{% endif %}
{% if isis.af.ipv6 is defined %}
topology ipv6-unicast
topology ipv6-unicast
{% endif %}
{% for afm in ['ipv4','ipv6'] if afm in isis.af %}
{% for is_level in ['1','2'] if is_level in isis.type %}
{{ redistribute.config(isis,af=afm,af_redistribute=True,isis_level='level-%s'|format(is_level)) }}
{% endfor %}
{% endfor %}
!
interface {{ loopback.ifname }}
{% if 'ipv4' in loopback and 'ipv4' in isis.af %}
ip router isis {{ isis.instance }}
ip router isis {{ isis.instance }}
{% endif %}
{% if 'ipv6' in loopback and 'ipv6' in isis.af %}
ipv6 router isis {{ isis.instance }}
ipv6 router isis {{ isis.instance }}
{% endif %}
!
{% for l in interfaces|default([]) if 'isis' in l %}
interface {{ l.ifname }}
! {{ l.name|default("") }}
{% if 'ipv4' in l and 'ipv4' in isis.af %}
ip router isis {{ isis.instance }}
ip router isis {{ isis.instance }}
{% endif %}
{% if 'ipv6' in l and 'ipv6' in isis.af %}
ipv6 router isis {{ isis.instance }}
ipv6 router isis {{ isis.instance }}
{% endif %}
{% if l.isis.network_type is defined %}
isis network {{ l.isis.network_type }}
isis network {{ l.isis.network_type }}
{% endif %}
{% if l.isis.cost is defined or l.isis.metric is defined %}
isis metric {{ l.isis.metric|default(l.isis.cost) }}
isis metric {{ l.isis.metric|default(l.isis.cost) }}
{% endif %}
{% if l.isis.passive %}
isis passive
isis passive
{% endif %}
!
{% endfor %}
Expand Down
6 changes: 6 additions & 0 deletions netsim/ansible/templates/isis/ios.j2
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{% import "templates/routing/_redistribute.ios.j2" as redistribute with context %}
!
{% if 'ipv6' in isis.af %}
ipv6 unicast-routing
{% endif %}
Expand Down Expand Up @@ -50,7 +52,11 @@ router isis {{ isis.instance }}
{% for l in interfaces|default([]) if 'isis' in l and l.isis.passive %}
passive-interface {{ l.ifname }}
{% endfor %}
{% if 'ipv4' in isis.af %}
{{ redistribute.config(isis,af='ipv4',ospf_pid=ospf.process|default(1))|indent(1,first=True) }}
{% endif %}
{% if isis.af.ipv6 is defined %}
address-family ipv6
multi-topology
{{ redistribute.config(isis,af='ipv6',ospf_pid=ospf.process|default(1))|indent(3,first=True) }}
{% endif %}
4 changes: 2 additions & 2 deletions netsim/ansible/templates/ospf/ios.ospfv3.j2
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ router ospfv3 {{ ospf_pid }}
{% for l in intf_data if l.ospf.passive|default(False) %}
passive-interface {{ l.ifname }}
{% endfor %}
{{ ospf_default.config(ospf_data,'ipv6') }}
{{ redistribute.config(ospf_data,af='ipv6') }}
{{ ospf_default.config(ospf_data,'ipv6')|indent(1,first=True) }}
{{ redistribute.config(ospf_data,af='ipv6')|indent(1,first=True) }}
!
{% for l in intf_data if 'ospf' in l and ('ipv6' in l or 'ipv6' in l.dhcp.client|default({})) %}
interface {{ l.ifname }}
Expand Down
18 changes: 14 additions & 4 deletions netsim/ansible/templates/routing/_redistribute.eos.j2
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
{% macro policy(sp_data,af) -%}
{% if 'policy' in sp_data %} route-map {{ sp_data.policy }}-{{ af }}{% endif +%}
{%- endmacro %}
{% macro config(pdata,af='ipv4',vrf=False) -%}
{% macro config(pdata,af='ipv4',vrf=False,ospf_match=[]) -%}
{% if pdata.import is defined %}
{% for s_proto,s_data in pdata.import.items() %}
{% if s_proto == 'ospf' and af == 'ipv6' %}
{% set s_proto = 'ospfv3' %}
{% set sp_config = 'ospfv3' if s_proto == 'ospf' and af == 'ipv6' else s_proto %}
{% if s_proto == 'isis' %}
{% set sp_config = sp_config + ' level-1-2' %}
{% endif %}
{% if vrf %}
{% set sp_config = sp_config + ' include leaked' %}
{% endif %}
{% if s_proto == 'ospf' and ospf_match %}
{% for osm in ospf_match %}
redistribute {{ sp_config }} match {{ osm }}{{ policy(s_data,af) }}
{% endfor %}
{% else %}
redistribute {{ sp_config }}{{ policy(s_data,af) }}
{% endif %}
redistribute {{ s_proto }}{% if vrf %} include leaked{% endif %}{{ policy(s_data,af) }}
{% endfor %}
{% endif %}
{%- endmacro %}
11 changes: 10 additions & 1 deletion netsim/ansible/templates/routing/_redistribute.frr.j2
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
{% macro policy(sp_data,af) -%}
{% if 'policy' in sp_data %} route-map {{ sp_data.policy }}-{{ af }}{% endif +%}
{%- endmacro %}
{% macro config(pdata,af) -%}
{% macro config(pdata,af,af_redistribute=False,isis_level='') -%}
{% if pdata.import is defined %}
{% for s_proto,s_data in pdata.import.items() %}
{% if s_proto == 'ospf' and af == 'ipv6' %}
{# FRR calls OSPFv3 ospf6 #}
{% set s_proto = 'ospf6' %}
{% endif %}
{% if af_redistribute %}
{# ISIS has to specify AF on redistribute command #}
{% set s_proto = af + ' ' + s_proto %}
{% endif %}
{% if isis_level %}
{# ISIS wants to know into which database it should redistribute #}
{% set s_proto = s_proto + ' ' + isis_level %}
{% endif %}
redistribute {{ s_proto }}{{ policy(s_data,af) }}
{% endfor %}
Expand Down
12 changes: 7 additions & 5 deletions netsim/ansible/templates/routing/_redistribute.ios.j2
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
{% if pdata.import is defined %}
{% set r_append = ' subnets' if t_proto == 'ospf' else '' %}
{% for s_proto,s_data in pdata.import.items() %}
{% set sp_config = s_proto %}
{% if s_proto == 'bgp' %}
{% set s_proto = s_proto + ' ' + bgp.as|string %}
{% set sp_config = sp_config + ' ' + bgp.as|string %}
{% elif s_proto == 'isis' %}
{% set sp_config = sp_config + ' ' + isis.instance + ' level-1-2' %}
{% elif s_proto == 'ospf' %}
{% set sp_config = sp_config + ' ' + ospf_pid|string + ' match internal external' %}
{% endif %}
{% if s_proto == 'ospf' %}
{% set s_proto = s_proto + ' ' + ospf_pid|string + ' match internal external' %}
{% endif %}
redistribute {{ s_proto }}{{ policy(s_data,af) }}
redistribute {{ sp_config }}{{ policy(s_data,af) }}
{% endfor %}
{% endif %}
{%- endmacro %}
5 changes: 3 additions & 2 deletions netsim/devices/eos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ features:
local_as_ibgp: true
rfc8950: true
vrf_local_as: true
import: [ ospf, ripv2, connected, vrf ]
import: [ ospf, isis, ripv2, connected, vrf ]
community:
standard: [ standard, large ]
large: [ large ]
Expand All @@ -49,14 +49,15 @@ features:
ipv4: true
ipv6: true
network: true
import: [ bgp, ospf, ripv2, connected, vrf ]
mpls:
6pe: true
bgp: true
ldp: true
vpn: true
ospf:
unnumbered: true
import: [ bgp, ripv2, connected, vrf ]
import: [ bgp, isis, ripv2, connected, vrf ]
default.policy: true
ripv2:
ipv4: true
Expand Down
5 changes: 3 additions & 2 deletions netsim/devices/frr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ features:
local_as_ibgp: true
rfc8950: true
vrf_local_as: true
import: [ ospf, ripv2, connected, vrf ]
import: [ ospf, ripv2, isis, connected, vrf ]
community:
standard: [ standard, large ]
large: [ large ]
Expand All @@ -64,6 +64,7 @@ features:
irb: true
asymmetrical_irb: True
isis:
import: [ bgp, ripv2, ospf, connected, vrf ]
unnumbered:
ipv4: true
ipv6: true
Expand All @@ -74,7 +75,7 @@ features:
ipv4: true
ospf:
unnumbered: true
import: [ bgp, ripv2, connected, vrf ]
import: [ bgp, ripv2, isis, connected, vrf ]
default: true
ripv2:
ipv4: true
Expand Down
Loading

0 comments on commit be101e3

Please sign in to comment.