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.c153
1 files changed, 117 insertions, 36 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 50b1a62d86..1ce3c435fe 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -126,6 +126,31 @@ static bool kernel_nexthops_supported(void)
}
/*
+ * Some people may only want to use NHGs created by protos and not
+ * implicitly created by Zebra. This check accounts for that.
+ */
+static bool proto_nexthops_only(void)
+{
+ return zebra_nhg_proto_nexthops_only();
+}
+
+/* Is this a proto created NHG? */
+static bool is_proto_nhg(uint32_t id, int type)
+{
+ /* If type is available, use it as the source of truth */
+ if (type) {
+ if (type != ZEBRA_ROUTE_NHG)
+ return true;
+ return false;
+ }
+
+ if (id >= ZEBRA_NHG_PROTO_LOWER)
+ return true;
+
+ return false;
+}
+
+/*
* The ipv4_ll data structure is used for all 5549
* additions to the kernel. Let's figure out the
* correct value one time instead for every
@@ -643,6 +668,11 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
return 0;
}
+ if (rtm->rtm_flags & RTM_F_TRAP)
+ flags |= ZEBRA_FLAG_TRAPPED;
+ if (rtm->rtm_flags & RTM_F_OFFLOAD)
+ flags |= ZEBRA_FLAG_OFFLOADED;
+
/* Route which inserted by Zebra. */
if (selfroute) {
flags |= ZEBRA_FLAG_SELFROUTE;
@@ -1743,7 +1773,10 @@ ssize_t netlink_route_multipath_msg_encode(int cmd,
nl_attr_nest_end(&req->n, nest);
}
- if ((!fpm && kernel_nexthops_supported()) || (fpm && force_nhg)) {
+ if ((!fpm && kernel_nexthops_supported()
+ && (!proto_nexthops_only()
+ || is_proto_nhg(dplane_ctx_get_nhe_id(ctx), 0)))
+ || (fpm && force_nhg)) {
/* Kernel supports nexthop objects */
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: %pFX nhg_id is %u", __func__, p,
@@ -2067,6 +2100,35 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
mpls_lse_t out_lse[MPLS_MAX_LABELS];
char label_buf[256];
int num_labels = 0;
+ uint32_t id = dplane_ctx_get_nhe_id(ctx);
+ int type = dplane_ctx_get_nhe_type(ctx);
+
+ if (!id) {
+ flog_err(
+ EC_ZEBRA_NHG_FIB_UPDATE,
+ "Failed trying to update a nexthop group in the kernel that does not have an ID");
+ return -1;
+ }
+
+ /*
+ * Nothing to do if the kernel doesn't support nexthop objects or
+ * we dont want to install this type of NHG
+ */
+ if (!kernel_nexthops_supported()) {
+ if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_NHG)
+ zlog_debug(
+ "%s: nhg_id %u (%s): kernel nexthops not supported, ignoring",
+ __func__, id, zebra_route_string(type));
+ return 0;
+ }
+
+ if (proto_nexthops_only() && !is_proto_nhg(id, type)) {
+ if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_NHG)
+ zlog_debug(
+ "%s: nhg_id %u (%s): proto-based nexthops only, ignoring",
+ __func__, id, zebra_route_string(type));
+ return 0;
+ }
label_buf[0] = '\0';
@@ -2087,15 +2149,6 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
req->nhm.nh_family = AF_UNSPEC;
/* TODO: Scope? */
- uint32_t id = dplane_ctx_get_nhe_id(ctx);
-
- if (!id) {
- flog_err(
- EC_ZEBRA_NHG_FIB_UPDATE,
- "Failed trying to update a nexthop group in the kernel that does not have an ID");
- return -1;
- }
-
if (!nl_attr_put32(&req->n, buflen, NHA_ID, id))
return 0;
@@ -2216,8 +2269,7 @@ nexthop_done:
nh->vrf_id, label_buf);
}
- req->nhm.nh_protocol =
- zebra2proto(dplane_ctx_get_nhe_type(ctx));
+req->nhm.nh_protocol = zebra2proto(type);
} else if (cmd != RTM_DELNEXTHOP) {
flog_err(
@@ -2680,9 +2732,9 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
static ssize_t netlink_neigh_update_msg_encode(
const struct zebra_dplane_ctx *ctx, int cmd, const struct ethaddr *mac,
const struct ipaddr *ip, bool replace_obj, uint8_t family, uint8_t type,
- uint8_t flags, uint16_t state, uint32_t nhg_id,
- bool nfy, uint8_t nfy_flags,
- void *data, size_t datalen)
+ uint8_t flags, uint16_t state, uint32_t nhg_id, bool nfy,
+ uint8_t nfy_flags, bool ext, uint32_t ext_flags, void *data,
+ size_t datalen)
{
uint8_t protocol = RTPROT_ZEBRA;
struct {
@@ -2731,6 +2783,12 @@ static ssize_t netlink_neigh_update_msg_encode(
return 0;
}
+ if (ext) {
+ if (!nl_attr_put(&req->n, datalen, NDA_EXT_FLAGS, &ext_flags,
+ sizeof(ext_flags)))
+ return 0;
+ }
+
ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN;
if (!nl_attr_put(&req->n, datalen, NDA_DST, &ip->ip.addr, ipa_len))
return 0;
@@ -2764,7 +2822,8 @@ netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd,
return netlink_neigh_update_msg_encode(
ctx, cmd, &dst_mac, dplane_ctx_neigh_get_ipaddr(ctx), false,
PF_BRIDGE, 0, NTF_SELF, (NUD_NOARP | NUD_PERMANENT), 0 /*nhg*/,
- false /*nfy*/, 0 /*nfy_flags*/, buf, buflen);
+ false /*nfy*/, 0 /*nfy_flags*/, false /*ext*/, 0 /*ext_flags*/,
+ buf, buflen);
}
#ifndef NDA_RTA
@@ -3174,30 +3233,26 @@ ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data,
else
vid_buf[0] = '\0';
- zlog_debug("Tx %s family %s IF %s(%u)%s %sMAC %s dst %s nhg %u%s%s%s%s%s",
- nl_msg_type_to_str(cmd), nl_family_to_str(AF_BRIDGE),
- dplane_ctx_get_ifname(ctx),
- dplane_ctx_get_ifindex(ctx), vid_buf,
- dplane_ctx_mac_is_sticky(ctx) ? "sticky " : "",
- prefix_mac2str(mac, buf, sizeof(buf)),
- ipaddr2str(&vtep_ip, ipbuf, sizeof(ipbuf)),
- nhg_id,
- (update_flags &
- DPLANE_MAC_REMOTE) ? " rem" : "",
- (update_flags &
- DPLANE_MAC_WAS_STATIC) ? " clr_sync" : "",
- (update_flags &
- DPLANE_MAC_SET_STATIC) ? " static" : "",
- (update_flags &
- DPLANE_MAC_SET_INACTIVE) ? " inactive" : "",
- (nfy &
- DPLANE_MAC_SET_INACTIVE) ? " nfy" : "");
+ zlog_debug(
+ "Tx %s family %s IF %s(%u)%s %sMAC %s dst %s nhg %u%s%s%s%s%s",
+ nl_msg_type_to_str(cmd), nl_family_to_str(AF_BRIDGE),
+ dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifindex(ctx),
+ vid_buf, dplane_ctx_mac_is_sticky(ctx) ? "sticky " : "",
+ prefix_mac2str(mac, buf, sizeof(buf)),
+ ipaddr2str(&vtep_ip, ipbuf, sizeof(ipbuf)), nhg_id,
+ (update_flags & DPLANE_MAC_REMOTE) ? " rem" : "",
+ (update_flags & DPLANE_MAC_WAS_STATIC) ? " clr_sync"
+ : "",
+ (update_flags & DPLANE_MAC_SET_STATIC) ? " static" : "",
+ (update_flags & DPLANE_MAC_SET_INACTIVE) ? " inactive"
+ : "",
+ nfy ? " nfy" : "");
}
total = netlink_neigh_update_msg_encode(
ctx, cmd, dplane_ctx_mac_get_addr(ctx), &vtep_ip, true,
AF_BRIDGE, 0, flags, state, nhg_id, nfy, nfy_flags,
- data, datalen);
+ false /*ext*/, 0 /*ext_flags*/, data, datalen);
return total;
}
@@ -3598,17 +3653,42 @@ static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
uint8_t flags;
uint16_t state;
uint8_t family;
+ uint32_t update_flags;
+ uint32_t ext_flags = 0;
+ bool ext = false;
ip = dplane_ctx_neigh_get_ipaddr(ctx);
mac = dplane_ctx_neigh_get_mac(ctx);
if (is_zero_mac(mac))
mac = NULL;
+ update_flags = dplane_ctx_neigh_get_update_flags(ctx);
flags = neigh_flags_to_netlink(dplane_ctx_neigh_get_flags(ctx));
state = neigh_state_to_netlink(dplane_ctx_neigh_get_state(ctx));
family = IS_IPADDR_V4(ip) ? AF_INET : AF_INET6;
+ if (update_flags & DPLANE_NEIGH_REMOTE) {
+ flags |= NTF_EXT_LEARNED;
+ /* if it was static-local previously we need to clear the
+ * ext flags on replace with remote
+ */
+ if (update_flags & DPLANE_NEIGH_WAS_STATIC)
+ ext = true;
+ } else {
+ ext = true;
+ /* local neigh */
+ if (update_flags & DPLANE_NEIGH_SET_STATIC)
+ ext_flags |= NTF_E_MH_PEER_SYNC;
+
+ /* the ndm_state set for local entries can be REACHABLE or
+ * STALE. if the dataplane has already establish reachability
+ * (in the meantime) FRR must not over-write it with STALE.
+ * this accidental race/over-write is avoided by using the
+ * WEAK_OVERRIDE_STATE
+ */
+ ext_flags |= NTF_E_WEAK_OVERRIDE_STATE;
+ }
if (IS_ZEBRA_DEBUG_KERNEL) {
char buf[INET6_ADDRSTRLEN];
char buf2[ETHER_ADDR_STRLEN];
@@ -3624,7 +3704,8 @@ static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
return netlink_neigh_update_msg_encode(
ctx, cmd, mac, ip, true, family, RTN_UNICAST, flags, state,
- 0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/, buf, buflen);
+ 0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/, ext, ext_flags, buf,
+ buflen);
}
static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx,