public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Hannes Laimer <h.laimer@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: superseded: [RFC cluster/docs/ifupdown2/manager/network/proxmox{-ebpf,-ve-rs,-perl-rs} 00/16] sdn: add microsegmentation support
Date: Thu, 9 Jul 2026 11:20:38 +0200	[thread overview]
Message-ID: <9da00602-7f6a-43d6-a817-c57a1c6cc0eb@proxmox.com> (raw)
In-Reply-To: <20260609132522.235917-1-h.laimer@proxmox.com>

superseded-by:
https://lore.proxmox.com/pve-devel/20260709091852.538885-1-h.laimer@proxmox.com/T/#m0cbbbfddbde18a12ffa26a5ae2ac0a1450ea0749

On 2026-06-09 15:25, Hannes Laimer wrote:
> This adds support for microsegmentation using eBPF programs attached to
> interfaces. Mostly the tap/veth interfaces on the guests directly.
> 
> # Overview
> Each guest interface can be assigned a group, then, on these groups it is
> possible to define policies/rules between these groups. A policy is a mapping
>  `(src,dst) -> allow`
> Each interface can be assigned to only a *single* group. Groups however can be
> part of groups, that should cover most use cases I came up with. In case multiple
> policies would match (possibly because groups/sub-groups could have policies that overlap)
> the most specific policy wins: the one that names the destination group closest in
> the tree, and if two name it equally closely, the one that names the source closest, so:
> 
>  - web      (db,web)->allow
>    - wiki                    # from `web`: (db,web)->allow
>      * CT100,net0
>    - wol    (db,wol)->deny   # closer than the (db,web)->allow inherited from web, so deny wins
>      * CT101,net0            # => packets from db to CT101,net0 are denied
> 
>  - db       (web,db)->allow
>    * CT200,net1              # packets from `web` reaching CT200,net1 will be allowed
> 
> Because each group has a single parent, the destination-then-source ordering always
> picks exactly one rule, so there is no tie to resolve (a malformed config with
> duplicate rules falls back to deny).
> 
> If an interface has a group assigned, it needs an explicit (0,dst) rule to
> accept un-tagged packets.
> 
> Enforcement happens on the receiving side, cause that's where we for sure know both
>  - where the packet is from
>  - and, its destination (us)
> 
> # config and API
> The config is a single section-config, `sdn/microseg.cfg`, owned by Rust (the types
> live in `proxmox-ve-config`, with a `PVE::RS::SDN::Microseg` binding) the same way the
> fabric config is. It holds four object types, keyed by section id:
>  - group, a numeric `mark` (auto-assigned if omitted) and an optional `parent`
>  - rule, `(src,dst) -> allow`, an absent `src` matches un-tagged traffic
>  - assignment, binds a guest NIC (`vmid` plus `iface` index) to a group
>  - bridge, marks a bridge-facing interface as an SRv6 carrier (no UI yet)
> The API exposes per-type endpoints under
> `/cluster/sdn/microseg/{group,rule,assignment,bridge}`, guarded by SDN.Audit for reads
> and SDN.Allocate for writes. Rule and assignment ids are derived from their contents
> (`p{src_mark}-{dst_mark}`, `vm{vmid}i{iface}`), groups and bridges take a chosen id. On
> commit the config is rendered into `.running-config`, which is what the agent reads.
> 
> # skb->mark
> Every packet in the kernel lives in a `sk_buff` struct, this struct has a
> 32-bit field `mark`. This field can be written to and read while the packet
> passes through the kernel. We don't do that currently in our SDN stack, so
> currently we can't really overwrite stuff written by a different part of our
> stack. But this is something to keep in mind in case we should end up using
> this again in the future. For now microsegmentation only uses the lower 16 bits.
> We use this to assign packets to groups, with these 16 bits we support up to
> 65535 distinct groups (mark 0 is reserved for unstamped traffic). This `mark`
> however only lives as long as the packet does not leave the kernel, and given
> the nature of networking, chances are it'll leave it eventually. To transport
> this group identity between hosts we have to attach it to the actual network
> packet that hits the wire. For this we currently support both
>  - VXLAN-GBP, the 16-bit GBP field on the VXLAN encapsulation
>  - and, SRv6, the 16-bit Tag field on the SRH
> conveniently the kernel already handles putting the `mark` into the VXLAN-GBP
> encapsulation, and also taking it out of there (found out way too late :P). For
> SRv6 we need a small eBPF program that handles this.
> 
> # eBPF
> Both tagging (setting `mark`) and enforcement happen in an eBPF program
> directly attached to the guest's interface. The programs themselves read and
> write to/from two maps:
>  - tap_to_group, so we know what to set `mark` to
>  - rules, map of (src,dst)->action, we know src from the `mark` and `dst` is
>    the group we are in
> 
> Specifically, on ingress we set the mark, and on egress we enforce.
> 
> # Implementation
> 
> We have an `agent` that reads the running sdn config, and applies that state to
> the kernel. The binary doing this is stateless, it runs on SDN apply, tap_plug
> of interfaces of guests and on boot after pve-sdn-commit but before guests
> start. It keeps track of what is currently running loaded in the kernel with
> two files under `/run/proxmox-ebpf`. One keeping track of the bpf program that
> was compiled into the binary, and one for keeping track of changes to the
> data structures the bpf program accesses. The distinction is useful cause for
> only a program change we can swap the currently attached program with the
> updated one atomically. In case the data structure (the maps) changed there is
> no other way than to tear-down all the current state and repopulate the maps
> and re-attach the programs. Swapping out the maps first would have old programs
> interact with a new data schema, and swapping the programs first will lead
> to new programs accessing an old data schema. Either way, not good, so we wipe
> the state in that case and re-build it. So, in case we change the structure of
> the data our bpf programs access, there will be a bunch of ms where the
> configured segmentation is not enforced. But that is the only scenario where
> that can happen.
> 
> ## aya, aya-ebpf
> Aya is a rust lib that helps with working with BPF more easily. It has both a
> userspace part(`aya`) and a part(`aya-ebpf`) that compiles to bpf. I chose to
> only use the userspace part, and use C for the BPF programs themselves. The reasons were:
>  - we don't have `aya-ebpf` packaged
>  - `aya-ebpf` *requires* nightly toolchain to compile
>  - the bpf programs are very small, in case this should change at some point we
>    can reconsider. Also, it doesn't matter what produces the .o file, so this
>    could be swapped in really easily if we decided to
> 
> So we compile the bpf program written in C to a .o targeting bpf using clang
> and include it when compiling the agent binary.
> 
> ## agent
> The agent is not a long running daemon, the triggers mentioned before should cover
> all situations where we'd have to touch the kernel state. When started, the
> first thing it does is check both the program and schema version, so what it
> was compiled with, and what the last invocation did to the kernel. If either
> the program or the schema differs it either swaps out the program currently
> loaded by the kernel and pins it. If the schema version differs it does that as
> well, but additionally also tears down all state and rebuilds it.
> 
> The agent also populates the `rules` map, so it creates all the inherited rules
> and resolves multiple matches to the closest one as described before.
> 
> ## SRv6
> This also adds support for SRv6 as a transport, we don't support that yet in
> our SDN stack, but could be useful for basic routing between simple zones on
> multiple nodes. A bit like EVPN-lite since it's only L3. I did most of my
> testing with SRv6 as transport between kernels, before I found out the kernel
> does it for VXLAN automatically. I didn't wire up any UI for it yet, but I
> decided to include it in this RFC for now.
> 
> # enabling VXLAN-GBP
> The kernel only moves the mark into the GBP field if the vxlan device was
> created with the GBP flag set, and it's create-only: the kernel won't
> toggle it on a running device. ifupdown2 had no attribute for this, so
> this series includes a small ifupdown2 patch adding `vxlan-gbp`, which
> threads the flag through to the netlink/iproute2 create path.
> 
> # testing
> I have put pre-built packages on sani, these include ifupdown2 with the patch
> 
> # building
> 1. proxmox-ve-rs (install)
> 2. proxmox-ebpf
> 3. pve-cluster (install)
> 4. proxmox-perl-rs (install)
> 5. pve-network
> 6. pve-manager
> 
> # notes
> I did not send the first commit for `proxmox-ebpf` since it contains a
> `vmlinux.h` which is rather large but is needed for compiling. The commit is in
> my staff repo.
> 
> # feedback wanted
>  - the general desgin, specifically with the agent being one-shot and triggered
>    rather than a running service
>  - I put the VXLAN-GBP flag into the zones that run on vxlan for now, so it has
>    to be enabled on the zone, and will affect all vxlan interfaces that are
>    part of it. The only real alternative is enabling it always, or trying to
>    infer if a nic is assigned a vnet that is in a zone that does vxlan and
>    corss-referencing that with potentially configured microseg
>    groups/assignments. This seemed brittle, and since the needed flag is
>    additionally create-only, a simple flag on the zone appeard to be the better
>    approach
>  - and the ui, very likely needs some polishing, and im very open to
>    alternative approaches
> 
> 
> proxmox-ebpf:
> 
> Hannes Laimer (3):
>   agent: add userspace coordinator and stateless policy subsystem
>   bpf: add bridge subsystem
>   debian: add packaging and boot-time oneshot unit
> 
>  Makefile                    |  66 +++++++
>  debian/changelog            |   5 +
>  debian/control              |  34 ++++
>  debian/copyright            |  18 ++
>  debian/proxmox-ebpf.install |   1 +
>  debian/proxmox-ebpf.postrm  |  11 ++
>  debian/proxmox-ebpf.prerm   |  12 ++
>  debian/proxmox-ebpf.service |  15 ++
>  debian/rules                |  33 ++++
>  debian/source/format        |   1 +
>  include/mark.h              |  30 +++
>  src/agent.rs                | 105 ++++++++++
>  src/bridge/bpf/srv6.bpf.c   |  76 +++++++
>  src/bridge/mod.rs           |  75 +++++++
>  src/main.rs                 |  69 +++++++
>  src/policy/bpf/tap.bpf.c    |  66 +++++++
>  src/policy/bpf/types.h      |  23 +++
>  src/policy/mod.rs           | 268 +++++++++++++++++++++++++
>  src/policy/types.rs         |  45 +++++
>  src/running_config.rs       |  38 ++++
>  src/state.rs                | 303 ++++++++++++++++++++++++++++
>  src/subsystem.rs            | 384 ++++++++++++++++++++++++++++++++++++
>  src/tc.rs                   | 152 ++++++++++++++
>  23 files changed, 1830 insertions(+)
>  create mode 100644 Makefile
>  create mode 100644 debian/changelog
>  create mode 100644 debian/control
>  create mode 100644 debian/copyright
>  create mode 100644 debian/proxmox-ebpf.install
>  create mode 100755 debian/proxmox-ebpf.postrm
>  create mode 100755 debian/proxmox-ebpf.prerm
>  create mode 100644 debian/proxmox-ebpf.service
>  create mode 100755 debian/rules
>  create mode 100644 debian/source/format
>  create mode 100644 include/mark.h
>  create mode 100644 src/agent.rs
>  create mode 100644 src/bridge/bpf/srv6.bpf.c
>  create mode 100644 src/bridge/mod.rs
>  create mode 100644 src/main.rs
>  create mode 100644 src/policy/bpf/tap.bpf.c
>  create mode 100644 src/policy/bpf/types.h
>  create mode 100644 src/policy/mod.rs
>  create mode 100644 src/policy/types.rs
>  create mode 100644 src/running_config.rs
>  create mode 100644 src/state.rs
>  create mode 100644 src/subsystem.rs
>  create mode 100644 src/tc.rs
> 
> 
> proxmox-ve-rs:
> 
> Hannes Laimer (1):
>   ve-config: sdn: add microseg config types
> 
>  proxmox-ve-config/src/sdn/config.rs   |   9 +-
>  proxmox-ve-config/src/sdn/microseg.rs | 847 ++++++++++++++++++++++++++
>  proxmox-ve-config/src/sdn/mod.rs      |   1 +
>  3 files changed, 856 insertions(+), 1 deletion(-)
>  create mode 100644 proxmox-ve-config/src/sdn/microseg.rs
> 
> 
> proxmox-perl-rs:
> 
> Hannes Laimer (1):
>   sdn: add microseg config binding
> 
>  pve-rs/Makefile                     |   1 +
>  pve-rs/src/bindings/sdn/microseg.rs | 172 ++++++++++++++++++++++++++++
>  pve-rs/src/bindings/sdn/mod.rs      |   1 +
>  3 files changed, 174 insertions(+)
>  create mode 100644 pve-rs/src/bindings/sdn/microseg.rs
> 
> 
> pve-cluster:
> 
> Hannes Laimer (1):
>   cfs: add 'sdn/microseg.cfg' to observed files
> 
>  src/PVE/Cluster.pm | 1 +
>  1 file changed, 1 insertion(+)
> 
> 
> pve-network:
> 
> Hannes Laimer (4):
>   sdn: microseg: add config and API
>   sdn: zones: trigger microseg apply on tap_plug
>   sdn: zones: add vxlan-gbp option to vxlan and evpn zones
>   evpn: disable vxlan-learning on create if GBP is enabled
> 
>  src/PVE/API2/Network/SDN.pm                   |  12 +
>  src/PVE/API2/Network/SDN/Makefile             |   2 +
>  src/PVE/API2/Network/SDN/Microseg.pm          | 126 +++++++
>  .../API2/Network/SDN/Microseg/Assignment.pm   | 163 +++++++++
>  src/PVE/API2/Network/SDN/Microseg/Bridge.pm   | 171 ++++++++++
>  src/PVE/API2/Network/SDN/Microseg/Group.pm    | 171 ++++++++++
>  src/PVE/API2/Network/SDN/Microseg/Makefile    |   8 +
>  src/PVE/API2/Network/SDN/Microseg/Rule.pm     | 163 +++++++++
>  src/PVE/Network/SDN.pm                        |   5 +
>  src/PVE/Network/SDN/Makefile                  |   1 +
>  src/PVE/Network/SDN/Microseg.pm               | 316 ++++++++++++++++++
>  src/PVE/Network/SDN/Zones.pm                  |   6 +
>  src/PVE/Network/SDN/Zones/EvpnPlugin.pm       |  11 +
>  src/PVE/Network/SDN/Zones/VxlanPlugin.pm      |   9 +
>  14 files changed, 1164 insertions(+)
>  create mode 100644 src/PVE/API2/Network/SDN/Microseg.pm
>  create mode 100644 src/PVE/API2/Network/SDN/Microseg/Assignment.pm
>  create mode 100644 src/PVE/API2/Network/SDN/Microseg/Bridge.pm
>  create mode 100644 src/PVE/API2/Network/SDN/Microseg/Group.pm
>  create mode 100644 src/PVE/API2/Network/SDN/Microseg/Makefile
>  create mode 100644 src/PVE/API2/Network/SDN/Microseg/Rule.pm
>  create mode 100644 src/PVE/Network/SDN/Microseg.pm
> 
> 
> pve-manager:
> 
> Hannes Laimer (3):
>   ui: sdn: add microsegmentation
>   network: apply microseg state on reload
>   ui: sdn: zones: add vxlan-gbp checkbox to vxlan and evpn
> 
>  PVE/API2/Network.pm                           |   4 +
>  www/manager6/Makefile                         |   9 +
>  www/manager6/Utils.js                         |  23 +
>  www/manager6/dc/Config.js                     |   8 +
>  www/manager6/form/MicrosegGroupSelector.js    |  64 +++
>  www/manager6/form/MicrosegGuestNicSelector.js | 107 +++++
>  www/manager6/form/MicrosegGuestSelector.js    |  83 ++++
>  www/manager6/sdn/MicrosegView.js              | 408 ++++++++++++++++++
>  www/manager6/sdn/microseg/AssignmentEdit.js   |  63 +++
>  www/manager6/sdn/microseg/Base.js             |  88 ++++
>  www/manager6/sdn/microseg/GroupEdit.js        |  61 +++
>  www/manager6/sdn/microseg/PolicyView.js       | 221 ++++++++++
>  www/manager6/sdn/microseg/RuleEdit.js         |  49 +++
>  www/manager6/sdn/zones/EvpnEdit.js            |   8 +
>  www/manager6/sdn/zones/VxlanEdit.js           |  11 +
>  15 files changed, 1207 insertions(+)
>  create mode 100644 www/manager6/form/MicrosegGroupSelector.js
>  create mode 100644 www/manager6/form/MicrosegGuestNicSelector.js
>  create mode 100644 www/manager6/form/MicrosegGuestSelector.js
>  create mode 100644 www/manager6/sdn/MicrosegView.js
>  create mode 100644 www/manager6/sdn/microseg/AssignmentEdit.js
>  create mode 100644 www/manager6/sdn/microseg/Base.js
>  create mode 100644 www/manager6/sdn/microseg/GroupEdit.js
>  create mode 100644 www/manager6/sdn/microseg/PolicyView.js
>  create mode 100644 www/manager6/sdn/microseg/RuleEdit.js
> 
> 
> pve-docs:
> 
> Hannes Laimer (2):
>   sdn: add microsegmentation section
>   sdn: add VXLAN-GBP flag to evpn/vxlan zone sections
> 
>  pvesdn.adoc | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 87 insertions(+)
> 
> 
> ifupdown2:
> 
> Hannes Laimer (1):
>   d/patches: add support for VXLAN-GBP flag
> 
>  ...addons-vxlan-add-vxlan-gbp-attribute.patch | 228 ++++++++++++++++++
>  debian/patches/series                         |   1 +
>  2 files changed, 229 insertions(+)
>  create mode 100644 debian/patches/pve/0016-addons-vxlan-add-vxlan-gbp-attribute.patch
> 
> 
> Summary over all repositories:
>   62 files changed, 5548 insertions(+), 1 deletions(-)
> 





      parent reply	other threads:[~2026-07-09  9:24 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-09 13:25 [RFC cluster/docs/ifupdown2/manager/network/proxmox{-ebpf,-ve-rs,-perl-rs} 00/16] sdn: add microsegmentation support Hannes Laimer
2026-06-09 13:25 ` [PATCH proxmox-ebpf 01/16] agent: add userspace coordinator and stateless policy subsystem Hannes Laimer
2026-06-09 13:25 ` [PATCH proxmox-ebpf 02/16] bpf: add bridge subsystem Hannes Laimer
2026-06-09 13:25 ` [PATCH proxmox-ebpf 03/16] debian: add packaging and boot-time oneshot unit Hannes Laimer
2026-06-09 13:25 ` [PATCH proxmox-ve-rs 04/16] ve-config: sdn: add microseg config types Hannes Laimer
2026-06-09 13:25 ` [PATCH proxmox-perl-rs 05/16] sdn: add microseg config binding Hannes Laimer
2026-06-09 13:25 ` [PATCH pve-cluster 06/16] cfs: add 'sdn/microseg.cfg' to observed files Hannes Laimer
2026-06-09 13:25 ` [PATCH pve-network 07/16] sdn: microseg: add config and API Hannes Laimer
2026-06-09 13:25 ` [PATCH pve-network 08/16] sdn: zones: trigger microseg apply on tap_plug Hannes Laimer
2026-06-09 13:25 ` [PATCH pve-network 09/16] sdn: zones: add vxlan-gbp option to vxlan and evpn zones Hannes Laimer
2026-06-09 13:25 ` [PATCH pve-network 10/16] evpn: disable vxlan-learning on create if GBP is enabled Hannes Laimer
2026-06-09 13:25 ` [PATCH pve-manager 11/16] ui: sdn: add microsegmentation Hannes Laimer
2026-06-09 13:25 ` [PATCH pve-manager 12/16] network: apply microseg state on reload Hannes Laimer
2026-06-09 13:25 ` [PATCH pve-manager 13/16] ui: sdn: zones: add vxlan-gbp checkbox to vxlan and evpn Hannes Laimer
2026-06-09 13:25 ` [PATCH pve-docs 14/16] sdn: add microsegmentation section Hannes Laimer
2026-06-09 13:25 ` [PATCH pve-docs 15/16] sdn: add VXLAN-GBP flag to evpn/vxlan zone sections Hannes Laimer
2026-06-09 13:25 ` [PATCH ifupdown2 16/16] d/patches: add support for VXLAN-GBP flag Hannes Laimer
2026-06-18 13:10 ` [RFC cluster/docs/ifupdown2/manager/network/proxmox{-ebpf,-ve-rs,-perl-rs} 00/16] sdn: add microsegmentation support Lukas Sichert
2026-07-09  9:20 ` Hannes Laimer [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9da00602-7f6a-43d6-a817-c57a1c6cc0eb@proxmox.com \
    --to=h.laimer@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal