Bill Octavia load-balancer traffic to the tenant that owns the load balancer - #298
Merged
Merged
Conversation
…r instead of the service project Signed-off-by: arashi.li <arashi.li@bigstack.co>
…g packed into mac_tenant_map Signed-off-by: arashi.li <arashi.li@bigstack.co>
…e amphora base address Signed-off-by: arashi.li <arashi.li@bigstack.co>
…tead of the conntrack design Signed-off-by: arashi.li <arashi.li@bigstack.co>
…nt attribution live Signed-off-by: arashi.li <arashi.li@bigstack.co>
… instead of only at cold-start Signed-off-by: arashi.li <arashi.li@bigstack.co>
…a floating IP on its VIP port Signed-off-by: arashi.li <arashi.li@bigstack.co>
… in WaitLBActive Signed-off-by: arashi.li <arashi.li@bigstack.co>
arasHi87
force-pushed
the
arashi.li/octavia-lb-owner
branch
from
August 17, 2026 07:30
3a2a7a1 to
8550a99
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes
Closes #131
What & why
Octavia runs a tenant's load balancer as an Amphora VM in the Octavia service project, so every byte it moves bills the operator. This bills the tenant who owns the load balancer instead.
Attribution is already a userspace lookup on the VM-side MAC, so the core of it needs no kernel change: a three-hop join (
load balancer → project_id,amphora → compute_id, then every port whosedevice_idmatches, minus the management port) rewrites the Amphora port's project. That one substitution moves both thetenant_idlabel and the interned tenant the kernel keys zone comparisons on.compute_idis the join key rather than the Amphora'svrrp_port_idbecause Octavia plugs an Amphora into a pool member's foreign subnet by handing Nova a network with no port — Nova then mints a port with no Octavia marker and no allowed-address pair. Confirmed live on c36:device_owner=compute:nova,aap=[], service project. Any narrower join silently leaves that traffic billing the operator.Two kernel-side pieces make Segment 2 read
infrawithout swallowing Segment 1:mac_tenant_mapvalue (oneAND, versus ~20–30 ns for a sidecar-map lookup on every packet whose peer resolves);amphora_base_ipset, probed only when the marker is set. HAProxy accepts Segment 1 on the VIP and originates Segment 2 from the port's base address, so the address is what separates them. Base addresses rather than VIPs because it fails safe: a gap drops Segment 2 tosame_tenant($0 either way), whereas a missing VIP would mark Segment 1infraand stop billing it.An intermediate commit (
a4a7ba1) zoned any L2-adjacent flow touching an Amphora asinfra;1b06184fixes it. That version made an internal cross-tenant client's load-balancer request free in both directions.The harness gained Octavia support: a DSL primitive, eight
Cloudverbs, the live driver, the fake, realize/down wiring,VIPTarget/LBFIPTarget, and a preflight-resolved optionallb_flavor_nameso multi-Amphora scenarios report SKIPPED on a cluster with noACTIVE_STANDBYflavor staged rather than failing.Test plan
task testtask test-integration(40/40 packages)task bench-gate+ per-packet ceiling (26 ns/packet, zero allocations)scenariotest run octavia-lb-attributionLive validation
c36 (10.32.36.x), 2026-08-17.
octavia-lb-attribution:ACTIVE_STANDBY(MASTER+BACKUP), three pool members across two subnets, internal same-tenant client, internal cross-tenant client, and an external client via a floating IP on the VIP port. All 8 assertions PASS:infra= 12.1 MiB is exactly the three flows' payload — every byte through the load balancer identified as Segment 2 plumbing.other_tenant= 4.0 MiB is the regression guard for the intermediate bug above.Two cluster prerequisites were needed and are worth knowing before reproducing:
[libvirt] num_pcie_portswas unset, so an Amphora booted with 8 PCIe root ports and 8 devices — no spare. Cross-subnet member plugs failedNo more available PCI slotswhile the LB stayed ACTIVE. Set to 28 on p4/p5/p6.ACTIVE_STANDBYcomes from an Octavia flavorprofile, not a per-LB flag. Stagedlachesis-ha.Scope / deliberately not touched
PROMETHEUSlistener, a userspace collector.docs/architecture/contracts.md.Notes
Touches the billing path. Contract 7 (monotone billing series) is preserved by keeping attribution VM-side: an earlier design branched on the peer being an Amphora, which would have put a
server_idunder atenant_idthat does not own it and broken thetotal → tenant → server → portnesting.reconcile.DesiredMACsis now the single definition of the desired metadata map, consumed by both cold-start and the reconciler, with a cross-check test — two copies of that logic is a billing bug waiting for someone to edit one.1007ee9fixes an observability bug found while debugging this:lachesis_neutron_amphora_portswas published only from the cold-start path, so a load balancer created after boot never moved it and the failure it exists to detect left it frozen at a healthy-looking value. It cost four wrong diagnoses before anyone grepped for its call sites.Handbook entry: bigstack-oss/bigstack-handbook#279.
DoD
/bigstack-core:save-to-handbook)