aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2024-01-27 17:38:06 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2024-01-27 17:38:06 +0100
commitf40e2bc270d3635be518ae80251ce0b5c519c6f4 (patch)
treeb1122bd3b91456656222ad4da849862a9f9c3fb9
parent472be46f7ab211f38e7662543f1436df30dca753 (diff)
downloadbird-f40e2bc270d3635be518ae80251ce0b5c519c6f4.tar.gz
Nest: Fix bug in recursive routes with MPLS-labeled nexthops
When a recursive route with MPLS-labeled nexthop was exported to kernel and read back, the nexthop_same() failed due to different labels_orig field and kernel protocol reinstalled it unnecessarily. For comparing hext hops, route cache has to distinguish ones with different labels_orig, but KRT has to ignore that, so we need two nexthop compare functions. Thanks to Marcel Menzel for the bugreport.
-rw-r--r--nest/route.h3
-rw-r--r--nest/rt-attr.c38
-rw-r--r--sysdep/unix/krt.c2
3 files changed, 33 insertions, 10 deletions
diff --git a/nest/route.h b/nest/route.h
index d26a4b8c..e6f6c64a 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -694,6 +694,9 @@ static inline size_t nexthop_size(const struct nexthop *nh)
int nexthop__same(struct nexthop *x, struct nexthop *y); /* Compare multipath nexthops */
static inline int nexthop_same(struct nexthop *x, struct nexthop *y)
{ return (x == y) || nexthop__same(x, y); }
+int nexthop_equal_(struct nexthop *x, struct nexthop *y); /* Compare multipath nexthops, ignore labels_orig */
+static inline int nexthop_equal(struct nexthop *x, struct nexthop *y)
+{ return (x == y) || nexthop_equal_(x, y); }
struct nexthop *nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, linpool *lp);
struct nexthop *nexthop_sort(struct nexthop *x);
static inline void nexthop_link(struct rta *a, const struct nexthop *from)
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index 7f3645ee..af864bdf 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -185,20 +185,40 @@ nexthop_hash(struct nexthop *x)
return h;
}
+static inline int
+nexthop_equal_1(struct nexthop *x, struct nexthop *y)
+{
+ if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) ||
+ (x->flags != y->flags) || (x->weight != y->weight) ||
+ (x->labels != y->labels))
+ return 0;
+
+ for (int i = 0; i < x->labels; i++)
+ if (x->label[i] != y->label[i])
+ return 0;
+
+ return 1;
+}
+
int
-nexthop__same(struct nexthop *x, struct nexthop *y)
+nexthop_equal_(struct nexthop *x, struct nexthop *y)
{
+ /* Like nexthop_same(), but ignores difference between local labels and labels from hostentry */
+
for (; x && y; x = x->next, y = y->next)
- {
- if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) ||
- (x->flags != y->flags) || (x->weight != y->weight) ||
- (x->labels_orig != y->labels_orig) || (x->labels != y->labels))
+ if (!nexthop_equal_1(x, y))
return 0;
- for (int i = 0; i < x->labels; i++)
- if (x->label[i] != y->label[i])
- return 0;
- }
+ return x == y;
+}
+
+int
+nexthop__same(struct nexthop *x, struct nexthop *y)
+{
+ for (; x && y; x = x->next, y = y->next)
+ if (!nexthop_equal_1(x, y) ||
+ (x->labels_orig != y->labels_orig))
+ return 0;
return x == y;
}
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 3a4b24dc..7a078fb9 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -619,7 +619,7 @@ krt_same_dest(rte *k, rte *e)
return 0;
if (ka->dest == RTD_UNICAST)
- return nexthop_same(&(ka->nh), &(ea->nh));
+ return nexthop_equal(&(ka->nh), &(ea->nh));
return 1;
}