From bb823a272c65b3a5fdc677d53ce02d824045f188 Mon Sep 17 00:00:00 2001 From: Dean Chen <862469039@qq.com> Date: Mon, 10 Aug 2026 11:46:19 +0500 Subject: [PATCH 1/2] table: skip rejected paths when building Drop withdrawals Rejected adj-RIB-In paths were never installed in the local RIB, so emitting withdrawals for them produces "No matching path for withdraw" noise on peer flaps. Clear them from adj state still, but only return withdrawals for paths that had been accepted. Fixes #3455 Signed-off-by: Dean Chen <862469039@qq.com> --- internal/pkg/table/adj.go | 5 +++++ internal/pkg/table/adj_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/internal/pkg/table/adj.go b/internal/pkg/table/adj.go index 2ec60c027..a017660eb 100644 --- a/internal/pkg/table/adj.go +++ b/internal/pkg/table/adj.go @@ -206,6 +206,11 @@ func (adj *AdjRib) Drop(rfList []bgp.Family) []*Path { l := make([]*Path, 0, adj.Count(rfList)) adj.walk(rfList, func(d *destination) bool { for _, p := range d.knownPathList { + // Rejected paths were never installed in the local RIB; do not + // emit withdrawals for them (avoids "No matching path for withdraw"). + if p.IsRejected() { + continue + } w := p.Clone(true) w.SetDropped(true) l = append(l, w) diff --git a/internal/pkg/table/adj_test.go b/internal/pkg/table/adj_test.go index 2c624b0c4..4dc67b273 100644 --- a/internal/pkg/table/adj_test.go +++ b/internal/pkg/table/adj_test.go @@ -138,6 +138,33 @@ func TestStale(t *testing.T) { assert.Equal(t, 1, len(adj.table[family].GetDestinations())) } + +func TestDropSkipsRejected(t *testing.T) { + pi := &PeerInfo{} + attrs := []bgp.PathAttributeInterface{bgp.NewPathAttributeOrigin(0)} + + nlri1, _ := bgp.NewIPAddrPrefix(netip.MustParsePrefix("20.20.10.0/24")) + p1 := NewPath(bgp.RF_IPv4_UC, pi, bgp.PathNLRI{NLRI: nlri1}, false, attrs, time.Now(), false) + nlri2, _ := bgp.NewIPAddrPrefix(netip.MustParsePrefix("20.20.20.0/24")) + p2 := NewPath(bgp.RF_IPv4_UC, pi, bgp.PathNLRI{NLRI: nlri2}, false, attrs, time.Now(), false) + p2.SetRejected(true) + + family := p1.GetFamily() + families := []bgp.Family{family} + + adj := NewAdjRib(slog.Default(), families) + adj.Update([]*Path{p1, p2}) + assert.Equal(t, 2, adj.Count(families)) + assert.Equal(t, 1, adj.Accepted(families)) + + // Drop must not emit withdrawals for rejected paths that never entered the RIB. + dropped := adj.Drop(families) + assert.Equal(t, 1, len(dropped)) + assert.False(t, dropped[0].IsRejected()) + assert.Equal(t, 0, adj.Count(families)) + assert.Equal(t, 0, adj.Accepted(families)) +} + func TestLLGRStale(t *testing.T) { pi := &PeerInfo{} attrs := []bgp.PathAttributeInterface{bgp.NewPathAttributeOrigin(0)} From ebcf2bb7396ece38edb51d68a3e87026e6f6fae6 Mon Sep 17 00:00:00 2001 From: Dean Chen <862469039@qq.com> Date: Wed, 12 Aug 2026 18:01:21 +0500 Subject: [PATCH 2/2] fix: gofmt adj_test.go Signed-off-by: Dean Chen <862469039@qq.com> --- internal/pkg/table/adj_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/pkg/table/adj_test.go b/internal/pkg/table/adj_test.go index 4dc67b273..42476ebae 100644 --- a/internal/pkg/table/adj_test.go +++ b/internal/pkg/table/adj_test.go @@ -138,7 +138,6 @@ func TestStale(t *testing.T) { assert.Equal(t, 1, len(adj.table[family].GetDestinations())) } - func TestDropSkipsRejected(t *testing.T) { pi := &PeerInfo{} attrs := []bgp.PathAttributeInterface{bgp.NewPathAttributeOrigin(0)}