Skip to content

Conversation

@dagrayvid
Copy link

This PR aims to solve two problems I faced using the source-based router CNI plugin for distributed LLM inference with vLLM / llm-d.

  1. Option to configure a statically defined gateway IP to set or override the gateway if not passed in from the CNI config chain.

In my environment (IBM Cloud), the DHCP server my secondary high-speed networks does not provide the gateway IP, so I needed a way to override / statically define the gateway IPs to ensure that the custom routing tables included the default route to the gateway.

  1. Option to "preserve default routes" in the main routing table, so that packets without a source IP are still routed correctly. For example in my environment after enabling SBR, ping -I 10.0.0.6 10.1.0.7 would work, but ping 10.1.0.7. With "preserveDefaultRoutes": true, both work.

Tested in my environment with this CNI config:

{
  "cniVersion": "0.3.1",
  "name": "dhcp-host-device-port-1",
  "plugins": [
    {
      "type": "host-device",
      "device": "enp163s0",
      "isRdma": true,
      "ipam": {
        "type": "dhcp"
      }
    },
    {
      "type": "sbr-custom",
      "gateway": "10.0.0.1",
      "preserveDefaultRoutes": true
    }
  ]
}

In a Pod, the result of the statically defined gateway:

bash-5.1# ip route show table 100
default via 10.0.0.1 dev net1
10.0.0.0/16 dev net1 proto kernel scope link src 10.0.0.5

and the result of preserve default route:

bash-5.1# ip route show table 254
default via 10.130.0.1 dev eth0
10.0.0.0/16 dev net1 scope link src 10.0.0.5
10.1.0.0/16 dev net2 scope link src 10.1.0.6
10.2.0.0/16 dev net3 scope link src 10.2.0.6
...

@dagrayvid dagrayvid force-pushed the main branch 3 times, most recently from 78e2abb to 0d9f9b1 Compare November 28, 2025 16:49
@squeed
Copy link
Member

squeed commented Dec 1, 2025

Looks nice!
Would there ever be a case where we wanted just source-hinted routes without the table?

@dagrayvid
Copy link
Author

dagrayvid commented Dec 1, 2025

Thanks for the review @squeed!

Would there ever be a case where we wanted just source-hinted routes without the table?

I'm not sure I fully understand the question. If a user wanted only source-hinted routes without custom tables, I don't think they'd need SBR at all - the kernel already creates these automatically when IPs are assigned.

In my case at least, without SBR on my interface at 10.5.0.5, the source-hinted route is already in the main table:

$ ip route show
...
10.5.0.0/16 dev net6 proto kernel scope link src 10.5.0.5

The SBR plugin (without this added preserveDefaultRoutes option) deletes these after copying them to the custom tables:

for _, route := range routes {
log.Printf("Deleting route %s from table %d", route.String(), route.Table)
err := netlink.RouteDel(&route)
if err != nil {
return fmt.Errorf("Failed to delete route: %v", err)
}
}

Does that make sense? Please let me know if I've misunderstood your question.

@squeed
Copy link
Member

squeed commented Dec 8, 2025

🤦 of course. I don't know what I was thinking.

Table *int `json:"table,omitempty"`
// Gateway allows specifying a static/hardcoded gateway IP address
// If set, this will be used instead of the gateway from prevResult
Gateway string `json:"gateway,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

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

Note: This should permit dual-stack :-). Ideally this is a list.

Copy link
Member

Choose a reason for hiding this comment

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

Also could be useful for anyone simply having multiple gateways

Copy link
Author

Choose a reason for hiding this comment

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

@squeed I have updated the plugin to support dual-stack, PTAL when you get a chance.

Copy link
Author

@dagrayvid dagrayvid Dec 10, 2025

Choose a reason for hiding this comment

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

Also could be useful for anyone simply having multiple gateways

Currently the static gateway option introduced in this PR will apply the same gateway to all IPs passed in from prevResult.

I see two potential enhancements here:

  1. Support multiple IPs by configuring a mapping of subnets to gateways, e.g.
{
  "type": "sbr",
  "gateways": {
    "192.168.1.209/24": "192.168.1.1",
    "192.168.101.209/24"": "192.168.101.1"
  },
  "preserveDefaultRoutes": true
}
  1. Support multiple gateways per subnet (multiple default routes per address, ECMP load-balancing). This would be a net-new feature that goes beyond what the sbr plugin currently does with prevResult

Are you ok with the current limitation on static gateways, or would you prefer if I implement matching gateways to subnets for the mulitiple IP case in this PR?

Table *int `json:"table,omitempty"`
// Gateway allows specifying a static/hardcoded gateway IP address
// If set, this will be used instead of the gateway from prevResult
Gateway string `json:"gateway,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

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

Also could be useful for anyone simply having multiple gateways

Copy link
Contributor

@karampok karampok left a comment

Choose a reason for hiding this comment

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

Some comments from my side

  • 5 commits seem too many imo, maybe 2 (one for static gateway on for preserveDefaultRoutes) or even 1 (like atomic commits)
  • test look a bit thin, like only ipv4 not unhappy path

(Note: I am not maintainer of the repo)

// PreserveDefaultRoutes keeps subnet routes in the main routing table
// with proper source IP hints for destination-based routing.
// This allows packets without an explicit source IP to be routed correctly.
PreserveDefaultRoutes bool `json:"preserveDefaultRoutes,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

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

PreserveDefaultRoutes: is not so clear to me.

The "defaultRoutes" suffix makes think that in the main table I see a default route, which is not true, I only should see the subnet via eth0 src x.y.z.k, is that correct?

thx

Copy link
Author

Choose a reason for hiding this comment

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

I think this is a good point. I renamed this option to AddSourceHints. Do you think that is more clear?

} else if ipCfg.Gateway != nil {
gateway = ipCfg.Gateway
}
} else {
Copy link
Contributor

Choose a reason for hiding this comment

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

It is more golang if we have code without else and else if

Copy link
Author

Choose a reason for hiding this comment

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

Thanks, I made this a switch statement.

"cniVersion": "0.3.0",
"name": "cni-plugin-sbr-test",
"type": "sbr",
"gateways": ["192.168.1.254"],
Copy link
Contributor

Choose a reason for hiding this comment

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

Ideally a test for ipv4, ipv6 and dualstack

Copy link
Member

@squeed squeed left a comment

Choose a reason for hiding this comment

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

Can you please squash your commits? And a v6 test would be good.

Add two new configuration options:

1. "gateways" ([]string): Static gateway IPs that override prevResult.
   Supports dual-stack (one IPv4 and/or one IPv6 address).

2. "addSourceHints" (bool): Preserves subnet routes in the main table
   with source IP hints, enabling destination-based routing to work
   alongside source-based routing.

Example:
{
  "type": "sbr",
  "gateways": ["10.0.0.1"],
  "addSourceHints": true
}

Signed-off-by: David Whyte-Gray <[email protected]>
@dagrayvid
Copy link
Author

dagrayvid commented Jan 7, 2026

Thanks @squeed @karampok for the review. I renamed PreserveDefaultRoutes to AddSourceHints and added tests for ipv6 and dual stack. Also squashed the commits. PTAL

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.

4 participants