Skip to content

connectivity: fix CrossSubnet defaulting to Always with host-prefix#959

Open
aritrbas wants to merge 1 commit intomasterfrom
abasu-fix-cross-subnet
Open

connectivity: fix CrossSubnet defaulting to Always with host-prefix#959
aritrbas wants to merge 1 commit intomasterfrom
abasu-fix-cross-subnet

Conversation

@aritrbas
Copy link
Collaborator

Problem

CrossSubnet mode for VXLAN and IPIP is not honored when the local node's BGP address has a host prefix (/128 for IPv6 or /32 for IPv4). Instead, it falls back to Always mode, forming tunnels to all peers including those within the same subnet.

RCA

GetNodeIPNet() returns the BGP spec's IPNet directly from Felix's HostMetadataV4V6Update. When DHCPv6 assigns /128 addresses, net.IPNet.Contains() with a /128 mask only matches the exact node IP. So, no peer can ever be "same subnet", and every peer gets a tunnel.

Fix

Query VPP for the actual subnet mask on the main uplink interface. vpp-manager already applies getUplinkAddressWithMask() (controlled by TranslateUplinkAddrMaskTo64) which widens /128 to /64 when configuring the VPP uplink. When GetNodeIPNet() detects a host prefix (/128 or /32), it calls getUplinkIPNetFromVPP() which uses vpplink.AddrList() on the main uplink interface to find the matching address and retrieve its actual subnet mask. This ensures we use the real subnet mask from VPP data plane and gracefully degrade to /128 BGP net if the VPP query fails.

When the local node's BGP address has a host prefix (/128 for IPv6,
/32 for IPv4), GetNodeIPNet() returned a subnet containing only the
node itself. This made nodeIPNet.Contains(peer) false for every peer,
causing CrossSubnet to behave identically to Always — tunnels were
formed to all peers including same-subnet ones.

Fixed by querying VPP for the actual subnet mask configured on the
main uplink interface. vpp-manager already widens /128 to /64 via
getUplinkAddressWithMask() for IPv6 host prefixes. When a host prefix
is detected, GetNodeIPNet() calls getUplinkIPNetFromVPP() to retrieve
the uplink's configured prefix via AddrList(), using that for the
CrossSubnet Contains() check to honor CrossSubnet for host prefix.

Signed-off-by: Aritra Basu <aritrbas@cisco.com>
@aritrbas aritrbas self-assigned this Mar 20, 2026
Copy link
Collaborator

@sknat sknat left a comment

Choose a reason for hiding this comment

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

Oh, good catch ! I think this could be solved by tweaking a bit vpp_runner.
More details inline

// "CrossSubnet" to behave like "Always". Fall back to the VPP uplink
// interface's configured subnet, which vpp-manager already widens from
// /128 to /64 via getUplinkAddressWithMask() for IPv6 host prefixes.
ones, bits := ipNet.Mask.Size()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can't this be solved by moving the call to getUplinkAddressWithMask()
to be in GetAddressesAsIPNet() and GetAddresses() ?

If we do this, updateCalicoNode() will advertise the updated /64 in v6 mode,
which we should then receive through felix in nodeBGPSpec

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.

2 participants