Skip to content

Commit

Permalink
Add Cisco IOL kind (#2211)
Browse files Browse the repository at this point in the history
* Add Cisco IOL kind

* Add IOL documentation

* Update resoruce requirements documentation

* Minor documentation fixes.

* Add KSM note in documentation and correct accuracy of management interface IP assignment.

* Remove erroneous 'VM' references in docs.

* added schema and slightly renamed examples

* Add NETMAP/IOUYAP generation and template configuration.

* Add full template configuration inclusive of L2 node and add NETMAP/IOUYAP population

* Fix link in documentation to point at `cisco_iol.md` instead of `iol.md`

* Add information about new `type` field

* Fix bind mount path for IOL nvram.

* Change node type to `default node` and add interface mapping to create ethX based interface names when adding endpoints.

* Use `IFaceAlias` instead of `IfaceName` when displaying incorrectly defined interface error message.

* Fix documentation information about discontigious interface naming + minor formatting.

* refactor type check

* move cidrtoddn to utils

* added basic test

* fix image urls

* added tmate

* add a timer

* bump wait timer

* bump timer even more

---------

Co-authored-by: Roman Dodin <[email protected]>
  • Loading branch information
kaelemc and hellt authored Oct 4, 2024
1 parent fbca124 commit 2764acc
Show file tree
Hide file tree
Showing 12 changed files with 686 additions and 1 deletion.
9 changes: 9 additions & 0 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,14 @@ jobs:
with:
py_ver: ${{ needs.file-changes.outputs.py_ver }}

cisco_iol-tests:
uses: ./.github/workflows/cisco_iol-tests.yml
needs:
- file-changes
- build-containerlab
with:
py_ver: ${{ needs.file-changes.outputs.py_ver }}

# a job that downloads coverage artifact and uses codecov to upload it
coverage:
runs-on: ubuntu-22.04
Expand All @@ -344,6 +352,7 @@ jobs:
- kind-tests
# - sros-tests
- fortigate-tests
- cisco_iol-tests

steps:
- name: Checkout
Expand Down
74 changes: 74 additions & 0 deletions .github/workflows/cisco_iol-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: cisco_iol-tests

"on":
workflow_call:
inputs:
py_ver:
required: true
type: string

jobs:
cisco_iol-tests:
runs-on: ubuntu-22.04
strategy:
matrix:
runtime:
- "docker"
test-suite:
- "01*.robot"
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/download-artifact@v4
with:
name: containerlab

- name: Move containerlab to usr/bin
run: sudo mv ./containerlab /usr/bin/containerlab && sudo chmod a+x /usr/bin/containerlab

- uses: actions/setup-python@v5
with:
python-version: ${{ inputs.py_ver }}
cache: pip
cache-dependency-path: "tests/requirements.txt"

- name: Install robotframework
run: |
pip install -r tests/requirements.txt
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Sanitize test-suite name
run: echo "TEST_SUITE=$(echo ${{ matrix.test-suite }} | tr -d '*')" >> $GITHUB_ENV

# - name: setup tmate session
# uses: mxschmitt/action-tmate@v3

- name: Run tests
run: |
bash ./tests/rf-run.sh ${{ matrix.runtime }} ./tests/10-basic-cisco_iol/${{ matrix.test-suite }}
# upload test reports as a zip file
- uses: actions/upload-artifact@v4
if: always()
with:
name: 10-cisco_iol-log-${{ env.TEST_SUITE }}-${{ matrix.runtime }}
path: ./tests/out/*.html

# upload coverage report from unit tests, as they are then
# merged with e2e tests coverage
- name: Upload coverage report
uses: actions/upload-artifact@v4
if: always()
with:
name: coverage-cisco_iol-tests-${{ env.TEST_SUITE }}-${{ matrix.runtime }}
path: /tmp/clab-tests/coverage/*
retention-days: 7
2 changes: 2 additions & 0 deletions clab/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
fortinet_fortigate "github.com/srl-labs/containerlab/nodes/fortinet_fortigate"
generic_vm "github.com/srl-labs/containerlab/nodes/generic_vm"
host "github.com/srl-labs/containerlab/nodes/host"
cisco_iol "github.com/srl-labs/containerlab/nodes/iol"
ipinfusion_ocnos "github.com/srl-labs/containerlab/nodes/ipinfusion_ocnos"
k8s_kind "github.com/srl-labs/containerlab/nodes/k8s_kind"
keysight_ixiacone "github.com/srl-labs/containerlab/nodes/keysight_ixiacone"
Expand Down Expand Up @@ -93,4 +94,5 @@ func (c *CLab) RegisterNodes() {
c8000.Register(c.Reg)
border0.Register(c.Reg)
k8s_kind.Register(c.Reg)
cisco_iol.Register(c.Reg)
}
148 changes: 148 additions & 0 deletions docs/manual/kinds/cisco_iol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
---
search:
boost: 4
kind_code_name: cisco_iol
kind_display_name: Cisco IOL
kind_short_display_name: IOL
---
# [[[ kind_display_name ]]]

[[[ kind_display_name ]]] (IOS On Linux or [[[ kind_short_display_name ]]] for short) is a version of Cisco IOS/IOS-XE software which is packaged as binary, in other words it does not require a virtual machine, hence the name IOS *On Linux*.

It is identified with `[[[ kind_code_name ]]]` kind in the [topology file](../topo-def-file.md) and built using [vrnetlab](../vrnetlab.md) project and essentially is the IOL binary packaged into a docker container.

## Getting and building [[[ kind_display_name ]]]

You can get [[[ kind_display_name ]]] from Cisco's CML refplat .iso. It is identified by the `iol` or `ioll2` prefix.

From the IOL binary you are required to build a container using the [vrnetlab](../vrnetlab.md) project.

IOL is distributed as two versions:

- **IOL** - For usage as an L3 router, lacks L2 switching functionality.
- **IOL-L2** - For usage as a virtual version of an IOS-XE switch. Still has support for some L3 features. See [usage information](#usage-and-sample-topology).

## Resource requirements

[[[ kind_display_name ]]] is very light on resources compared to VM-based Cisco products. Each IOL node requires at minimum:

- 1vCPU per node, you are able oversubscribe and run many IOL nodes per vCPU.
- 768Mb of RAM.
- 1Mb of disk space for the NVRAM (where configuration is saved).

Using [KSM](../vrnetlab.md#memory-optimization) you can achieve a higher density of IOL nodes per GB of RAM.

## Managing [[[ kind_display_name ]]] nodes

You can manage the [[[ kind_display_name ]]] with containerlab via the following interfaces:

/// tab | CLI
to connect to the [[[ kind_short_display_name ]]] CLI

```bash
ssh admin@<container-name/id>
```

///
/// tab | bash
to connect to a `bash` shell of a running [[[ kind_short_display_name ]]] container:

```bash
docker exec -it <container-name/id> bash
```

///

/// note
Default credentials: `admin:admin`
///

## Interface naming

You can use [interfaces names](../topo-def-file.md#interface-naming) in the topology file like they appear in the [[[ kind_display_name ]]] CLI.

The interface naming convention is: `Ethernet0/X` (or `e0/X`), where `X` is the port number.

With that naming convention in mind:

- `e0/1` - First data-plane interface available
- `e0/2` - Second data-plane interface, and so on...

Keep in mind IOL defines interfaces in groups of 4. Every four interfaces (zero-indexed), the slot index increments by one.

- `e0/3` - Third data-plane interface
- `e1/0` - Fourth data-plane interface
- `e1/1` - Fifth data-plane interface

The example ports above would be mapped to the following Linux interfaces inside the container running [[[ kind_display_name ]]]:

- `eth0` - management interface connected to the containerlab management network. Mapped to `Ethernet0/0`.
- `eth1` - First data-plane interface. Mapped to `Ethernet0/1` interface.
- `eth2` - Second data-plane interface. Mapped to `Ethernet0/2` interface
- `eth3` - Third data-plane interface. Mapped to `Ethernet0/3` interface
- `eth4` - Fourth data-plane interface. Mapped to `Ethernet1/0` interface
- `eth5` - Fifth data-plane interface. Mapped to `Ethernet1/1` interface and so on...

When containerlab launches [[[ kind_display_name ]]], the `Ethernet0/0` or `Vlan1` interface of the container gets assigned management IPv4 and IPv6 addresses from docker. On IOL the `Ethernet0/0` is in it's own management VRF so configuration in the global context will not affect the management interface. On IOL-L2 the management interface is the `Vlan1` interface, it is also in it's own management VRF.

Interfaces can be defined in a non-contigous manner in your toplogy file. See the example below.

```yaml
name: my-iol-lab
topology:
nodes:
iol-1:
kind: cisco_iol
image: vrnetlab/cisco_iol:17.12.01
iol-2:
kind: cisco_iol
image: vrnetlab/cisco_iol:17.12.01

links:
- endpoints: ["iol-1:Ethernet0/1","iol-2:Ethernet0/1"]
- endpoints: ["iol-1:Ethernet1/3", "iol-2:Ethernet1/0"]
```
/// warning
When defining interfaces non-contigiously you may see more interfaces than you have defined in the [[[ kind_short_display_name ]]] CLI, this is because interfaces are provisioned in groups.
At minimum you will see all numerically-lower indexed interfaces in the CLI compared to the interface you have defined, you may also see interfaces with a higher numerical index.
**Links/interfaces that you did not define in your containerlab topology will *not* pass any traffic.**
///
Data interfaces `Ethernet0/1+` need to be configured with IP addressing manually using CLI or other available management interfaces and will appear `unset` in the CLI:

```
iol#sh ip int br
Interface IP-Address OK? Method Status Protocol
Ethernet0/0 172.20.20.5 YES TFTP up up
Ethernet0/1 unassigned YES unset administratively down down
Ethernet0/2 unassigned YES unset administratively down down
Ethernet0/3 unassigned YES unset administratively down down
```
## Usage and sample topology
IOL-L2 has a different startup configuration compared to the regular IOL. You can tell containerlab you are using the L2 image by supplying the `type` field in your topology.
See the sample topology below
```yaml
name: iol
topology:
nodes:
router1:
kind: cisco_iol
image: vrnetlab/cisco_iol:17.12.01
router2:
kind: cisco_iol
image: vrnetlab/cisco_iol:17.12.01
switch:
kind: cisco_iol
image: vrnetlab/cisco_iol:L2-17.12.01
type: l2
links:
- endpoints: ["router1:Ethernet0/1","switch:Ethernet0/1"]
- endpoints: ["router2:Ethernet0/1","switch:e0/2"]
```
1 change: 1 addition & 0 deletions docs/manual/kinds/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Within each predefined kind, we store the necessary information that is used to
| **Cisco Nexus 9000v** | [`vr-n9kv/vr-cisco_n9kv`](vr-n9kv.md) | supported | VM |
| **Cisco 8000** | [`c8000/cisco_c8000`](c8000.md) | supported | VM+ |
| **Cisco Catalyst 9000v** | [`cat9kv/vr-cisco_cat9kv`](vr-cat9kv.md) | supported | VM |
| **Cisco IOL** | [`cisco_iol`](cisco_iol.md) | supported | container |
| **Cisco FTDv** | [`cisco_ftdv`](vr-ftdv.md) | supported | VM |
| **Cumulus VX** | [`cvx/cumulus_cvx`](cvx.md) | supported | container |
| **Aruba ArubaOS-CX** | [`vr-aoscx/vr-aruba_aoscx`](vr-aoscx.md) | supported | VM |
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ nav:
- Cisco 8000: manual/kinds/c8000.md
- Cisco c8000v: manual/kinds/vr-c8000v.md
- Cisco Catalyst 9000v: manual/kinds/vr-cat9kv.md
- Cisco IOL: manual/kinds/cisco_iol.md
- Cisco FTDv: manual/kinds/vr-ftdv.md
- Juniper:
- Juniper cRPD: manual/kinds/crpd.md
Expand Down
56 changes: 56 additions & 0 deletions nodes/iol/iol.cfg.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
hostname {{ .Hostname }}
!
no aaa new-model
!
ip domain name lab
!
ip cef
!
ipv6 unicast-routing
!
no ip domain lookup
!
username admin privilege 15 secret admin
!
vrf definition clab-mgmt
address-family ipv4
!
address-family ipv6
!
!
{{ if .IsL2Node }}
interface Vlan1
vrf forwarding clab-mgmt
ip address {{ .MgmtIPv4Addr }} {{ .MgmtIPv4SubnetMask }}
ipv6 address {{ .MgmtIPv6Addr }}/{{ .MgmtIPv6PrefixLen }}
!
{{ end }}
interface Ethernet0/0
no shutdown
mac-address {{ .MgmtIntfMacAddr }}
{{ if .IsL2Node }}
switchport mode access
switchport access vlan 1
{{ else }}
vrf forwarding clab-mgmt
ip address {{ .MgmtIPv4Addr }} {{ .MgmtIPv4SubnetMask }}
ipv6 address {{ .MgmtIPv6Addr }}/{{ .MgmtIPv6PrefixLen }}
{{ end }}
!{{ range $index, $item := .DataIFaces }}
interface Ethernet{{ .Slot }}/{{ .Port }}
no shutdown
mac-address {{ .MacAddr }}
!{{ end }}
ip forward-protocol nd
!
ip route vrf clab-mgmt 0.0.0.0 0.0.0.0 {{ if .IsL2Node }}Vlan1{{ else }}Ethernet0/0{{ end }} {{ .MgmtIPv4GW }}
ipv6 route vrf clab-mgmt ::/0 {{ if .IsL2Node }}Vlan1{{ else }}Ethernet0/0{{ end }} {{ .MgmtIPv6GW }}
!
ip ssh version 2
crypto key generate rsa modulus 2048
!
line vty 0 4
login local
transport input ssh
!
end
Loading

0 comments on commit 2764acc

Please sign in to comment.