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
268 changes: 265 additions & 3 deletions frr/rt_grout.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#include "log_grout.h"
#include "rt_grout.h"

#include <gr_srv6.h>

#include <lib/srv6.h>
#include <zebra/rib.h>
#include <zebra/table_manager.h>
#include <zebra_dplane_grout.h>
Expand Down Expand Up @@ -195,6 +198,10 @@ static int grout_gr_nexthop_to_frr_nexthop(
gr_log_debug("no vrf support for nexthop, nexthop not sync");
return -1;
}
if (gr_nh->type != GR_NH_T_L3) {
gr_log_err("sync nexthop not L3 from grout is not supported");
return -1;
}
if (gr_nh->iface_id)
nh->ifindex = gr_nh->iface_id + GROUT_INDEX_OFFSET;
else
Expand Down Expand Up @@ -382,6 +389,234 @@ void grout_route6_change(bool new, struct gr_ip6_route *gr_r6) {
);
}

static_assert(SRV6_MAX_SEGS <= GR_SRV6_ROUTE_SEGLIST_COUNT_MAX);

static enum zebra_dplane_result grout_add_del_srv6_route(
struct zebra_dplane_ctx *ctx,
const struct prefix *p,
gr_nh_origin_t origin,
struct nexthop *nh,
vrf_id_t vrf_id,
bool new
) {
union {
struct {
struct gr_srv6_route_add_req rsrv6_add;
struct rte_ipv6_addr seglist[SRV6_MAX_SEGS];
};
struct gr_srv6_route_del_req rsrv6_del;
} req;
struct seg6_seg_stack *segs = nh->nh_srv6->seg6_segs;
struct gr_srv6_route *srv6_route;
struct gr_srv6_route_key *key;
uint32_t req_type;
size_t req_len;
int i;

if (new) {
req.rsrv6_add = (struct gr_srv6_route_add_req) {
.r.key.vrf_id = vrf_id,
.exist_ok = true,
.origin = origin,
};
srv6_route = &req.rsrv6_add.r;
key = &srv6_route->key;
req_type = GR_SRV6_ROUTE_ADD;
req_len = sizeof(struct gr_srv6_route_add_req);
} else {
req.rsrv6_del = (struct gr_srv6_route_del_req) {
.key.vrf_id = vrf_id,
.missing_ok = false,
};
srv6_route = NULL;
key = &req.rsrv6_del.key;
req_type = GR_SRV6_ROUTE_DEL;
req_len = sizeof(struct gr_srv6_route_del_req);
}
*key = (struct gr_srv6_route_key) {.vrf_id = vrf_id, .is_dest6 = (p->family == AF_INET6)};

if (key->is_dest6) {
memcpy(key->dest6.ip.a, p->u.prefix6.s6_addr, sizeof(key->dest6.ip.a));
key->dest6.prefixlen = p->prefixlen;

gr_log_debug(
"%s srv6 route %pI6/%u (origin %s)",
new ? "add" : "del",
&key->dest6.ip,
key->dest6.prefixlen,
gr_nh_origin_name(origin)
);

} else {
key->dest4.ip = p->u.prefix4.s_addr;
key->dest4.prefixlen = p->prefixlen;

gr_log_debug(
"%s srv6 route %pI4/%u (origin %s)",
new ? "add" : "del",
&key->dest4.ip,
key->dest4.prefixlen,
gr_nh_origin_name(origin)
);
}

// just need key to delete
if (!new)
goto end;

switch (segs->encap_behavior) {
case SRV6_HEADEND_BEHAVIOR_H_ENCAPS:
srv6_route->encap_behavior = SR_H_ENCAPS;
break;
case SRV6_HEADEND_BEHAVIOR_H_ENCAPS_RED:
srv6_route->encap_behavior = SR_H_ENCAPS_RED;
break;
default:
zlog_err(
"%s: encap behavior '%s' not supported by grout",
__func__,
srv6_headend_behavior2str(segs->encap_behavior, true)
);
return ZEBRA_DPLANE_REQUEST_FAILURE;
}

if (segs->num_segs > SRV6_MAX_SEGS) {
zlog_err(
"%s: too many segments %u (max zebra %u, max grout %u)",
__func__,
segs->num_segs,
SRV6_MAX_SEGS,
GR_SRV6_ROUTE_SEGLIST_COUNT_MAX
);
return ZEBRA_DPLANE_REQUEST_FAILURE;
}

srv6_route->n_seglist = segs->num_segs;
for (i = 0; i < segs->num_segs; i++) {
memcpy(&srv6_route->seglist[i], &segs->seg[i], sizeof(srv6_route->seglist[i]));
req_len += sizeof(srv6_route->seglist[i]);
}

end:

if (!is_selfroute(origin)) {
gr_log_debug("no frr route, skip it");
return ZEBRA_DPLANE_REQUEST_SUCCESS;
}

if (grout_client_send_recv(req_type, req_len, &req, NULL) < 0)
return ZEBRA_DPLANE_REQUEST_FAILURE;

return ZEBRA_DPLANE_REQUEST_SUCCESS;
}

static enum zebra_dplane_result grout_add_del_srv6_local(
struct zebra_dplane_ctx *ctx,
const struct prefix *p,
gr_nh_origin_t origin,
struct nexthop *nh,
vrf_id_t vrf_id,
bool new
) {
union {
struct gr_srv6_localsid_add_req localsid_add;
struct gr_srv6_localsid_del_req localsid_del;
} req;
const struct seg6local_flavors_info *flv;
const struct seg6local_context *ctx6;
struct gr_srv6_localsid *gr_l;
uint32_t action, req_type;
size_t req_len;

if (p->family != AF_INET6) {
gr_log_err("impossible to add/del local srv6 with family %u", p->family);
return ZEBRA_DPLANE_REQUEST_FAILURE;
}

if (p->prefixlen != 128) {
gr_log_err(
"impossible to add/del local srv6 with prefix len %u (should be 128)",
p->prefixlen
);
return ZEBRA_DPLANE_REQUEST_FAILURE;
}

if (!new) {
req.localsid_del = (struct gr_srv6_localsid_del_req) {
.vrf_id = vrf_id,
.missing_ok = true,
};
memcpy(&req.localsid_del.lsid, p->u.prefix6.s6_addr, sizeof(req.localsid_del.lsid));

req_type = GR_SRV6_LOCALSID_DEL;
req_len = sizeof(struct gr_srv6_localsid_del_req);
goto end;
}

req.localsid_add = (struct gr_srv6_localsid_add_req) {
.l.vrf_id = vrf_id,
.origin = origin,
.exist_ok = true,
};
req_type = GR_SRV6_LOCALSID_ADD;
req_len = sizeof(struct gr_srv6_localsid_add_req);

gr_l = &req.localsid_add.l;
memcpy(&gr_l->lsid, p->u.prefix6.s6_addr, sizeof(gr_l->lsid));
action = nh->nh_srv6->seg6local_action;
ctx6 = &nh->nh_srv6->seg6local_ctx;

switch (action) {
case ZEBRA_SEG6_LOCAL_ACTION_END:
gr_l->behavior = SR_BEHAVIOR_END;
break;
case ZEBRA_SEG6_LOCAL_ACTION_END_T:
gr_l->behavior = SR_BEHAVIOR_END_T;
gr_l->out_vrf_id = zebra_vrf_lookup_by_table(ctx6->table, NS_DEFAULT);
break;
case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
gr_l->behavior = SR_BEHAVIOR_END_DT6;
gr_l->out_vrf_id = zebra_vrf_lookup_by_table(ctx6->table, NS_DEFAULT);
break;
case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
gr_l->behavior = SR_BEHAVIOR_END_DT4;
gr_l->out_vrf_id = zebra_vrf_lookup_by_table(ctx6->table, NS_DEFAULT);
break;
case ZEBRA_SEG6_LOCAL_ACTION_END_DT46:
gr_l->behavior = SR_BEHAVIOR_END_DT4;
gr_l->out_vrf_id = zebra_vrf_lookup_by_table(ctx6->table, NS_DEFAULT);
break;
default:
zlog_err("%s: not supported srv6 local behaviour action=%u", __func__, action);
return ZEBRA_DPLANE_REQUEST_FAILURE;
}

flv = &ctx6->flv;
if (flv->flv_ops == ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID) {
zlog_err("%s: not supported next-c-sid for srv6 local", __func__);
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
if (flv->flv_ops == ZEBRA_SEG6_LOCAL_FLV_OP_PSP)
gr_l->flags |= GR_SR_FL_FLAVOR_PSP;
if (flv->flv_ops == ZEBRA_SEG6_LOCAL_FLV_OP_USD)
gr_l->flags |= GR_SR_FL_FLAVOR_USD;
// XXX: if (flv->flv_ops == ZEBRA_SEG6_LOCAL_FLV_OP_USP)
if (flv->flv_ops == ZEBRA_SEG6_LOCAL_FLV_OP_UNSPEC)
zlog_debug("%s: USP is always configured", __func__);

end:

if (!is_selfroute(origin)) {
gr_log_debug("no frr route, skip it");
return ZEBRA_DPLANE_REQUEST_SUCCESS;
}

if (grout_client_send_recv(req_type, req_len, &req, NULL) < 0)
return ZEBRA_DPLANE_REQUEST_FAILURE;

return ZEBRA_DPLANE_REQUEST_SUCCESS;
}

enum zebra_dplane_result grout_add_del_route(struct zebra_dplane_ctx *ctx) {
union {
struct gr_ip4_route_add_req r4_add;
Expand All @@ -390,8 +625,10 @@ enum zebra_dplane_result grout_add_del_route(struct zebra_dplane_ctx *ctx) {
struct gr_ip6_route_del_req r6_del;
} req;
uint32_t nh_id = dplane_ctx_get_nhe_id(ctx);
const struct nexthop_group *ng;
const struct prefix *p;
gr_nh_origin_t origin;
struct nexthop *nh;
uint32_t req_type;
size_t req_len;
bool new;
Expand All @@ -418,6 +655,27 @@ enum zebra_dplane_result grout_add_del_route(struct zebra_dplane_ctx *ctx) {
origin = zebra2origin(dplane_ctx_get_type(ctx));
new = dplane_ctx_get_op(ctx) != DPLANE_OP_ROUTE_DELETE;

ng = dplane_ctx_get_ng(ctx);
nh = ng->nexthop;
if (nh && nh->nh_srv6) {
if (nexthop_group_nexthop_num(ng) > 1) {
gr_log_err(
"impossible to add/del srv6 route with several nexthop (not "
"supported)"
);
return ZEBRA_DPLANE_REQUEST_FAILURE;
}

if (nh->nh_srv6->seg6local_action != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC)
return grout_add_del_srv6_local(ctx, p, origin, nh, VRF_DEFAULT, new);
if (nh->nh_srv6->seg6_segs && nh->nh_srv6->seg6_segs->num_segs
&& !sid_zero(nh->nh_srv6->seg6_segs))
return grout_add_del_srv6_route(ctx, p, origin, nh, VRF_DEFAULT, new);

gr_log_err("impossible to add/del srv6 route (invalid format)");
return ZEBRA_DPLANE_REQUEST_FAILURE;
}

if (new && nh_id == 0) {
gr_log_err("impossible to add route with no nexthop id");
return ZEBRA_DPLANE_REQUEST_FAILURE;
Expand Down Expand Up @@ -474,8 +732,8 @@ enum zebra_dplane_result grout_add_del_route(struct zebra_dplane_ctx *ctx) {
.missing_ok = true, .vrf_id = 0
};

req_type = GR_IP6_ROUTE_ADD;
req_len = sizeof(struct gr_ip6_route_add_req);
req_type = GR_IP6_ROUTE_DEL;
req_len = sizeof(struct gr_ip6_route_del_req);

dest = &req.r6_del.dest;
new = false;
Expand Down Expand Up @@ -542,6 +800,10 @@ enum zebra_dplane_result grout_add_del_nexthop(struct zebra_dplane_ctx *ctx) {
gr_log_err("impossible to add/del blackhole nexthop (not supported)");
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
if (nh->nh_srv6) {
gr_log_err("impossible to add/del srv6 nexthop (not supported)");
return ZEBRA_DPLANE_REQUEST_SUCCESS;
}

new = dplane_ctx_get_op(ctx) != DPLANE_OP_NH_DELETE;
if (new) {
Expand Down Expand Up @@ -597,7 +859,7 @@ enum zebra_dplane_result grout_add_del_nexthop(struct zebra_dplane_ctx *ctx) {
break;
case NEXTHOP_TYPE_IFINDEX:
gr_log_debug("add nexthop id %u ifindex %u", nh_id, gr_nh->iface_id);
break;
return ZEBRA_DPLANE_REQUEST_FAILURE;
default:
gr_log_err("impossible to add nexthop %u (type %u not supported)", nh_id, nh->type);
return ZEBRA_DPLANE_REQUEST_FAILURE;
Expand Down
9 changes: 9 additions & 0 deletions frr/zebra_dplane_grout.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "rt_grout.h"

#include <gr_api_client_impl.h>
#include <gr_srv6.h>

#include <lib/frr_pthread.h>
#include <lib/libfrr.h>
Expand Down Expand Up @@ -161,6 +162,14 @@ static const char *gr_req_type_to_str(uint32_t e) {
return TOSTRING(GR_NH_ADD);
case GR_NH_DEL:
return TOSTRING(GR_NH_DEL);
case GR_SRV6_LOCALSID_ADD:
return TOSTRING(GR_SRV6_LOCALSID_ADD);
case GR_SRV6_LOCALSID_DEL:
return TOSTRING(GR_SRV6_LOCALSID_DEL);
case GR_SRV6_ROUTE_ADD:
return TOSTRING(GR_SRV6_ROUTE_ADD);
case GR_SRV6_ROUTE_DEL:
return TOSTRING(GR_SRV6_ROUTE_DEL);

default:
return "unknown";
Expand Down
1 change: 1 addition & 0 deletions modules/infra/control/gr_nh_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const struct nexthop_af_ops *nexthop_af_ops_get(addr_family_t af);
struct nexthop_type_ops {
// Callback that will be invoked the nexthop refcount reaches zero.
void (*free)(struct nexthop *);
bool (*equal)(const struct nexthop *, const struct nexthop *);
};

void nexthop_type_ops_register(gr_nh_type_t type, const struct nexthop_type_ops *);
Expand Down
Loading