From 0972cf4aa10e349a5482776697b73b535e63d488 Mon Sep 17 00:00:00 2001 From: Pim van Pelt Date: Sun, 4 May 2025 17:30:04 +0200 Subject: [PATCH] A few readability fixes --- content/articles/2025-05-04-containerlab-2.md | 70 +++++++++++-------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/content/articles/2025-05-04-containerlab-2.md b/content/articles/2025-05-04-containerlab-2.md index 5dfb843..ff73025 100644 --- a/content/articles/2025-05-04-containerlab-2.md +++ b/content/articles/2025-05-04-containerlab-2.md @@ -61,19 +61,19 @@ CMD ["/sbin/init-container.sh"] ``` A few notable additions: -* ***vppcfg*** is the utility I wrote and described in a previous [[article]({{< ref - 2022-04-02-vppcfg-2 >}})]. It's purpose is to take YAML file that describes the configuration of - the dataplane (like which interfaces, sub-interfaces, MTU, IP addresses and so on), and apply - this safely to a running dataplane. You can check it out in the +* ***vppcfg*** is a handy utility I wrote and discussed in a previous [[article]({{< ref + 2022-04-02-vppcfg-2 >}})]. Its purpose is to take YAML file that describes the configuration of + the dataplane (like which interfaces, sub-interfaces, MTU, IP addresses and so on), and then + apply this safely to a running dataplane. You can check it out in my [[vppcfg](https://git.ipng.ch/ipng/vppcfg)] git repository. * ***openssh-server*** will come in handy to log in to the container, in addition to the already available `docker exec`. -* ***bird2*** which will be my controlplane of choice. In a future date, I might also add FRR, +* ***bird2*** which will be my controlplane of choice. At a future date, I might also add FRR, which may be a good alterantive for some. VPP works well with both. You can check out Bird on the nic.cz [[website](https://bird.network.cz/?get_doc&f=bird.html&v=20)]. I'll add a couple of default config files for Bird and VPP, and replace the CMD with a generic -`init-container.sh` in which I can do any late binding stuff. +`/sbin/init-container.sh` in which I can do any late binding stuff before launching VPP. ### Initializing the Container @@ -93,7 +93,8 @@ echo "Creating dataplane namespace" #### VPP Containerlab: SSH -Then, I'll set the root password and start aan SSH daemon which allows for password-less logins: +Then, I'll set the root password (which is `vpp` by the way), and start aan SSH daemon which allows +for password-less logins: ``` echo "Starting SSH, with credentials root:vpp" @@ -104,8 +105,9 @@ sed -i -e 's,^root:.*,root:$y$j9T$kG8pyZEVmwLXEtXekQCRK.$9iJxq/bEx5buni1hrC8Vmvk #### VPP Containerlab: Bird2 -I can already predict that Bird2 won't be the only option for a controlplane. Therefore, I'll make -it configurable: +I can already predict that Bird2 won't be the only option for a controlplane, even though I'm a huge +fan of it. Therefore, I'll make it configurable to leave the door open for other controlplane +implementations in the future: ``` BIRD_ENABLED=${BIRD_ENABLED:="true"} @@ -120,20 +122,21 @@ if [ "$BIRD_ENABLED" == "true" ]; then fi ``` -I remember that Bird won't start if it cannot determine its _router id_. When I start it in the -`dataplane` namespace, it will immediately exit. But luckily, it logs its complaint and it's easily -addressed. I decide to take the management IPv4 address, from `eth0` and write that into the -`bird.conf` file, which does some basic initialization which I've described in a previous -[[article]({{< ref 2021-09-02-vpp-5 >}})], so I'll skip that here. However, I do include an empty -file called `/etc/bird/bird-local.conf` for users to further configure Bird2. +I am reminded that Bird won't start if it cannot determine its _router id_. When I start it in the +`dataplane` namespace, it will immediately exit, because there will be no IP addresses configured +yet. But luckily, it logs its complaint and it's easily addressed. I decide to take the management +IPv4 address from `eth0` and write that into the `bird.conf` file, which otherwise does some basic +initialization that I described in a previous [[article]({{< ref 2021-09-02-vpp-5 >}})], so I'll +skip that here. However, I do include an empty file called `/etc/bird/bird-local.conf` for users to +further configure Bird2. #### VPP Containerlab: Binding veth pairs When Containerlab starts the VPP container, it'll offer it a set of `veth` ports that connect this -container to any other node in the lab. This is done by the `links` list in the topology file +container to other nodes in the lab. This is done by the `links` list in the topology file [[ref](https://containerlab.dev/manual/network/)]. It's my goal to take all of the interfaces -that are of type `veth`, and generate a little snippet to grab them and bind them into VPP, as -follows: +that are of type `veth`, and generate a little snippet to grab them and bind them into VPP while +setting their MTU to 9216 to allow for jumbo frames: ``` CLAB_VPP_FILE=${CLAB_VPP_FILE:=/etc/vpp/clab.vpp} @@ -155,6 +158,12 @@ EOF done ``` +{{< image width="5em" float="left" src="/assets/shared/warning.png" alt="Warning" >}} + +One thing I realized is that VPP will assign a random MAC address on its copy of the `veth` port, +which is not great. I'll explicitly configure it with the same MAC address as the `veth` interface +itself, otherwise I'd have to put the interface into promiscuous mode. + #### VPP Containerlab: VPPcfg I'm almost ready, but I have one more detail. The user will be able to offer a @@ -171,8 +180,8 @@ if [ -r /etc/vpp/vppcfg.yaml ]; then fi ``` -Once VPP starts, it'll execute `/etc/vpp/bootstrap.vpp`, which in turn executes these newly -generated `/etc/vpp/clab.vpp` to grab the `veth` interfaces, and then `/etc/vpp/vppcfg.vpp` to +Once the VPP process starts, it'll execute `/etc/vpp/bootstrap.vpp`, which in turn executes these +newly generated `/etc/vpp/clab.vpp` to grab the `veth` interfaces, and then `/etc/vpp/vppcfg.vpp` to further configure the dataplane. Easy peasy! ### Adding VPP to Containerlab @@ -183,7 +192,8 @@ get me started. I fork the repo, create a branch so that Roman can also add a fe together we start hacking in [[PR#2571](https://github.com/srl-labs/containerlab/pull/2571)]. First, I add the documentation skeleton in `docs/manual/kinds/fdio_vpp.md`, which links in from a -few other places, and will be where the end-user facing documentation will live. +few other places, and will be where the end-user facing documentation will live. That's about half +the contributed LOC, right there! Next, I'll create a Go module in `nodes/fdio_vpp/fdio_vpp.go` which doesn't do much other than creating the `struct`, and its required `Register` and `Init` functions. The `Init` function ensures @@ -196,10 +206,10 @@ So, containerlab informs the container using an environment variable called `CLA script simply sleeps for a while until that exact amount of interfaces are present. Ok, cool beans. Roman helps me a bit with Go templating. You see, I think it'll be slick to have the CLI prompt for -the VPP containers to reflect their hostname, because normally, VPP will assign `vpp# `. When -running many VPP containers in the lab, it could get confusing. So, I add the template in -`nodes/fdio_vpp/vpp_startup_config.go.tpl` and it only has one variable: `cli-prompt {{ .ShortName -}}# `, et voila! +the VPP containers to reflect their hostname, because normally, VPP will assign `vpp# `. I add the +template in `nodes/fdio_vpp/vpp_startup_config.go.tpl` and it only has one variable expansion: `unix +{ cli-prompt {{ .ShortName }}# }`. But I totally think it's worth it, because when running many VPP +containers in the lab, it could otherwise get confusing. Roman also shows me a trick in the function `PostDeploy()`, which will write the user's SSH pubkeys to `/root/.ssh/authorized_keys`. This allows users to log in without having to use password @@ -208,7 +218,7 @@ authentication. Collectively, we decide to punt on the `SaveConfig` function until we're a bit further along. I have an idea how this would work, basically along the lines of calling `vppcfg dump` and bind-mounting that file into the lab directory somewhere. This way, upon restarting, the YAML file can be re-read -and the dataplane initialized. +and the dataplane initialized. But it'll be for another day. After the main module is finished, all I have to do is add it to `clab/register.go` and that's just about it. In about 170 lines of code, 50 lines of Go template, and 170 lines of Markdown, this @@ -234,7 +244,7 @@ one Alpine linux container, in the following topology: {{< image src="/assets/containerlab/learn-vpp.png" alt="Containerlab Topo" width="100%" >}} -Two relevant files for VPP are included in this +Two relevant files for each VPP router are included in this [[repository](https://git.ipng.ch/ipng/vpp-containerlab)]: 1. `config/vpp*/vppcfg.yaml` configures the dataplane interfaces, including a loopback address. 1. `config/vpp*/bird-local.conf` configures the controlplane to enable BFD and OSPF. @@ -261,7 +271,7 @@ loopbacks: addresses: [ 10.82.98.0/32, 2001:db8:8298::/128 ] ``` -Then, I enable BFD, OSPF and OSPFv3 on `eth2' and 'loop0` on both of the VPP routers: +Then, I enable BFD, OSPF and OSPFv3 on `eth2` and `loop0` on both of the VPP routers: ``` pim@summer:~/src/vpp-containerlab$ cat config/vpp1/bird-local.conf protocol bfd bfd1 { @@ -287,8 +297,8 @@ protocol ospf v3 ospf6 { #### Containerlab: playtime! -Once the lab comes up, I can SSH to the VPP containers (`vpp1` and `vpp2`) for which Roman's code -saw to it that my SSH keys are installed. Otherwise, I could still log in as user `root` using +Once the lab comes up, I can SSH to the VPP containers (`vpp1` and `vpp2`) which have my SSH pubkeys +installed thanks to Roman's work. Barring that, I could still log in as user `root` using password `vpp`. VPP runs its own network namespace called `dataplane`, which is very similar to SR Linux default `network-instance`. I can join that namespace to take a closer look: