forked from Mirror/frr
zebra: add support for protodown reason code
Add support for setting the protodown reason code.
829eb208e8
These patches handle all our netlink code for setting the reason.
For protodown reason we only set `frr` as the reason externally
but internally we have more descriptive reasoning available via
`show interface IFNAME`. The kernel only provides a bitwidth of 32
that all userspace programs have to share so this makes the most sense.
Since this is new functionality, it needs to be added to the dplane
pthread instead. So these patches, also move the protodown setting we
were doing before into the dplane pthread. For this, we abstract it a
bit more to make it a general interface LINK update dplane API. This
API can be expanded to support gernal link creation/updating when/if
someone ever adds that code.
We also move a more common entrypoint for evpn-mh and from zapi clients
like vrrpd. They both call common code now to set our internal flags
for protodown and protodown reason.
Also add debugging code for dumping netlink packets with
protodown/protodown_reason.
Signed-off-by: Stephen Worley <sworley@nvidia.com>
This commit is contained in:
parent
8e23507a63
commit
5d41413833
110
zebra/debug_nl.c
110
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)
|
const char *rta_type2str(int type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -358,6 +392,8 @@ const char *rta_type2str(int type)
|
||||||
case IFLA_EVENT:
|
case IFLA_EVENT:
|
||||||
return "EVENT";
|
return "EVENT";
|
||||||
#endif /* IFLA_EVENT */
|
#endif /* IFLA_EVENT */
|
||||||
|
case IFLA_PROTO_DOWN_REASON:
|
||||||
|
return "PROTO_DOWN_REASON";
|
||||||
default:
|
default:
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
|
@ -838,6 +874,42 @@ const char *nh_flags2str(uint32_t flags, char *buf, size_t buflen)
|
||||||
/*
|
/*
|
||||||
* Netlink abstractions.
|
* 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)
|
static void nllink_linkinfo_dump(struct rtattr *rta, size_t msglen)
|
||||||
{
|
{
|
||||||
size_t plen;
|
size_t plen;
|
||||||
|
@ -851,7 +923,7 @@ next_rta:
|
||||||
plen = RTA_PAYLOAD(rta);
|
plen = RTA_PAYLOAD(rta);
|
||||||
zlog_debug(" linkinfo [len=%d (payload=%zu) type=(%d) %s]",
|
zlog_debug(" linkinfo [len=%d (payload=%zu) type=(%d) %s]",
|
||||||
rta->rta_len, plen, rta->rta_type,
|
rta->rta_len, plen, rta->rta_type,
|
||||||
rta_type2str(rta->rta_type));
|
ifla_info_type2str(rta->rta_type));
|
||||||
switch (rta->rta_type) {
|
switch (rta->rta_type) {
|
||||||
case IFLA_INFO_KIND:
|
case IFLA_INFO_KIND:
|
||||||
if (plen == 0) {
|
if (plen == 0) {
|
||||||
|
@ -888,8 +960,10 @@ static void nllink_dump(struct ifinfomsg *ifi, size_t msglen)
|
||||||
struct rtattr *rta;
|
struct rtattr *rta;
|
||||||
size_t plen, it;
|
size_t plen, it;
|
||||||
uint32_t u32v;
|
uint32_t u32v;
|
||||||
|
uint8_t u8v;
|
||||||
char bytestr[16];
|
char bytestr[16];
|
||||||
char dbuf[128];
|
char dbuf[128];
|
||||||
|
unsigned short rta_type;
|
||||||
|
|
||||||
/* Get the first attribute and go from there. */
|
/* Get the first attribute and go from there. */
|
||||||
rta = IFLA_RTA(ifi);
|
rta = IFLA_RTA(ifi);
|
||||||
|
@ -899,10 +973,10 @@ next_rta:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
plen = RTA_PAYLOAD(rta);
|
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,
|
zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
|
||||||
plen, rta->rta_type, rta_type2str(rta->rta_type));
|
plen, rta_type, rta_type2str(rta_type));
|
||||||
switch (rta->rta_type) {
|
switch (rta_type) {
|
||||||
case IFLA_IFNAME:
|
|
||||||
case IFLA_IFALIAS:
|
case IFLA_IFALIAS:
|
||||||
if (plen == 0) {
|
if (plen == 0) {
|
||||||
zlog_debug(" invalid length");
|
zlog_debug(" invalid length");
|
||||||
|
@ -927,6 +1001,7 @@ next_rta:
|
||||||
#endif /* IFLA_GSO_MAX_SIZE */
|
#endif /* IFLA_GSO_MAX_SIZE */
|
||||||
case IFLA_CARRIER_CHANGES:
|
case IFLA_CARRIER_CHANGES:
|
||||||
case IFLA_MASTER:
|
case IFLA_MASTER:
|
||||||
|
case IFLA_LINK:
|
||||||
if (plen < sizeof(uint32_t)) {
|
if (plen < sizeof(uint32_t)) {
|
||||||
zlog_debug(" invalid length");
|
zlog_debug(" invalid length");
|
||||||
break;
|
break;
|
||||||
|
@ -936,6 +1011,15 @@ next_rta:
|
||||||
zlog_debug(" %u", u32v);
|
zlog_debug(" %u", u32v);
|
||||||
break;
|
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:
|
case IFLA_ADDRESS:
|
||||||
datap = RTA_DATA(rta);
|
datap = RTA_DATA(rta);
|
||||||
dbuf[0] = 0;
|
dbuf[0] = 0;
|
||||||
|
@ -952,7 +1036,11 @@ next_rta:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IFLA_LINKINFO:
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1027,6 +1115,7 @@ static void nlneigh_dump(struct ndmsg *ndm, size_t msglen)
|
||||||
uint16_t vid;
|
uint16_t vid;
|
||||||
char bytestr[16];
|
char bytestr[16];
|
||||||
char dbuf[128];
|
char dbuf[128];
|
||||||
|
unsigned short rta_type;
|
||||||
|
|
||||||
#ifndef NDA_RTA
|
#ifndef NDA_RTA
|
||||||
#define NDA_RTA(ndm) \
|
#define NDA_RTA(ndm) \
|
||||||
|
@ -1043,9 +1132,10 @@ next_rta:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
plen = RTA_PAYLOAD(rta);
|
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,
|
zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
|
||||||
plen, rta->rta_type, neigh_rta2str(rta->rta_type));
|
plen, rta->rta_type, neigh_rta2str(rta_type));
|
||||||
switch (rta->rta_type & ~ NLA_F_NESTED) {
|
switch (rta_type) {
|
||||||
case NDA_LLADDR:
|
case NDA_LLADDR:
|
||||||
datap = RTA_DATA(rta);
|
datap = RTA_DATA(rta);
|
||||||
dbuf[0] = 0;
|
dbuf[0] = 0;
|
||||||
|
@ -1153,6 +1243,7 @@ static void nlnh_dump(struct nhmsg *nhm, size_t msglen)
|
||||||
uint32_t u32v;
|
uint32_t u32v;
|
||||||
unsigned long count, i;
|
unsigned long count, i;
|
||||||
struct nexthop_grp *nhgrp;
|
struct nexthop_grp *nhgrp;
|
||||||
|
unsigned short rta_type;
|
||||||
|
|
||||||
rta = RTM_NHA(nhm);
|
rta = RTM_NHA(nhm);
|
||||||
|
|
||||||
|
@ -1162,9 +1253,10 @@ next_rta:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
plen = RTA_PAYLOAD(rta);
|
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,
|
zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
|
||||||
plen, rta->rta_type, nhm_rta2str(rta->rta_type));
|
plen, rta->rta_type, nhm_rta2str(rta_type));
|
||||||
switch (rta->rta_type & ~NLA_F_NESTED) {
|
switch (rta_type) {
|
||||||
case NHA_ID:
|
case NHA_ID:
|
||||||
u32v = *(uint32_t *)RTA_DATA(rta);
|
u32v = *(uint32_t *)RTA_DATA(rta);
|
||||||
zlog_debug(" %u", u32v);
|
zlog_debug(" %u", u32v);
|
||||||
|
|
|
@ -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_ADD:
|
||||||
case DPLANE_OP_INTF_ADDR_DEL:
|
case DPLANE_OP_INTF_ADDR_DEL:
|
||||||
case DPLANE_OP_INTF_NETCONFIG:
|
case DPLANE_OP_INTF_NETCONFIG:
|
||||||
|
case DPLANE_OP_INTF_INSTALL:
|
||||||
|
case DPLANE_OP_INTF_UPDATE:
|
||||||
|
case DPLANE_OP_INTF_DELETE:
|
||||||
case DPLANE_OP_NONE:
|
case DPLANE_OP_NONE:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,7 @@
|
||||||
#include "zebra/netconf_netlink.h"
|
#include "zebra/netconf_netlink.h"
|
||||||
|
|
||||||
extern struct zebra_privs_t zserv_privs;
|
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
|
/* Note: on netlink systems, there should be a 1-to-1 mapping between interface
|
||||||
names and ifindex values. */
|
names and ifindex values. */
|
||||||
|
@ -822,6 +823,12 @@ static void netlink_proc_dplane_if_protodown(struct zebra_if *zif,
|
||||||
{
|
{
|
||||||
bool zif_protodown;
|
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);
|
zif_protodown = !!(zif->flags & ZIF_FLAG_PROTODOWN);
|
||||||
if (protodown == zif_protodown)
|
if (protodown == zif_protodown)
|
||||||
return;
|
return;
|
||||||
|
@ -835,7 +842,7 @@ static void netlink_proc_dplane_if_protodown(struct zebra_if *zif,
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
"bond mbr %s re-instate protdown %s in the dplane",
|
"bond mbr %s re-instate protdown %s in the dplane",
|
||||||
zif->ifp->name, zif_protodown ? "on" : "off");
|
zif->ifp->name, zif_protodown ? "on" : "off");
|
||||||
netlink_protodown(zif->ifp, zif_protodown);
|
netlink_protodown(zif->ifp, zif_protodown, zif->protodown_rc);
|
||||||
} else {
|
} else {
|
||||||
if (protodown)
|
if (protodown)
|
||||||
zif->flags |= ZIF_FLAG_PROTODOWN;
|
zif->flags |= ZIF_FLAG_PROTODOWN;
|
||||||
|
@ -1244,6 +1251,41 @@ netlink_put_address_update_msg(struct nl_batch *bth,
|
||||||
false);
|
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 netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
@ -2049,9 +2091,78 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||||
return 0;
|
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 zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
|
||||||
|
struct rtattr *nest_protodown_reason;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct nlmsghdr n;
|
struct nlmsghdr n;
|
||||||
|
@ -2068,9 +2179,24 @@ int netlink_protodown(struct interface *ifp, bool down)
|
||||||
|
|
||||||
req.ifa.ifi_index = ifp->ifindex;
|
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);
|
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,
|
return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
|
||||||
extern int interface_lookup_netlink(struct zebra_ns *zns);
|
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
|
extern enum netlink_msg_status
|
||||||
netlink_put_gre_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx);
|
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,
|
netlink_put_address_update_msg(struct nl_batch *bth,
|
||||||
struct zebra_dplane_ctx *ctx);
|
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.
|
* Set protodown status of interface.
|
||||||
*
|
*
|
||||||
|
@ -56,10 +64,13 @@ netlink_put_address_update_msg(struct nl_batch *bth,
|
||||||
* down
|
* down
|
||||||
* If true, set protodown on. If false, set protodown off.
|
* If true, set protodown on. If false, set protodown off.
|
||||||
*
|
*
|
||||||
|
* reason
|
||||||
|
* bitfield representing reason codes
|
||||||
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* 0
|
* 0
|
||||||
*/
|
*/
|
||||||
int netlink_protodown(struct interface *ifp, bool down);
|
int netlink_protodown(struct interface *ifp, bool down, uint32_t r_bitfield);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
#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
|
#else
|
||||||
zlog_warn("Protodown is not supported on this platform");
|
zlog_warn("Protodown is not supported on this platform");
|
||||||
#endif
|
#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
|
* This runs in the main pthread, using the info in the context object to
|
||||||
* modify an interface.
|
* 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;
|
uint8_t flags = 0;
|
||||||
const char *label = NULL;
|
const char *label = NULL;
|
||||||
ns_id_t ns_id;
|
|
||||||
struct zebra_ns *zns;
|
|
||||||
uint32_t metric = METRIC_MAX;
|
uint32_t metric = METRIC_MAX;
|
||||||
ifindex_t ifindex;
|
|
||||||
const struct prefix *addr, *dest = NULL;
|
const struct prefix *addr, *dest = NULL;
|
||||||
enum dplane_op_e op;
|
enum dplane_op_e op;
|
||||||
|
|
||||||
op = dplane_ctx_get_op(ctx);
|
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);
|
addr = dplane_ctx_get_intf_addr(ctx);
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||||
zlog_debug("%s: %s: ifindex %u, addr %pFX", __func__,
|
zlog_debug("%s: %s: ifindex %s(%u), addr %pFX", __func__,
|
||||||
dplane_op2str(op), ifindex, addr);
|
dplane_op2str(dplane_ctx_get_op(ctx)), ifp->name,
|
||||||
|
ifp->ifindex, addr);
|
||||||
|
|
||||||
/* Is there a peer or broadcast address? */
|
/* Is there a peer or broadcast address? */
|
||||||
dest = dplane_ctx_get_intf_dest(ctx);
|
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)
|
if (op != DPLANE_OP_INTF_ADDR_ADD)
|
||||||
rib_update(RIB_UPDATE_KERNEL);
|
rib_update(RIB_UPDATE_KERNEL);
|
||||||
|
}
|
||||||
|
|
||||||
done:
|
static void zebra_if_update_ctx(struct zebra_dplane_ctx *ctx,
|
||||||
/* We're responsible for the ctx object */
|
struct interface *ifp)
|
||||||
dplane_ctx_fini(&ctx);
|
{
|
||||||
|
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
|
* Handle netconf change from a dplane context object; runs in the main
|
||||||
* pthread so it can update zebra data structs.
|
* 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;
|
struct zebra_if *zif;
|
||||||
enum dplane_netconf_status_e mpls;
|
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;
|
zif = ifp->info;
|
||||||
if (zif == NULL) {
|
if (!zif) {
|
||||||
ret = -1;
|
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||||
goto done;
|
zlog_debug("%s: if %s(%u) zebra info pointer is NULL",
|
||||||
|
__func__, ifp->name, ifp->ifindex);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mpls = dplane_ctx_get_netconf_mpls(ctx);
|
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",
|
zlog_debug("%s: if %s, ifindex %d, mpls %s",
|
||||||
__func__, ifp->name, ifp->ifindex,
|
__func__, ifp->name, ifp->ifindex,
|
||||||
(zif->mpls ? "ON" : "OFF"));
|
(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:
|
done:
|
||||||
/* Free the context */
|
|
||||||
dplane_ctx_fini(&ctx);
|
dplane_ctx_fini(&ctx);
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dump if address information to vty. */
|
/* 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,
|
const char *zebra_protodown_rc_str(uint32_t protodown_rc, char *pd_buf,
|
||||||
char *pd_buf, uint32_t pd_buf_len)
|
uint32_t pd_buf_len)
|
||||||
{
|
{
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
|
@ -1660,6 +1791,14 @@ const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc,
|
||||||
|
|
||||||
strlcat(pd_buf, "(", pd_buf_len);
|
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 (protodown_rc & ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY) {
|
||||||
if (first)
|
if (first)
|
||||||
first = false;
|
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 (protodown_rc & ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN) {
|
||||||
if (!first)
|
if (first)
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
strlcat(pd_buf, ",", pd_buf_len);
|
strlcat(pd_buf, ",", pd_buf_len);
|
||||||
strlcat(pd_buf, "uplinks-down", 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);
|
strlcat(pd_buf, ")", pd_buf_len);
|
||||||
|
|
||||||
return pd_buf;
|
return pd_buf;
|
||||||
|
|
|
@ -403,7 +403,7 @@ struct zebra_if {
|
||||||
* in the dataplane. This results in a carrier/L1 down on the
|
* in the dataplane. This results in a carrier/L1 down on the
|
||||||
* physical device.
|
* physical device.
|
||||||
*/
|
*/
|
||||||
enum protodown_reasons protodown_rc;
|
uint32_t protodown_rc;
|
||||||
|
|
||||||
/* list of zebra_mac entries using this interface as destination */
|
/* list of zebra_mac entries using this interface as destination */
|
||||||
struct list *mac_list;
|
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,
|
extern void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex,
|
||||||
ns_id_t ns_id);
|
ns_id_t ns_id);
|
||||||
extern void zebra_if_update_all_links(struct zebra_ns *zns);
|
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,
|
extern int if_ip_address_install(struct interface *ifp, struct prefix *prefix,
|
||||||
const char *label, struct prefix *pp);
|
const char *label, struct prefix *pp);
|
||||||
extern int if_ipv6_address_install(struct interface *ifp, struct prefix *prefix,
|
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 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_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 void zebra_l2_unmap_slave_from_bond(struct zebra_if *zif);
|
||||||
extern const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc,
|
extern const char *zebra_protodown_rc_str(uint32_t protodown_rc, char *pd_buf,
|
||||||
char *pd_buf, uint32_t pd_buf_len);
|
uint32_t pd_buf_len);
|
||||||
void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx);
|
void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx);
|
||||||
int zebra_if_netconf_update_ctx(struct zebra_dplane_ctx *ctx);
|
|
||||||
|
|
||||||
#ifdef HAVE_PROC_NET_DEV
|
#ifdef HAVE_PROC_NET_DEV
|
||||||
extern void ifstat_update_proc(void);
|
extern void ifstat_update_proc(void);
|
||||||
|
|
|
@ -94,6 +94,7 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"},
|
||||||
{RTM_DELROUTE, "RTM_DELROUTE"},
|
{RTM_DELROUTE, "RTM_DELROUTE"},
|
||||||
{RTM_GETROUTE, "RTM_GETROUTE"},
|
{RTM_GETROUTE, "RTM_GETROUTE"},
|
||||||
{RTM_NEWLINK, "RTM_NEWLINK"},
|
{RTM_NEWLINK, "RTM_NEWLINK"},
|
||||||
|
{RTM_SETLINK, "RTM_SETLINK"},
|
||||||
{RTM_DELLINK, "RTM_DELLINK"},
|
{RTM_DELLINK, "RTM_DELLINK"},
|
||||||
{RTM_GETLINK, "RTM_GETLINK"},
|
{RTM_GETLINK, "RTM_GETLINK"},
|
||||||
{RTM_NEWADDR, "RTM_NEWADDR"},
|
{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_INTF_NETCONFIG:
|
||||||
case DPLANE_OP_NONE:
|
case DPLANE_OP_NONE:
|
||||||
return FRR_NETLINK_ERROR;
|
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;
|
return FRR_NETLINK_ERROR;
|
||||||
|
|
|
@ -128,6 +128,8 @@ const char *af_type2str(int type);
|
||||||
const char *ifi_type2str(int type);
|
const char *ifi_type2str(int type);
|
||||||
const char *rta_type2str(int type);
|
const char *rta_type2str(int type);
|
||||||
const char *rtm_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_protocol2str(int type);
|
||||||
const char *rtm_scope2str(int type);
|
const char *rtm_scope2str(int type);
|
||||||
const char *rtm_rta2str(int type);
|
const char *rtm_rta2str(int type);
|
||||||
|
|
|
@ -1487,6 +1487,7 @@ static void zread_interface_set_protodown(ZAPI_HANDLER_ARGS)
|
||||||
ifindex_t ifindex;
|
ifindex_t ifindex;
|
||||||
struct interface *ifp;
|
struct interface *ifp;
|
||||||
char down;
|
char down;
|
||||||
|
enum protodown_reasons reason;
|
||||||
|
|
||||||
STREAM_GETL(msg, ifindex);
|
STREAM_GETL(msg, ifindex);
|
||||||
STREAM_GETC(msg, down);
|
STREAM_GETC(msg, down);
|
||||||
|
@ -1494,16 +1495,27 @@ static void zread_interface_set_protodown(ZAPI_HANDLER_ARGS)
|
||||||
/* set ifdown */
|
/* set ifdown */
|
||||||
ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), ifindex);
|
ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), ifindex);
|
||||||
|
|
||||||
if (ifp) {
|
if (!ifp) {
|
||||||
zlog_info("Setting interface %s (%u): protodown %s", ifp->name,
|
|
||||||
ifindex, down ? "on" : "off");
|
|
||||||
zebra_if_set_protodown(ifp, down);
|
|
||||||
} else {
|
|
||||||
zlog_warn(
|
zlog_warn(
|
||||||
"Cannot set protodown %s for interface %u; does not exist",
|
"Cannot set protodown %s for interface %u; does not exist",
|
||||||
down ? "on" : "off", ifindex);
|
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:
|
stream_failure:
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -192,6 +192,9 @@ struct dplane_intf_info {
|
||||||
|
|
||||||
uint32_t metric;
|
uint32_t metric;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
uint32_t r_bitfield;
|
||||||
|
|
||||||
|
bool protodown;
|
||||||
|
|
||||||
#define DPLANE_INTF_CONNECTED (1 << 0) /* Connected peer, p2p */
|
#define DPLANE_INTF_CONNECTED (1 << 0) /* Connected peer, p2p */
|
||||||
#define DPLANE_INTF_SECONDARY (1 << 1)
|
#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_in;
|
||||||
_Atomic uint32_t dg_gre_set_errors;
|
_Atomic uint32_t dg_gre_set_errors;
|
||||||
|
|
||||||
|
_Atomic uint32_t dg_intfs_in;
|
||||||
|
_Atomic uint32_t dg_intf_errors;
|
||||||
|
|
||||||
/* Dataplane pthread */
|
/* Dataplane pthread */
|
||||||
struct frr_pthread *dg_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_NONE:
|
||||||
case DPLANE_OP_IPSET_ADD:
|
case DPLANE_OP_IPSET_ADD:
|
||||||
case DPLANE_OP_IPSET_DELETE:
|
case DPLANE_OP_IPSET_DELETE:
|
||||||
|
case DPLANE_OP_INTF_INSTALL:
|
||||||
|
case DPLANE_OP_INTF_UPDATE:
|
||||||
|
case DPLANE_OP_INTF_DELETE:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DPLANE_OP_IPSET_ENTRY_ADD:
|
case DPLANE_OP_IPSET_ENTRY_ADD:
|
||||||
|
@ -1073,6 +1082,16 @@ const char *dplane_op2str(enum dplane_op_e op)
|
||||||
|
|
||||||
case DPLANE_OP_INTF_NETCONFIG:
|
case DPLANE_OP_INTF_NETCONFIG:
|
||||||
return "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;
|
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;
|
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? */
|
/* Is interface addr p2p? */
|
||||||
bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx)
|
bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx)
|
||||||
{
|
{
|
||||||
|
@ -2638,6 +2679,57 @@ done:
|
||||||
return ret;
|
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.
|
* 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;
|
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).
|
* 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_mpls(ctx),
|
||||||
dplane_ctx_get_netconf_mcast(ctx));
|
dplane_ctx_get_netconf_mcast(ctx));
|
||||||
break;
|
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,
|
&zdplane_info.dg_gre_set_errors, 1,
|
||||||
memory_order_relaxed);
|
memory_order_relaxed);
|
||||||
break;
|
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 */
|
/* Ignore 'notifications' - no-op */
|
||||||
case DPLANE_OP_SYS_ROUTE_ADD:
|
case DPLANE_OP_SYS_ROUTE_ADD:
|
||||||
case DPLANE_OP_SYS_ROUTE_DELETE:
|
case DPLANE_OP_SYS_ROUTE_DELETE:
|
||||||
|
|
|
@ -188,6 +188,11 @@ enum dplane_op_e {
|
||||||
|
|
||||||
/* Incoming interface config events */
|
/* Incoming interface config events */
|
||||||
DPLANE_OP_INTF_NETCONFIG,
|
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 */
|
/* Accessors for interface information */
|
||||||
uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx);
|
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);
|
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? */
|
/* Is interface addr p2p? */
|
||||||
bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx);
|
bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx);
|
||||||
void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx);
|
void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx);
|
||||||
|
@ -676,6 +685,13 @@ enum zebra_dplane_result dplane_intf_addr_set(const struct interface *ifp,
|
||||||
enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp,
|
enum zebra_dplane_result dplane_intf_addr_unset(const struct interface *ifp,
|
||||||
const struct connected *ifc);
|
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.
|
* Link layer operations for the dataplane.
|
||||||
*/
|
*/
|
||||||
|
@ -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,
|
int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
|
||||||
struct nhg_hash_entry *nhe);
|
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. */
|
/* Retrieve the limit on the number of pending, unprocessed updates. */
|
||||||
uint32_t dplane_get_in_queue_limit(void);
|
uint32_t dplane_get_in_queue_limit(void);
|
||||||
|
|
||||||
|
|
|
@ -791,6 +791,15 @@ static struct log_ref ferr_zebra_err[] = {
|
||||||
.description = "Zebra's srv6-locator chunk cleanup procedure ran, but no srv6 locator chunks were released.",
|
.description = "Zebra's srv6-locator chunk cleanup procedure ran, but no srv6 locator chunks were released.",
|
||||||
.suggestion = "Ignore this error.",
|
.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,
|
.code = END_FERR,
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,6 +136,7 @@ enum zebra_log_refs {
|
||||||
EC_ZEBRA_ES_CREATE,
|
EC_ZEBRA_ES_CREATE,
|
||||||
EC_ZEBRA_GRE_SET_UPDATE,
|
EC_ZEBRA_GRE_SET_UPDATE,
|
||||||
EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK,
|
EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK,
|
||||||
|
EC_ZEBRA_INTF_UPDATE_FAILURE,
|
||||||
};
|
};
|
||||||
|
|
||||||
void zebra_error_init(void);
|
void zebra_error_init(void);
|
||||||
|
|
|
@ -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,
|
void zebra_evpn_mh_update_protodown_bond_mbr(struct zebra_if *zif, bool clear,
|
||||||
const char *caller)
|
const char *caller)
|
||||||
{
|
{
|
||||||
bool old_protodown;
|
|
||||||
bool new_protodown;
|
bool new_protodown;
|
||||||
enum protodown_reasons old_protodown_rc = 0;
|
uint32_t old_protodown_rc = 0;
|
||||||
enum protodown_reasons protodown_rc = 0;
|
uint32_t new_protodown_rc = 0;
|
||||||
|
uint32_t protodown_rc = 0;
|
||||||
|
|
||||||
if (!clear) {
|
if (!clear) {
|
||||||
struct zebra_if *bond_zif;
|
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;
|
protodown_rc = bond_zif->protodown_rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
old_protodown = !!(zif->flags & ZIF_FLAG_PROTODOWN);
|
|
||||||
old_protodown_rc = zif->protodown_rc;
|
old_protodown_rc = zif->protodown_rc;
|
||||||
zif->protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
|
new_protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
|
||||||
zif->protodown_rc |= (protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
|
new_protodown_rc |= (protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
|
||||||
new_protodown = !!zif->protodown_rc;
|
new_protodown = !!new_protodown_rc;
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES
|
if (IS_ZEBRA_DEBUG_EVPN_MH_ES && (new_protodown_rc != old_protodown_rc))
|
||||||
&& (zif->protodown_rc != old_protodown_rc))
|
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
"%s bond mbr %s protodown_rc changed; old 0x%x new 0x%x",
|
"%s bond mbr %s protodown_rc changed; old 0x%x new 0x%x",
|
||||||
caller, zif->ifp->name, old_protodown_rc,
|
caller, zif->ifp->name, old_protodown_rc,
|
||||||
zif->protodown_rc);
|
new_protodown_rc);
|
||||||
|
|
||||||
if (old_protodown == new_protodown)
|
if (zebra_if_set_protodown(zif->ifp, new_protodown, new_protodown_rc) ==
|
||||||
return;
|
0) {
|
||||||
|
if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
|
||||||
if (new_protodown)
|
zlog_debug("%s protodown %s", zif->ifp->name,
|
||||||
zif->flags |= ZIF_FLAG_PROTODOWN;
|
new_protodown ? "on" : "off");
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The bond members inherit the protodown reason code from the bond */
|
/* 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)
|
bool resync_dplane)
|
||||||
{
|
{
|
||||||
struct zebra_if *zif;
|
struct zebra_if *zif;
|
||||||
enum protodown_reasons old_protodown_rc;
|
uint32_t old_protodown_rc;
|
||||||
|
|
||||||
zif = es->zif;
|
zif = es->zif;
|
||||||
/* if the reason code is the same bail unless it is a new
|
/* 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)
|
static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es *es)
|
||||||
{
|
{
|
||||||
struct zebra_if *zif;
|
struct zebra_if *zif;
|
||||||
enum protodown_reasons old_protodown_rc;
|
uint32_t old_protodown_rc;
|
||||||
|
|
||||||
zif = es->zif;
|
zif = es->zif;
|
||||||
if (!(zif->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL))
|
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*/);
|
zebra_evpn_mh_update_protodown_es(es, false /*resync_dplane*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zebra_evpn_mh_update_protodown(enum protodown_reasons protodown_rc,
|
static void zebra_evpn_mh_update_protodown(uint32_t protodown_rc, bool set)
|
||||||
bool set)
|
|
||||||
{
|
{
|
||||||
enum protodown_reasons old_protodown_rc = zmh_info->protodown_rc;
|
uint32_t old_protodown_rc = zmh_info->protodown_rc;
|
||||||
|
|
||||||
if (set) {
|
if (set) {
|
||||||
if ((protodown_rc & zmh_info->protodown_rc) == protodown_rc)
|
if ((protodown_rc & zmh_info->protodown_rc) == protodown_rc)
|
||||||
|
|
|
@ -263,7 +263,7 @@ struct zebra_evpn_mh_info {
|
||||||
uint32_t uplink_oper_up_cnt;
|
uint32_t uplink_oper_up_cnt;
|
||||||
|
|
||||||
/* These protodown bits are inherited by all ES bonds */
|
/* 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 */
|
/* returns TRUE if the EVPN is ready to be sent to BGP */
|
||||||
|
|
|
@ -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_ADD:
|
||||||
case DPLANE_OP_INTF_ADDR_DEL:
|
case DPLANE_OP_INTF_ADDR_DEL:
|
||||||
case DPLANE_OP_INTF_NETCONFIG:
|
case DPLANE_OP_INTF_NETCONFIG:
|
||||||
|
case DPLANE_OP_INTF_INSTALL:
|
||||||
|
case DPLANE_OP_INTF_UPDATE:
|
||||||
|
case DPLANE_OP_INTF_DELETE:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4318,11 +4318,11 @@ static void rib_process_dplane_results(struct thread *thread)
|
||||||
|
|
||||||
case DPLANE_OP_INTF_ADDR_ADD:
|
case DPLANE_OP_INTF_ADDR_ADD:
|
||||||
case DPLANE_OP_INTF_ADDR_DEL:
|
case DPLANE_OP_INTF_ADDR_DEL:
|
||||||
zebra_if_addr_update_ctx(ctx);
|
case DPLANE_OP_INTF_INSTALL:
|
||||||
break;
|
case DPLANE_OP_INTF_UPDATE:
|
||||||
|
case DPLANE_OP_INTF_DELETE:
|
||||||
case DPLANE_OP_INTF_NETCONFIG:
|
case DPLANE_OP_INTF_NETCONFIG:
|
||||||
zebra_if_netconf_update_ctx(ctx);
|
zebra_if_dplane_result(ctx);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Some op codes not handled here */
|
/* Some op codes not handled here */
|
||||||
|
|
|
@ -68,19 +68,24 @@ enum multicast_mode {
|
||||||
* physical device.
|
* physical device.
|
||||||
*/
|
*/
|
||||||
enum protodown_reasons {
|
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
|
/* On startup local ESs are held down for some time to
|
||||||
* allow the underlay to converge and EVPN routes to
|
* allow the underlay to converge and EVPN routes to
|
||||||
* get learnt
|
* 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
|
/* If all the uplinks are down the switch has lost access
|
||||||
* to the VxLAN overlay and must shut down the access
|
* to the VxLAN overlay and must shut down the access
|
||||||
* ports to allow servers to re-direct their traffic to
|
* ports to allow servers to re-direct their traffic to
|
||||||
* other switches on the Ethernet Segment
|
* other switches on the Ethernet Segment
|
||||||
*/
|
*/
|
||||||
ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN = (1 << 1),
|
ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN = (1 << 2),
|
||||||
ZEBRA_PROTODOWN_EVPN_ALL = (ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN
|
ZEBRA_PROTODOWN_EVPN_ALL = (ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN |
|
||||||
| ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY)
|
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
|
#define ZEBRA_PROTODOWN_RC_STR_LEN 80
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue