Merge pull request #17581 from mjstapp/fix_fpm_netlink

zebra: avoid race between FPM pthread and zebra main pthread in netlink encode/decode
This commit is contained in:
Donald Sharp 2025-01-14 13:42:29 -05:00 committed by GitHub
commit 67da971218
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 509 additions and 161 deletions

View File

@ -587,6 +587,7 @@ static void fpm_read(struct event *t)
struct zebra_dplane_ctx *ctx;
size_t available_bytes;
size_t hdr_available_bytes;
int ival;
/* Let's ignore the input at the moment. */
rv = stream_read_try(fnc->ibuf, fnc->socket,
@ -715,17 +716,28 @@ static void fpm_read(struct event *t)
break;
}
/* Parse the route data into a dplane ctx, then
* enqueue it to zebra for processing.
*/
ctx = dplane_ctx_alloc();
dplane_ctx_route_init(ctx, DPLANE_OP_ROUTE_NOTIFY, NULL,
NULL);
if (netlink_route_change_read_unicast_internal(
hdr, 0, false, ctx) != 1) {
dplane_ctx_fini(&ctx);
stream_pulldown(fnc->ibuf);
if (netlink_route_notify_read_ctx(hdr, 0, ctx) >= 0) {
/* In the FPM encoding, the vrfid is present */
ival = dplane_ctx_get_table(ctx);
dplane_ctx_set_vrf(ctx, ival);
dplane_ctx_set_table(ctx,
ZEBRA_ROUTE_TABLE_UNKNOWN);
dplane_provider_enqueue_to_zebra(ctx);
} else {
/*
* Let's continue to read other messages
* Even if we ignore this one.
*/
dplane_ctx_fini(&ctx);
stream_pulldown(fnc->ibuf);
}
break;
default:

View File

@ -723,44 +723,52 @@ static uint16_t parse_multipath_nexthops_unicast(ns_id_t ns_id, struct nexthop_g
return nhop_num;
}
/* Looking up routing table by netlink interface. */
int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
ns_id_t ns_id, int startup,
struct zebra_dplane_ctx *ctx)
/*
* Parse netlink route message and capture info into a dplane ctx.
* Returns <0 if the message is to be skipped (might be an error)
*/
static int netlink_route_read_unicast_ctx(struct nlmsghdr *h, ns_id_t ns_id,
struct rtattr **tb_in,
struct zebra_dplane_ctx *ctx)
{
int ret = 0;
int len;
struct rtmsg *rtm;
struct rtattr *tb[RTA_MAX + 1];
struct rtattr **tb, *tb_array[RTA_MAX + 1];
uint32_t flags = 0;
struct prefix p;
struct prefix_ipv6 src_p = {};
vrf_id_t vrf_id;
struct prefix src_p = {};
bool selfroute;
char anyaddr[16] = {0};
char anyaddr[16] = {};
int proto = ZEBRA_ROUTE_KERNEL;
int index = 0;
int table;
int tableid;
int metric = 0;
uint32_t mtu = 0;
uint8_t distance = 0;
route_tag_t tag = 0;
uint32_t nhe_id = 0;
uint32_t nhg_id = 0;
void *dest = NULL;
void *gate = NULL;
int gate_len;
void *prefsrc = NULL; /* IPv4 preferred source host address */
int prefsrc_len;
void *src = NULL; /* IPv6 srcdest source prefix */
enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
afi_t afi = AFI_IP;
struct ipaddr addr = {};
frrtrace(3, frr_zebra, netlink_route_change_read_unicast, h, ns_id,
startup);
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
if (len < 0) {
zlog_err(
"%s: Netlink route message received with invalid size %d %zu",
__func__, h->nlmsg_len,
(size_t)NLMSG_LENGTH(sizeof(struct rtmsg)));
return -1;
}
rtm = NLMSG_DATA(h);
if (startup && h->nlmsg_type != RTM_NEWROUTE)
return 0;
switch (rtm->rtm_type) {
case RTN_UNICAST:
break;
@ -778,54 +786,42 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
zlog_debug("Route rtm_type: %s(%d) intentionally ignoring",
nl_rttype_to_str(rtm->rtm_type),
rtm->rtm_type);
return 0;
ret = -1;
goto done;
}
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
if (len < 0) {
zlog_err(
"%s: Message received from netlink is of a broken size %d %zu",
__func__, h->nlmsg_len,
(size_t)NLMSG_LENGTH(sizeof(struct rtmsg)));
return -1;
}
netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len);
if (rtm->rtm_flags & RTM_F_CLONED)
return 0;
if (rtm->rtm_protocol == RTPROT_REDIRECT)
return 0;
selfroute = is_selfroute(rtm->rtm_protocol);
if (!startup && selfroute && h->nlmsg_type == RTM_NEWROUTE &&
!zrouter.asic_offloaded && !ctx) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("Route type: %d Received that we think we have originated, ignoring",
rtm->rtm_protocol);
return 0;
if ((rtm->rtm_flags & RTM_F_CLONED) ||
(rtm->rtm_protocol == RTPROT_REDIRECT)) {
ret = -1;
goto done;
}
/* We don't care about change notifications for the MPLS table. */
/* TODO: Revisit this. */
if (rtm->rtm_family == AF_MPLS)
return 0;
if (rtm->rtm_family == AF_MPLS) {
ret = -1;
goto done;
}
dplane_ctx_set_ns_id(ctx, ns_id);
/* Parse attrs if necessary */
if (tb_in != NULL) {
tb = tb_in;
} else {
netlink_parse_rtattr(tb_array, RTA_MAX, RTM_RTA(rtm), len);
tb = tb_array;
}
selfroute = is_selfroute(rtm->rtm_protocol);
/* Table corresponding to route. */
if (tb[RTA_TABLE])
table = *(int *)RTA_DATA(tb[RTA_TABLE]);
tableid = *(int *)RTA_DATA(tb[RTA_TABLE]);
else
table = rtm->rtm_table;
/* Map to VRF */
vrf_id = zebra_vrf_lookup_by_table(table, ns_id);
if (vrf_id == VRF_DEFAULT) {
if (!is_zebra_valid_kernel_table(table)
&& !is_zebra_main_routing_table(table))
return 0;
}
tableid = rtm->rtm_table;
/* Map flags values */
if (rtm->rtm_flags & RTM_F_TRAP)
flags |= ZEBRA_FLAG_TRAPPED;
if (rtm->rtm_flags & RTM_F_OFFLOAD)
@ -836,7 +832,7 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
if (h->nlmsg_flags & NLM_F_APPEND)
flags |= ZEBRA_FLAG_OUTOFSYNC;
/* Route which inserted by Zebra. */
/* Route which was inserted by Zebra. */
if (selfroute) {
flags |= ZEBRA_FLAG_SELFROUTE;
proto = proto2zebra(rtm->rtm_protocol, rtm->rtm_family, false);
@ -854,14 +850,18 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
else
src = anyaddr;
if (tb[RTA_PREFSRC])
if (tb[RTA_PREFSRC]) {
prefsrc = RTA_DATA(tb[RTA_PREFSRC]);
prefsrc_len = RTA_PAYLOAD(tb[RTA_PREFSRC]);
}
if (tb[RTA_GATEWAY])
if (tb[RTA_GATEWAY]) {
gate = RTA_DATA(tb[RTA_GATEWAY]);
gate_len = RTA_PAYLOAD(tb[RTA_GATEWAY]);
}
if (tb[RTA_NH_ID])
nhe_id = *(uint32_t *)RTA_DATA(tb[RTA_NH_ID]);
nhg_id = *(uint32_t *)RTA_DATA(tb[RTA_NH_ID]);
if (tb[RTA_PRIORITY])
metric = *(int *)RTA_DATA(tb[RTA_PRIORITY]);
@ -887,7 +887,8 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
zlog_err(
"Invalid destination prefix length: %u received from kernel route change",
rtm->rtm_dst_len);
return -1;
ret = -1;
goto done;
}
memcpy(&p.u.prefix4, dest, 4);
p.prefixlen = rtm->rtm_dst_len;
@ -895,14 +896,16 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
if (rtm->rtm_src_len != 0) {
flog_warn(
EC_ZEBRA_UNSUPPORTED_V4_SRCDEST,
"unsupported IPv4 sourcedest route (dest %pFX vrf %u)",
&p, vrf_id);
return 0;
"unsupported IPv4 sourcedest route (dest %pFX table %u)",
&p, tableid);
ret = -1;
goto done;
}
/* Force debug below to not display anything for source */
src_p.prefixlen = 0;
} else if (rtm->rtm_family == AF_INET6) {
afi = AFI_IP6;
p.family = AF_INET6;
if (rtm->rtm_dst_len > IPV6_MAX_BITLEN) {
zlog_err(
@ -920,14 +923,15 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
rtm->rtm_src_len);
return -1;
}
memcpy(&src_p.prefix, src, 16);
memcpy(&src_p.u.prefix6, src, 16);
src_p.prefixlen = rtm->rtm_src_len;
} else {
/* We only handle the AFs we handle... */
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: unknown address-family %u", __func__,
rtm->rtm_family);
return 0;
ret = -1;
goto done;
}
/*
@ -952,6 +956,249 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
metric = (metric & 0x00FFFFFF);
}
if (IS_ZEBRA_DEBUG_KERNEL) {
char buf2[PREFIX_STRLEN];
zlog_debug(
"%s %pFX%s%s nsid: %u table_id: %u metric: %d Admin Distance: %d",
nl_msg_type_to_str(h->nlmsg_type), &p,
src_p.prefixlen ? " from " : "",
src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2))
: "",
ns_id, tableid, metric, distance);
}
/* Set values in ctx. Note that vrf is not set, because we can only
* resolve the FRR vrf info in the main pthread.
*/
dplane_ctx_set_afi(ctx, afi);
dplane_ctx_set_safi(ctx, SAFI_UNICAST);
dplane_ctx_set_table(ctx, tableid);
dplane_ctx_set_vrf(ctx, VRF_UNKNOWN);
dplane_ctx_set_ns_id(ctx, ns_id);
dplane_ctx_set_dest(ctx, &p);
if (src_p.prefixlen > 0)
dplane_ctx_set_src(ctx, &src_p);
else
dplane_ctx_set_src(ctx, NULL);
dplane_ctx_set_type(ctx, proto);
dplane_ctx_set_flags(ctx, flags);
dplane_ctx_set_route_metric(ctx, metric);
dplane_ctx_set_route_mtu(ctx, mtu);
dplane_ctx_set_distance(ctx, distance);
dplane_ctx_set_tag(ctx, tag);
dplane_ctx_set_ifindex(ctx, index);
dplane_ctx_set_route_bhtype(ctx, bh_type);
if (prefsrc) {
/* Convert to ipaddr */
memset(&addr, 0, sizeof(addr));
if (afi == AFI_IP) {
SET_IPADDR_V4(&addr);
memcpy(&addr.ipaddr_v4, prefsrc, prefsrc_len);
} else {
SET_IPADDR_V6(&addr);
memcpy(&addr.ipaddr_v6, prefsrc, prefsrc_len);
}
dplane_ctx_set_route_prefsrc(ctx, &addr);
} else {
dplane_ctx_set_route_prefsrc(ctx, NULL);
}
if (gate) {
/* Convert to ipaddr */
memset(&addr, 0, sizeof(addr));
if (afi == AFI_IP) {
SET_IPADDR_V4(&addr);
memcpy(&addr.ipaddr_v4, gate, gate_len);
} else {
SET_IPADDR_V6(&addr);
memcpy(&addr.ipaddr_v6, gate, gate_len);
}
dplane_ctx_set_route_gw(ctx, &addr);
}
if (nhg_id > 0)
dplane_ctx_set_nhg_id(ctx, nhg_id);
done:
return ret;
}
/*
* Public api for use parsing a route notification message: this notification
* only parses the top-level route attributes, and doesn't include nexthops.
*/
int netlink_route_notify_read_ctx(struct nlmsghdr *h, ns_id_t ns_id,
struct zebra_dplane_ctx *ctx)
{
/* Use the common parser for route-level netlink message info;
* we expect the caller to have set the context up with the correct
* dplane opcode, and we expect the caller to submit the resulting ctx
* for processing in zebra.
*/
return netlink_route_read_unicast_ctx(h, ns_id, NULL, ctx);
}
/*
* Parse a route update netlink message, extract and validate its data,
* call into zebra with an update.
*/
static int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
ns_id_t ns_id, int startup)
{
int len;
struct rtmsg *rtm;
struct rtattr *tb[RTA_MAX + 1];
uint32_t flags = 0;
struct prefix p;
struct prefix src_p = {};
vrf_id_t vrf_id;
bool selfroute;
int proto = ZEBRA_ROUTE_KERNEL;
int index = 0;
int table;
int metric = 0;
uint32_t mtu = 0;
uint8_t distance = 0;
route_tag_t tag = 0;
uint32_t nhe_id = 0;
void *gate = NULL;
const struct ipaddr *gate_addr;
void *prefsrc = NULL; /* IPv4 preferred source host address */
const struct ipaddr *prefsrc_addr;
enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
afi_t afi;
struct zebra_dplane_ctx *ctx = NULL;
int ret;
frrtrace(3, frr_zebra, netlink_route_change_read_unicast, h, ns_id,
startup);
rtm = NLMSG_DATA(h);
if (startup && h->nlmsg_type != RTM_NEWROUTE)
return 0;
switch (rtm->rtm_type) {
case RTN_UNICAST:
case RTN_BLACKHOLE:
case RTN_UNREACHABLE:
case RTN_PROHIBIT:
break;
default:
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("Route rtm_type: %s(%d) intentionally ignoring",
nl_rttype_to_str(rtm->rtm_type),
rtm->rtm_type);
return 0;
}
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
if (len < 0) {
zlog_err(
"%s: Message received from netlink is of a broken size %d %zu",
__func__, h->nlmsg_len,
(size_t)NLMSG_LENGTH(sizeof(struct rtmsg)));
return -1;
}
if (rtm->rtm_flags & RTM_F_CLONED)
return 0;
if (rtm->rtm_protocol == RTPROT_REDIRECT)
return 0;
/* We don't care about change notifications for the MPLS table. */
/* TODO: Revisit this. */
if (rtm->rtm_family == AF_MPLS)
return 0;
netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len);
/*
* Allocate a context object and parse the core parts of the route
* message.
* After this point, note that we need to 'goto done' to exit,
* so that the ctx gets cleaned-up.
*/
ctx = dplane_ctx_alloc();
dplane_ctx_route_init(ctx,
h->nlmsg_type == RTM_NEWROUTE ?
DPLANE_OP_ROUTE_INSTALL :
DPLANE_OP_ROUTE_DELETE, NULL, NULL);
/* Finish parsing the core route info */
ret = netlink_route_read_unicast_ctx(h, ns_id, tb, ctx);
if (ret < 0) {
ret = 0;
goto done;
}
flags = dplane_ctx_get_flags(ctx);
selfroute = CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE);
if (!startup && selfroute && h->nlmsg_type == RTM_NEWROUTE &&
!zrouter.asic_offloaded) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("Route type: %d Received that we think we have originated, ignoring",
rtm->rtm_protocol);
ret = 0;
goto done;
}
/* Table corresponding to route. */
table = dplane_ctx_get_table(ctx);
/* Map to VRF: note that this can _only_ be done in the main pthread */
vrf_id = zebra_vrf_lookup_by_table(table, ns_id);
if (vrf_id == VRF_DEFAULT) {
if (!is_zebra_valid_kernel_table(table)
&& !is_zebra_main_routing_table(table)) {
ret = 0;
goto done;
}
}
/* Route which inserted by Zebra. */
if (selfroute)
proto = dplane_ctx_get_type(ctx);
index = dplane_ctx_get_ifindex(ctx);
p = *(dplane_ctx_get_dest(ctx));
if (dplane_ctx_get_src(ctx) == NULL)
src_p.prefixlen = 0;
else
src_p = *(dplane_ctx_get_src(ctx));
prefsrc_addr = dplane_ctx_get_route_prefsrc(ctx);
if (prefsrc_addr)
prefsrc = (void *)&(prefsrc_addr->ip.addr);
gate_addr = dplane_ctx_get_route_gw(ctx);
if (!IS_IPADDR_NONE(gate_addr))
gate = (void *)&(gate_addr->ip.addr);
nhe_id = dplane_ctx_get_nhe_id(ctx);
metric = dplane_ctx_get_metric(ctx);
distance = dplane_ctx_get_distance(ctx);
tag = dplane_ctx_get_tag(ctx);
mtu = dplane_ctx_get_mtu(ctx);
afi = dplane_ctx_get_afi(ctx);
bh_type = dplane_ctx_get_route_bhtype(ctx);
if (IS_ZEBRA_DEBUG_KERNEL) {
char buf2[PREFIX_STRLEN];
@ -965,10 +1212,6 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
distance);
}
afi_t afi = AFI_IP;
if (rtm->rtm_family == AF_INET6)
afi = AFI_IP6;
if (h->nlmsg_type == RTM_NEWROUTE) {
struct route_entry *re;
struct nexthop_group *ng = NULL;
@ -1018,12 +1261,11 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
}
}
if (nhe_id || ng) {
dplane_rib_add_multipath(afi, SAFI_UNICAST, &p, &src_p,
re, ng, startup, ctx);
rib_add_multipath(afi, SAFI_UNICAST, &p,
(struct prefix_ipv6 *)&src_p,
re, ng, startup);
if (ng)
nexthop_group_delete(&ng);
if (ctx)
zebra_rib_route_entry_free(re);
} else {
/*
* I really don't see how this is possible
@ -1038,17 +1280,10 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
zebra_rib_route_entry_free(re);
}
} else {
if (ctx) {
zlog_err(
"%s: %pFX RTM_DELROUTE received but received a context as well",
__func__, &p);
return 0;
}
if (nhe_id) {
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
&p, &src_p, NULL, nhe_id, table, metric,
distance, true);
&p, (struct prefix_ipv6 *)&src_p, NULL,
nhe_id, table, metric, distance, true);
} else {
if (!tb[RTA_MULTIPATH]) {
struct nexthop nh;
@ -1057,26 +1292,33 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
ns_id, rtm, tb, bh_type, index, prefsrc,
gate, afi, vrf_id);
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
flags, &p, &src_p, &nh, 0, table,
metric, distance, true);
flags, &p,
(struct prefix_ipv6 *)&src_p, &nh, 0,
table, metric, distance, true);
} else {
/* XXX: need to compare the entire list of
* nexthops here for NLM_F_APPEND stupidity */
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
flags, &p, &src_p, NULL, 0, table,
metric, distance, true);
flags, &p,
(struct prefix_ipv6 *)&src_p, NULL, 0,
table, metric, distance, true);
}
}
}
return 1;
ret = 1;
done:
if (ctx)
dplane_ctx_fini(&ctx);
return ret;
}
static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
int startup)
{
return netlink_route_change_read_unicast_internal(h, ns_id, startup,
NULL);
return netlink_route_change_read_unicast_internal(h, ns_id, startup);
}
static struct mcast_route_data *mroute = NULL;
@ -1615,13 +1857,10 @@ static bool _netlink_route_build_singlepath(const struct prefix *p,
{
char label_buf[256];
struct vrf *vrf;
char addrstr[INET6_ADDRSTRLEN];
assert(nexthop);
vrf = vrf_lookup_by_id(nexthop->vrf_id);
if (!_netlink_route_encode_label_info(nexthop, nlmsg, req_size, rtmsg,
label_buf, sizeof(label_buf)))
return false;
@ -1782,10 +2021,10 @@ static bool _netlink_route_build_singlepath(const struct prefix *p,
}
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: 5549 (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
zlog_debug("%s: 5549 (%s): %pFX nexthop via %s %s if %u vrf %u",
__func__, routedesc, p, ipv4_ll_buf,
label_buf, nexthop->ifindex,
VRF_LOGNAME(vrf), nexthop->vrf_id);
nexthop->vrf_id);
return true;
}
@ -1808,10 +2047,9 @@ static bool _netlink_route_build_singlepath(const struct prefix *p,
if (IS_ZEBRA_DEBUG_KERNEL) {
inet_ntop(AF_INET, &nexthop->gate.ipv4, addrstr,
sizeof(addrstr));
zlog_debug("%s: (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
zlog_debug("%s: (%s): %pFX nexthop via %s %s if %u vrf %u",
__func__, routedesc, p, addrstr, label_buf,
nexthop->ifindex, VRF_LOGNAME(vrf),
nexthop->vrf_id);
nexthop->ifindex, nexthop->vrf_id);
}
}
@ -1832,10 +2070,9 @@ static bool _netlink_route_build_singlepath(const struct prefix *p,
if (IS_ZEBRA_DEBUG_KERNEL) {
inet_ntop(AF_INET6, &nexthop->gate.ipv6, addrstr,
sizeof(addrstr));
zlog_debug("%s: (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
zlog_debug("%s: (%s): %pFX nexthop via %s %s if %u vrf %u",
__func__, routedesc, p, addrstr, label_buf,
nexthop->ifindex, VRF_LOGNAME(vrf),
nexthop->vrf_id);
nexthop->ifindex, nexthop->vrf_id);
}
}
@ -1857,9 +2094,9 @@ static bool _netlink_route_build_singlepath(const struct prefix *p,
}
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: (%s): %pFX nexthop via if %u vrf %s(%u)",
zlog_debug("%s: (%s): %pFX nexthop via if %u vrf %u",
__func__, routedesc, p, nexthop->ifindex,
VRF_LOGNAME(vrf), nexthop->vrf_id);
nexthop->vrf_id);
}
return true;
@ -1943,7 +2180,6 @@ static bool _netlink_route_build_multipath(const struct prefix *p,
route_tag_t tag, bool fpm)
{
char label_buf[256];
struct vrf *vrf;
struct rtnexthop *rtnh;
rtnh = nl_attr_rtnh(nlmsg, req_size);
@ -1952,8 +2188,6 @@ static bool _netlink_route_build_multipath(const struct prefix *p,
assert(nexthop);
vrf = vrf_lookup_by_id(nexthop->vrf_id);
if (!_netlink_route_encode_label_info(nexthop, nlmsg, req_size, rtmsg,
label_buf, sizeof(label_buf)))
return false;
@ -1976,10 +2210,9 @@ static bool _netlink_route_build_multipath(const struct prefix *p,
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
"%s: 5549 (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
"%s: 5549 (%s): %pFX nexthop via %s %s if %u vrf %u",
__func__, routedesc, p, ipv4_ll_buf, label_buf,
nexthop->ifindex, VRF_LOGNAME(vrf),
nexthop->vrf_id);
nexthop->ifindex, nexthop->vrf_id);
nl_attr_rtnh_end(nlmsg, rtnh);
return true;
}
@ -1997,10 +2230,9 @@ static bool _netlink_route_build_multipath(const struct prefix *p,
*src = &nexthop->src;
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: (%s): %pFX nexthop via %pI4 %s if %u vrf %s(%u)",
zlog_debug("%s: (%s): %pFX nexthop via %pI4 %s if %u vrf %u",
__func__, routedesc, p, &nexthop->gate.ipv4,
label_buf, nexthop->ifindex,
VRF_LOGNAME(vrf), nexthop->vrf_id);
label_buf, nexthop->ifindex, nexthop->vrf_id);
}
if (nexthop->type == NEXTHOP_TYPE_IPV6
|| nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
@ -2015,10 +2247,9 @@ static bool _netlink_route_build_multipath(const struct prefix *p,
*src = &nexthop->src;
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: (%s): %pFX nexthop via %pI6 %s if %u vrf %s(%u)",
zlog_debug("%s: (%s): %pFX nexthop via %pI6 %s if %u vrf %u",
__func__, routedesc, p, &nexthop->gate.ipv6,
label_buf, nexthop->ifindex,
VRF_LOGNAME(vrf), nexthop->vrf_id);
label_buf, nexthop->ifindex, nexthop->vrf_id);
}
/*
@ -2037,9 +2268,9 @@ static bool _netlink_route_build_multipath(const struct prefix *p,
*src = &nexthop->src;
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: (%s): %pFX nexthop via if %u vrf %s(%u)",
zlog_debug("%s: (%s): %pFX nexthop via if %u vrf %u",
__func__, routedesc, p, nexthop->ifindex,
VRF_LOGNAME(vrf), nexthop->vrf_id);
nexthop->vrf_id);
}
if (nexthop->weight)
@ -3057,9 +3288,8 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
nexthop_done:
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: ID (%u): %pNHv(%d) vrf %s(%u) %s ",
zlog_debug("%s: ID (%u): %pNHv(%d) vrf %u %s ",
__func__, id, nh, nh->ifindex,
vrf_id_to_name(nh->vrf_id),
nh->vrf_id, label_buf);
}

View File

@ -64,6 +64,15 @@ extern ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx,
extern int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
extern int netlink_route_read(struct zebra_ns *zns);
/*
* Public api for parsing a route notification message: this notification
* only parses the top-level route attributes, and doesn't include nexthops.
* FPM, for example, is a user.
* Returns <0 if the message should be ignored/skipped.
*/
int netlink_route_notify_read_ctx(struct nlmsghdr *h, ns_id_t ns_id,
struct zebra_dplane_ctx *ctx);
extern int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id,
int startup);
extern int netlink_nexthop_read(struct zebra_ns *zns);
@ -109,10 +118,6 @@ netlink_put_lsp_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
extern enum netlink_msg_status
netlink_put_pw_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
ns_id_t ns_id, int startup,
struct zebra_dplane_ctx *ctx);
#ifdef NETLINK_DEBUG
const char *nlmsg_type2str(uint16_t type);
const char *af_type2str(int type);

View File

@ -150,6 +150,11 @@ struct dplane_route_info {
/* Optional list of extra interface info */
struct dplane_intf_extra_list_head intf_extra_list;
/* Route-level info that aligns with some netlink route data */
enum blackhole_type zd_bh_type;
struct ipaddr zd_prefsrc;
struct ipaddr zd_gateway;
};
/*
@ -1906,6 +1911,12 @@ void dplane_ctx_set_flags(struct zebra_dplane_ctx *ctx, uint32_t flags)
ctx->u.rinfo.zd_flags = flags;
}
void dplane_ctx_set_route_metric(struct zebra_dplane_ctx *ctx, uint32_t metric)
{
DPLANE_CTX_VALID(ctx);
ctx->u.rinfo.zd_metric = metric;
}
uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
@ -1927,6 +1938,12 @@ uint32_t dplane_ctx_get_mtu(const struct zebra_dplane_ctx *ctx)
return ctx->u.rinfo.zd_mtu;
}
void dplane_ctx_set_route_mtu(struct zebra_dplane_ctx *ctx, uint32_t mtu)
{
DPLANE_CTX_VALID(ctx);
ctx->u.rinfo.zd_mtu = mtu;
}
uint32_t dplane_ctx_get_nh_mtu(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
@ -1955,6 +1972,58 @@ uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx)
return ctx->u.rinfo.zd_old_distance;
}
/* Route blackhole type */
enum blackhole_type dplane_ctx_get_route_bhtype(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
return ctx->u.rinfo.zd_bh_type;
}
void dplane_ctx_set_route_bhtype(struct zebra_dplane_ctx *ctx,
enum blackhole_type bhtype)
{
DPLANE_CTX_VALID(ctx);
ctx->u.rinfo.zd_bh_type = bhtype;
}
/* IP 'preferred source', at route-level */
const struct ipaddr *dplane_ctx_get_route_prefsrc(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
if (ctx->u.rinfo.zd_prefsrc.ipa_type != 0)
return &(ctx->u.rinfo.zd_prefsrc);
else
return NULL;
}
void dplane_ctx_set_route_prefsrc(struct zebra_dplane_ctx *ctx,
const struct ipaddr *addr)
{
DPLANE_CTX_VALID(ctx);
if (addr)
ctx->u.rinfo.zd_prefsrc = *addr;
else
memset(&ctx->u.rinfo.zd_prefsrc, 0,
sizeof(ctx->u.rinfo.zd_prefsrc));
}
/* Route-level 'gateway' */
const struct ipaddr *dplane_ctx_get_route_gw(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
return &(ctx->u.rinfo.zd_gateway);
}
void dplane_ctx_set_route_gw(struct zebra_dplane_ctx *ctx, const struct ipaddr *gw)
{
DPLANE_CTX_VALID(ctx);
if (gw)
ctx->u.rinfo.zd_gateway = *gw;
else
memset(&ctx->u.rinfo.zd_gateway, 0, sizeof(ctx->u.rinfo.zd_gateway));
}
int dplane_ctx_tc_qdisc_get_kind(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
@ -2179,6 +2248,12 @@ uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx)
return ctx->u.rinfo.zd_nhg_id;
}
void dplane_ctx_set_nhg_id(struct zebra_dplane_ctx *ctx, uint32_t nhgid)
{
DPLANE_CTX_VALID(ctx);
ctx->u.rinfo.zd_nhg_id = nhgid;
}
const struct nexthop_group *dplane_ctx_get_ng(
const struct zebra_dplane_ctx *ctx)
{
@ -6923,20 +6998,6 @@ kernel_dplane_process_ipset_entry(struct zebra_dplane_provider *prov,
dplane_provider_enqueue_out_ctx(prov, ctx);
}
void dplane_rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
struct prefix_ipv6 *src_p, struct route_entry *re,
struct nexthop_group *ng, int startup,
struct zebra_dplane_ctx *ctx)
{
if (!ctx)
rib_add_multipath(afi, safi, p, src_p, re, ng, startup);
else {
dplane_ctx_route_init_basic(ctx, dplane_ctx_get_op(ctx), re, p,
src_p, afi, safi);
dplane_provider_enqueue_to_zebra(ctx);
}
}
/*
* Kernel provider callback
*/

View File

@ -524,11 +524,26 @@ uint32_t dplane_ctx_get_flags(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_flags(struct zebra_dplane_ctx *ctx, uint32_t flags);
uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_get_old_metric(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_route_metric(struct zebra_dplane_ctx *ctx, uint32_t metric);
void dplane_ctx_set_route_mtu(struct zebra_dplane_ctx *ctx, uint32_t mtu);
uint32_t dplane_ctx_get_mtu(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_get_nh_mtu(const struct zebra_dplane_ctx *ctx);
uint8_t dplane_ctx_get_distance(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_distance(struct zebra_dplane_ctx *ctx, uint8_t distance);
uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx);
/* Route blackhole type */
enum blackhole_type dplane_ctx_get_route_bhtype(
const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_route_bhtype(struct zebra_dplane_ctx *ctx,
enum blackhole_type bhtype);
/* IPv4 'preferred source', at route-level */
const struct ipaddr *dplane_ctx_get_route_prefsrc(
const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_route_prefsrc(struct zebra_dplane_ctx *ctx,
const struct ipaddr *addr);
/* Route 'gateway', at route-level */
const struct ipaddr *dplane_ctx_get_route_gw(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_route_gw(struct zebra_dplane_ctx *ctx, const struct ipaddr *gw);
/* Accessors for traffic control context */
int dplane_ctx_tc_qdisc_get_kind(const struct zebra_dplane_ctx *ctx);
@ -572,6 +587,7 @@ void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh);
void dplane_ctx_set_backup_nhg(struct zebra_dplane_ctx *ctx,
const struct nexthop_group *nhg);
void dplane_ctx_set_nhg_id(struct zebra_dplane_ctx *ctx, uint32_t nhgid);
uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx);
const struct nexthop_group *dplane_ctx_get_ng(
const struct zebra_dplane_ctx *ctx);
@ -1256,16 +1272,6 @@ void zebra_dplane_shutdown(void);
void zebra_dplane_startup_stage(struct zebra_ns *zns,
enum zebra_dplane_startup_notifications spot);
/*
* decision point for sending a routing update through the old
* straight to zebra master pthread or through the dplane to
* the master pthread for handling
*/
void dplane_rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
struct prefix_ipv6 *src_p, struct route_entry *re,
struct nexthop_group *ng, int startup,
struct zebra_dplane_ctx *ctx);
enum zebra_dplane_startup_notifications
dplane_ctx_get_startup_spot(struct zebra_dplane_ctx *ctx);

View File

@ -2220,8 +2220,20 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
bool fib_changed = false;
bool debug_p = IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_RIB;
int start_count, end_count;
vrf_id_t vrf_id;
int tableid;
vrf = vrf_lookup_by_id(dplane_ctx_get_vrf(ctx));
/* Locate vrf and route table - we must have one or the other */
tableid = dplane_ctx_get_table(ctx);
vrf_id = dplane_ctx_get_vrf(ctx);
if (vrf_id == VRF_UNKNOWN)
vrf_id = zebra_vrf_lookup_by_table(tableid,
dplane_ctx_get_ns_id(ctx));
else if (tableid == ZEBRA_ROUTE_TABLE_UNKNOWN)
tableid = zebra_vrf_lookup_tableid(vrf_id,
dplane_ctx_get_ns_id(ctx));
vrf = vrf_lookup_by_id(vrf_id);
/* Locate rn and re(s) from ctx */
rn = rib_find_rn_from_ctx(ctx);
@ -2230,7 +2242,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
zlog_debug(
"Failed to process dplane notification: no routes for %s(%u:%u):%pRN",
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
dplane_ctx_get_table(ctx), rn);
tableid, rn);
}
goto done;
}
@ -2240,7 +2252,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
if (debug_p)
zlog_debug("%s(%u:%u):%pRN Processing dplane notif ctx %p",
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
dplane_ctx_get_table(ctx), rn, ctx);
tableid, rn, ctx);
/*
* Take a pass through the routes, look for matches with the context
@ -2257,7 +2269,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
zlog_debug(
"%s(%u:%u):%pRN Unable to process dplane notification: no entry for type %s",
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
dplane_ctx_get_table(ctx), rn,
tableid, rn,
zebra_route_string(dplane_ctx_get_type(ctx)));
goto done;
@ -2293,7 +2305,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
"%s(%u:%u):%pRN dplane notif, uninstalled type %s route",
VRF_LOGNAME(vrf),
dplane_ctx_get_vrf(ctx),
dplane_ctx_get_table(ctx), rn,
tableid, rn,
zebra_route_string(
dplane_ctx_get_type(ctx)));
} else {
@ -2303,7 +2315,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
"%s(%u:%u):%pRN dplane notif, but type %s not selected_fib",
VRF_LOGNAME(vrf),
dplane_ctx_get_vrf(ctx),
dplane_ctx_get_table(ctx), rn,
tableid, rn,
zebra_route_string(
dplane_ctx_get_type(ctx)));
}
@ -2342,7 +2354,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
zlog_debug(
"%s(%u:%u):%pRN dplane notification: rib_update returns FALSE",
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
dplane_ctx_get_table(ctx), rn);
tableid, rn);
}
/*
@ -2361,7 +2373,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
"%s(%u:%u):%pRN applied nexthop changes from dplane notification",
VRF_LOGNAME(vrf),
dplane_ctx_get_vrf(ctx),
dplane_ctx_get_table(ctx), rn);
tableid, rn);
/* Changed nexthops - update kernel/others */
dplane_route_notif_update(rn, re,
@ -2373,7 +2385,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
"%s(%u:%u):%pRN installed transition from dplane notification",
VRF_LOGNAME(vrf),
dplane_ctx_get_vrf(ctx),
dplane_ctx_get_table(ctx), rn);
tableid, rn);
/* We expect this to be the selected route, so we want
* to tell others about this transition.
@ -2393,7 +2405,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
"%s(%u:%u):%pRN un-installed transition from dplane notification",
VRF_LOGNAME(vrf),
dplane_ctx_get_vrf(ctx),
dplane_ctx_get_table(ctx), rn);
tableid, rn);
/* Transition from _something_ installed to _nothing_
* installed.
@ -3973,10 +3985,10 @@ static void rib_link(struct route_node *rn, struct route_entry *re, int process)
dest = rib_dest_from_rnode(rn);
if (!dest) {
dest = zebra_rib_create_dest(rn);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
rnode_debug(rn, re->vrf_id, "rn %p adding dest", rn);
dest = zebra_rib_create_dest(rn);
}
re_list_add_head(&dest->routes, re);

View File

@ -417,6 +417,25 @@ vrf_id_t zebra_vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id)
return VRF_DEFAULT;
}
/*
* Lookup tableid by vrfid; handle vrf-lite and vrf-netns cases
*/
int zebra_vrf_lookup_tableid(vrf_id_t vrf_id, ns_id_t ns_id)
{
struct zebra_vrf *zvrf;
/* Handle vrf-lite and vrf-netns */
if (vrf_is_backend_netns())
zvrf = vrf_info_lookup(ns_id);
else
zvrf = vrf_info_lookup(vrf_id);
if (zvrf)
return zvrf->table_id;
else
return ZEBRA_ROUTE_TABLE_UNKNOWN;
}
/* Lookup VRF by identifier. */
struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id)
{

View File

@ -24,6 +24,8 @@ FRR_CFG_DEFAULT_BOOL(ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT,
{ .val_bool = false },
);
#define ZEBRA_ROUTE_TABLE_UNKNOWN 0
/* MPLS (Segment Routing) global block */
struct mpls_srgb {
uint32_t start_label;
@ -247,6 +249,7 @@ extern struct zebra_vrf *zebra_vrf_lookup_by_name(const char *);
extern vrf_id_t zebra_vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id);
extern struct zebra_vrf *zebra_vrf_alloc(struct vrf *vrf);
extern struct route_table *zebra_vrf_table(afi_t, safi_t, vrf_id_t);
int zebra_vrf_lookup_tableid(vrf_id_t vrf_id, ns_id_t ns_id);
/*
* API to associate a VRF with a NETNS.