summaryrefslogtreecommitdiff
path: root/zebra/rt_netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/rt_netlink.c')
-rw-r--r--zebra/rt_netlink.c104
1 files changed, 58 insertions, 46 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 466e985494..2e6cc7cd06 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -1552,7 +1552,8 @@ static void netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen,
* Routing table change via netlink interface, using a dataplane context object
*/
ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
- uint8_t *data, size_t datalen, bool fpm)
+ uint8_t *data, size_t datalen, bool fpm,
+ bool force_nhg)
{
int bytelen;
struct nexthop *nexthop = NULL;
@@ -1674,7 +1675,7 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
RTA_PAYLOAD(rta));
}
- if (kernel_nexthops_supported()) {
+ if (kernel_nexthops_supported() || force_nhg) {
/* Kernel supports nexthop objects */
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
@@ -1954,43 +1955,42 @@ static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
}
/**
- * netlink_nexthop() - Nexthop change via the netlink interface
+ * Next hop packet encoding helper function.
*
- * @ctx: Dataplane ctx
+ * \param[in] cmd netlink command.
+ * \param[in] ctx dataplane context (information snapshot).
+ * \param[out] buf buffer to hold the packet.
+ * \param[in] buflen amount of buffer bytes.
*
- * Return: Result status
+ * \returns -1 on failure or the number of bytes written to buf.
*/
-static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
+ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
{
struct {
struct nlmsghdr n;
struct nhmsg nhm;
- char buf[NL_PKT_BUF_SIZE];
- } req;
+ char buf[];
+ } *req = buf;
mpls_lse_t out_lse[MPLS_MAX_LABELS];
char label_buf[256];
int num_labels = 0;
- size_t req_size = sizeof(req);
-
- /* Nothing to do if the kernel doesn't support nexthop objects */
- if (!kernel_nexthops_supported())
- return 0;
label_buf[0] = '\0';
- memset(&req, 0, req_size);
+ memset(req, 0, buflen);
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
- req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+ req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
+ req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
if (cmd == RTM_NEWNEXTHOP)
- req.n.nlmsg_flags |= NLM_F_REPLACE;
+ req->n.nlmsg_flags |= NLM_F_REPLACE;
- req.n.nlmsg_type = cmd;
- req.n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid;
+ req->n.nlmsg_type = cmd;
+ req->n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid;
- req.nhm.nh_family = AF_UNSPEC;
+ req->nhm.nh_family = AF_UNSPEC;
/* TODO: Scope? */
uint32_t id = dplane_ctx_get_nhe_id(ctx);
@@ -2002,7 +2002,7 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
return -1;
}
- addattr32(&req.n, req_size, NHA_ID, id);
+ addattr32(&req->n, buflen, NHA_ID, id);
if (cmd == RTM_NEWNEXTHOP) {
/*
@@ -2013,7 +2013,7 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
*/
if (dplane_ctx_get_nhe_nh_grp_count(ctx))
_netlink_nexthop_build_group(
- &req.n, req_size, id,
+ &req->n, buflen, id,
dplane_ctx_get_nhe_nh_grp(ctx),
dplane_ctx_get_nhe_nh_grp_count(ctx));
else {
@@ -2022,23 +2022,23 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
afi_t afi = dplane_ctx_get_nhe_afi(ctx);
if (afi == AFI_IP)
- req.nhm.nh_family = AF_INET;
+ req->nhm.nh_family = AF_INET;
else if (afi == AFI_IP6)
- req.nhm.nh_family = AF_INET6;
+ req->nhm.nh_family = AF_INET6;
switch (nh->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
- addattr_l(&req.n, req_size, NHA_GATEWAY,
+ addattr_l(&req->n, buflen, NHA_GATEWAY,
&nh->gate.ipv4, IPV4_MAX_BYTELEN);
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
- addattr_l(&req.n, req_size, NHA_GATEWAY,
+ addattr_l(&req->n, buflen, NHA_GATEWAY,
&nh->gate.ipv6, IPV6_MAX_BYTELEN);
break;
case NEXTHOP_TYPE_BLACKHOLE:
- addattr_l(&req.n, req_size, NHA_BLACKHOLE, NULL,
+ addattr_l(&req->n, buflen, NHA_BLACKHOLE, NULL,
0);
/* Blackhole shouldn't have anymore attributes
*/
@@ -2055,10 +2055,10 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
return -1;
}
- addattr32(&req.n, req_size, NHA_OIF, nh->ifindex);
+ addattr32(&req->n, buflen, NHA_OIF, nh->ifindex);
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK))
- req.nhm.nh_flags |= RTNH_F_ONLINK;
+ req->nhm.nh_flags |= RTNH_F_ONLINK;
num_labels =
build_label_stack(nh->nh_label, out_lse,
@@ -2072,10 +2072,10 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
/*
* TODO: MPLS unsupported for now in kernel.
*/
- if (req.nhm.nh_family == AF_MPLS)
+ if (req->nhm.nh_family == AF_MPLS)
goto nexthop_done;
#if 0
- addattr_l(&req.n, req_size, NHA_NEWDST,
+ addattr_l(&req->n, buflen, NHA_NEWDST,
&out_lse,
num_labels
* sizeof(mpls_lse_t));
@@ -2084,16 +2084,16 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
struct rtattr *nest;
uint16_t encap = LWTUNNEL_ENCAP_MPLS;
- addattr_l(&req.n, req_size,
+ addattr_l(&req->n, buflen,
NHA_ENCAP_TYPE, &encap,
sizeof(uint16_t));
- nest = addattr_nest(&req.n, req_size,
+ nest = addattr_nest(&req->n, buflen,
NHA_ENCAP);
- addattr_l(&req.n, req_size,
+ addattr_l(&req->n, buflen,
MPLS_IPTUNNEL_DST, &out_lse,
num_labels
* sizeof(mpls_lse_t));
- addattr_nest_end(&req.n, nest);
+ addattr_nest_end(&req->n, nest);
}
}
@@ -2106,7 +2106,8 @@ nexthop_done:
nh->vrf_id, label_buf);
}
- req.nhm.nh_protocol = zebra2proto(dplane_ctx_get_nhe_type(ctx));
+ req->nhm.nh_protocol =
+ zebra2proto(dplane_ctx_get_nhe_type(ctx));
} else if (cmd != RTM_DELNEXTHOP) {
flog_err(
@@ -2120,8 +2121,7 @@ nexthop_done:
zlog_debug("%s: %s, id=%u", __func__, nl_msg_type_to_str(cmd),
id);
- return netlink_talk_info(netlink_talk_filter, &req.n,
- dplane_ctx_get_ns(ctx), 0);
+ return NLMSG_ALIGN(req->n.nlmsg_len);
}
/**
@@ -2136,6 +2136,7 @@ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
enum dplane_op_e op;
int cmd = 0;
int ret = 0;
+ char buf[NL_PKT_BUF_SIZE];
op = dplane_ctx_get_op(ctx);
if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE)
@@ -2149,7 +2150,15 @@ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
- ret = netlink_nexthop(cmd, ctx);
+ /* Nothing to do if the kernel doesn't support nexthop objects */
+ if (!kernel_nexthops_supported())
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
+
+ if (netlink_nexthop_encode(cmd, ctx, buf, sizeof(buf)) > 0)
+ ret = netlink_talk_info(netlink_talk_filter, (void *)&buf,
+ dplane_ctx_get_ns(ctx), 0);
+ else
+ ret = 0;
return (ret == 0 ? ZEBRA_DPLANE_REQUEST_SUCCESS
: ZEBRA_DPLANE_REQUEST_FAILURE);
@@ -2188,7 +2197,7 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
netlink_route_multipath(RTM_DELROUTE, ctx,
nl_pkt, sizeof(nl_pkt),
- false);
+ false, false);
netlink_talk_info(netlink_talk_filter,
(struct nlmsghdr *)nl_pkt,
dplane_ctx_get_ns(ctx), 0);
@@ -2209,7 +2218,7 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
netlink_route_multipath(RTM_DELROUTE, ctx,
nl_pkt, sizeof(nl_pkt),
- false);
+ false, false);
netlink_talk_info(netlink_talk_filter,
(struct nlmsghdr *)nl_pkt,
dplane_ctx_get_ns(ctx), 0);
@@ -2222,7 +2231,7 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
}
if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) {
- netlink_route_multipath(cmd, ctx, nl_pkt, sizeof(nl_pkt),
+ netlink_route_multipath(cmd, ctx, nl_pkt, sizeof(nl_pkt), false,
false);
ret = netlink_talk_info(netlink_talk_filter,
(struct nlmsghdr *)nl_pkt,
@@ -2552,10 +2561,15 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
/**
* netlink_update_neigh_ctx_internal() - Common helper api for evpn
* neighbor updates using dataplane context object.
+ * Here, a neighbor refers to a bridge forwarding database entry for
+ * either unicast forwarding or head-end replication or an IP neighbor
+ * entry.
* @ctx: Dataplane context
* @cmd: Netlink command (RTM_NEWNEIGH or RTM_DELNEIGH)
* @mac: A neighbor cache link layer address
* @ip: A neighbor cache n/w layer destination address
+ * In the case of bridge FDB, this represnts the remote
+ * VTEP IP.
* @replace_obj: Whether NEW request should replace existing object or
* add to the end of the list
* @family: AF_* netlink family
@@ -2975,7 +2989,6 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data,
int cmd;
uint8_t flags;
uint16_t state;
- uint8_t nl_pkt[NL_PKT_BUF_SIZE];
cmd = dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL
? RTM_NEWNEIGH : RTM_DELNEIGH;
@@ -3014,9 +3027,8 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data,
}
total = netlink_update_neigh_ctx_internal(
- ctx, cmd, dplane_ctx_mac_get_addr(ctx),
- dplane_ctx_neigh_get_ipaddr(ctx), true, AF_BRIDGE, 0,
- flags, state, nl_pkt, sizeof(nl_pkt));
+ ctx, cmd, dplane_ctx_mac_get_addr(ctx), &vtep_ip,
+ true, AF_BRIDGE, 0, flags, state, data, datalen);
return total;
}