Skip to content

Add vpp device support - #3492

Merged
ipspace merged 58 commits into
ipspace:devfrom
jbemmel:vpp-support
Aug 1, 2026
Merged

Add vpp device support#3492
ipspace merged 58 commits into
ipspace:devfrom
jbemmel:vpp-support

Conversation

@jbemmel

@jbemmel jbemmel commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Summary
Adds VPP as a buildable containerlab device (vpp), similar to BIRD: netlab clab build vpp produces netlab/vpp:latest, then lab nodes can use it under provider: clab.

This is a rework of the earlier VPP branch. It deliberately does not use Containerlab’s fdio_vpp kind; it uses the same daemon/image pattern as BIRD while keeping comparable dataplane plumbing (VPP + Linux CP in the dataplane netns).

Highlights

  • Local image build (netlab clab build vpp, optional --sw-version)
  • Router and bridge roles (not host)
  • Selectable control plane: bird (default) or frr via defaults.daemons.vpp.control_plane or per-node control_plane
  • Initial interface, loopback, MTU, RA, and unnumbered support
  • Full VLAN support using native VPP mechanisms
  • Docs: docs/labs/vpp.md

initial test results:

./device-module-test -d vpp -p clab initial
Pre-test cleanup: 
17:15:44 initial/01-interfaces.yml: create(ok) up(ok) config(ok) validate(ok) cleanup(ok) OK
17:15:55 initial/01a-scripts.yml: create(FAIL) 
17:15:56 initial/01b-startup-config.yml: create(FAIL) 
17:15:56 initial/02-loopback.yml: create(ok) up(ok) config(ok) validate(ok) cleanup(ok) OK
17:16:05 initial/03-unnumbered.yml: create(ok) up(ok) config(ok) validate(SKIPPED) cleanup(ok) OK
17:16:07 initial/04-mtu.yml: create(ok) up(ok) config(ok) validate(ok) cleanup(ok) OK
17:17:01 initial/05-host.yml: create(FAIL) 
17:17:02 initial/06-bridge.yml: create(ok) up(ok) config(ok) validate(ok) cleanup(ok) OK
17:17:11 initial/07-router.yml: create(ok) up(ok) config(ok) validate(ok) cleanup(ok) OK
17:17:23 initial/08-ra.yml: create(ok) up(ok) config(ok) validate(ok) cleanup(ok) OK
17:17:59 initial/10-reload.yml: create(FAIL) 

@jbemmel
jbemmel marked this pull request as draft June 16, 2026 23:24
create loopback interface instance {{ lb_instance }}
{% set vpp_if = l.ifname %}
{% else %}
{% set vpp_if = 'host-' ~ l.ifname %}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried using interface_name: host-eth{ifindex} but that breaks the bridge scenario

Comment thread netsim/augment/nodes.py Outdated
@jbemmel
jbemmel marked this pull request as ready for review June 16, 2026 23:59

@pimvanpelt pimvanpelt left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love this! I left a bunch of nits and comments.

The one thing I think you should not do, is autogen a setup.conf or setup.vpp file. It makes it ~impossible to make any changes to the dataplane configuration while operating the netlab. What if you wanted to add a sub-interface, or remove an address, or make an L2XC between two interfaces, or bind an MPLS tunnel? Your users would end up resorting to 'vppctl' debug CLI, which is cumbersome at best, and perilous at worst, because ordering matters, and the CLI/API do very limited syntax and semantic checking.

Also, there will be no config persistence if they restart the container. There is no vppctl show run or vppctl write mem, by design it is a configurable dataplane with an API that is meant to be configured by another system. Users will risk crashing the dataplane if they do things in the wrong order, or with the wrong arguments.

Consider using vppcfg and have ansible generate /etc/vpp/vppcfg.yaml, and explain to users how to edit that file and run vppcfg plan and vppcfg apply. When starting the container, you can generate the file you're now hand-crafting with vppcfg plan --novpp -c vppcfg.yaml -o vppcfg.vpp and start the dataplane with that instead. I guarantee you that is a better user experience, even if you rely on an external component (you can pip install it).

Good luck with the netlab integration!

Comment thread netsim/daemons/vpp/setup.vpp.j2 Outdated
Comment thread netsim/daemons/vpp/setup.vpp.j2 Outdated
Comment thread netsim/daemons/vpp/setup.vpp.j2 Outdated
Comment thread netsim/daemons/vpp/setup.vpp.j2 Outdated
Comment thread netsim/daemons/vpp/setup.vpp.j2 Outdated
Comment thread docs/platforms.md Outdated
Comment thread netsim/augment/nodes.py Outdated
Comment thread netsim/daemons/vpp/vpp.j2 Outdated
Comment thread netsim/daemons/vpp.yml
Comment thread netsim/daemons/vpp.yml
@jbemmel
jbemmel marked this pull request as draft June 18, 2026 19:07
@jbemmel

jbemmel commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator Author

I love this! I left a bunch of nits and comments.

The one thing I think you should not do, is autogen a setup.conf or setup.vpp file. It makes it ~impossible to make any changes to the dataplane configuration while operating the netlab. What if you wanted to add a sub-interface, or remove an address, or make an L2XC between two interfaces, or bind an MPLS tunnel? Your users would end up resorting to 'vppctl' debug CLI, which is cumbersome at best, and perilous at worst, because ordering matters, and the CLI/API do very limited syntax and semantic checking.

Also, there will be no config persistence if they restart the container. There is no vppctl show run or vppctl write mem, by design it is a configurable dataplane with an API that is meant to be configured by another system. Users will risk crashing the dataplane if they do things in the wrong order, or with the wrong arguments.

Consider using vppcfg and have ansible generate /etc/vpp/vppcfg.yaml, and explain to users how to edit that file and run vppcfg plan and vppcfg apply. When starting the container, you can generate the file you're now hand-crafting with vppcfg plan --novpp -c vppcfg.yaml -o vppcfg.vpp and start the dataplane with that instead. I guarantee you that is a better user experience, even if you rely on an external component (you can pip install it).

Good luck with the netlab integration!

I hear what you're saying, and in a production setup that makes total sense. The Netlab workflow / mental model deviates from that though, in ways that fundamentally impact these usage concerns.

Netlab provides an abstracted single topology definition file from which all configuration is derived. This "vendor neutral" intent gets mapped to platform specific syntax - soon including VPP.

That means that if a user wants to add a sub interface, they'd edit this Netlab topology file and redeploy the lab. That would work for VPP, but also Arista, SR Linux, FRR or any of the other platforms. Same for addressing, MPLS tunnels, etc.

Basically the same idea as your vppcfg - abstract YAML syntax mapped to platform specific commands in the right order and validated - but applied to all platforms. netlab create will (eventually) be a close alternative for vppcfg plan.

A major benefit for you/VPP will be that once we finalize this config mapping, we can validate against the Netlab 250+ integration tests, and run virtual interop tests between any and all supported platforms.

@jbemmel
jbemmel marked this pull request as ready for review June 19, 2026 04:22
@DanPartelly

DanPartelly commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

That means that if a user wants to add a sub interface, they'd edit this Netlab topology file and redeploy the lab. That would work for VPP, but also Arista, SR Linux, FRR or any of the other platforms. Same for addressing, MPLS tunnels, etc.

Well, there is no canonical "one true way" to use netlab. Certainly I would not always restart Netlab with an edited topology file just to make some changes to the running config of a device. Sometimes it makes sense to do that, sometimes it doesn't. And if the topology device it's one of the devices with a long boot time, yeah, forget that, I wont restart. To save time Ill just duplicate the topology , modify it, and dump the new config. Netlab create only, not a full deploy. Reconcile manually on the long running lab, if needed, copy / paste does the rest.

Vppctl is really not the end of the world. As of today, it's the only way to really dig and learn VPP. Regardless you use vppcfg as planner or write the config yourself, there is no other way to learn VPP but vppctl command line. And crashing things or getting invalid configs is part of the learning experience.

I am good with it as is, without using vppcfg planner.

@jbemmel

jbemmel commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator Author

Well, there is no canonical "one true way" to use netlab

You’re right of course, it is not that black and white

@jbemmel
jbemmel marked this pull request as draft June 24, 2026 21:04
@jbemmel
jbemmel force-pushed the vpp-support branch 2 times, most recently from 4973c4e to fa057ca Compare July 8, 2026 14:46
@DanPartelly

DanPartelly commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

@jbemmel What is the status of this one? Do you want to add more things, or should we focus on merging it in the near future? I have a personal interest in the platform.

@jbemmel
jbemmel marked this pull request as ready for review July 24, 2026 17:02
@jbemmel

jbemmel commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator Author

@jbemmel What is the status of this one? Do you want to add more things, or should we focus on merging it in the near future? I have a personal interest in the platform.

Thanks for the trigger - I think this is ready for review. It adds vpp as a device with either BIRD or frr as control_plane; the initial integration tests pass (with some minor exceptions).

Adding other things to make it useful (ospf, bgp, etc.) should be done in separate PRs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new VPP (FD.io Vector Packet Processor) containerlab daemon/device (device: vpp) with a locally buildable image (netlab clab build vpp), integrates it into the daemon/framework plumbing, and documents how to build/use it.

Changes:

  • Added VPP device quirks to select/merge a Linux control plane (BIRD default, optional FRR) and control which daemon/module artifacts get generated and bound into the container.
  • Added VPP daemon templates (VPP startup config, runtime start script, setup CLI config, MPLS stub, and a Dockerfile template for local image builds).
  • Updated documentation to list VPP as a platform daemon and describe build/use caveats and workflow.

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
netsim/devices/vpp.py Adds VPP-specific quirks and control-plane selection/merge logic (BIRD/FRR).
netsim/daemons/vpp/vpp.j2 New VPP startup.conf template.
netsim/daemons/vpp/start.vpp.j2 New entrypoint script to start VPP, handle unnumbered peers, and launch the selected control-plane daemon.
netsim/daemons/vpp/setup.vpp.j2 New VPP CLI setup template (interfaces, MTU, addressing, RA, unnumbered, exec extra .vpp snippets).
netsim/daemons/vpp/ospf.areas.j2 Placeholder note for OSPF areas handling with bird control plane.
netsim/daemons/vpp/mpls.vpp.j2 Minimal MPLS setup snippet for VPP.
netsim/daemons/vpp/hosts.j2 Reuses linux hosts template for VPP.
netsim/daemons/vpp/Dockerfile.j2 Dockerfile template for building netlab/vpp with optional version pinning and BIRD/FRR installed.
netsim/daemons/vpp/daemons.j2 Includes FRR daemons template for VPP use.
netsim/daemons/vpp/bird.j2 Includes BIRD template for VPP use.
netsim/daemons/vpp.yml Registers VPP daemon/device defaults (clab build/image, features, config templates, and control_plane attribute).
netsim/daemons/bird/bird.j2 Prevents BIRD from including its own config via _daemon_config when used as a control plane for other devices.
netsim/ansible/templates/mpls/vpp.initial.j2 Adds VPP-specific MPLS sysctl setting for initial config.
netsim/ansible/templates/initial/vpp.j2 Adds VPP initial script creating dataplane netns and generating clab-interfaces.vpp.
docs/platforms.md Documents VPP as a platform daemon and its configuration/deployment characteristics.
docs/netlab/defaults.md Adds VPP image default example.
docs/netlab/clab.md References VPP build documentation from clab build docs.
docs/labs/vpp.md New documentation page for building/using VPP containers and control-plane selection.
docs/labs/clab.md Adds VPP to containerlab lab-image list and build instructions section.
docs/caveats.md Adds VPP caveats section (must build image; clab-only).
Comments suppressed due to low confidence (1)

netsim/daemons/vpp/start.vpp.j2:21

  • This interface readiness loop also has no timeout; a missing/misnamed interface will block startup forever.
{% for l in interfaces if l._unnumbered_peer is defined %}
until ip -n "$NETNS" link show {{ l.ifname }} >/dev/null 2>&1; do sleep 0.1; done
ip -n "$NETNS" addr flush dev {{ l.ifname }} scope global 2>/dev/null || true

Comment thread netsim/daemons/vpp/Dockerfile.j2
Comment thread netsim/daemons/vpp/start.vpp.j2

@ipspace ipspace left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starting with a few documentation nits and a major question: why do you think it's a good idea to define VPP as a daemon (as opposed to a regular device)?

After all, you start the VPP daemon at the end of the initial configuration and delay the start of the BIRD process until the dataplane configuration is completed.

Comment thread docs/netlab/clab.md Outdated

To use a custom container image, specify it with the **image** node parameter or the **defaults.daemons._daemon_.clab.image** [default setting](topo-defaults).

See [Building BIRD containers](../labs/bird.md) and [Building VPP containers](../labs/vpp.md) for configurable software releases.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use anchors

Comment thread docs/caveats.md Outdated
## VPP (Vector Packet Processor)

* You must build the VPP container image with the **netlab clab build vpp** command. See [](build-vpp) for version options.
* VPP is available only on the [containerlab](labs/clab.md) provider.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this clear enough from the "platforms" table?

Comment thread docs/platforms.md Outdated
|-----------------------|:--:|:--:| :--:|
| Arista EOS | ✅ | ✅ | ✅ |
| BIRD | ✅ | ✅ | ❌ |
| VPP | ✅ | ❌ | ✅ |

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorting...

Comment thread docs/platforms.md Outdated
|--------|----------|---------------------------------|
| bird | clab | **bash** scripts or daemon configuration files[^BBS] |
| dnsmasq | clab | **bash** scripts or daemon configuration files[^DBS] |
| vpp | clab | **bash** scripts, daemon configuration files, and VPP CLI configuration files[^VPPC] |

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use case-insensitive sort ;)

@jbemmel

jbemmel commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator Author

why do you think it's a good idea to define VPP as a daemon (as opposed to a regular device)?

After all, you start the VPP daemon at the end of the initial configuration and delay the start of the BIRD process until the dataplane configuration is completed.

I initially conceptualized this as "BIRD with a different data plane", hence I started from a daemon. It wasn't so much "a good idea" but more "a logical progression".

I guess I never really paid much attention to the difference between devices and daemons, it's not a distinction I tend to make naturally.

We could easily reconceive VPP as a device - I'll make that change

@ipspace

ipspace commented Jul 29, 2026

Copy link
Copy Markdown
Owner

We could easily reconceive VPP as a device - I'll make that change

Thank you!

@jbemmel
jbemmel marked this pull request as draft July 30, 2026 00:51
ipspace and others added 5 commits July 29, 2026 19:52
Move VPP to netsim/daemons with a custom netlab/vpp image, host-netns
initial provisioning, split startup/setup templates, and IPv6 RA support.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add minimal user docs for building and using the VPP daemon, including router/host/bridge roles and ns config mode.

Co-authored-by: Cursor <cursoragent@cursor.com>
Emit one ip6 nd prefix line with optional flags and declare initial module roles for clab.

Co-authored-by: Cursor <cursoragent@cursor.com>
@jbemmel jbemmel changed the title Add vpp daemon support Add vpp device support Jul 30, 2026
jbemmel and others added 2 commits July 29, 2026 23:19
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@jbemmel
jbemmel marked this pull request as ready for review July 30, 2026 04:23
@ipspace

ipspace commented Jul 30, 2026

Copy link
Copy Markdown
Owner

We could easily reconceive VPP as a device - I'll make that change

Thanks for making that change, but why do you still have files in the "daemons/vpp" directory?

@jbemmel
jbemmel marked this pull request as draft July 30, 2026 13:37
jbemmel and others added 11 commits July 30, 2026 08:43
Leave only Dockerfile.j2 under daemons/vpp for netlab clab build.

Co-authored-by: Cursor <cursoragent@cursor.com>
Move MPLS under ansible/templates, drop the unused OSPF areas stub,
and rename the VPP start template to netlab-start.sh.

Co-authored-by: Cursor <cursoragent@cursor.com>
FRR was fed bash VLAN scripts via vtysh, and Linux bridges on LCP taps
do not forward between host-interfaces. Apply vlan as VPP CLI, wait for
LCP before starting the control plane, and run shell vs vtysh by shebang.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
VPP VLAN snippets (*.vpp) were pulled into bird.conf and crashed bird.

Co-authored-by: Cursor <cursoragent@cursor.com>
Bridge-only access ports worked, but IRB labs had no L3 interface in the
bridge-domain, so host-to-DUT and inter-subnet pings failed.

Co-authored-by: Cursor <cursoragent@cursor.com>
IRB host-to-switch pings target the DUT loopback (10.0.0.x); setup.vpp
had filtered all virtual_interface entries and never created loop0.

Co-authored-by: Cursor <cursoragent@cursor.com>
Bridge-trunk labs failed because vlan_member subifs were never created
before L2 bridge assignment; pop-1 rewrite is required for access/trunk.

Co-authored-by: Cursor <cursoragent@cursor.com>
Skip unused bird plugin daemon_config maps and configure L3 VLAN
subinterfaces with IP/LCP instead of L2 tag-rewrite.

Co-authored-by: Cursor <cursoragent@cursor.com>
Move bridge-domain, subif, and BVI setup into initial/vpp.vlan.j2
(skip unsupported BVI MTU) and keep access-port bridging in vlan/vpp.j2.

Co-authored-by: Cursor <cursoragent@cursor.com>
Defer vlan-init until after parent TAP MACs match host-interface
hw-addr so af_packet does not reject secondary MACs on subif LCP.

Co-authored-by: Cursor <cursoragent@cursor.com>
@jbemmel

jbemmel commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for making that change, but why do you still have files in the "daemons/vpp" directory?

clab build currently only looks under daemons/ so I left Dockerfile.j2, I moved the rest

./device-module-test -d vpp -p clab initial
NETLAB_DEVICES_VPP_CONTROL__PLANE=frr ./device-module-test -d vpp -p clab initial

both pass

The bridge test was failing for frr, so I also added proper vlan support. Those tests now pass too :)

@jbemmel
jbemmel marked this pull request as ready for review July 30, 2026 21:26

@ipspace ipspace left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job, with a few leftover bits and pieces.

I cleaned up a few documentation quirks. You also forgot to add VPP to a lot of "supported platforms" tables, but if neither your AI friend nor you care about that, neither do I 🤷🏻‍♂️

I also disabled features that work only on Linux but not VPP, or on FRR but not BIRD. If you want to have them, add corresponding device quirks. Starting a device, not getting any errors, and having a broken network is not the best user experience.

MTU on VLANs is probably broken, and the loopback interface is not working with OSPFv3. Will open separate bug reports for that.

ipspace added a commit that referenced this pull request Jul 31, 2026
@jbemmel

jbemmel commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator Author

MTU on VLANs is probably broken, and the loopback interface is not working with OSPFv3. Will open separate bug reports for that.

I tried setting MTU on the VLANs but it failed with an error that the underlying device doesn't support it - so I left it out. Note that all the VLAN tests pass - perhaps MTU on VLANs could use a more specific test, so it gets flagged?

I didn't fully test OSPF yet - I figured it might be better to merge the baseline first, and then incrementally fix some remaining quirks.

@jbemmel

jbemmel commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator Author

I also disabled features that work only on Linux but not VPP, or on FRR but not BIRD. If you want to have them, add corresponding device quirks. Starting a device, not getting any errors, and having a broken network is not the best user experience.

Thinking more about this, it may be better to model this as 2 devices e.g. vpp-bird and vpp-frr as opposed to a 'vpp' device with a control_plane parameter. We could declare the vpp device as an abstract parent (_meta_device: True), and model the difference in features appropriately. No quirks necessary

@ipspace

ipspace commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Thinking more about this, it may be better to model this as 2 devices e.g. vpp-bird and vpp-frr as opposed to a 'vpp' device with a control_plane parameter.

I was thinking along the exact same lines ;) Yes, that would make a lot of sense, and be (probably) simpler than trying to deal with two sets of control-plane features.

@ipspace

ipspace commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Note that all the VLAN tests pass - perhaps MTU on VLANs could use a more specific test, so it gets flagged?

OSPF is the only protocol that reliably complains about the MTU mismatch. You could try to use dataplane tricks, but you know how "reliable" those are.

@ipspace
ipspace merged commit 73a56f3 into ipspace:dev Aug 1, 2026
5 checks passed
@ipspace

ipspace commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Thinking more about this, it may be better to model this as 2 devices e.g. vpp-bird and vpp-frr as opposed to a 'vpp' device with a control_plane parameter.

Wait before moving forward with this. I plan to implement "device plugins" for cases where we need more functionality (beyond post-transform quirks). I'll try it out on the "kind" device, and if it works, it might be easier to implement feature merge etc.

@sdktr

sdktr commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

You also forgot to add VPP to a lot of "supported platforms" tables, but if neither your AI friend nor you care about that, neither do I

Are all the docs tables not generatable by the feature yamls? Seems odd that those are handled separately?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants