Skip to content

Commit 7fd2c04

Browse files
committed
ip,ip6: reject duplicate routes with different nexthops
Previously, adding a route that already existed would silently succeed if exist_ok was true, even when the nexthop was different. This behavior is incorrect, as the user expects either the same route with the same nexthop to exist, or an error to be returned. This patch ensures that an error is returned when a route exists with a different nexthop, regardless of the exist_ok flag. Signed-off-by: Maxime Leroy <[email protected]>
1 parent 0a339c3 commit 7fd2c04

File tree

4 files changed

+29
-4
lines changed

4 files changed

+29
-4
lines changed

modules/infra/control/gr_nh_control.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ struct hoplist {
3939
struct nexthop *
4040
nexthop_lookup(gr_nh_type_t type, uint16_t vrf_id, uint16_t iface_id, const void *addr);
4141

42+
// Compare two nexthops, return True if the same, else False
43+
bool nexthop_equal(struct nexthop *nh1, struct nexthop *nh2);
44+
4245
// Allocate a new nexthop from the global pool with the provided initial values.
4346
struct nexthop *
4447
nexthop_new(gr_nh_type_t type, uint16_t vrf_id, uint16_t iface_id, const void *addr);

modules/infra/control/nexthop.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,24 @@ nexthop_new(gr_nh_type_t type, uint16_t vrf_id, uint16_t iface_id, const void *a
137137
return nh;
138138
}
139139

140+
bool nexthop_equal(struct nexthop *nh1, struct nexthop *nh2) {
141+
if (nh1->vrf_id != nh2->vrf_id || nh1->iface_id != nh2->iface_id || nh1->type != nh2->type)
142+
return false;
143+
144+
switch (nh1->type) {
145+
case GR_NH_IPV4:
146+
case GR_NH_SR6_IPV4:
147+
return (memcmp(&nh1->ipv4, &nh2->ipv4, sizeof(nh1->ipv4)) == 0);
148+
case GR_NH_IPV6:
149+
case GR_NH_SR6_IPV6:
150+
return (memcmp(&nh1->ipv6, &nh2->ipv6, sizeof(nh1->ipv6)) == 0);
151+
default:
152+
ABORT("invalid nexthop type %hhu", nh1->type);
153+
}
154+
155+
return false;
156+
}
157+
140158
struct pool_iterator {
141159
nh_iter_cb_t user_cb;
142160
void *priv;

modules/ip/control/route.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ int rib4_insert(
131131
) {
132132
struct rte_rib *rib = get_or_create_rib(vrf_id);
133133
struct rte_rib_node *rn;
134+
struct nexthop *_nh;
134135
gr_rt_origin_t *o;
135136
int ret;
136137

@@ -140,8 +141,9 @@ int rib4_insert(
140141
ret = -errno;
141142
goto fail;
142143
}
143-
if (rib4_lookup_exact(vrf_id, ip, prefixlen) != NULL) {
144-
ret = -EEXIST;
144+
_nh = rib4_lookup_exact(vrf_id, ip, prefixlen);
145+
if (_nh != NULL) {
146+
ret = nexthop_equal(nh, _nh) ? -EEXIST : -EBUSY;
145147
goto fail;
146148
}
147149

modules/ip6/control/route.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ int rib6_insert(
144144
const struct rte_ipv6_addr *scoped_ip;
145145
struct rte_ipv6_addr tmp;
146146
struct rte_rib6_node *rn;
147+
struct nexthop *_nh;
147148
gr_rt_origin_t *o;
148149
int ret;
149150

@@ -153,8 +154,9 @@ int rib6_insert(
153154
ret = -errno;
154155
goto fail;
155156
}
156-
if (rib6_lookup_exact(vrf_id, iface_id, ip, prefixlen) != NULL) {
157-
ret = -EEXIST;
157+
_nh = rib6_lookup_exact(vrf_id, iface_id, ip, prefixlen);
158+
if (_nh != NULL) {
159+
ret = nexthop_equal(nh, _nh) ? -EEXIST : -EBUSY;
158160
goto fail;
159161
}
160162

0 commit comments

Comments
 (0)