Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 34 additions & 14 deletions modules/ip/control/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,16 @@ struct nexthop *rib4_lookup_exact(uint16_t vrf_id, ip4_addr_t ip, uint8_t prefix
return nh_id_to_ptr(nh_id);
}

int rib4_insert(
static int rib4_insert_or_replace(
uint16_t vrf_id,
ip4_addr_t ip,
uint8_t prefixlen,
gr_nh_origin_t origin,
struct nexthop *nh
struct nexthop *nh,
bool replace
) {
struct rte_rib *rib = get_or_create_rib(vrf_id);
struct nexthop *existing;
struct nexthop *existing = NULL;
struct rte_rib_node *rn;
gr_nh_origin_t *o;
int ret;
Expand All @@ -141,15 +142,21 @@ int rib4_insert(
ret = -errno;
goto fail;
}
existing = rib4_lookup_exact(vrf_id, ip, prefixlen);
if (existing != NULL) {
ret = nexthop_equal(nh, existing) ? -EEXIST : -EBUSY;
goto fail;
}

if ((rn = rte_rib_insert(rib, rte_be_to_cpu_32(ip), prefixlen)) == NULL) {
ret = -rte_errno;
goto fail;
if ((rn = rte_rib_lookup_exact(rib, rte_be_to_cpu_32(ip), prefixlen)) == NULL) {
rn = rte_rib_insert(rib, rte_be_to_cpu_32(ip), prefixlen);
if (rn == NULL) {
ret = -rte_errno;
goto fail;
}
} else {
uintptr_t nh_id;
rte_rib_get_nh(rn, &nh_id);
existing = nh_id_to_ptr(nh_id);
if (!replace) {
ret = nexthop_equal(nh, existing) ? -EEXIST : -EBUSY;
goto fail;
}
}

nh->flags |= GR_NH_F_GATEWAY;
Expand All @@ -170,12 +177,25 @@ int rib4_insert(
);
}

if (existing)
nexthop_decref(existing);

return 0;
fail:
nexthop_decref(nh);
return errno_set(-ret);
}

int rib4_insert(
uint16_t vrf_id,
ip4_addr_t ip,
uint8_t prefixlen,
gr_nh_origin_t origin,
struct nexthop *nh
) {
return rib4_insert_or_replace(vrf_id, ip, prefixlen, origin, nh, false);
}

int rib4_delete(uint16_t vrf_id, ip4_addr_t ip, uint8_t prefixlen, gr_nh_type_t nh_type) {
struct rte_rib *rib = get_rib(vrf_id);
gr_nh_origin_t *o, origin;
Expand Down Expand Up @@ -252,9 +272,9 @@ static struct api_out route4_add(const void *request, void ** /*response*/) {
}

// if route insert fails, the created nexthop will be freed
ret = rib4_insert(req->vrf_id, req->dest.ip, req->dest.prefixlen, req->origin, nh);
if (ret == -EEXIST && req->exist_ok)
ret = 0;
ret = rib4_insert_or_replace(
req->vrf_id, req->dest.ip, req->dest.prefixlen, req->origin, nh, req->exist_ok
);

return api_out(-ret, 0);
}
Expand Down
61 changes: 43 additions & 18 deletions modules/ip6/control/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,40 +132,49 @@ struct nexthop *rib6_lookup_exact(
return nh_id_to_ptr(nh_id);
}

int rib6_insert(
static int rib6_insert_or_replace(
uint16_t vrf_id,
uint16_t iface_id,
const struct rte_ipv6_addr *ip,
uint8_t prefixlen,
gr_nh_origin_t origin,
struct nexthop *nh
struct nexthop *nh,
bool replace
) {
struct rte_rib6 *rib = get_or_create_rib6(vrf_id);
const struct rte_ipv6_addr *scoped_ip;
struct nexthop *existing = NULL;
struct rte_ipv6_addr tmp;
struct rte_rib6_node *rn;
struct nexthop *existing;
gr_nh_origin_t *o;
int ret;

nexthop_incref(nh);
scoped_ip = addr6_linklocal_scope(ip, &tmp, iface_id);

if (rib == NULL) {
ret = -errno;
goto fail;
}
existing = rib6_lookup_exact(vrf_id, iface_id, ip, prefixlen);
if (existing != NULL) {
ret = nexthop_equal(nh, existing) ? -EEXIST : -EBUSY;
goto fail;
}

scoped_ip = addr6_linklocal_scope(ip, &tmp, iface_id);
if ((rn = rte_rib6_insert(rib, scoped_ip, prefixlen)) == NULL) {
ret = -rte_errno;
goto fail;
if ((rn = rte_rib6_lookup_exact(rib, scoped_ip, prefixlen)) == NULL) {
rn = rte_rib6_insert(rib, scoped_ip, prefixlen);
if (rn == NULL) {
ret = -rte_errno;
goto fail;
}
} else {
uintptr_t nh_id;
rte_rib6_get_nh(rn, &nh_id);
existing = nh_id_to_ptr(nh_id);
if (!replace) {
ret = nexthop_equal(nh, existing) ? -EEXIST : -EBUSY;
goto fail;
}
}

nh->flags |= GR_NH_F_GATEWAY;

rte_rib6_set_nh(rn, nh_ptr_to_id(nh));
o = rte_rib6_get_ext(rn);
*o = origin;
Expand All @@ -182,12 +191,26 @@ int rib6_insert(
);
}

if (existing)
nexthop_decref(existing);

return 0;
fail:
nexthop_decref(nh);
return errno_set(-ret);
}

int rib6_insert(
uint16_t vrf_id,
uint16_t iface_id,
const struct rte_ipv6_addr *ip,
uint8_t prefixlen,
gr_nh_origin_t origin,
struct nexthop *nh
) {
return rib6_insert_or_replace(vrf_id, iface_id, ip, prefixlen, origin, nh, false);
}

int rib6_delete(
uint16_t vrf_id,
uint16_t iface_id,
Expand Down Expand Up @@ -272,13 +295,15 @@ static struct api_out route6_add(const void *request, void ** /*response*/) {
}

// if route insert fails, the created nexthop will be freed
ret = rib6_insert(
req->vrf_id, nh->iface_id, &req->dest.ip, req->dest.prefixlen, req->origin, nh
ret = rib6_insert_or_replace(
req->vrf_id,
nh->iface_id,
&req->dest.ip,
req->dest.prefixlen,
req->origin,
nh,
req->exist_ok
);
if (ret == -EEXIST && req->exist_ok)
ret = 0;

nh->flags |= GR_NH_F_GATEWAY;

return api_out(-ret, 0);
}
Expand Down
2 changes: 2 additions & 0 deletions smoke/config_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ grcli add nexthop address 4.3.2.1 iface p1 mac ba:d0:ca:ca:00:01
grcli add ip address 10.0.0.1/24 iface p0
grcli add ip address 10.1.0.1/24 iface p1
grcli add ip route 0.0.0.0/0 via 10.0.0.2
grcli add ip route 0.0.0.0/0 via 10.0.0.1 || fail "route replace should succeed"
grcli add ip route 4.5.21.2/27 via id 47
grcli add ip route 172.16.47.0/24 via id 1047
grcli add ip6 address 2345::1/24 iface p0
grcli add ip6 address 2346::1/24 iface p1
grcli add ip6 route ::/0 via 2345::2
grcli add ip6 route ::/0 via 2345::1 || fail "route6 replace should succeed"
grcli add ip6 route 2521:111::4/37 via id 1047
grcli add ip6 route 2521:112::/64 via id 45
grcli add ip6 route 2521:113::/64 via id 47
Expand Down