summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zebra/debug_nl.c110
-rw-r--r--zebra/dplane_fpm_nl.c3
-rw-r--r--zebra/if_netlink.c132
-rw-r--r--zebra/if_netlink.h13
-rw-r--r--zebra/interface.c273
-rw-r--r--zebra/interface.h12
-rw-r--r--zebra/kernel_netlink.c6
-rw-r--r--zebra/rt_netlink.h2
-rw-r--r--zebra/zapi_msg.c22
-rw-r--r--zebra/zebra_dplane.c189
-rw-r--r--zebra/zebra_dplane.h20
-rw-r--r--zebra/zebra_errors.c9
-rw-r--r--zebra/zebra_errors.h1
-rw-r--r--zebra/zebra_evpn_mh.c46
-rw-r--r--zebra/zebra_evpn_mh.h2
-rw-r--r--zebra/zebra_nhg.c3
-rw-r--r--zebra/zebra_rib.c8
-rw-r--r--zebra/zebra_router.h13
18 files changed, 744 insertions, 120 deletions
diff --git a/zebra/debug_nl.c b/zebra/debug_nl.c
index 260ba30b3c..b7d12bf537 100644
--- a/zebra/debug_nl.c
+++ b/zebra/debug_nl.c
@@ -255,6 +255,40 @@ const char *ifi_type2str(int type)
}
}
+const char *ifla_pdr_type2str(int type)
+{
+ switch (type) {
+ case IFLA_PROTO_DOWN_REASON_UNSPEC:
+ return "UNSPEC";
+ case IFLA_PROTO_DOWN_REASON_MASK:
+ return "MASK";
+ case IFLA_PROTO_DOWN_REASON_VALUE:
+ return "VALUE";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+const char *ifla_info_type2str(int type)
+{
+ switch (type) {
+ case IFLA_INFO_UNSPEC:
+ return "UNSPEC";
+ case IFLA_INFO_KIND:
+ return "KIND";
+ case IFLA_INFO_DATA:
+ return "DATA";
+ case IFLA_INFO_XSTATS:
+ return "XSTATS";
+ case IFLA_INFO_SLAVE_KIND:
+ return "SLAVE_KIND";
+ case IFLA_INFO_SLAVE_DATA:
+ return "SLAVE_DATA";
+ default:
+ return "UNKNOWN";
+ }
+}
+
const char *rta_type2str(int type)
{
switch (type) {
@@ -358,6 +392,8 @@ const char *rta_type2str(int type)
case IFLA_EVENT:
return "EVENT";
#endif /* IFLA_EVENT */
+ case IFLA_PROTO_DOWN_REASON:
+ return "PROTO_DOWN_REASON";
default:
return "UNKNOWN";
}
@@ -838,6 +874,42 @@ const char *nh_flags2str(uint32_t flags, char *buf, size_t buflen)
/*
* Netlink abstractions.
*/
+static void nllink_pdr_dump(struct rtattr *rta, size_t msglen)
+{
+ size_t plen;
+ uint32_t u32v;
+
+next_rta:
+ /* Check the header for valid length and for outbound access. */
+ if (RTA_OK(rta, msglen) == 0)
+ return;
+
+ plen = RTA_PAYLOAD(rta);
+ zlog_debug(" linkinfo [len=%d (payload=%zu) type=(%d) %s]",
+ rta->rta_len, plen, rta->rta_type,
+ ifla_pdr_type2str(rta->rta_type));
+ switch (rta->rta_type) {
+ case IFLA_PROTO_DOWN_REASON_MASK:
+ case IFLA_PROTO_DOWN_REASON_VALUE:
+ if (plen < sizeof(uint32_t)) {
+ zlog_debug(" invalid length");
+ break;
+ }
+
+ u32v = *(uint32_t *)RTA_DATA(rta);
+ zlog_debug(" %u", u32v);
+ break;
+
+ default:
+ /* NOTHING: unhandled. */
+ break;
+ }
+
+ /* Get next pointer and start iteration again. */
+ rta = RTA_NEXT(rta, msglen);
+ goto next_rta;
+}
+
static void nllink_linkinfo_dump(struct rtattr *rta, size_t msglen)
{
size_t plen;
@@ -851,7 +923,7 @@ next_rta:
plen = RTA_PAYLOAD(rta);
zlog_debug(" linkinfo [len=%d (payload=%zu) type=(%d) %s]",
rta->rta_len, plen, rta->rta_type,
- rta_type2str(rta->rta_type));
+ ifla_info_type2str(rta->rta_type));
switch (rta->rta_type) {
case IFLA_INFO_KIND:
if (plen == 0) {
@@ -888,8 +960,10 @@ static void nllink_dump(struct ifinfomsg *ifi, size_t msglen)
struct rtattr *rta;
size_t plen, it;
uint32_t u32v;
+ uint8_t u8v;
char bytestr[16];
char dbuf[128];
+ unsigned short rta_type;
/* Get the first attribute and go from there. */
rta = IFLA_RTA(ifi);
@@ -899,10 +973,10 @@ next_rta:
return;
plen = RTA_PAYLOAD(rta);
+ rta_type = rta->rta_type & ~NLA_F_NESTED;
zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
- plen, rta->rta_type, rta_type2str(rta->rta_type));
- switch (rta->rta_type) {
- case IFLA_IFNAME:
+ plen, rta_type, rta_type2str(rta_type));
+ switch (rta_type) {
case IFLA_IFALIAS:
if (plen == 0) {
zlog_debug(" invalid length");
@@ -927,6 +1001,7 @@ next_rta:
#endif /* IFLA_GSO_MAX_SIZE */
case IFLA_CARRIER_CHANGES:
case IFLA_MASTER:
+ case IFLA_LINK:
if (plen < sizeof(uint32_t)) {
zlog_debug(" invalid length");
break;
@@ -936,6 +1011,15 @@ next_rta:
zlog_debug(" %u", u32v);
break;
+ case IFLA_PROTO_DOWN:
+ if (plen < sizeof(uint8_t)) {
+ zlog_debug(" invalid length");
+ break;
+ }
+
+ u8v = *(uint8_t *)RTA_DATA(rta);
+ zlog_debug(" %u", u8v);
+ break;
case IFLA_ADDRESS:
datap = RTA_DATA(rta);
dbuf[0] = 0;
@@ -952,7 +1036,11 @@ next_rta:
break;
case IFLA_LINKINFO:
- nllink_linkinfo_dump(RTA_DATA(rta), msglen);
+ nllink_linkinfo_dump(RTA_DATA(rta), plen);
+ break;
+
+ case IFLA_PROTO_DOWN_REASON:
+ nllink_pdr_dump(RTA_DATA(rta), plen);
break;
default:
@@ -1027,6 +1115,7 @@ static void nlneigh_dump(struct ndmsg *ndm, size_t msglen)
uint16_t vid;
char bytestr[16];
char dbuf[128];
+ unsigned short rta_type;
#ifndef NDA_RTA
#define NDA_RTA(ndm) \
@@ -1043,9 +1132,10 @@ next_rta:
return;
plen = RTA_PAYLOAD(rta);
+ rta_type = rta->rta_type & ~NLA_F_NESTED;
zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
- plen, rta->rta_type, neigh_rta2str(rta->rta_type));
- switch (rta->rta_type & ~ NLA_F_NESTED) {
+ plen, rta->rta_type, neigh_rta2str(rta_type));
+ switch (rta_type) {
case NDA_LLADDR:
datap = RTA_DATA(rta);
dbuf[0] = 0;
@@ -1153,6 +1243,7 @@ static void nlnh_dump(struct nhmsg *nhm, size_t msglen)
uint32_t u32v;
unsigned long count, i;
struct nexthop_grp *nhgrp;
+ unsigned short rta_type;
rta = RTM_NHA(nhm);
@@ -1162,9 +1253,10 @@ next_rta:
return;
plen = RTA_PAYLOAD(rta);
+ rta_type = rta->rta_type & ~NLA_F_NESTED;
zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
- plen, rta->rta_type, nhm_rta2str(rta->rta_type));
- switch (rta->rta_type & ~NLA_F_NESTED) {
+ plen, rta->rta_type, nhm_rta2str(rta_type));
+ switch (rta_type) {
case NHA_ID:
u32v = *(uint32_t *)RTA_DATA(rta);
zlog_debug(" %u", u32v);
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index 8c8004190b..ae5ce25a70 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -812,6 +812,9 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
case DPLANE_OP_INTF_NETCONFIG:
+ case DPLANE_OP_INTF_INSTALL:
+ case DPLANE_OP_INTF_UPDATE:
+ case DPLANE_OP_INTF_DELETE:
case DPLANE_OP_NONE:
break;
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index a75b165270..748f239db9 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -77,6 +77,7 @@
#include "zebra/netconf_netlink.h"
extern struct zebra_privs_t zserv_privs;
+uint8_t frr_protodown_r_bit = FRR_PROTODOWN_REASON_DEFAULT_BIT;
/* Note: on netlink systems, there should be a 1-to-1 mapping between interface
names and ifindex values. */
@@ -822,6 +823,12 @@ static void netlink_proc_dplane_if_protodown(struct zebra_if *zif,
{
bool zif_protodown;
+ /* Set our reason code to note it wasn't us */
+ if (protodown)
+ zif->protodown_rc |= ZEBRA_PROTODOWN_EXTERNAL;
+ else
+ zif->protodown_rc &= ~ZEBRA_PROTODOWN_EXTERNAL;
+
zif_protodown = !!(zif->flags & ZIF_FLAG_PROTODOWN);
if (protodown == zif_protodown)
return;
@@ -835,7 +842,7 @@ static void netlink_proc_dplane_if_protodown(struct zebra_if *zif,
zlog_debug(
"bond mbr %s re-instate protdown %s in the dplane",
zif->ifp->name, zif_protodown ? "on" : "off");
- netlink_protodown(zif->ifp, zif_protodown);
+ netlink_protodown(zif->ifp, zif_protodown, zif->protodown_rc);
} else {
if (protodown)
zif->flags |= ZIF_FLAG_PROTODOWN;
@@ -1244,6 +1251,41 @@ netlink_put_address_update_msg(struct nl_batch *bth,
false);
}
+static ssize_t netlink_intf_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf,
+ size_t buflen)
+{
+ enum dplane_op_e op;
+ int cmd = 0;
+
+ op = dplane_ctx_get_op(ctx);
+
+ switch (op) {
+ case DPLANE_OP_INTF_UPDATE:
+ cmd = RTM_SETLINK;
+ break;
+ case DPLANE_OP_INTF_INSTALL:
+ cmd = RTM_NEWLINK;
+ break;
+ case DPLANE_OP_INTF_DELETE:
+ cmd = RTM_DELLINK;
+ break;
+ default:
+ flog_err(
+ EC_ZEBRA_NHG_FIB_UPDATE,
+ "Context received for kernel interface update with incorrect OP code (%u)",
+ op);
+ return -1;
+ }
+
+ return netlink_intf_msg_encode(cmd, ctx, buf, buflen);
+}
+
+enum netlink_msg_status
+netlink_put_intf_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx)
+{
+ return netlink_batch_add_msg(bth, ctx, netlink_intf_msg_encoder, false);
+}
+
int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
{
int len;
@@ -2049,9 +2091,78 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
return 0;
}
-int netlink_protodown(struct interface *ifp, bool down)
+/**
+ * Interface encoding helper function.
+ *
+ * \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.
+ */
+
+ssize_t netlink_intf_msg_encode(uint16_t cmd,
+ const struct zebra_dplane_ctx *ctx, void *buf,
+ size_t buflen)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ifinfomsg ifa;
+ char buf[];
+ } *req = buf;
+
+ struct rtattr *nest_protodown_reason;
+ ifindex_t ifindex = dplane_ctx_get_ifindex(ctx);
+ uint32_t r_bitfield = dplane_ctx_get_intf_r_bitfield(ctx);
+ bool down = dplane_ctx_intf_is_protodown(ctx);
+ struct nlsock *nl =
+ kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx));
+
+ if (buflen < sizeof(*req))
+ return 0;
+
+ memset(req, 0, sizeof(*req));
+
+ if (cmd != RTM_SETLINK)
+ flog_err(
+ EC_ZEBRA_INTF_UPDATE_FAILURE,
+ "Only RTM_SETLINK message type currently supported in dplane pthread");
+
+ req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req->n.nlmsg_flags = NLM_F_REQUEST;
+ req->n.nlmsg_type = cmd;
+ req->n.nlmsg_pid = nl->snl.nl_pid;
+
+ req->ifa.ifi_index = ifindex;
+
+ nl_attr_put8(&req->n, buflen, IFLA_PROTO_DOWN, down);
+ nl_attr_put32(&req->n, buflen, IFLA_LINK, ifindex);
+
+ if (r_bitfield) {
+ nest_protodown_reason =
+ nl_attr_nest(&req->n, buflen, IFLA_PROTO_DOWN_REASON);
+
+ if (!nest_protodown_reason)
+ return -1;
+
+ nl_attr_put32(&req->n, buflen, IFLA_PROTO_DOWN_REASON_MASK,
+ (1 << frr_protodown_r_bit));
+ nl_attr_put32(&req->n, buflen, IFLA_PROTO_DOWN_REASON_VALUE,
+ ((int)down) << frr_protodown_r_bit);
+
+ nl_attr_nest_end(&req->n, nest_protodown_reason);
+ }
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: %s, protodown=%d ifindex=%u", __func__,
+ nl_msg_type_to_str(cmd), down, ifindex);
+
+ return NLMSG_ALIGN(req->n.nlmsg_len);
+}
+
+int netlink_protodown(struct interface *ifp, bool down, uint32_t r_bitfield)
{
struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
+ struct rtattr *nest_protodown_reason;
struct {
struct nlmsghdr n;
@@ -2068,9 +2179,24 @@ int netlink_protodown(struct interface *ifp, bool down)
req.ifa.ifi_index = ifp->ifindex;
- nl_attr_put(&req.n, sizeof(req), IFLA_PROTO_DOWN, &down, sizeof(down));
+ nl_attr_put8(&req.n, sizeof(req), IFLA_PROTO_DOWN, down);
nl_attr_put32(&req.n, sizeof(req), IFLA_LINK, ifp->ifindex);
+ if (r_bitfield) {
+ nest_protodown_reason = nl_attr_nest(&req.n, sizeof(req),
+ IFLA_PROTO_DOWN_REASON);
+
+ if (!nest_protodown_reason)
+ return -1;
+
+ nl_attr_put32(&req.n, sizeof(req), IFLA_PROTO_DOWN_REASON_MASK,
+ (1 << frr_protodown_r_bit));
+ nl_attr_put32(&req.n, sizeof(req), IFLA_PROTO_DOWN_REASON_VALUE,
+ ((int)down) << frr_protodown_r_bit);
+
+ nl_attr_nest_end(&req.n, nest_protodown_reason);
+ }
+
return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
false);
}
diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h
index a1ce7af8c7..d5a73bb467 100644
--- a/zebra/if_netlink.h
+++ b/zebra/if_netlink.h
@@ -40,6 +40,9 @@ int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id,
extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
extern int interface_lookup_netlink(struct zebra_ns *zns);
+extern ssize_t netlink_intf_msg_encode(uint16_t cmd,
+ const struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen);
extern enum netlink_msg_status
netlink_put_gre_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
@@ -47,6 +50,11 @@ extern enum netlink_msg_status
netlink_put_address_update_msg(struct nl_batch *bth,
struct zebra_dplane_ctx *ctx);
+extern enum netlink_msg_status
+netlink_put_intf_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
+
+#define FRR_PROTODOWN_REASON_DEFAULT_BIT 7
+#define PROTODOWN_REASON_NUM_BITS 32
/*
* Set protodown status of interface.
*
@@ -56,10 +64,13 @@ netlink_put_address_update_msg(struct nl_batch *bth,
* down
* If true, set protodown on. If false, set protodown off.
*
+ * reason
+ * bitfield representing reason codes
+ *
* Returns:
* 0
*/
-int netlink_protodown(struct interface *ifp, bool down);
+int netlink_protodown(struct interface *ifp, bool down, uint32_t r_bitfield);
#ifdef __cplusplus
}
diff --git a/zebra/interface.c b/zebra/interface.c
index a76f8741e0..d326109c19 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -1229,58 +1229,73 @@ void zebra_if_update_all_links(struct zebra_ns *zns)
}
}
-void zebra_if_set_protodown(struct interface *ifp, bool down)
+int zebra_if_set_protodown(struct interface *ifp, bool new_down,
+ enum protodown_reasons new_reason)
{
+ struct zebra_if *zif;
+ bool old_down;
+ uint32_t new_protodown_rc;
+
+ zif = ifp->info;
+
+ old_down = !!(zif->flags & ZIF_FLAG_PROTODOWN);
+
+ if (new_down)
+ new_protodown_rc = zif->protodown_rc | new_reason;
+ else
+ new_protodown_rc = zif->protodown_rc & ~new_reason;
+
+ /* Early return if already set down & reason bitfield matches */
+ if ((new_down == old_down) && (new_protodown_rc == zif->protodown_rc)) {
+
+ if (IS_ZEBRA_DEBUG_KERNEL) {
+ zlog_debug(
+ "Ignoring %s (%u): protodown %s already set reason: old 0x%x new 0x%x",
+ ifp->name, ifp->ifindex,
+ new_down ? "on" : "off", zif->protodown_rc,
+ new_protodown_rc);
+ return 1;
+ }
+ }
+
+ zlog_info(
+ "Setting interface %s (%u): protodown %s reason: old 0x%x new 0x%x",
+ ifp->name, ifp->ifindex, new_down ? "on" : "off",
+ zif->protodown_rc, new_protodown_rc);
+
+ zif->protodown_rc = new_protodown_rc;
+
#ifdef HAVE_NETLINK
- netlink_protodown(ifp, down);
+ // TODO: remove this as separate commit
+ // netlink_protodown(ifp, new_down, zif->protodown_rc);
+ dplane_intf_update(ifp);
#else
zlog_warn("Protodown is not supported on this platform");
#endif
+ return 0;
}
/*
- * Handle an interface addr event based on info in a dplane context object.
+ * Handle an interface events based on info in a dplane context object.
* This runs in the main pthread, using the info in the context object to
* modify an interface.
*/
-void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx)
+static void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx,
+ struct interface *ifp)
{
- struct interface *ifp;
uint8_t flags = 0;
const char *label = NULL;
- ns_id_t ns_id;
- struct zebra_ns *zns;
uint32_t metric = METRIC_MAX;
- ifindex_t ifindex;
const struct prefix *addr, *dest = NULL;
enum dplane_op_e op;
op = dplane_ctx_get_op(ctx);
- ns_id = dplane_ctx_get_ns_id(ctx);
-
- zns = zebra_ns_lookup(ns_id);
- if (zns == NULL) {
- /* No ns - deleted maybe? */
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("%s: can't find zns id %u", __func__, ns_id);
- goto done;
- }
-
- ifindex = dplane_ctx_get_ifindex(ctx);
-
- ifp = if_lookup_by_index_per_ns(zns, ifindex);
- if (ifp == NULL) {
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("%s: can't find ifp at nsid %u index %d",
- __func__, ns_id, ifindex);
- goto done;
- }
-
addr = dplane_ctx_get_intf_addr(ctx);
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("%s: %s: ifindex %u, addr %pFX", __func__,
- dplane_op2str(op), ifindex, addr);
+ zlog_debug("%s: %s: ifindex %s(%u), addr %pFX", __func__,
+ dplane_op2str(dplane_ctx_get_op(ctx)), ifp->name,
+ ifp->ifindex, addr);
/* Is there a peer or broadcast address? */
dest = dplane_ctx_get_intf_dest(ctx);
@@ -1335,41 +1350,64 @@ void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx)
*/
if (op != DPLANE_OP_INTF_ADDR_ADD)
rib_update(RIB_UPDATE_KERNEL);
+}
-done:
- /* We're responsible for the ctx object */
- dplane_ctx_fini(&ctx);
+static void zebra_if_update_ctx(struct zebra_dplane_ctx *ctx,
+ struct interface *ifp)
+{
+ enum zebra_dplane_result dp_res;
+ struct zebra_if *zif;
+ uint32_t r_bitfield;
+ bool down;
+
+ dp_res = dplane_ctx_get_status(ctx);
+ r_bitfield = dplane_ctx_get_intf_r_bitfield(ctx);
+ down = dplane_ctx_intf_is_protodown(ctx);
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: %s: if %s(%u) ctx-protodown %s ctx-reason 0x%x",
+ __func__, dplane_op2str(dplane_ctx_get_op(ctx)),
+ ifp->name, ifp->ifindex, down ? "on" : "off",
+ r_bitfield);
+
+ zif = ifp->info;
+ if (!zif) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: if %s(%u) zebra info pointer is NULL",
+ __func__, ifp->name, ifp->ifindex);
+ return;
+ }
+
+ if (dp_res != ZEBRA_DPLANE_REQUEST_SUCCESS) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: if %s(%u) dplane update failed",
+ __func__, ifp->name, ifp->ifindex);
+ return;
+ }
+
+ /* Update our info */
+ if (down)
+ zif->flags |= ZIF_FLAG_PROTODOWN;
+ else
+ zif->flags &= ~ZIF_FLAG_PROTODOWN;
}
/*
* Handle netconf change from a dplane context object; runs in the main
* pthread so it can update zebra data structs.
*/
-int zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx)
+static void zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx,
+ struct interface *ifp)
{
- struct zebra_ns *zns;
- struct interface *ifp;
struct zebra_if *zif;
enum dplane_netconf_status_e mpls;
- int ret = 0;
-
- zns = zebra_ns_lookup(dplane_ctx_get_netconf_ns_id(ctx));
- if (zns == NULL) {
- ret = -1;
- goto done;
- }
-
- ifp = if_lookup_by_index_per_ns(zns,
- dplane_ctx_get_netconf_ifindex(ctx));
- if (ifp == NULL) {
- ret = -1;
- goto done;
- }
zif = ifp->info;
- if (zif == NULL) {
- ret = -1;
- goto done;
+ if (!zif) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: if %s(%u) zebra info pointer is NULL",
+ __func__, ifp->name, ifp->ifindex);
+ return;
}
mpls = dplane_ctx_get_netconf_mpls(ctx);
@@ -1383,12 +1421,105 @@ int zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx)
zlog_debug("%s: if %s, ifindex %d, mpls %s",
__func__, ifp->name, ifp->ifindex,
(zif->mpls ? "ON" : "OFF"));
+}
+
+void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx)
+{
+ struct zebra_ns *zns;
+ struct interface *ifp;
+ ns_id_t ns_id;
+ enum dplane_op_e op;
+ enum zebra_dplane_result dp_res;
+ ifindex_t ifindex;
+
+ ns_id = dplane_ctx_get_ns_id(ctx);
+ dp_res = dplane_ctx_get_status(ctx);
+ op = dplane_ctx_get_op(ctx);
+ ifindex = dplane_ctx_get_ifindex(ctx);
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL || IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("Intf dplane ctx %p, op %s, ifindex (%u), result %s",
+ ctx, dplane_op2str(op), ifindex,
+ dplane_res2str(dp_res));
+
+ zns = zebra_ns_lookup(ns_id);
+ if (zns == NULL) {
+ /* No ns - deleted maybe? */
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: can't find zns id %u", __func__, ns_id);
+
+ goto done;
+ }
+ ifp = if_lookup_by_index_per_ns(zns, ifindex);
+ if (ifp == NULL) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("%s: can't find ifp at nsid %u index %d",
+ __func__, ns_id, ifindex);
+
+ goto done;
+ }
+
+ switch (op) {
+ case DPLANE_OP_INTF_ADDR_ADD:
+ case DPLANE_OP_INTF_ADDR_DEL:
+ zebra_if_addr_update_ctx(ctx, ifp);
+ break;
+
+ case DPLANE_OP_INTF_INSTALL:
+ case DPLANE_OP_INTF_UPDATE:
+ case DPLANE_OP_INTF_DELETE:
+ zebra_if_update_ctx(ctx, ifp);
+ break;
+
+ case DPLANE_OP_INTF_NETCONFIG:
+ zebra_if_netconf_update_ctx(ctx, ifp);
+ break;
+
+ case DPLANE_OP_ROUTE_INSTALL:
+ case DPLANE_OP_ROUTE_UPDATE:
+ case DPLANE_OP_ROUTE_DELETE:
+ case DPLANE_OP_NH_DELETE:
+ case DPLANE_OP_NH_INSTALL:
+ case DPLANE_OP_NH_UPDATE:
+ case DPLANE_OP_ROUTE_NOTIFY:
+ case DPLANE_OP_LSP_INSTALL:
+ case DPLANE_OP_LSP_UPDATE:
+ case DPLANE_OP_LSP_DELETE:
+ case DPLANE_OP_LSP_NOTIFY:
+ case DPLANE_OP_PW_INSTALL:
+ case DPLANE_OP_PW_UNINSTALL:
+ case DPLANE_OP_SYS_ROUTE_ADD:
+ case DPLANE_OP_SYS_ROUTE_DELETE:
+ case DPLANE_OP_ADDR_INSTALL:
+ case DPLANE_OP_ADDR_UNINSTALL:
+ case DPLANE_OP_MAC_INSTALL:
+ case DPLANE_OP_MAC_DELETE:
+ case DPLANE_OP_NEIGH_INSTALL:
+ case DPLANE_OP_NEIGH_UPDATE:
+ case DPLANE_OP_NEIGH_DELETE:
+ case DPLANE_OP_NEIGH_IP_INSTALL:
+ case DPLANE_OP_NEIGH_IP_DELETE:
+ case DPLANE_OP_VTEP_ADD:
+ case DPLANE_OP_VTEP_DELETE:
+ case DPLANE_OP_RULE_ADD:
+ case DPLANE_OP_RULE_DELETE:
+ case DPLANE_OP_RULE_UPDATE:
+ case DPLANE_OP_NEIGH_DISCOVER:
+ case DPLANE_OP_BR_PORT_UPDATE:
+ case DPLANE_OP_NONE:
+ case DPLANE_OP_IPTABLE_ADD:
+ case DPLANE_OP_IPTABLE_DELETE:
+ case DPLANE_OP_IPSET_ADD:
+ case DPLANE_OP_IPSET_DELETE:
+ case DPLANE_OP_IPSET_ENTRY_ADD:
+ case DPLANE_OP_IPSET_ENTRY_DELETE:
+ case DPLANE_OP_NEIGH_TABLE_UPDATE:
+ case DPLANE_OP_GRE_SET:
+ break; /* should never hit here */
+ }
done:
- /* Free the context */
dplane_ctx_fini(&ctx);
-
- return ret;
}
/* Dump if address information to vty. */
@@ -1651,8 +1782,8 @@ static void ifs_dump_brief_vty_json(json_object *json, struct vrf *vrf)
}
}
-const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc,
- char *pd_buf, uint32_t pd_buf_len)
+const char *zebra_protodown_rc_str(uint32_t protodown_rc, char *pd_buf,
+ uint32_t pd_buf_len)
{
bool first = true;
@@ -1660,6 +1791,14 @@ const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc,
strlcat(pd_buf, "(", pd_buf_len);
+ if (protodown_rc & ZEBRA_PROTODOWN_EXTERNAL) {
+ if (first)
+ first = false;
+ else
+ strlcat(pd_buf, ",", pd_buf_len);
+ strlcat(pd_buf, "external", pd_buf_len);
+ }
+
if (protodown_rc & ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY) {
if (first)
first = false;
@@ -1669,11 +1808,27 @@ const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc,
}
if (protodown_rc & ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN) {
- if (!first)
+ if (first)
+ first = false;
+ else
strlcat(pd_buf, ",", pd_buf_len);
strlcat(pd_buf, "uplinks-down", pd_buf_len);
}
+ if (protodown_rc & ZEBRA_PROTODOWN_VRRP) {
+ if (first)
+ first = false;
+ else
+ strlcat(pd_buf, ",", pd_buf_len);
+ strlcat(pd_buf, "vrrp", pd_buf_len);
+ }
+
+ if (protodown_rc & ZEBRA_PROTODOWN_SHARP) {
+ if (!first)
+ strlcat(pd_buf, ",", pd_buf_len);
+ strlcat(pd_buf, "sharp", pd_buf_len);
+ }
+
strlcat(pd_buf, ")", pd_buf_len);
return pd_buf;
diff --git a/zebra/interface.h b/zebra/interface.h
index 315a3170d8..2c3784ee15 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -403,7 +403,7 @@ struct zebra_if {
* in the dataplane. This results in a carrier/L1 down on the
* physical device.
*/
- enum protodown_reasons protodown_rc;
+ uint32_t protodown_rc;
/* list of zebra_mac entries using this interface as destination */
struct list *mac_list;
@@ -497,7 +497,8 @@ extern void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id);
extern void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex,
ns_id_t ns_id);
extern void zebra_if_update_all_links(struct zebra_ns *zns);
-extern void zebra_if_set_protodown(struct interface *ifp, bool down);
+extern int zebra_if_set_protodown(struct interface *ifp, bool down,
+ enum protodown_reasons new_reason);
extern int if_ip_address_install(struct interface *ifp, struct prefix *prefix,
const char *label, struct prefix *pp);
extern int if_ipv6_address_install(struct interface *ifp, struct prefix *prefix,
@@ -521,10 +522,9 @@ extern bool if_nhg_dependents_is_empty(const struct interface *ifp);
extern void vrf_add_update(struct vrf *vrfp);
extern void zebra_l2_map_slave_to_bond(struct zebra_if *zif, vrf_id_t vrf);
extern void zebra_l2_unmap_slave_from_bond(struct zebra_if *zif);
-extern const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc,
- char *pd_buf, uint32_t pd_buf_len);
-void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx);
-int zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx);
+extern const char *zebra_protodown_rc_str(uint32_t protodown_rc, char *pd_buf,
+ uint32_t pd_buf_len);
+void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx);
#ifdef HAVE_PROC_NET_DEV
extern void ifstat_update_proc(void);
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index d84b0c1325..60bce6e03f 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -94,6 +94,7 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"},
{RTM_DELROUTE, "RTM_DELROUTE"},
{RTM_GETROUTE, "RTM_GETROUTE"},
{RTM_NEWLINK, "RTM_NEWLINK"},
+ {RTM_SETLINK, "RTM_SETLINK"},
{RTM_DELLINK, "RTM_DELLINK"},
{RTM_GETLINK, "RTM_GETLINK"},
{RTM_NEWADDR, "RTM_NEWADDR"},
@@ -1491,6 +1492,11 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth,
case DPLANE_OP_INTF_NETCONFIG:
case DPLANE_OP_NONE:
return FRR_NETLINK_ERROR;
+
+ case DPLANE_OP_INTF_INSTALL:
+ case DPLANE_OP_INTF_UPDATE:
+ case DPLANE_OP_INTF_DELETE:
+ return netlink_put_intf_update_msg(bth, ctx);
}
return FRR_NETLINK_ERROR;
diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h
index 0a79771708..b1af4b20e1 100644
--- a/zebra/rt_netlink.h
+++ b/zebra/rt_netlink.h
@@ -128,6 +128,8 @@ const char *af_type2str(int type);
const char *ifi_type2str(int type);
const char *rta_type2str(int type);
const char *rtm_type2str(int type);
+const char *ifla_pdr_type2str(int type);
+const char *ifla_info_type2str(int type);
const char *rtm_protocol2str(int type);
const char *rtm_scope2str(int type);
const char *rtm_rta2str(int type);
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 1b6f37ec6a..e94aee5c1a 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1487,6 +1487,7 @@ static void zread_interface_set_protodown(ZAPI_HANDLER_ARGS)
ifindex_t ifindex;
struct interface *ifp;
char down;
+ enum protodown_reasons reason;
STREAM_GETL(msg, ifindex);
STREAM_GETC(msg, down);
@@ -1494,16 +1495,27 @@ static void zread_interface_set_protodown(ZAPI_HANDLER_ARGS)
/* set ifdown */
ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), ifindex);
- if (ifp) {
- zlog_info("Setting interface %s (%u): protodown %s", ifp->name,
- ifindex, down ? "on" : "off");
- zebra_if_set_protodown(ifp, down);
- } else {
+ if (!ifp) {
zlog_warn(
"Cannot set protodown %s for interface %u; does not exist",
down ? "on" : "off", ifindex);
+
+ return;
+ }
+
+ switch (client->proto) {
+ case ZEBRA_ROUTE_VRRP:
+ reason = ZEBRA_PROTODOWN_VRRP;
+ break;
+ case ZEBRA_ROUTE_SHARP:
+ reason = ZEBRA_PROTODOWN_SHARP;
+ break;
+ default:
+ reason = 0;
+ break;
}
+ zebra_if_set_protodown(ifp, down, reason);
stream_failure:
return;
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 6de2be3ab8..abafa6f8fe 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -192,6 +192,9 @@ struct dplane_intf_info {
uint32_t metric;
uint32_t flags;
+ uint32_t r_bitfield;
+
+ bool protodown;
#define DPLANE_INTF_CONNECTED (1 << 0) /* Connected peer, p2p */
#define DPLANE_INTF_SECONDARY (1 << 1)
@@ -526,6 +529,9 @@ static struct zebra_dplane_globals {
_Atomic uint32_t dg_gre_set_in;
_Atomic uint32_t dg_gre_set_errors;
+ _Atomic uint32_t dg_intfs_in;
+ _Atomic uint32_t dg_intf_errors;
+
/* Dataplane pthread */
struct frr_pthread *dg_pthread;
@@ -760,6 +766,9 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_NONE:
case DPLANE_OP_IPSET_ADD:
case DPLANE_OP_IPSET_DELETE:
+ case DPLANE_OP_INTF_INSTALL:
+ case DPLANE_OP_INTF_UPDATE:
+ case DPLANE_OP_INTF_DELETE:
break;
case DPLANE_OP_IPSET_ENTRY_ADD:
@@ -1073,6 +1082,16 @@ const char *dplane_op2str(enum dplane_op_e op)
case DPLANE_OP_INTF_NETCONFIG:
return "INTF_NETCONFIG";
+
+ case DPLANE_OP_INTF_INSTALL:
+ ret = "INTF_INSTALL";
+ break;
+ case DPLANE_OP_INTF_UPDATE:
+ ret = "INTF_UPDATE";
+ break;
+ case DPLANE_OP_INTF_DELETE:
+ ret = "INTF_DELETE";
+ break;
}
return ret;
@@ -1771,6 +1790,28 @@ void dplane_ctx_set_intf_metric(struct zebra_dplane_ctx *ctx, uint32_t metric)
ctx->u.intf.metric = metric;
}
+uint32_t dplane_ctx_get_intf_r_bitfield(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.intf.r_bitfield;
+}
+
+void dplane_ctx_set_intf_r_bitfield(struct zebra_dplane_ctx *ctx,
+ uint32_t r_bitfield)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ ctx->u.intf.r_bitfield = r_bitfield;
+}
+
+bool dplane_ctx_intf_is_protodown(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.intf.protodown;
+}
+
/* Is interface addr p2p? */
bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx)
{
@@ -2638,6 +2679,57 @@ done:
return ret;
}
+/**
+ * dplane_ctx_intf_init() - Initialize a context block for a inteface update
+ *
+ * @ctx: Dataplane context to init
+ * @op: Operation being performed
+ * @ifp: Interface
+ *
+ * Return: Result status
+ */
+int dplane_ctx_intf_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
+ const struct interface *ifp)
+{
+ struct zebra_ns *zns = NULL;
+ struct zebra_if *zif = NULL;
+ int ret = EINVAL;
+
+ if (!ctx || !ifp)
+ goto done;
+
+ ctx->zd_op = op;
+ ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+ ctx->zd_vrf_id = ifp->vrf->vrf_id;
+
+ strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname));
+ ctx->zd_ifindex = ifp->ifindex;
+
+ zns = zebra_ns_lookup(ifp->vrf->vrf_id);
+ dplane_ctx_ns_init(ctx, zns, false);
+
+
+ /* Copy over ifp info */
+ ctx->u.intf.metric = ifp->metric;
+ ctx->u.intf.flags = ifp->flags;
+
+ /* Copy over extra zebra info, if available */
+ zif = (struct zebra_if *)ifp->info;
+
+ if (zif) {
+ ctx->u.intf.r_bitfield = zif->protodown_rc;
+ ctx->u.intf.protodown = !!(zif->flags & ZIF_FLAG_PROTODOWN);
+ }
+
+ dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_INTF_UPDATE));
+ ctx->zd_is_update = (op == DPLANE_OP_INTF_UPDATE);
+
+ ret = AOK;
+
+done:
+ return ret;
+}
+
/*
* Capture information for an LSP update in a dplane context.
*/
@@ -3824,6 +3916,85 @@ static enum zebra_dplane_result intf_addr_update_internal(
return result;
}
+/**
+ * dplane_intf_update_internal() - Helper for enqueuing interface changes
+ *
+ * @ifp: Interface where the change occured
+ * @op: The operation to be enqued
+ *
+ * Return: Result of the change
+ */
+static enum zebra_dplane_result
+dplane_intf_update_internal(const struct interface *ifp, enum dplane_op_e op)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ int ret = EINVAL;
+ struct zebra_dplane_ctx *ctx = NULL;
+
+ /* Obtain context block */
+ ctx = dplane_ctx_alloc();
+ if (!ctx) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = dplane_ctx_intf_init(ctx, op, ifp);
+ if (ret == AOK)
+ ret = dplane_update_enqueue(ctx);
+
+done:
+ /* Update counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_intfs_in, 1,
+ memory_order_relaxed);
+
+ if (ret == AOK)
+ result = ZEBRA_DPLANE_REQUEST_QUEUED;
+ else {
+ atomic_fetch_add_explicit(&zdplane_info.dg_intf_errors, 1,
+ memory_order_relaxed);
+ if (ctx)
+ dplane_ctx_free(&ctx);
+ }
+
+ return result;
+}
+
+/*
+ * Enqueue a interface add for the dataplane.
+ */
+enum zebra_dplane_result dplane_intf_add(const struct interface *ifp)
+{
+ enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
+
+ if (ifp)
+ ret = dplane_intf_update_internal(ifp, DPLANE_OP_INTF_INSTALL);
+ return ret;
+}
+
+/*
+ * Enqueue a interface update for the dataplane.
+ */
+enum zebra_dplane_result dplane_intf_update(const struct interface *ifp)
+{
+ enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
+
+ if (ifp)
+ ret = dplane_intf_update_internal(ifp, DPLANE_OP_INTF_UPDATE);
+ return ret;
+}
+
+/*
+ * Enqueue a interface delete for the dataplane.
+ */
+enum zebra_dplane_result dplane_intf_delete(const struct interface *ifp)
+{
+ enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
+
+ if (ifp)
+ ret = dplane_intf_update_internal(ifp, DPLANE_OP_INTF_DELETE);
+ return ret;
+}
+
/*
* Enqueue vxlan/evpn mac add (or update).
*/
@@ -5241,6 +5412,15 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
dplane_ctx_get_netconf_mpls(ctx),
dplane_ctx_get_netconf_mcast(ctx));
break;
+
+ case DPLANE_OP_INTF_INSTALL:
+ case DPLANE_OP_INTF_UPDATE:
+ case DPLANE_OP_INTF_DELETE:
+ zlog_debug("Dplane intf %s, idx %u, protodown %d",
+ dplane_op2str(dplane_ctx_get_op(ctx)),
+ dplane_ctx_get_ifindex(ctx),
+ dplane_ctx_intf_is_protodown(ctx));
+ break;
}
}
@@ -5375,6 +5555,15 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx)
&zdplane_info.dg_gre_set_errors, 1,
memory_order_relaxed);
break;
+
+ case DPLANE_OP_INTF_INSTALL:
+ case DPLANE_OP_INTF_UPDATE:
+ case DPLANE_OP_INTF_DELETE:
+ if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
+ atomic_fetch_add_explicit(&zdplane_info.dg_intf_errors,
+ 1, memory_order_relaxed);
+ break;
+
/* Ignore 'notifications' - no-op */
case DPLANE_OP_SYS_ROUTE_ADD:
case DPLANE_OP_SYS_ROUTE_DELETE:
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index 29555d5b56..73acf03411 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -188,6 +188,11 @@ enum dplane_op_e {
/* Incoming interface config events */
DPLANE_OP_INTF_NETCONFIG,
+
+ /* Interface update */
+ DPLANE_OP_INTF_INSTALL,
+ DPLANE_OP_INTF_UPDATE,
+ DPLANE_OP_INTF_DELETE,
};
/*
@@ -480,6 +485,10 @@ dplane_ctx_get_pw_backup_nhg(const struct zebra_dplane_ctx *ctx);
/* Accessors for interface information */
uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_set_intf_metric(struct zebra_dplane_ctx *ctx, uint32_t metric);
+uint32_t dplane_ctx_get_intf_r_bitfield(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_intf_r_bitfield(struct zebra_dplane_ctx *ctx,
+ uint32_t r_bitfield);
+bool dplane_ctx_intf_is_protodown(const struct zebra_dplane_ctx *ctx);
/* Is interface addr p2p? */
bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx);
void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx);
@@ -677,6 +686,13 @@ enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp,
const struct connected *ifc);
/*
+ * Enqueue interface link changes for the dataplane.
+ */
+enum zebra_dplane_result dplane_intf_add(const struct interface *ifp);
+enum zebra_dplane_result dplane_intf_update(const struct interface *ifp);
+enum zebra_dplane_result dplane_intf_delete(const struct interface *ifp);
+
+/*
* Link layer operations for the dataplane.
*/
enum zebra_dplane_result dplane_neigh_ip_update(enum dplane_op_e op,
@@ -814,6 +830,10 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
struct nhg_hash_entry *nhe);
+/* Encode interface information into data plane context. */
+int dplane_ctx_intf_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
+ const struct interface *ifp);
+
/* Retrieve the limit on the number of pending, unprocessed updates. */
uint32_t dplane_get_in_queue_limit(void);
diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c
index c3890f7220..7549a3d5c0 100644
--- a/zebra/zebra_errors.c
+++ b/zebra/zebra_errors.c
@@ -792,6 +792,15 @@ static struct log_ref ferr_zebra_err[] = {
.suggestion = "Ignore this error.",
},
{
+ .code = EC_ZEBRA_INTF_UPDATE_FAILURE,
+ .title =
+ "Zebra failed to update interface in the kernel",
+ .description =
+ "Zebra made an attempt to update an interfce in the kernel, but it was not successful.",
+ .suggestion =
+ "Wait for Zebra to reattempt update.",
+ },
+ {
.code = END_FERR,
}
};
diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h
index 540c6dd7d0..5164de09d6 100644
--- a/zebra/zebra_errors.h
+++ b/zebra/zebra_errors.h
@@ -136,6 +136,7 @@ enum zebra_log_refs {
EC_ZEBRA_ES_CREATE,
EC_ZEBRA_GRE_SET_UPDATE,
EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK,
+ EC_ZEBRA_INTF_UPDATE_FAILURE,
};
void zebra_error_init(void);
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index 50eecd31d5..463ede158c 100644
--- a/zebra/zebra_evpn_mh.c
+++ b/zebra/zebra_evpn_mh.c
@@ -3623,10 +3623,10 @@ bool zebra_evpn_is_es_bond_member(struct interface *ifp)
void zebra_evpn_mh_update_protodown_bond_mbr(struct zebra_if *zif, bool clear,
const char *caller)
{
- bool old_protodown;
bool new_protodown;
- enum protodown_reasons old_protodown_rc = 0;
- enum protodown_reasons protodown_rc = 0;
+ uint32_t old_protodown_rc = 0;
+ uint32_t new_protodown_rc = 0;
+ uint32_t protodown_rc = 0;
if (!clear) {
struct zebra_if *bond_zif;
@@ -3635,32 +3635,23 @@ void zebra_evpn_mh_update_protodown_bond_mbr(struct zebra_if *zif, bool clear,
protodown_rc = bond_zif->protodown_rc;
}
- old_protodown = !!(zif->flags & ZIF_FLAG_PROTODOWN);
old_protodown_rc = zif->protodown_rc;
- zif->protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
- zif->protodown_rc |= (protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
- new_protodown = !!zif->protodown_rc;
+ new_protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
+ new_protodown_rc |= (protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
+ new_protodown = !!new_protodown_rc;
- if (IS_ZEBRA_DEBUG_EVPN_MH_ES
- && (zif->protodown_rc != old_protodown_rc))
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES && (new_protodown_rc != old_protodown_rc))
zlog_debug(
"%s bond mbr %s protodown_rc changed; old 0x%x new 0x%x",
caller, zif->ifp->name, old_protodown_rc,
- zif->protodown_rc);
-
- if (old_protodown == new_protodown)
- return;
+ new_protodown_rc);
- if (new_protodown)
- zif->flags |= ZIF_FLAG_PROTODOWN;
- else
- zif->flags &= ~ZIF_FLAG_PROTODOWN;
-
- if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
- zlog_debug("%s protodown %s", zif->ifp->name,
- new_protodown ? "on" : "off");
-
- zebra_if_set_protodown(zif->ifp, new_protodown);
+ if (zebra_if_set_protodown(zif->ifp, new_protodown, new_protodown_rc) ==
+ 0) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+ zlog_debug("%s protodown %s", zif->ifp->name,
+ new_protodown ? "on" : "off");
+ }
}
/* The bond members inherit the protodown reason code from the bond */
@@ -3683,7 +3674,7 @@ static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es,
bool resync_dplane)
{
struct zebra_if *zif;
- enum protodown_reasons old_protodown_rc;
+ uint32_t old_protodown_rc;
zif = es->zif;
/* if the reason code is the same bail unless it is a new
@@ -3714,7 +3705,7 @@ static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es,
static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es *es)
{
struct zebra_if *zif;
- enum protodown_reasons old_protodown_rc;
+ uint32_t old_protodown_rc;
zif = es->zif;
if (!(zif->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL))
@@ -3742,10 +3733,9 @@ static void zebra_evpn_mh_update_protodown_es_all(void)
zebra_evpn_mh_update_protodown_es(es, false /*resync_dplane*/);
}
-static void zebra_evpn_mh_update_protodown(enum protodown_reasons protodown_rc,
- bool set)
+static void zebra_evpn_mh_update_protodown(uint32_t protodown_rc, bool set)
{
- enum protodown_reasons old_protodown_rc = zmh_info->protodown_rc;
+ uint32_t old_protodown_rc = zmh_info->protodown_rc;
if (set) {
if ((protodown_rc & zmh_info->protodown_rc) == protodown_rc)
diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h
index af6832092b..ce7b920de1 100644
--- a/zebra/zebra_evpn_mh.h
+++ b/zebra/zebra_evpn_mh.h
@@ -263,7 +263,7 @@ struct zebra_evpn_mh_info {
uint32_t uplink_oper_up_cnt;
/* These protodown bits are inherited by all ES bonds */
- enum protodown_reasons protodown_rc;
+ uint32_t protodown_rc;
};
/* returns TRUE if the EVPN is ready to be sent to BGP */
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 469a94a65b..1b926dba5f 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -2993,6 +2993,9 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
case DPLANE_OP_INTF_NETCONFIG:
+ case DPLANE_OP_INTF_INSTALL:
+ case DPLANE_OP_INTF_UPDATE:
+ case DPLANE_OP_INTF_DELETE:
break;
}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index e376d4b2af..c6840a503c 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -4318,11 +4318,11 @@ static void rib_process_dplane_results(struct thread *thread)
case DPLANE_OP_INTF_ADDR_ADD:
case DPLANE_OP_INTF_ADDR_DEL:
- zebra_if_addr_update_ctx(ctx);
- break;
-
+ case DPLANE_OP_INTF_INSTALL:
+ case DPLANE_OP_INTF_UPDATE:
+ case DPLANE_OP_INTF_DELETE:
case DPLANE_OP_INTF_NETCONFIG:
- zebra_if_netconf_update_ctx(ctx);
+ zebra_if_dplane_result(ctx);
break;
/* Some op codes not handled here */
diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h
index 63a61d5293..40f7d87980 100644
--- a/zebra/zebra_router.h
+++ b/zebra/zebra_router.h
@@ -68,19 +68,24 @@ enum multicast_mode {
* physical device.
*/
enum protodown_reasons {
+ /* A process outside of FRR's control protodowned the interface */
+ ZEBRA_PROTODOWN_EXTERNAL = (1 << 0),
/* On startup local ESs are held down for some time to
* allow the underlay to converge and EVPN routes to
* get learnt
*/
- ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY = (1 << 0),
+ ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY = (1 << 1),
/* If all the uplinks are down the switch has lost access
* to the VxLAN overlay and must shut down the access
* ports to allow servers to re-direct their traffic to
* other switches on the Ethernet Segment
*/
- ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN = (1 << 1),
- ZEBRA_PROTODOWN_EVPN_ALL = (ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN
- | ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY)
+ ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN = (1 << 2),
+ ZEBRA_PROTODOWN_EVPN_ALL = (ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN |
+ ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY),
+ ZEBRA_PROTODOWN_VRRP = (1 << 3),
+ /* This reason used exclusively for testing */
+ ZEBRA_PROTODOWN_SHARP = (1 << 4)
};
#define ZEBRA_PROTODOWN_RC_STR_LEN 80