Skip to content

Commit

Permalink
Transparent management interfaces for Cisco nodes. (#290)
Browse files Browse the repository at this point in the history
* Add function to convert CIDR to DDN notation

* Add IOS-XE device support for transparent mgmt intf

* Implement transparent mgmt intf on XRv

* Add transparent mgmt if functionality to xrv9k

* Add transparent mgmt intf to vIOS

* Add transparent mgmt intf to n9kv and use 2048 bit keys

* Remove incorrectly pasted command from n9kv

* Add explicit IPv6 enablement to vIOS

* Update vIOS default creds to `admin:admin`

* NXOS: Add transparent mgmt intf support + mgmt vrf + 2048-bit SSH keys

* change n9kv version parser and FROM image

* fix comment

* Update images to `debian:bookworm-slim`

* Update `cidr_to_ddn()` func to use stdlib for address splitting

* use `super().gen_mgmt()` to extend `gen_mgmt()` fn on XRv9k

---------

Co-authored-by: Roman Dodin <[email protected]>
  • Loading branch information
kaelemc and hellt authored Dec 8, 2024
1 parent 8d977ba commit 7ff8969
Show file tree
Hide file tree
Showing 16 changed files with 117 additions and 64 deletions.
14 changes: 11 additions & 3 deletions c8000v/docker/launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ def bootstrap_spin(self):
def bootstrap_config(self):
"""Do the actual bootstrap config"""
self.logger.info("applying bootstrap configuration")

v4_mgmt_address = vrnetlab.cidr_to_ddn(self.mgmt_address_ipv4)

self.wait_write("", None)
self.wait_write("enable", wait=">")
Expand All @@ -165,17 +167,23 @@ def bootstrap_config(self):
self.wait_write("ip domain-name example.com")
self.wait_write("crypto key generate rsa modulus 2048")

self.wait_write("ipv6 unicast-routing")

self.wait_write("vrf definition clab-mgmt")
self.wait_write("description Containerlab management VRF (DO NOT DELETE)")
self.wait_write("address-family ipv4")
self.wait_write("exit")
self.wait_write("description Containerlab management VRF (DO NOT DELETE)")
self.wait_write("address-family ipv6")
self.wait_write("exit")
self.wait_write("exit")

self.wait_write("ip route vrf clab-mgmt 0.0.0.0 0.0.0.0 10.0.0.2")
self.wait_write(f"ip route vrf clab-mgmt 0.0.0.0 0.0.0.0 {self.mgmt_gw_ipv4}")
self.wait_write(f"ipv6 route vrf clab-mgmt ::/0 {self.mgmt_gw_ipv6}")

self.wait_write("interface GigabitEthernet1")
self.wait_write("vrf forwarding clab-mgmt")
self.wait_write("ip address 10.0.0.15 255.255.255.0")
self.wait_write(f"ip address {v4_mgmt_address[0]} {v4_mgmt_address[1]}")
self.wait_write(f"ipv6 address {self.mgmt_address_ipv6}")
self.wait_write("no shut")
self.wait_write("exit")
self.wait_write("restconf")
Expand Down
10 changes: 8 additions & 2 deletions cat9kv/docker/launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ def bootstrap_spin(self):
def bootstrap_config(self):
"""Do the actual bootstrap config"""
self.logger.info("applying bootstrap configuration")

v4_mgmt_address = vrnetlab.cidr_to_ddn(self.mgmt_address_ipv4)

self.wait_write("", None)
self.wait_write("enable", wait=">")
Expand All @@ -173,12 +175,16 @@ def bootstrap_config(self):
self.wait_write("crypto key generate rsa modulus 2048")

self.wait_write("no ip domain lookup")

self.wait_write("ipv6 unicast-routing")

# add mgmt vrf static route
self.wait_write("ip route vrf Mgmt-vrf 0.0.0.0 0.0.0.0 10.0.0.2")
self.wait_write(f"ip route vrf clab-mgmt 0.0.0.0 0.0.0.0 {self.mgmt_gw_ipv4}")
self.wait_write(f"ipv6 route vrf clab-mgmt ::/0 {self.mgmt_gw_ipv6}")

self.wait_write("interface GigabitEthernet0/0")
self.wait_write("ip address 10.0.0.15 255.255.255.0")
self.wait_write(f"ip address {v4_mgmt_address[0]} {v4_mgmt_address[1]}")
self.wait_write(f"ipv6 address {self.mgmt_address_ipv6}")
self.wait_write("no shut")
self.wait_write("exit")

Expand Down
14 changes: 14 additions & 0 deletions common/vrnetlab.py
Original file line number Diff line number Diff line change
Expand Up @@ -837,3 +837,17 @@ def get_digits(input_str: str) -> int:

non_string_chars = re.findall(r"\d", input_str)
return int("".join(non_string_chars))

def cidr_to_ddn(prefix: str) -> list[str]:
"""
Convert a IPv4 CIDR notation prefix to address + mask in DDN notation
Returns a list of IP address (str) and mask (str) in dotted decimal
Example:
get_ddn_mask('192.168.0.1/24')
returns ['192.168.0.1' ,'255.255.255.0']
"""

network = ipaddress.IPv4Interface(prefix)
return [str(network.ip), str(network.netmask)]
2 changes: 1 addition & 1 deletion csr/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ubuntu:20.04
FROM public.ecr.aws/docker/library/debian:bookworm-slim
MAINTAINER Kristian Larsson <[email protected]>
MAINTAINER Denis Pointer <[email protected]>

Expand Down
14 changes: 11 additions & 3 deletions csr/docker/launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ def bootstrap_spin(self):
def bootstrap_config(self):
"""Do the actual bootstrap config"""
self.logger.info("applying bootstrap configuration")

v4_mgmt_address = vrnetlab.cidr_to_ddn(self.mgmt_address_ipv4)

self.wait_write("", None)
self.wait_write("enable", wait=">")
Expand All @@ -159,17 +161,23 @@ def bootstrap_config(self):
self.wait_write("ip domain-name example.com")
self.wait_write("crypto key generate rsa modulus 2048")

self.wait_write("ipv6 unicast-routing")

self.wait_write("vrf definition clab-mgmt")
self.wait_write("description Containerlab management VRF (DO NOT DELETE)")
self.wait_write("address-family ipv4")
self.wait_write("exit")
self.wait_write("description Containerlab management VRF (DO NOT DELETE)")
self.wait_write("address-family ipv6")
self.wait_write("exit")
self.wait_write("exit")

self.wait_write("ip route vrf clab-mgmt 0.0.0.0 0.0.0.0 10.0.0.2")
self.wait_write(f"ip route vrf clab-mgmt 0.0.0.0 0.0.0.0 {self.mgmt_gw_ipv4}")
self.wait_write(f"ipv6 route vrf clab-mgmt ::/0 {self.mgmt_gw_ipv6}")

self.wait_write("interface GigabitEthernet1")
self.wait_write("vrf forwarding clab-mgmt")
self.wait_write("ip address 10.0.0.15 255.255.255.0")
self.wait_write(f"ip address {v4_mgmt_address[0]} {v4_mgmt_address[1]}")
self.wait_write(f"ipv6 address {self.mgmt_address_ipv6}")
self.wait_write("no shut")
self.wait_write("exit")
self.wait_write("restconf")
Expand Down
15 changes: 5 additions & 10 deletions n9kv/Makefile
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
VENDOR=Cisco
NAME=NXOS 9000v
NAME=n9kv
IMAGE_FORMAT=qcow2
IMAGE_GLOB=*.qcow2

# Match versions similar to the following:
# - nxosv-final.7.0.3.I7.5a.qcow2
# - nxosv-final.7.0.3.I7.9.qcow2
# - nxosv.9.2.1.qcow2
# - nxosv.9.2.4.qcow2
# - nexus9300v.9.3.9.qcow2
# - nexus9300v.9.3.10.qcow2
# - nexus9300v64.10.2.2.F.qcow
VERSION=$(shell echo $(IMAGE) | sed -e 's/.\+\?\.\(\(7\.0\.3\.I[0-9]\.[0-9a-z]\+\)\|\([0-9]\+\.[0-9]\+\.[0-9]\+\)\)\(\..*\|$$\)/\1/')
# rename the disk image file as n9kv-<version>.qcow2
# examples:
# for a file named "n9kv-9300-10.5.2.qcow2" the image will be named "vrnetlab/cisco_n9kv:9300-10.5.2"
VERSION=$(shell echo $(IMAGE) | sed -e 's/n9kv-\(.*\)\.qcow2/\1/')

-include ../makefile-sanity.include
-include ../makefile.include
8 changes: 3 additions & 5 deletions n9kv/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
FROM ubuntu:20.04
LABEL maintainer="Kristian Larsson <[email protected]>"
LABEL maintainer="Roman Dodin <[email protected]>"
FROM public.ecr.aws/docker/library/debian:bookworm-slim
LABEL maintainer="Roman Dodin <[email protected]>, Kaelem Chandra <[email protected]>"

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update -qy \
&& apt-get upgrade -qy \
&& apt-get install -y \
&& apt-get install -y --no-install-recommends \
bridge-utils \
iproute2 \
python3-ipy \
Expand Down
10 changes: 8 additions & 2 deletions n9kv/docker/launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,19 @@ def bootstrap_config(self):

# configure management vrf
self.wait_write("vrf context management")
self.wait_write("ip route 0.0.0.0/0 10.0.0.2")
self.wait_write(f"ip route 0.0.0.0/0 {self.mgmt_gw_ipv4}")
self.wait_write(f"ipv6 route ::/0 {self.mgmt_gw_ipv6}")
self.wait_write("exit")

# configure mgmt interface
self.wait_write("interface mgmt0")
self.wait_write("ip address 10.0.0.15/24")
self.wait_write(f"ip address {self.mgmt_address_ipv4}")
self.wait_write(f"ipv6 address {self.mgmt_address_ipv6}")
self.wait_write("exit")

# configure longer ssh keys
self.wait_write("ssh key rsa 2048 force")
self.wait_write("feature ssh")

# setup nxapi/scp server
self.wait_write("feature scp-server")
Expand Down
2 changes: 1 addition & 1 deletion nxos/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ubuntu:20.04
FROM public.ecr.aws/docker/library/debian:bookworm-slim
LABEL org.opencontainers.image.authors="[email protected]"

ENV DEBIAN_FRONTEND=noninteractive
Expand Down
15 changes: 14 additions & 1 deletion nxos/docker/launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,23 @@ def bootstrap_config(self):
)
self.wait_write("hostname %s" % (self.hostname))

# configure management vrf
self.wait_write("vrf context management")
self.wait_write(f"ip route 0.0.0.0/0 {self.mgmt_gw_ipv4}")
self.wait_write(f"ipv6 route ::/0 {self.mgmt_gw_ipv6}")
self.wait_write("exit")

# configure mgmt interface
self.wait_write("interface mgmt0")
self.wait_write("ip address 10.0.0.15/24")
self.wait_write(f"ip address {self.mgmt_address_ipv4}")
self.wait_write(f"ipv6 address {self.mgmt_address_ipv6}")
self.wait_write("exit")

# configure longer ssh keys
self.wait_write("no feature ssh")
self.wait_write("ssh key rsa 2048 force")
self.wait_write("feature ssh")

self.wait_write("exit")
self.wait_write("copy running-config startup-config")

Expand Down
9 changes: 3 additions & 6 deletions vios/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ The following protocols are enabled on the management interface:

| ID | Description | Default |
|-----------------|---------------------------|------------|
| USERNAME | SSH username | vrnetlab |
| PASSWORD | SSH password | VR-netlab9 |
| USERNAME | SSH username | admin |
| PASSWORD | SSH password | admin |
| HOSTNAME | device hostname | vios |
| TRACE | enable trace logging | false |
| CONNECTION_MODE | interface connection mode | tc |
Expand All @@ -75,10 +75,7 @@ name: vios-lab
topology:
kinds:
linux:
image: vrnetlab/vr-vios:15.9.3M6
env:
USERNAME: admin
PASSWORD: admin
image: vrnetlab/cisco_vios:15.9.3M6
nodes:
vios1:
kind: linux
Expand Down
20 changes: 15 additions & 5 deletions vios/docker/launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ def _bootstrap_config(self):
self.wait_write(f"hostname {self.hostname}")
self.wait_write(f"ip domain-name {self.hostname}.clab")
self.wait_write("no ip domain-lookup")

# Explicitly enable IPv6
self.wait_write("ipv6 unicast-routing")

self.wait_write(f"username {self.username} privilege 15 secret {self.password}")

Expand All @@ -138,17 +141,24 @@ def _bootstrap_config(self):
self.wait_write("exit")

self.wait_write("vrf definition clab-mgmt")
self.wait_write("description Containerlab management VRF (DO NOT DELETE)")
self.wait_write("address-family ipv4")
self.wait_write("exit")
self.wait_write("description Management network")
self.wait_write("address-family ipv6")
self.wait_write("exit")
self.wait_write("exit")

v4_mgmt_address = vrnetlab.cidr_to_ddn(self.mgmt_address_ipv4)

self.wait_write("interface GigabitEthernet0/0")
self.wait_write("vrf forwarding clab-mgmt")
self.wait_write("ip address 10.0.0.15 255.255.255.0")
self.wait_write(f"ip address {v4_mgmt_address[0]} {v4_mgmt_address[1]}")
self.wait_write(f"ipv6 address {self.mgmt_address_ipv6}")
self.wait_write("no shutdown")
self.wait_write("exit")
self.wait_write("ip route vrf clab-mgmt 0.0.0.0 0.0.0.0 10.0.0.2")

self.wait_write(f"ip route vrf clab-mgmt 0.0.0.0 0.0.0.0 {self.mgmt_gw_ipv4}")
self.wait_write(f"ipv6 route vrf clab-mgmt ::/0 {self.mgmt_gw_ipv6}")

self.wait_write("crypto key generate rsa modulus 2048")
self.wait_write("ip ssh version 2")
Expand Down Expand Up @@ -195,10 +205,10 @@ def __init__(self, hostname: str, username: str, password: str, conn_mode: str):
default=os.getenv("TRACE", "false").lower() == "true",
)
parser.add_argument(
"--username", help="Username", default=os.getenv("USERNAME", "vrnetlab")
"--username", help="Username", default=os.getenv("USERNAME", "admin")
)
parser.add_argument(
"--password", help="Password", default=os.getenv("PASSWORD", "VR-netlab9")
"--password", help="Password", default=os.getenv("PASSWORD", "admin")
)
parser.add_argument(
"--hostname", help="Router hostname", default=os.getenv("HOSTNAME", "vios")
Expand Down
2 changes: 1 addition & 1 deletion xrv/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ubuntu:20.04
FROM public.ecr.aws/docker/library/debian:bookworm-slim
LABEL org.opencontainers.image.authors="[email protected]"

ARG DEBIAN_FRONTEND=noninteractive
Expand Down
10 changes: 8 additions & 2 deletions xrv/docker/launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,18 @@ def bootstrap_config(self):
self.wait_write("description Containerlab management VRF (DO NOT DELETE)")
self.wait_write("address-family ipv4 unicast")
self.wait_write("exit")
self.wait_write("address-family ipv6 unicast")
self.wait_write("exit")
self.wait_write("exit")

# add static route for management
self.wait_write("router static")
self.wait_write("vrf clab-mgmt")
self.wait_write("address-family ipv4 unicast")
self.wait_write("0.0.0.0/0 10.0.0.2")
self.wait_write(f"0.0.0.0/0 {self.mgmt_gw_ipv4}")
self.wait_write("exit")
self.wait_write("address-family ipv6 unicast")
self.wait_write(f"::/0 {self.mgmt_gw_ipv6}")
self.wait_write("exit")
self.wait_write("exit")
self.wait_write("exit")
Expand All @@ -203,7 +208,8 @@ def bootstrap_config(self):
self.wait_write("interface MgmtEth 0/0/CPU0/0")
self.wait_write("vrf clab-mgmt")
self.wait_write("no shutdown")
self.wait_write("ipv4 address 10.0.0.15/24")
self.wait_write(f"ipv4 address {self.mgmt_address_ipv4}")
self.wait_write(f"ipv6 address {self.mgmt_address_ipv6}")
self.wait_write("exit")
self.wait_write("commit")
self.wait_write("exit")
Expand Down
2 changes: 1 addition & 1 deletion xrv9k/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ubuntu:20.04
FROM public.ecr.aws/docker/library/debian:bookworm-slim
LABEL org.opencontainers.image.authors="[email protected]"

ARG DEBIAN_FRONTEND=noninteractive
Expand Down
Loading

0 comments on commit 7ff8969

Please sign in to comment.