Skip to content

Enable BGP next-hop-self - #666

Draft
nikatza wants to merge 1 commit into
mainfrom
bgp-nexthop-self
Draft

nikatza wants to merge 1 commit into
mainfrom
bgp-nexthop-self

Conversation

@nikatza

@nikatza nikatza commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

See commit message for design and implementation details.

---
apiVersion: networking.metal.ironcore.dev/v1alpha1
kind: BGPPeer
metadata:
  labels:
    app.kubernetes.io/name: network-operator
    app.kubernetes.io/managed-by: kustomize
  name: leaf1-spine1-next-hop-self
spec:
  deviceRef:
    name: leaf1
  bgpRef:
    name: bgp
  address: 10.0.0.4
  asNumber: 65000
  localAddress:
    interfaceRef:
      name: lo0
  addressFamilies:
    ipv4Unicast:
      enabled: true
      outboundRoutingPolicyRef:
        name: bgp-next-hop-self
---
apiVersion: networking.metal.ironcore.dev/v1alpha1
kind: RoutingPolicy
metadata:
  labels:
    app.kubernetes.io/name: network-operator
    app.kubernetes.io/managed-by: kustomize
  name: bgp-next-hop-self
spec:
  deviceRef:
    name: leaf1
  name: BGP-NEXT-HOP-SELF
  statements:
    - sequence: 10
      actions:
        routeDisposition: AcceptRoute
        bgpActions:
          setNextHop:
            type: Self
 ---

Tested with a cisco nxos device:

router bgp 65000
  router-id 10.0.0.10
  address-family ipv4 unicast
    maximum-paths 4
  address-family ipv6 unicast
    maximum-paths 2
  address-family l2vpn evpn
    retain route-target all
  template peer __operator-managed--default__
  neighbor 10.0.0.1
    remote-as 65000
    update-source loopback0
    address-family l2vpn evpn
      send-community
      send-community extended
  neighbor 10.0.0.4
    remote-as 65000
    update-source loopback0
    address-family ipv4 unicast
      next-hop-self

@felix-kaestner felix-kaestner added the review-scheduled The PR is being reviewed. label Oct 22, 2026
@nikatza
nikatza force-pushed the bgp-nexthop-self branch 7 times, most recently from f4c55e7 to ce1c9a6 Compare October 27, 2026 10:23
@github-actions github-actions Bot added size/XXL and removed size/XL labels Oct 27, 2026
@nikatza
nikatza force-pushed the bgp-nexthop-self branch 7 times, most recently from 6bb9e48 to ba22390 Compare October 27, 2026 15:47
@nikatza

nikatza commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Note for the reviewers: with this commit we introduce a new dependency effect for unsupported next-hop configurations. If a referenced policy contains one, BGP resources become Configured=False. All BGPPeer resources referencing that BGP enter WaitingForDependencies and pause configuration updates. Existing device configuration and sessions remain active. Correcting the policy triggers reconciliation and allows updates to resume. This behavior applies to the new next-hop action; existing policies without it keep their previous behavior.

I want to raise this point as we might want to handle this differently.

@nikatza
nikatza marked this pull request as ready for review October 27, 2026 15:54
@github-actions

Copy link
Copy Markdown

Caution

No coverage for base commit 7fb91bd was found, so this report compares against its ancestor 10cc35f (1 commit earlier)

Merging this branch changes the coverage (2 decrease, 4 increase)

Impacted Packages Coverage Δ 🤖
github.com/ironcore-dev/network-operator/api/core/v1alpha1 2.38% (-0.01%) 👎
github.com/ironcore-dev/network-operator/internal/controller/cisco/nx 64.80% (-0.53%) 👎
github.com/ironcore-dev/network-operator/internal/controller/core 62.64% (+0.38%) 👍
github.com/ironcore-dev/network-operator/internal/controller/pool 75.53% (+1.48%) 👍
github.com/ironcore-dev/network-operator/internal/provider 1.75% (ø)
github.com/ironcore-dev/network-operator/internal/provider/cisco/iosxr 40.43% (+0.04%) 👍
github.com/ironcore-dev/network-operator/internal/provider/cisco/nxos 21.59% (+3.82%) 👍
github.com/ironcore-dev/network-operator/internal/provider/openconfig 9.51% (-0.03%) 👎
github.com/ironcore-dev/network-operator/internal/webhook/core/v1alpha1 95.04% (ø)
Coverage details

Compared to commit 10cc35f (run #40321897417)

Changed File Coverage Δ Total Covered Missed 🤖
github.com/ironcore-dev/network-operator/api/core/v1alpha1/routingpolicy_types.go 12.50% (ø) 8 1 7
github.com/ironcore-dev/network-operator/api/core/v1alpha1/zz_generated.deepcopy.go 0.00% (ø) 2982 (+13) 0 2982 (+13)
github.com/ironcore-dev/network-operator/internal/controller/core/bgp_controller.go 69.33% (+0.16%) 238 (-2) 165 (-1) 73 (-1) 👍
github.com/ironcore-dev/network-operator/internal/controller/core/bgp_peer_controller.go 67.22% (+7.28%) 360 (-2) 242 (+25) 118 (-27) 👍
github.com/ironcore-dev/network-operator/internal/provider/cisco/iosxr/route_policies.go 72.63% (-0.49%) 95 (+2) 69 (+1) 26 (+1) 👎
github.com/ironcore-dev/network-operator/internal/provider/cisco/nxos/bgp.go 48.57% (+28.57%) 140 (+55) 68 (+51) 72 (+4) 🌟
github.com/ironcore-dev/network-operator/internal/provider/cisco/nxos/provider.go 8.10% (+3.78%) 2569 (+43) 208 (+99) 2361 (-56) 👍
github.com/ironcore-dev/network-operator/internal/provider/openconfig/bgppeer.go 2.70% (ø) 74 2 72
github.com/ironcore-dev/network-operator/internal/provider/openconfig/routingpolicy.go 0.00% (ø) 26 (+2) 0 26 (+2)
github.com/ironcore-dev/network-operator/internal/provider/provider.go 1.75% (ø) 57 1 56

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

Changed unit test files:

  • github.com/ironcore-dev/network-operator/internal/controller/core/bgp_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/bgp_peer_controller_test.go
  • github.com/ironcore-dev/network-operator/internal/controller/core/suite_test.go
  • github.com/ironcore-dev/network-operator/internal/provider/cisco/nxos/bgp_test.go
  • github.com/ironcore-dev/network-operator/internal/webhook/core/v1alpha1/routingpolicy_webhook_test.go

Comment thread api/core/v1alpha1/routingpolicy_types.go
Comment thread api/core/v1alpha1/routingpolicy_types.go Outdated
Comment thread internal/controller/core/bgp_controller.go Outdated
return false
},
}),
builder.WithPredicates(predicate.GenerationChangedPredicate{}),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same as in the bgp controller. We favor more narrow predicates to only trigger, when field are changed, that are read during the reconcilation and therefore change the result of the reconcilation.

current := new(v1alpha1.BGP)
g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(bgp), current)).To(Succeed())
g.Expect(conditions.IsConfigured(current)).To(BeTrue())
g.Expect(current.Generation).To(Equal(bgp.Generation))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What is the reason we are checking the generation here?

Comment thread internal/provider/cisco/nxos/bgp_test.go Outdated
Comment thread internal/provider/cisco/nxos/bgp_test.go Outdated
Comment thread internal/provider/cisco/nxos/bgp_test.go Outdated
func TestNextHopSelfOnlyPolicy(t *testing.T) {
tests := []struct {
name string
change func(*v1alpha1.RoutingPolicy)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Again. Just make this a *v1alpha1.RoutingPolicy field. You trade a repetetive &v1alpha1.RoutingPolicy{...} (easier to follow) for callback-like abstraction.

case *gpb.GetRequest:
path := req.GetPath()[0]
value := state
if path.Elem[len(path.Elem)-1].Name == "Dom-list" {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why do we write a full gnmi server mock with xpath parsing? As with other tests, I would just remove this.

@nikatza
nikatza marked this pull request as draft October 28, 2026 17:40
This commit enables introduces methods to control the next-hop for
advertised routes. Vendors like Cisco support a `nexthop-self` knob in
the peers address-family configuration. This is however not modeled in
OpenConfig, for which the same can be achieved by configuring routing
policies (and so for every vendor). As most vendors support this kind of
knob, we add this into the API core type BGPPeer. We also add the
SetNexhopAction to the RoutingPolicy statements.

Cisco exposes the NX-OS peer address-family controls as a typed bitmask.
We update provider to handle properly the comma-separated gNMI values
returned by the device and avoid unnecessary device writes due to
different order.

Signed-off-by: Pujol <enric.pujol@sap.com>

This branch has not been deployed

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

Labels

review-scheduled The PR is being reviewed. size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants