From 7d5c21acc1dab9b7ca53bc89a5ee2ff2ee6cd64f Mon Sep 17 00:00:00 2001 From: Akiel Aries <56521583+akielaries@users.noreply.github.com> Date: Wed, 13 Dec 2023 03:14:47 -0700 Subject: [PATCH] Add support for vJunosEvolved (#1775) * adding support for vJunosEvolved * removing vim files * Update vr-vjunosevolved.md * update link README.md * adding vJunosEvolved lab example doc, mkdocs.yml, and link in README * removing vr- prefixed instances of vJunos-switch and Evo. updating lab-example to reference upcoming release of clab * removing vr- prefix in `vr-vjunosswitch.go` --- README.md | 2 + clab/register.go | 2 + docs/lab-examples/srl-vjunosevolved.md | 25 +++++ docs/manual/kinds/vr-vjunosevolved.md | 83 ++++++++++++++ docs/manual/vrnetlab.md | 1 + lab-examples/srlvjunos02/srl.cli | 39 +++++++ lab-examples/srlvjunos02/srlvjunos02.clab.yml | 18 +++ lab-examples/srlvjunos02/vjunos.cfg | 23 ++++ mkdocs.yml | 2 + nodes/vr_vjunosevolved/vr-vjunosevolved.go | 103 ++++++++++++++++++ nodes/vr_vjunosswitch/vr-vjunosswitch.go | 2 +- schemas/clab.schema.json | 7 +- 12 files changed, 303 insertions(+), 4 deletions(-) create mode 100644 docs/lab-examples/srl-vjunosevolved.md create mode 100644 docs/manual/kinds/vr-vjunosevolved.md create mode 100644 lab-examples/srlvjunos02/srl.cli create mode 100644 lab-examples/srlvjunos02/srlvjunos02.clab.yml create mode 100644 lab-examples/srlvjunos02/vjunos.cfg create mode 100644 nodes/vr_vjunosevolved/vr-vjunosevolved.go diff --git a/README.md b/README.md index 9603b96ca..ffec6d245 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,8 @@ In addition to native containerized NOSes, containerlab can launch traditional v * [Juniper vMX](https://containerlab.dev/manual/kinds/vr-vmx/) * [Juniper vQFX](https://containerlab.dev/manual/kinds/vr-vqfx/) * [Juniper vSRX](https://containerlab.dev/manual/kinds/vr-vsrx/) +* [Juniper vJunos-switch](https://containerlab.dev/manual/kinds/vr-vjunosswitch/) +* [Juniper vJunosEvolved](https://containerlab.dev/manual/kinds/vr-vjunosevolved/) * [Cisco IOS XRv9k](https://containerlab.dev/manual/kinds/vr-xrv9k/) * [Cisco Nexus 9000v](https://containerlab.dev/manual/kinds/vr-n9kv) * [Cisco CSR 1000v](https://containerlab.dev/manual/kinds/vr-csr) diff --git a/clab/register.go b/clab/register.go index 13be1157a..4ed8b5bed 100644 --- a/clab/register.go +++ b/clab/register.go @@ -31,6 +31,7 @@ import ( vr_sros "github.com/srl-labs/containerlab/nodes/vr_sros" vr_veos "github.com/srl-labs/containerlab/nodes/vr_veos" vr_vjunosswitch "github.com/srl-labs/containerlab/nodes/vr_vjunosswitch" + vr_vjunosevolved "github.com/srl-labs/containerlab/nodes/vr_vjunosevolved" vr_vmx "github.com/srl-labs/containerlab/nodes/vr_vmx" vr_vqfx "github.com/srl-labs/containerlab/nodes/vr_vqfx" vr_vsrx "github.com/srl-labs/containerlab/nodes/vr_vsrx" @@ -67,6 +68,7 @@ func (c *CLab) RegisterNodes() { vr_vsrx.Register(c.Reg) vr_vqfx.Register(c.Reg) vr_vjunosswitch.Register(c.Reg) + vr_vjunosevolved.Register(c.Reg) vr_xrv.Register(c.Reg) vr_xrv9k.Register(c.Reg) xrd.Register(c.Reg) diff --git a/docs/lab-examples/srl-vjunosevolved.md b/docs/lab-examples/srl-vjunosevolved.md new file mode 100644 index 000000000..25132ebfb --- /dev/null +++ b/docs/lab-examples/srl-vjunosevolved.md @@ -0,0 +1,25 @@ +| | | +| ----------------------------- | ---------------------------------------------------------------------------------------- | +| **Description** | A Nokia SR Linux connected back-to-back with Juniper vJunosEvolved | +| **Components** | [Nokia SR Linux][srl], [Juniper vJunosEvolved][vjunos] | +| **Resource requirements**[^1] | :fontawesome-solid-microchip: 6
:fontawesome-solid-memory: 12 GB | +| **Topology file** | [srlvjunos02.clab.yml][topofile] | +| **Name** | srlvjunos02 | +| **Version information**[^2] | `containerlab:0.49.0`, `srlinux:23.7.1`, `vJunosEvolved-23.2R1-S1.8`, `docker-ce:24.0.7,` | + +## Description + +A lab consists of an SR Linux node connected with Juniper vJunosEvolved via three point-to-point ethernet links. Both nodes are also connected with their management interfaces to the `clab` docker network. + +## Use cases + +The nodes are provisioned with a basic interface configuration for three interfaces they are connected with. Pings between the nodes should work out of the box using all three interfaces. + +[srl]: ../manual/kinds/srl.md +[vjunos]: ../manual/kinds/vr-vjunosevolved.md +[topofile]: https://github.com/srl-labs/containerlab/tree/main/lab-examples/srlvjunos02/srlvjunos02.clab.yml + +[^1]: Resource requirements are provisional. Consult with the installation guides for additional information. +[^2]: The lab has been validated using these versions of the required tools/components. Using versions other than stated might lead to a non-operational setup process. + + diff --git a/docs/manual/kinds/vr-vjunosevolved.md b/docs/manual/kinds/vr-vjunosevolved.md new file mode 100644 index 000000000..63e38b078 --- /dev/null +++ b/docs/manual/kinds/vr-vjunosevolved.md @@ -0,0 +1,83 @@ +--- +search: + boost: 4 +--- +# Juniper vJunosEvolved + +[Juniper vJunosEvolved](https://support.juniper.net/support/downloads/?p=vjunos-evolved) is a virtualized PTX10001 router identified with `juniper_vjunosevolved` kind in the [topology file](../topo-def-file.md). It is built using [vrnetlab](../vrnetlab.md) project and essentially is a Qemu VM packaged in a docker container format. + +Juniper vJunosEvolved nodes launched with containerlab come up pre-provisioned with SSH, SNMP, NETCONF and gNMI services enabled. + +## How to obtain the image + +The qcow2 image can be downloaded from [Juniper website](https://support.juniper.net/support/downloads/?p=vjunos-evolved) and built with [vrnetlab](../vrnetlab.md). + +## Managing Juniper vJunosEvolved nodes + +!!!note + Containers with vJunosEvolved inside will take ~15min to fully boot. + You can monitor the progress with `docker logs -f `. + +Juniper vJunosEvolved node launched with containerlab can be managed via the following interfaces: + +=== "bash" + to connect to a `bash` shell of a running Juniper vJunosEvolved container: + ```bash + docker exec -it bash + ``` +=== "CLI via SSH" + to connect to the vJunosEvolved CLI + ```bash + ssh admin@ + ``` +=== "NETCONF" + NETCONF server is running over port 830 + ```bash + ssh admin@ -p 830 -s netconf + ``` + +!!!info + Default user credentials: `admin:admin@123` + +## Interfaces mapping + +Juniper vJunosEvolved container can have up to 17 interfaces and uses the following mapping rules: + +* `eth0` - management interface connected to the containerlab management network +* `eth1` - first data interface, mapped to a first data port of vJunosEvolved VM +* `eth2+` - second and subsequent data interface + +When containerlab launches Juniper vJunosEvolved node, it will assign IPv4/6 address to the `eth0` interface. These addresses can be used to reach the management plane of the router. + +Data interfaces `eth1+` need to be configured with IP addressing manually using CLI/management protocols or via a startup-config text file. + +## Features and options + +### Node configuration + +Juniper vJunosEvolved nodes come up with a basic configuration supplied by a mountable configuration disk to the main VM image. Users, management interfaces, and protocols such as SSH and NETCONF are configured. + +#### Startup configuration + +It is possible to make vJunosEvolved nodes boot up with a user-defined startup-config instead of a built-in one. With a [`startup-config`](../nodes.md#startup-config) property of the node/kind user sets the path to the config file that will be mounted to a container and used as a startup-config: + +```yaml +topology: + nodes: + node: + kind: juniper_vjunosevolved + startup-config: myconfig.txt +``` + +With this knob containerlab is instructed to take a file `myconfig.txt` from the directory that hosts the topology file, and copy it to the lab directory for that specific node under the `/config/startup-config.cfg` name. Then the directory that hosts the startup-config dir is mounted to the container. This will result in this config being applied at startup by the node. + +Configuration is applied after the node is started, thus it can contain partial configuration snippets that you desire to add on top of the default config that a node boots up with. + +## Lab examples + +The following labs feature the Juniper vJunosEvolved node: + +* [SR Linux and Juniper vJunosEvolved](../../../lab-examples/srlvjunos02/srlvjunos02.yml + +## Known issues and limitations +* To check the boot log, use `docker logs -f `. diff --git a/docs/manual/vrnetlab.md b/docs/manual/vrnetlab.md index a9d9c0655..244d9bdba 100644 --- a/docs/manual/vrnetlab.md +++ b/docs/manual/vrnetlab.md @@ -90,6 +90,7 @@ The images that work with containerlab will appear in the supported list as we i | Juniper vQFX | [juniper_vqfx](kinds/vr-vqfx.md) | | | | Juniper vSRX | [juniper_vsrx](kinds/vr-vsrx.md) | | | | Juniper vJunos-Switch | [juniper_vjunosswitch](kinds/vr-vjunosswitch.md) | | | +| Juniper vJunosEvolved | [juniper_vjunosevolved](kinds/vr-vjunosevolved.md) | | | | Cisco XRv | [cisco_xrv](kinds/vr-xrv.md) | [SRL & XRv](../lab-examples/vr-xrv.md) | | | Cisco XRv9k | [cisco_xrv9k](kinds/vr-xrv9k.md) | [SRL & XRv9k](../lab-examples/vr-xrv9k.md) | | | Cisco CSR1000v | [cisco_csr](kinds/vr-csr.md) | | | diff --git a/lab-examples/srlvjunos02/srl.cli b/lab-examples/srlvjunos02/srl.cli new file mode 100644 index 000000000..9d820f24f --- /dev/null +++ b/lab-examples/srlvjunos02/srl.cli @@ -0,0 +1,39 @@ +interface ethernet-1/1 { + admin-state enable + subinterface 0 { + ipv4 { + admin-state enable + address 192.168.0.2/24 { + } + } + } +} +interface ethernet-1/2 { + admin-state enable + subinterface 0 { + ipv4 { + admin-state enable + address 192.168.1.2/24 { + } + } + } +} +interface ethernet-1/3 { + admin-state enable + subinterface 0 { + ipv4 { + admin-state enable + address 192.168.2.2/24 { + } + } + } +} + +network-instance default { + interface ethernet-1/1.0 { + } + interface ethernet-1/2.0 { + } + interface ethernet-1/3.0 { + } +} \ No newline at end of file diff --git a/lab-examples/srlvjunos02/srlvjunos02.clab.yml b/lab-examples/srlvjunos02/srlvjunos02.clab.yml new file mode 100644 index 000000000..953dd83db --- /dev/null +++ b/lab-examples/srlvjunos02/srlvjunos02.clab.yml @@ -0,0 +1,18 @@ +name: srlvjunos02 + +topology: + nodes: + srl: + kind: nokia_srlinux + image: ghcr.io/nokia/srlinux:23.7.1 + startup-config: srl.cli + + vevo: + kind: juniper_vjunosevolved + image: vrnetlab/vr-vjunosevolved:23.2R1-S1.8-EVO + startup-config: vjunos.cfg + + links: + - endpoints: ["srl:e1-1", "vevo:eth1"] + - endpoints: ["srl:e1-2", "vevo:eth2"] + - endpoints: ["srl:e1-3", "vevo:eth3"] diff --git a/lab-examples/srlvjunos02/vjunos.cfg b/lab-examples/srlvjunos02/vjunos.cfg new file mode 100644 index 000000000..f6de73d7e --- /dev/null +++ b/lab-examples/srlvjunos02/vjunos.cfg @@ -0,0 +1,23 @@ +interfaces { + et-0/0/0 { + unit 0 { + family inet { + address 192.168.0.1/24; + } + } + } + et-0/0/1 { + unit 0 { + family inet { + address 192.168.1.1/24; + } + } + } + et-0/0/2 { + unit 0 { + family inet { + address 192.168.2.1/24; + } + } + } +} diff --git a/mkdocs.yml b/mkdocs.yml index b465522f9..535b68336 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -18,6 +18,7 @@ nav: - Juniper vQFX: manual/kinds/vr-vqfx.md - Juniper vSRX: manual/kinds/vr-vsrx.md - Juniper vJunos-switch: manual/kinds/vr-vjunosswitch.md + - Juniper vJunosEvolved: manual/kinds/vr-vjunosevolved.md - Cisco XRd: manual/kinds/xrd.md - Cisco XRv9k: manual/kinds/vr-xrv9k.md - Cisco XRv: manual/kinds/vr-xrv.md @@ -97,6 +98,7 @@ nav: - Nokia SR Linux and Cisco XRv: lab-examples/vr-xrv.md - Nokia SR Linux and FRR: lab-examples/srl-frr.md - Nokia SR Linux and Juniper vJunos-switch: lab-examples/srl-vjunos-switch.md + - Nokia SR Linux and Juniper vJunosEvolved: lab-examples/srl-vjunosevolved.md - FRR: lab-examples/frr01.md - Cumulus Linux and FRR: lab-examples/cvx01.md - Cumulus Linux (docker runtime) and Host: lab-examples/cvx02.md diff --git a/nodes/vr_vjunosevolved/vr-vjunosevolved.go b/nodes/vr_vjunosevolved/vr-vjunosevolved.go new file mode 100644 index 000000000..4e17e2fe4 --- /dev/null +++ b/nodes/vr_vjunosevolved/vr-vjunosevolved.go @@ -0,0 +1,103 @@ +// Copyright 2020 Nokia +// Licensed under the BSD 3-Clause License. +// SPDX-License-Identifier: BSD-3-Clause + +package vr_vjunosevolved + +import ( + "context" + "fmt" + "path" + + log "github.com/sirupsen/logrus" + "github.com/srl-labs/containerlab/netconf" + "github.com/srl-labs/containerlab/nodes" + "github.com/srl-labs/containerlab/types" + "github.com/srl-labs/containerlab/utils" +) + +var ( + kindnames = []string{"juniper_vjunosevolved"} + defaultCredentials = nodes.NewCredentials("admin", "admin@123") +) + +const ( + scrapliPlatformName = "juniper_junos" + + configDirName = "config" + startupCfgFName = "startup-config.cfg" +) + +// Register registers the node in the NodeRegistry. +func Register(r *nodes.NodeRegistry) { + r.Register(kindnames, func() nodes.Node { + return new(vrVJUNOSEVOLVED) + }, defaultCredentials) +} + +type vrVJUNOSEVOLVED struct { + nodes.DefaultNode +} + +func (n *vrVJUNOSEVOLVED) Init(cfg *types.NodeConfig, opts ...nodes.NodeOption) error { + // Init DefaultNode + n.DefaultNode = *nodes.NewDefaultNode(n) + // set virtualization requirement + n.HostRequirements.VirtRequired = true + + n.Cfg = cfg + for _, o := range opts { + o(n) + } + // env vars are used to set launch.py arguments in vrnetlab container + defEnv := map[string]string{ + "USERNAME": defaultCredentials.GetUsername(), + "PASSWORD": defaultCredentials.GetPassword(), + "CONNECTION_MODE": nodes.VrDefConnMode, + "DOCKER_NET_V4_ADDR": n.Mgmt.IPv4Subnet, + "DOCKER_NET_V6_ADDR": n.Mgmt.IPv6Subnet, + } + n.Cfg.Env = utils.MergeStringMaps(defEnv, n.Cfg.Env) + + // mount config dir to support startup-config functionality + n.Cfg.Binds = append(n.Cfg.Binds, fmt.Sprint(path.Join(n.Cfg.LabDir, configDirName), ":/config")) + + if n.Cfg.Env["CONNECTION_MODE"] == "macvtap" { + // mount dev dir to enable macvtap + n.Cfg.Binds = append(n.Cfg.Binds, "/dev:/dev") + } + + n.Cfg.Cmd = fmt.Sprintf("--username %s --password %s --hostname %s --connection-mode %s --trace", + defaultCredentials.GetUsername(), defaultCredentials.GetPassword(), n.Cfg.ShortName, n.Cfg.Env["CONNECTION_MODE"]) + + return nil +} + +func (n *vrVJUNOSEVOLVED) PreDeploy(_ context.Context, params *nodes.PreDeployParams) error { + utils.CreateDirectory(n.Cfg.LabDir, 0777) + _, err := n.LoadOrGenerateCertificate(params.Cert, params.TopologyName) + if err != nil { + return nil + } + return nodes.LoadStartupConfigFileVr(n, configDirName, startupCfgFName) +} + +func (n *vrVJUNOSEVOLVED) SaveConfig(_ context.Context) error { + err := netconf.SaveConfig(n.Cfg.LongName, + defaultCredentials.GetUsername(), + defaultCredentials.GetPassword(), + scrapliPlatformName, + ) + if err != nil { + return err + } + + log.Infof("saved %s running configuration to startup configuration file\n", n.Cfg.ShortName) + return nil +} + +// CheckInterfaceName checks if a name of the interface referenced in the topology file correct. +func (n *vrVJUNOSEVOLVED) CheckInterfaceName() error { + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) +} + diff --git a/nodes/vr_vjunosswitch/vr-vjunosswitch.go b/nodes/vr_vjunosswitch/vr-vjunosswitch.go index 2b3934ad3..4c9435182 100644 --- a/nodes/vr_vjunosswitch/vr-vjunosswitch.go +++ b/nodes/vr_vjunosswitch/vr-vjunosswitch.go @@ -17,7 +17,7 @@ import ( ) var ( - kindnames = []string{"juniper_vjunosswitch", "vr-vjunosswitch", "vr-juniper_vjunosswitch"} + kindnames = []string{"juniper_vjunosswitch"} defaultCredentials = nodes.NewCredentials("admin", "admin@123") ) diff --git a/schemas/clab.schema.json b/schemas/clab.schema.json index 91f4e9ce4..97bc4c7d8 100644 --- a/schemas/clab.schema.json +++ b/schemas/clab.schema.json @@ -62,6 +62,7 @@ "vr-vjunosswitch", "vr-juniper_vjunosswitch", "juniper_vjunosswitch", + "juniper_vjunosevolved", "vr-xrv", "vr-cisco_xrv", "cisco_xrv", @@ -728,10 +729,10 @@ "vr-vsrx": { "$ref": "#/definitions/node-config" }, - "vr-juniper_vjunosswitch": { + "juniper_vjunosswitch": { "$ref": "#/definitions/node-config" }, - "vr-vjunosswitch": { + "juniper_vjunosevolved": { "$ref": "#/definitions/node-config" }, "vr-aruba_aoscx": { @@ -844,4 +845,4 @@ "name", "topology" ] -} \ No newline at end of file +}