mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
zebra: refactor netlink route message parsing
Separate core netlink route message parsing into a new api that uses a dplane ctx to hold the parsed attribute data. Use the new api in two paths: the normal netlink update message parsing path, and in the FPM plugin, which also uses netlink encoding. The FPM route-notificatin code runs in its own pthread, and only needs a subset of the route info that zebra ordinarily develops. This change stops that pthread from accessing zebra's internal data, such as vrfs and ifps, that are not thread-safe. Signed-off-by: Mark Stapp <mjs@cisco.com>
This commit is contained in:
parent
99ecf5ead0
commit
29122bc9b8
|
@ -587,6 +587,7 @@ static void fpm_read(struct event *t)
|
||||||
struct zebra_dplane_ctx *ctx;
|
struct zebra_dplane_ctx *ctx;
|
||||||
size_t available_bytes;
|
size_t available_bytes;
|
||||||
size_t hdr_available_bytes;
|
size_t hdr_available_bytes;
|
||||||
|
int ival;
|
||||||
|
|
||||||
/* Let's ignore the input at the moment. */
|
/* Let's ignore the input at the moment. */
|
||||||
rv = stream_read_try(fnc->ibuf, fnc->socket,
|
rv = stream_read_try(fnc->ibuf, fnc->socket,
|
||||||
|
@ -715,17 +716,28 @@ static void fpm_read(struct event *t)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse the route data into a dplane ctx, then
|
||||||
|
* enqueue it to zebra for processing.
|
||||||
|
*/
|
||||||
ctx = dplane_ctx_alloc();
|
ctx = dplane_ctx_alloc();
|
||||||
dplane_ctx_route_init(ctx, DPLANE_OP_ROUTE_NOTIFY, NULL,
|
dplane_ctx_route_init(ctx, DPLANE_OP_ROUTE_NOTIFY, NULL,
|
||||||
NULL);
|
NULL);
|
||||||
if (netlink_route_change_read_unicast_internal(
|
|
||||||
hdr, 0, false, ctx) != 1) {
|
if (netlink_route_notify_read_ctx(hdr, 0, ctx) >= 0) {
|
||||||
dplane_ctx_fini(&ctx);
|
/* In the FPM encoding, the vrfid is present */
|
||||||
stream_pulldown(fnc->ibuf);
|
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
|
* Let's continue to read other messages
|
||||||
* Even if we ignore this one.
|
* Even if we ignore this one.
|
||||||
*/
|
*/
|
||||||
|
dplane_ctx_fini(&ctx);
|
||||||
|
stream_pulldown(fnc->ibuf);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -723,44 +723,52 @@ static uint16_t parse_multipath_nexthops_unicast(ns_id_t ns_id, struct nexthop_g
|
||||||
return nhop_num;
|
return nhop_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Looking up routing table by netlink interface. */
|
/*
|
||||||
int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
|
* Parse netlink route message and capture info into a dplane ctx.
|
||||||
ns_id_t ns_id, int startup,
|
* Returns <0 if the message is to be skipped (might be an error)
|
||||||
struct zebra_dplane_ctx *ctx)
|
*/
|
||||||
|
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;
|
int len;
|
||||||
struct rtmsg *rtm;
|
struct rtmsg *rtm;
|
||||||
struct rtattr *tb[RTA_MAX + 1];
|
struct rtattr **tb, *tb_array[RTA_MAX + 1];
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
struct prefix p;
|
struct prefix p;
|
||||||
struct prefix_ipv6 src_p = {};
|
struct prefix src_p = {};
|
||||||
vrf_id_t vrf_id;
|
|
||||||
bool selfroute;
|
bool selfroute;
|
||||||
|
char anyaddr[16] = {};
|
||||||
char anyaddr[16] = {0};
|
|
||||||
|
|
||||||
int proto = ZEBRA_ROUTE_KERNEL;
|
int proto = ZEBRA_ROUTE_KERNEL;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int table;
|
int tableid;
|
||||||
int metric = 0;
|
int metric = 0;
|
||||||
uint32_t mtu = 0;
|
uint32_t mtu = 0;
|
||||||
uint8_t distance = 0;
|
uint8_t distance = 0;
|
||||||
route_tag_t tag = 0;
|
route_tag_t tag = 0;
|
||||||
uint32_t nhe_id = 0;
|
uint32_t nhg_id = 0;
|
||||||
|
|
||||||
void *dest = NULL;
|
void *dest = NULL;
|
||||||
void *gate = NULL;
|
void *gate = NULL;
|
||||||
|
int gate_len;
|
||||||
void *prefsrc = NULL; /* IPv4 preferred source host address */
|
void *prefsrc = NULL; /* IPv4 preferred source host address */
|
||||||
|
int prefsrc_len;
|
||||||
void *src = NULL; /* IPv6 srcdest source prefix */
|
void *src = NULL; /* IPv6 srcdest source prefix */
|
||||||
enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
|
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,
|
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||||
startup);
|
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);
|
rtm = NLMSG_DATA(h);
|
||||||
|
|
||||||
if (startup && h->nlmsg_type != RTM_NEWROUTE)
|
|
||||||
return 0;
|
|
||||||
switch (rtm->rtm_type) {
|
switch (rtm->rtm_type) {
|
||||||
case RTN_UNICAST:
|
case RTN_UNICAST:
|
||||||
break;
|
break;
|
||||||
|
@ -778,54 +786,42 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
|
||||||
zlog_debug("Route rtm_type: %s(%d) intentionally ignoring",
|
zlog_debug("Route rtm_type: %s(%d) intentionally ignoring",
|
||||||
nl_rttype_to_str(rtm->rtm_type),
|
nl_rttype_to_str(rtm->rtm_type),
|
||||||
rtm->rtm_type);
|
rtm->rtm_type);
|
||||||
return 0;
|
ret = -1;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
|
if ((rtm->rtm_flags & RTM_F_CLONED) ||
|
||||||
if (len < 0) {
|
(rtm->rtm_protocol == RTPROT_REDIRECT)) {
|
||||||
zlog_err(
|
ret = -1;
|
||||||
"%s: Message received from netlink is of a broken size %d %zu",
|
goto done;
|
||||||
__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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We don't care about change notifications for the MPLS table. */
|
/* We don't care about change notifications for the MPLS table. */
|
||||||
/* TODO: Revisit this. */
|
/* TODO: Revisit this. */
|
||||||
if (rtm->rtm_family == AF_MPLS)
|
if (rtm->rtm_family == AF_MPLS) {
|
||||||
return 0;
|
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. */
|
/* Table corresponding to route. */
|
||||||
if (tb[RTA_TABLE])
|
if (tb[RTA_TABLE])
|
||||||
table = *(int *)RTA_DATA(tb[RTA_TABLE]);
|
tableid = *(int *)RTA_DATA(tb[RTA_TABLE]);
|
||||||
else
|
else
|
||||||
table = rtm->rtm_table;
|
tableid = 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Map flags values */
|
||||||
if (rtm->rtm_flags & RTM_F_TRAP)
|
if (rtm->rtm_flags & RTM_F_TRAP)
|
||||||
flags |= ZEBRA_FLAG_TRAPPED;
|
flags |= ZEBRA_FLAG_TRAPPED;
|
||||||
if (rtm->rtm_flags & RTM_F_OFFLOAD)
|
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)
|
if (h->nlmsg_flags & NLM_F_APPEND)
|
||||||
flags |= ZEBRA_FLAG_OUTOFSYNC;
|
flags |= ZEBRA_FLAG_OUTOFSYNC;
|
||||||
|
|
||||||
/* Route which inserted by Zebra. */
|
/* Route which was inserted by Zebra. */
|
||||||
if (selfroute) {
|
if (selfroute) {
|
||||||
flags |= ZEBRA_FLAG_SELFROUTE;
|
flags |= ZEBRA_FLAG_SELFROUTE;
|
||||||
proto = proto2zebra(rtm->rtm_protocol, rtm->rtm_family, false);
|
proto = proto2zebra(rtm->rtm_protocol, rtm->rtm_family, false);
|
||||||
|
@ -854,14 +850,18 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
|
||||||
else
|
else
|
||||||
src = anyaddr;
|
src = anyaddr;
|
||||||
|
|
||||||
if (tb[RTA_PREFSRC])
|
if (tb[RTA_PREFSRC]) {
|
||||||
prefsrc = RTA_DATA(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 = RTA_DATA(tb[RTA_GATEWAY]);
|
||||||
|
gate_len = RTA_PAYLOAD(tb[RTA_GATEWAY]);
|
||||||
|
}
|
||||||
|
|
||||||
if (tb[RTA_NH_ID])
|
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])
|
if (tb[RTA_PRIORITY])
|
||||||
metric = *(int *)RTA_DATA(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(
|
zlog_err(
|
||||||
"Invalid destination prefix length: %u received from kernel route change",
|
"Invalid destination prefix length: %u received from kernel route change",
|
||||||
rtm->rtm_dst_len);
|
rtm->rtm_dst_len);
|
||||||
return -1;
|
ret = -1;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
memcpy(&p.u.prefix4, dest, 4);
|
memcpy(&p.u.prefix4, dest, 4);
|
||||||
p.prefixlen = rtm->rtm_dst_len;
|
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) {
|
if (rtm->rtm_src_len != 0) {
|
||||||
flog_warn(
|
flog_warn(
|
||||||
EC_ZEBRA_UNSUPPORTED_V4_SRCDEST,
|
EC_ZEBRA_UNSUPPORTED_V4_SRCDEST,
|
||||||
"unsupported IPv4 sourcedest route (dest %pFX vrf %u)",
|
"unsupported IPv4 sourcedest route (dest %pFX table %u)",
|
||||||
&p, vrf_id);
|
&p, tableid);
|
||||||
return 0;
|
ret = -1;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Force debug below to not display anything for source */
|
/* Force debug below to not display anything for source */
|
||||||
src_p.prefixlen = 0;
|
src_p.prefixlen = 0;
|
||||||
} else if (rtm->rtm_family == AF_INET6) {
|
} else if (rtm->rtm_family == AF_INET6) {
|
||||||
|
afi = AFI_IP6;
|
||||||
p.family = AF_INET6;
|
p.family = AF_INET6;
|
||||||
if (rtm->rtm_dst_len > IPV6_MAX_BITLEN) {
|
if (rtm->rtm_dst_len > IPV6_MAX_BITLEN) {
|
||||||
zlog_err(
|
zlog_err(
|
||||||
|
@ -920,14 +923,15 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
|
||||||
rtm->rtm_src_len);
|
rtm->rtm_src_len);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memcpy(&src_p.prefix, src, 16);
|
memcpy(&src_p.u.prefix6, src, 16);
|
||||||
src_p.prefixlen = rtm->rtm_src_len;
|
src_p.prefixlen = rtm->rtm_src_len;
|
||||||
} else {
|
} else {
|
||||||
/* We only handle the AFs we handle... */
|
/* We only handle the AFs we handle... */
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||||
zlog_debug("%s: unknown address-family %u", __func__,
|
zlog_debug("%s: unknown address-family %u", __func__,
|
||||||
rtm->rtm_family);
|
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);
|
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) {
|
if (IS_ZEBRA_DEBUG_KERNEL) {
|
||||||
char buf2[PREFIX_STRLEN];
|
char buf2[PREFIX_STRLEN];
|
||||||
|
|
||||||
|
@ -965,10 +1212,6 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
|
||||||
distance);
|
distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
afi_t afi = AFI_IP;
|
|
||||||
if (rtm->rtm_family == AF_INET6)
|
|
||||||
afi = AFI_IP6;
|
|
||||||
|
|
||||||
if (h->nlmsg_type == RTM_NEWROUTE) {
|
if (h->nlmsg_type == RTM_NEWROUTE) {
|
||||||
struct route_entry *re;
|
struct route_entry *re;
|
||||||
struct nexthop_group *ng = NULL;
|
struct nexthop_group *ng = NULL;
|
||||||
|
@ -1018,12 +1261,11 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nhe_id || ng) {
|
if (nhe_id || ng) {
|
||||||
dplane_rib_add_multipath(afi, SAFI_UNICAST, &p, &src_p,
|
rib_add_multipath(afi, SAFI_UNICAST, &p,
|
||||||
re, ng, startup, ctx);
|
(struct prefix_ipv6 *)&src_p,
|
||||||
|
re, ng, startup);
|
||||||
if (ng)
|
if (ng)
|
||||||
nexthop_group_delete(&ng);
|
nexthop_group_delete(&ng);
|
||||||
if (ctx)
|
|
||||||
zebra_rib_route_entry_free(re);
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* I really don't see how this is possible
|
* 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);
|
zebra_rib_route_entry_free(re);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ctx) {
|
|
||||||
zlog_err(
|
|
||||||
"%s: %pFX RTM_DELROUTE received but received a context as well",
|
|
||||||
__func__, &p);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nhe_id) {
|
if (nhe_id) {
|
||||||
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
|
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
|
||||||
&p, &src_p, NULL, nhe_id, table, metric,
|
&p, (struct prefix_ipv6 *)&src_p, NULL,
|
||||||
distance, true);
|
nhe_id, table, metric, distance, true);
|
||||||
} else {
|
} else {
|
||||||
if (!tb[RTA_MULTIPATH]) {
|
if (!tb[RTA_MULTIPATH]) {
|
||||||
struct nexthop nh;
|
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,
|
ns_id, rtm, tb, bh_type, index, prefsrc,
|
||||||
gate, afi, vrf_id);
|
gate, afi, vrf_id);
|
||||||
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
|
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
|
||||||
flags, &p, &src_p, &nh, 0, table,
|
flags, &p,
|
||||||
metric, distance, true);
|
(struct prefix_ipv6 *)&src_p, &nh, 0,
|
||||||
|
table, metric, distance, true);
|
||||||
} else {
|
} else {
|
||||||
/* XXX: need to compare the entire list of
|
/* XXX: need to compare the entire list of
|
||||||
* nexthops here for NLM_F_APPEND stupidity */
|
* nexthops here for NLM_F_APPEND stupidity */
|
||||||
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
|
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
|
||||||
flags, &p, &src_p, NULL, 0, table,
|
flags, &p,
|
||||||
metric, distance, true);
|
(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,
|
static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
|
||||||
int startup)
|
int startup)
|
||||||
{
|
{
|
||||||
return netlink_route_change_read_unicast_internal(h, ns_id, startup,
|
return netlink_route_change_read_unicast_internal(h, ns_id, startup);
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct mcast_route_data *mroute = NULL;
|
static struct mcast_route_data *mroute = NULL;
|
||||||
|
|
|
@ -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_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
|
||||||
extern int netlink_route_read(struct zebra_ns *zns);
|
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,
|
extern int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id,
|
||||||
int startup);
|
int startup);
|
||||||
extern int netlink_nexthop_read(struct zebra_ns *zns);
|
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
|
extern enum netlink_msg_status
|
||||||
netlink_put_pw_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
|
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
|
#ifdef NETLINK_DEBUG
|
||||||
const char *nlmsg_type2str(uint16_t type);
|
const char *nlmsg_type2str(uint16_t type);
|
||||||
const char *af_type2str(int type);
|
const char *af_type2str(int type);
|
||||||
|
|
|
@ -2279,8 +2279,20 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
|
||||||
bool fib_changed = false;
|
bool fib_changed = false;
|
||||||
bool debug_p = IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_RIB;
|
bool debug_p = IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_RIB;
|
||||||
int start_count, end_count;
|
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 */
|
/* Locate rn and re(s) from ctx */
|
||||||
rn = rib_find_rn_from_ctx(ctx);
|
rn = rib_find_rn_from_ctx(ctx);
|
||||||
|
@ -2289,7 +2301,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
"Failed to process dplane notification: no routes for %s(%u:%u):%pRN",
|
"Failed to process dplane notification: no routes for %s(%u:%u):%pRN",
|
||||||
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
|
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
|
||||||
dplane_ctx_get_table(ctx), rn);
|
tableid, rn);
|
||||||
}
|
}
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -2299,7 +2311,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
|
||||||
if (debug_p)
|
if (debug_p)
|
||||||
zlog_debug("%s(%u:%u):%pRN Processing dplane notif ctx %p",
|
zlog_debug("%s(%u:%u):%pRN Processing dplane notif ctx %p",
|
||||||
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
|
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
|
* Take a pass through the routes, look for matches with the context
|
||||||
|
@ -2316,7 +2328,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
"%s(%u:%u):%pRN Unable to process dplane notification: no entry for type %s",
|
"%s(%u:%u):%pRN Unable to process dplane notification: no entry for type %s",
|
||||||
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
|
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
|
||||||
dplane_ctx_get_table(ctx), rn,
|
tableid, rn,
|
||||||
zebra_route_string(dplane_ctx_get_type(ctx)));
|
zebra_route_string(dplane_ctx_get_type(ctx)));
|
||||||
|
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -2352,7 +2364,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
|
||||||
"%s(%u:%u):%pRN dplane notif, uninstalled type %s route",
|
"%s(%u:%u):%pRN dplane notif, uninstalled type %s route",
|
||||||
VRF_LOGNAME(vrf),
|
VRF_LOGNAME(vrf),
|
||||||
dplane_ctx_get_vrf(ctx),
|
dplane_ctx_get_vrf(ctx),
|
||||||
dplane_ctx_get_table(ctx), rn,
|
tableid, rn,
|
||||||
zebra_route_string(
|
zebra_route_string(
|
||||||
dplane_ctx_get_type(ctx)));
|
dplane_ctx_get_type(ctx)));
|
||||||
} else {
|
} else {
|
||||||
|
@ -2362,7 +2374,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
|
||||||
"%s(%u:%u):%pRN dplane notif, but type %s not selected_fib",
|
"%s(%u:%u):%pRN dplane notif, but type %s not selected_fib",
|
||||||
VRF_LOGNAME(vrf),
|
VRF_LOGNAME(vrf),
|
||||||
dplane_ctx_get_vrf(ctx),
|
dplane_ctx_get_vrf(ctx),
|
||||||
dplane_ctx_get_table(ctx), rn,
|
tableid, rn,
|
||||||
zebra_route_string(
|
zebra_route_string(
|
||||||
dplane_ctx_get_type(ctx)));
|
dplane_ctx_get_type(ctx)));
|
||||||
}
|
}
|
||||||
|
@ -2401,7 +2413,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
"%s(%u:%u):%pRN dplane notification: rib_update returns FALSE",
|
"%s(%u:%u):%pRN dplane notification: rib_update returns FALSE",
|
||||||
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
|
VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx),
|
||||||
dplane_ctx_get_table(ctx), rn);
|
tableid, rn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2420,7 +2432,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
|
||||||
"%s(%u:%u):%pRN applied nexthop changes from dplane notification",
|
"%s(%u:%u):%pRN applied nexthop changes from dplane notification",
|
||||||
VRF_LOGNAME(vrf),
|
VRF_LOGNAME(vrf),
|
||||||
dplane_ctx_get_vrf(ctx),
|
dplane_ctx_get_vrf(ctx),
|
||||||
dplane_ctx_get_table(ctx), rn);
|
tableid, rn);
|
||||||
|
|
||||||
/* Changed nexthops - update kernel/others */
|
/* Changed nexthops - update kernel/others */
|
||||||
dplane_route_notif_update(rn, re,
|
dplane_route_notif_update(rn, re,
|
||||||
|
@ -2432,7 +2444,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
|
||||||
"%s(%u:%u):%pRN installed transition from dplane notification",
|
"%s(%u:%u):%pRN installed transition from dplane notification",
|
||||||
VRF_LOGNAME(vrf),
|
VRF_LOGNAME(vrf),
|
||||||
dplane_ctx_get_vrf(ctx),
|
dplane_ctx_get_vrf(ctx),
|
||||||
dplane_ctx_get_table(ctx), rn);
|
tableid, rn);
|
||||||
|
|
||||||
/* We expect this to be the selected route, so we want
|
/* We expect this to be the selected route, so we want
|
||||||
* to tell others about this transition.
|
* to tell others about this transition.
|
||||||
|
@ -2452,7 +2464,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
|
||||||
"%s(%u:%u):%pRN un-installed transition from dplane notification",
|
"%s(%u:%u):%pRN un-installed transition from dplane notification",
|
||||||
VRF_LOGNAME(vrf),
|
VRF_LOGNAME(vrf),
|
||||||
dplane_ctx_get_vrf(ctx),
|
dplane_ctx_get_vrf(ctx),
|
||||||
dplane_ctx_get_table(ctx), rn);
|
tableid, rn);
|
||||||
|
|
||||||
/* Transition from _something_ installed to _nothing_
|
/* Transition from _something_ installed to _nothing_
|
||||||
* installed.
|
* installed.
|
||||||
|
|
|
@ -417,6 +417,25 @@ vrf_id_t zebra_vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id)
|
||||||
return VRF_DEFAULT;
|
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. */
|
/* Lookup VRF by identifier. */
|
||||||
struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id)
|
struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,6 +24,8 @@ FRR_CFG_DEFAULT_BOOL(ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT,
|
||||||
{ .val_bool = false },
|
{ .val_bool = false },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#define ZEBRA_ROUTE_TABLE_UNKNOWN 0
|
||||||
|
|
||||||
/* MPLS (Segment Routing) global block */
|
/* MPLS (Segment Routing) global block */
|
||||||
struct mpls_srgb {
|
struct mpls_srgb {
|
||||||
uint32_t start_label;
|
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 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 zebra_vrf *zebra_vrf_alloc(struct vrf *vrf);
|
||||||
extern struct route_table *zebra_vrf_table(afi_t, safi_t, vrf_id_t);
|
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.
|
* API to associate a VRF with a NETNS.
|
||||||
|
|
Loading…
Reference in a new issue