Skip to content

Commit

Permalink
nokia_sros: Add pass-through management interface support (#272)
Browse files Browse the repository at this point in the history
* vrnetlab: Add pass-through management interfaces

* vjunos: Add pass-through management interface support

* vrnetlab: Use JSON output of iproute2

* vrnetlab: Add exception for serial console ports 5000-5007 for transparent mode mgmt interface

* vrnetlab: Remove non-working port 5000 tc mirred exception, redirect to correct interface

* vrnetlab: Use tc clsact qdisc and flower matching as best practice

* vrnetlab: Re-add workaround for serial ports in transparent mgmt mode

* vrnetlab: Add IPv6 support to management address/gw functions

* vjunos: Add IPv6 management addresses, fix v4 address templating

* vrnetlab: Set dummy IPv6 address/gw for hostfwd management

* Fix CSR1000v and c8000v (#269)

* Remove whitespaces from IMG_NAME and IMG_VENDOR

* Fix Cisco CSR1000v

* Fix Cisco c8000v

* Use env var passed from containerlab for IOL launch PID (#270)

* nokia_sros: Add pass-through management interface support

* fix comment

* change mgmt address parsing

* added self.mgmt_nic_passthrough to VR and VM classes

* remove copy of a healthcheck

* formatting

* added mgmt passthrough to the VR class and aligned SR OS

* added v6 address to bof

---------

Co-authored-by: vista <[email protected]>
Co-authored-by: Athanasios Kompouras <[email protected]>
Co-authored-by: Kaelem <[email protected]>
Co-authored-by: Roman Dodin <[email protected]>
  • Loading branch information
5 people authored Dec 3, 2024
1 parent baeab04 commit 9078c56
Show file tree
Hide file tree
Showing 3 changed files with 371 additions and 152 deletions.
69 changes: 43 additions & 26 deletions common/vrnetlab.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def __init__(
self._cpu = cpu
self._smp = smp

# various settings
# various settings
self.uuid = None
self.fake_start_date = None
self.nic_type = "e1000"
Expand All @@ -109,14 +109,18 @@ def __init__(
# to have them allocated sequential from eth1
self.highest_provisioned_nic_num = 0

# Whether the management interface is pass-through or host-forwarded
self.mgmt_nic_passthrough = mgmt_passthrough
# Whether the management interface is pass-through or host-forwarded.
# Host-forwarded is the original vrnetlab mode where a VM gets a static IP for its management address,
# which **does not** match the eth0 interface of a container.
# In pass-through mode the VM container uses the same IP as the container's eth0 interface and transparently forwards traffic between the two interfaces.
# See https://github.com/hellt/vrnetlab/issues/286
self.mgmt_passthrough = mgmt_passthrough
mgmt_passthrough_override = os.environ.get("CLAB_MGMT_PASSTHROUGH", "")
if mgmt_passthrough_override:
self.mgmt_nic_passthrough = mgmt_passthrough_override.lower() == "true"
self.mgmt_passthrough = mgmt_passthrough_override.lower() == "true"

# Populate management IP and gateway
if self.mgmt_nic_passthrough:
if self.mgmt_passthrough:
self.mgmt_address_ipv4, self.mgmt_address_ipv6 = self.get_mgmt_address()
self.mgmt_gw_ipv4, self.mgmt_gw_ipv6 = self.get_mgmt_gw()
else:
Expand Down Expand Up @@ -353,11 +357,13 @@ def gen_mgmt(self):
self.mgmt_mac = mac
res.append(self.nic_type + f",netdev=p00,mac={self.mgmt_mac}")

if self.mgmt_nic_passthrough:
if self.mgmt_passthrough:
# mgmt interface is passthrough - we just create a normal mirred tap interface
if self.conn_mode == "tc":
res.append("-netdev")
res.append("tap,id=p00,ifname=tap0,script=/etc/tc-tap-mgmt-ifup,downscript=no")
res.append(
"tap,id=p00,ifname=tap0,script=/etc/tc-tap-mgmt-ifup,downscript=no"
)
self.create_tc_tap_mgmt_ifup()
else:
# mgmt interface is special - we use qemu user mode network
Expand All @@ -379,41 +385,42 @@ def gen_mgmt(self):
return res

def get_mgmt_address(self):
""" Returns the IPv4 and IPv6 address of the eth0 interface of the container"""
"""Returns the IPv4 and IPv6 address of the eth0 interface of the container"""
stdout, _ = run_command(["ip", "--json", "address", "show", "dev", "eth0"])
command_json = json.loads(stdout.decode('utf-8'))
intf_addrinfos = command_json[0]['addr_info']

command_json = json.loads(stdout.decode("utf-8"))
intf_addrinfos = command_json[0]["addr_info"]
mgmt_cidr_v4 = None
mgmt_cidr_v6 = None
for addrinfo in intf_addrinfos:
if addrinfo['family'] == 'inet' and addrinfo['scope'] == 'global':
mgmt_address_v4 = addrinfo['local']
mgmt_prefixlen_v4 = addrinfo['prefixlen']
mgmt_cidr_v4 = mgmt_address_v4 + '/' + str(mgmt_prefixlen_v4)
if addrinfo['family'] == 'inet6' and addrinfo['scope'] == 'global':
mgmt_address_v6 = addrinfo['local']
mgmt_prefixlen_v6 = addrinfo['prefixlen']
mgmt_cidr_v6 = mgmt_address_v6 + '/' + str(mgmt_prefixlen_v6)
if addrinfo["family"] == "inet" and addrinfo["scope"] == "global":
mgmt_address_v4 = addrinfo["local"]
mgmt_prefixlen_v4 = addrinfo["prefixlen"]
mgmt_cidr_v4 = mgmt_address_v4 + "/" + str(mgmt_prefixlen_v4)
if addrinfo["family"] == "inet6" and addrinfo["scope"] == "global":
mgmt_address_v6 = addrinfo["local"]
mgmt_prefixlen_v6 = addrinfo["prefixlen"]
mgmt_cidr_v6 = mgmt_address_v6 + "/" + str(mgmt_prefixlen_v6)

if not mgmt_cidr_v4:
raise ValueError("No IPv4 address set on management interface eth0!")

return mgmt_cidr_v4, mgmt_cidr_v6

def get_mgmt_gw(self):
""" Returns the IPv4 and IPv6 default gateways of the container, used for generating the management default route"""
"""Returns the IPv4 and IPv6 default gateways of the container, used for generating the management default route"""
stdout_v4, _ = run_command(["ip", "--json", "-4", "route", "show", "default"])
command_json_v4 = json.loads(stdout_v4.decode('utf-8'))
command_json_v4 = json.loads(stdout_v4.decode("utf-8"))
try:
mgmt_gw_v4 = command_json_v4[0]['gateway']
mgmt_gw_v4 = command_json_v4[0]["gateway"]
except IndexError as e:
raise IndexError("No default gateway route on management interface eth0!") from e
raise IndexError(
"No default gateway route on management interface eth0!"
) from e

stdout_v6, _ = run_command(["ip", "--json", "-6", "route", "show", "default"])
command_json_v6 = json.loads(stdout_v6.decode('utf-8'))
command_json_v6 = json.loads(stdout_v6.decode("utf-8"))
try:
mgmt_gw_v6 = command_json_v6[0]['gateway']
mgmt_gw_v6 = command_json_v6[0]["gateway"]
except IndexError:
mgmt_gw_v6 = None

Expand Down Expand Up @@ -723,9 +730,19 @@ def qemu_additional_args(self):


class VR:
def __init__(self, username, password):
def __init__(self, username, password, mgmt_passthrough: bool = False):
self.logger = logging.getLogger()

# Whether the management interface is pass-through or host-forwarded.
# Host-forwarded is the original vrnetlab mode where a VM gets a static IP for its management address,
# which **does not** match the eth0 interface of a container.
# In pass-through mode the VM container uses the same IP as the container's eth0 interface and transparently forwards traffic between the two interfaces.
# See https://github.com/hellt/vrnetlab/issues/286
self.mgmt_passthrough = mgmt_passthrough
mgmt_passthrough_override = os.environ.get("CLAB_MGMT_PASSTHROUGH", "")
if mgmt_passthrough_override:
self.mgmt_passthrough = mgmt_passthrough_override.lower() == "true"

try:
os.mkdir("/tftpboot")
except:
Expand Down
18 changes: 0 additions & 18 deletions sros/docker/healthcheck.py

This file was deleted.

Loading

0 comments on commit 9078c56

Please sign in to comment.