summaryrefslogtreecommitdiff
path: root/net/bird3/files/patch-16-Table-old-best-route-refeed-fix
blob: 60dc7cece2a20ff8623325554d081e0b4f1941bb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
From 2e14832d36c83b2ab5b7fb28b701de554fa5fdd9 Mon Sep 17 00:00:00 2001
From: Maria Matejka <mq@ucw.cz>
Date: Tue, 7 Jan 2025 12:13:57 +0100
Subject: [PATCH] Table: old best route refeed fix

When refeeding with RA_OPTIMAL, the old best routes weren't announced,
leading to weird behavior of protocols, mostly kernel. Fixed.
---
 nest/rt-table.c | 30 ++++++++++++++++++++++++++----
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/nest/rt-table.c b/nest/rt-table.c
index fc6d0d4e0..18a445a62 100644
--- nest/rt-table.c
+++ nest/rt-table.c
@@ -1485,11 +1485,18 @@ channel_notify_basic(void *_channel)
 	    rte *new = &u->feed->block[i];
 	    rte *old = NULL;
 	    for (uint o = oldpos; o < u->feed->count_routes; o++)
-	      if (new->src == u->feed->block[o].src)
+	      if ((c->ra_mode == RA_ANY) && (new->src == u->feed->block[o].src))
 	      {
 		old = &u->feed->block[o];
 		break;
 	      }
+	      else if ((c->ra_mode == RA_OPTIMAL) && (
+		    bmap_test(&c->export_accepted_map, u->feed->block[o].id) || 
+		    bmap_test(&c->export_rejected_map, u->feed->block[o].id)))
+	      {
+		ASSERT_DIE(!old);
+		old = &u->feed->block[o];
+	      }
 
 	    rt_notify_basic(c, new, old);
 
@@ -2542,10 +2549,14 @@ rt_feed_net_best(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, bool
   last_in_net = atomic_load_explicit(&n->best.last, memory_order_acquire);
   first = rt_net_feed_validate_first(tr, first_in_net, last_in_net, first);
 
-  uint ecnt = 0;
+  uint ecnt = 0, ocnt = 0;
   for (const struct rt_pending_export *rpe = first; rpe;
       rpe = atomic_load_explicit(&rpe->next, memory_order_acquire))
+  {
     ecnt++;
+    if (rpe->it.old)
+      ocnt++;
+  }
 
   if (ecnt) {
     const net_addr *a = (first->it.new ?: first->it.old)->net;
@@ -2558,10 +2569,11 @@ rt_feed_net_best(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, bool
   if (!ecnt && (!best || prefilter && !prefilter(f, best->rte.net)))
     return NULL;
 
-  struct rt_export_feed *feed = rt_alloc_feed(!!best, ecnt);
+  struct rt_export_feed *feed = rt_alloc_feed(!!best + ocnt, ecnt);
+  uint bpos = 0;
   if (best)
   {
-    feed->block[0] = best->rte;
+    feed->block[bpos++] = best->rte;
     feed->ni = NET_TO_INDEX(best->rte.net);
   }
   else
@@ -2575,8 +2587,18 @@ rt_feed_net_best(struct rt_exporter *e, struct rcu_unwinder *u, u32 index, bool
       if (e >= ecnt)
 	RT_READ_RETRY(tr);
       else
+      {
 	feed->exports[e++] = rpe->it.seq;
+	if (rpe->it.old)
+	{
+	  ASSERT_DIE(bpos < !!best + ocnt);
+	  feed->block[bpos] = *rpe->it.old;
+	  feed->block[bpos].flags |= REF_OBSOLETE;
+	  bpos++;
+	}
+      }
 
+    ASSERT_DIE(bpos == !!best + ocnt);
     ASSERT_DIE(e == ecnt);
   }
 
-- 
GitLab