mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 17:01:51 +00:00
Merge pull request #10427 from sworleys/Protodown-Reason-Upstream
Add Support for Setting Protodown Reason Code
This commit is contained in:
commit
5d97021ba3
@ -296,3 +296,7 @@ keyword. At present, no sharp commands will be preserved in the config.
|
||||
|
||||
router# show sharp segment-routing srv6
|
||||
(nothing)
|
||||
|
||||
.. clicmd:: sharp interface IFNAME protodown
|
||||
|
||||
Set an interface protodown.
|
||||
|
@ -255,6 +255,17 @@ Link Parameters Commands
|
||||
for InterASv2 link in OSPF (RFC5392). Note that this option is not yet
|
||||
supported for ISIS (RFC5316).
|
||||
|
||||
Global Commands
|
||||
------------------------
|
||||
|
||||
.. clicmd:: zebra protodown reason-bit (0-31)
|
||||
|
||||
This command is only supported for linux and a kernel > 5.1.
|
||||
Change reason-bit frr uses for setting protodown. We default to 7, but
|
||||
if another userspace app ever conflicts with this, you can change it here.
|
||||
The descriptor for this bit should exist in :file:`/etc/iproute2/protodown_reasons.d/`
|
||||
to display with :clicmd:`ip -d link show`.
|
||||
|
||||
Nexthop Tracking
|
||||
================
|
||||
|
||||
|
@ -167,12 +167,25 @@ enum {
|
||||
IFLA_NEW_IFINDEX,
|
||||
IFLA_MIN_MTU,
|
||||
IFLA_MAX_MTU,
|
||||
IFLA_PROP_LIST,
|
||||
IFLA_ALT_IFNAME, /* Alternative ifname */
|
||||
IFLA_PERM_ADDRESS,
|
||||
IFLA_PROTO_DOWN_REASON,
|
||||
__IFLA_MAX
|
||||
};
|
||||
|
||||
|
||||
#define IFLA_MAX (__IFLA_MAX - 1)
|
||||
|
||||
enum {
|
||||
IFLA_PROTO_DOWN_REASON_UNSPEC,
|
||||
IFLA_PROTO_DOWN_REASON_MASK, /* u32, mask for reason bits */
|
||||
IFLA_PROTO_DOWN_REASON_VALUE, /* u32, reason bit value */
|
||||
|
||||
__IFLA_PROTO_DOWN_REASON_CNT,
|
||||
IFLA_PROTO_DOWN_REASON_MAX = __IFLA_PROTO_DOWN_REASON_CNT - 1
|
||||
};
|
||||
|
||||
/* backwards compatibility for userspace */
|
||||
#ifndef __KERNEL__
|
||||
#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
|
||||
|
@ -1258,6 +1258,67 @@ DEFPY (show_sharp_cspf,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static struct interface *if_lookup_vrf_all(const char *ifname)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct vrf *vrf;
|
||||
|
||||
RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
|
||||
ifp = if_lookup_by_name(ifname, vrf->vrf_id);
|
||||
if (ifp)
|
||||
return ifp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEFPY (sharp_interface_protodown,
|
||||
sharp_interface_protodown_cmd,
|
||||
"sharp interface IFNAME$ifname protodown",
|
||||
SHARP_STR
|
||||
INTERFACE_STR
|
||||
IFNAME_STR
|
||||
"Set interface protodown\n")
|
||||
{
|
||||
struct interface *ifp;
|
||||
|
||||
ifp = if_lookup_vrf_all(ifname);
|
||||
|
||||
if (!ifp) {
|
||||
vty_out(vty, "%% Can't find interface %s\n", ifname);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (sharp_zebra_send_interface_protodown(ifp, true) != 0)
|
||||
return CMD_WARNING;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY (no_sharp_interface_protodown,
|
||||
no_sharp_interface_protodown_cmd,
|
||||
"no sharp interface IFNAME$ifname protodown",
|
||||
NO_STR
|
||||
SHARP_STR
|
||||
INTERFACE_STR
|
||||
IFNAME_STR
|
||||
"Set interface protodown\n")
|
||||
{
|
||||
struct interface *ifp;
|
||||
|
||||
ifp = if_lookup_vrf_all(ifname);
|
||||
|
||||
if (!ifp) {
|
||||
vty_out(vty, "%% Can't find interface %s\n", ifname);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (sharp_zebra_send_interface_protodown(ifp, false) != 0)
|
||||
return CMD_WARNING;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
void sharp_vty_init(void)
|
||||
{
|
||||
install_element(ENABLE_NODE, &install_routes_data_dump_cmd);
|
||||
@ -1290,5 +1351,8 @@ void sharp_vty_init(void)
|
||||
&sharp_srv6_manager_release_locator_chunk_cmd);
|
||||
install_element(ENABLE_NODE, &show_sharp_segment_routing_srv6_cmd);
|
||||
|
||||
install_element(ENABLE_NODE, &sharp_interface_protodown_cmd);
|
||||
install_element(ENABLE_NODE, &no_sharp_interface_protodown_cmd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -969,6 +969,18 @@ static int sharp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sharp_zebra_send_interface_protodown(struct interface *ifp, bool down)
|
||||
{
|
||||
zlog_debug("Sending zebra to set %s protodown %s", ifp->name,
|
||||
down ? "on" : "off");
|
||||
|
||||
if (zclient_send_interface_protodown(zclient, ifp->vrf->vrf_id, ifp,
|
||||
down) == ZCLIENT_SEND_FAILURE)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static zclient_handler *const sharp_handlers[] = {
|
||||
[ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add,
|
||||
[ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete,
|
||||
|
@ -73,4 +73,6 @@ extern void sharp_install_seg6local_route_helper(struct prefix *p,
|
||||
enum seg6local_action_t act,
|
||||
struct seg6local_context *ctx);
|
||||
|
||||
extern int sharp_zebra_send_interface_protodown(struct interface *ifp,
|
||||
bool down);
|
||||
#endif
|
||||
|
@ -31,6 +31,7 @@ import sys
|
||||
from functools import partial
|
||||
import pytest
|
||||
import json
|
||||
import platform
|
||||
|
||||
# Save the Current Working Directory to find configuration files.
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
@ -45,6 +46,20 @@ from time import sleep
|
||||
|
||||
|
||||
pytestmark = [pytest.mark.sharpd]
|
||||
krel = platform.release()
|
||||
|
||||
|
||||
def config_macvlan(tgen, r_str, device, macvlan):
|
||||
"Creates specified macvlan interace on physical device"
|
||||
|
||||
if topotest.version_cmp(krel, "5.1") < 0:
|
||||
return
|
||||
|
||||
router = tgen.gears[r_str]
|
||||
router.run(
|
||||
"ip link add {} link {} type macvlan mode bridge".format(macvlan, device)
|
||||
)
|
||||
router.run("ip link set {} up".format(macvlan))
|
||||
|
||||
|
||||
def setup_module(mod):
|
||||
@ -62,6 +77,8 @@ def setup_module(mod):
|
||||
TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))
|
||||
)
|
||||
|
||||
# Macvlan interface for protodown func test */
|
||||
config_macvlan(tgen, "r1", "r1-eth0", "r1-eth0-macvlan")
|
||||
# Initialize all routers.
|
||||
tgen.start_router()
|
||||
|
||||
@ -269,6 +286,46 @@ def test_route_map_usage():
|
||||
assert ok, result
|
||||
|
||||
|
||||
def test_protodown():
|
||||
"Run protodown basic functionality test and report results."
|
||||
pdown = False
|
||||
count = 0
|
||||
tgen = get_topogen()
|
||||
if topotest.version_cmp(krel, "5.1") < 0:
|
||||
tgen.errors = "kernel 5.1 needed for protodown tests"
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
r1 = tgen.gears["r1"]
|
||||
|
||||
# Set interface protodown on
|
||||
r1.vtysh_cmd("sharp interface r1-eth0-macvlan protodown")
|
||||
|
||||
# Timeout to wait for dplane to handle it
|
||||
while count < 10:
|
||||
count += 1
|
||||
output = r1.vtysh_cmd("show interface r1-eth0-macvlan")
|
||||
if re.search(r"protodown reasons:.*sharp", output):
|
||||
pdown = True
|
||||
break
|
||||
sleep(1)
|
||||
|
||||
assert pdown is True, "Interface r1-eth0-macvlan not set protodown"
|
||||
|
||||
# Set interface protodown off
|
||||
r1.vtysh_cmd("no sharp interface r1-eth0-macvlan protodown")
|
||||
|
||||
# Timeout to wait for dplane to handle it
|
||||
while count < 10:
|
||||
count += 1
|
||||
output = r1.vtysh_cmd("show interface r1-eth0-macvlan")
|
||||
if not re.search(r"protodown reasons:.*sharp", output):
|
||||
pdown = False
|
||||
break
|
||||
sleep(1)
|
||||
|
||||
assert pdown is False, "Interface r1-eth0-macvlan not set protodown off"
|
||||
|
||||
|
||||
def test_memory_leak():
|
||||
"Run the memory leak test and report results."
|
||||
tgen = get_topogen()
|
||||
|
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)
|
||||
{
|
||||
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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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. */
|
||||
@ -814,33 +815,90 @@ static int netlink_bridge_interface(struct nlmsghdr *h, int len, ns_id_t ns_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the interface is an es bond member then it must follow EVPN's
|
||||
* protodown setting
|
||||
static bool is_if_protodown_reason_only_frr(uint32_t rc_bitfield)
|
||||
{
|
||||
/* This shouldn't be possible */
|
||||
assert(frr_protodown_r_bit < 32);
|
||||
return (rc_bitfield == (((uint32_t)1) << frr_protodown_r_bit));
|
||||
}
|
||||
|
||||
/*
|
||||
* Process interface protodown dplane update.
|
||||
*
|
||||
* If the interface is an es bond member then it must follow EVPN's
|
||||
* protodown setting.
|
||||
*/
|
||||
static void netlink_proc_dplane_if_protodown(struct zebra_if *zif,
|
||||
bool protodown)
|
||||
struct rtattr **tb)
|
||||
{
|
||||
bool zif_protodown;
|
||||
bool protodown;
|
||||
bool old_protodown;
|
||||
uint32_t rc_bitfield = 0;
|
||||
struct rtattr *pd_reason_info[IFLA_MAX + 1];
|
||||
|
||||
zif_protodown = !!(zif->flags & ZIF_FLAG_PROTODOWN);
|
||||
if (protodown == zif_protodown)
|
||||
protodown = !!*(uint8_t *)RTA_DATA(tb[IFLA_PROTO_DOWN]);
|
||||
|
||||
if (tb[IFLA_PROTO_DOWN_REASON]) {
|
||||
netlink_parse_rtattr_nested(pd_reason_info, IFLA_INFO_MAX,
|
||||
tb[IFLA_PROTO_DOWN_REASON]);
|
||||
|
||||
if (pd_reason_info[IFLA_PROTO_DOWN_REASON_VALUE])
|
||||
rc_bitfield = *(uint32_t *)RTA_DATA(
|
||||
pd_reason_info[IFLA_PROTO_DOWN_REASON_VALUE]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set our reason code to note it wasn't us.
|
||||
* If the reason we got from the kernel is ONLY frr though, don't
|
||||
* set it.
|
||||
*/
|
||||
COND_FLAG(zif->protodown_rc, ZEBRA_PROTODOWN_EXTERNAL,
|
||||
protodown && rc_bitfield &&
|
||||
!is_if_protodown_reason_only_frr(rc_bitfield));
|
||||
|
||||
|
||||
old_protodown = !!ZEBRA_IF_IS_PROTODOWN(zif);
|
||||
if (protodown == old_protodown)
|
||||
return;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug("interface %s dplane change, protdown %s",
|
||||
zif->ifp->name, protodown ? "on" : "off");
|
||||
|
||||
/* Set protodown, respectively */
|
||||
COND_FLAG(zif->flags, ZIF_FLAG_PROTODOWN, protodown);
|
||||
|
||||
if (zebra_evpn_is_es_bond_member(zif->ifp)) {
|
||||
/* Check it's not already being sent to the dplane first */
|
||||
if (protodown &&
|
||||
CHECK_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN)) {
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug(
|
||||
"bond mbr %s protodown on recv'd but already sent protodown on to the dplane",
|
||||
zif->ifp->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!protodown &&
|
||||
CHECK_FLAG(zif->flags, ZIF_FLAG_UNSET_PROTODOWN)) {
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug(
|
||||
"bond mbr %s protodown off recv'd but already sent protodown off to the dplane",
|
||||
zif->ifp->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL)
|
||||
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);
|
||||
} else {
|
||||
if (protodown)
|
||||
zif->flags |= ZIF_FLAG_PROTODOWN;
|
||||
"bond mbr %s reinstate protodown %s in the dplane",
|
||||
zif->ifp->name, old_protodown ? "on" : "off");
|
||||
|
||||
if (old_protodown)
|
||||
SET_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN);
|
||||
else
|
||||
zif->flags &= ~ZIF_FLAG_PROTODOWN;
|
||||
SET_FLAG(zif->flags, ZIF_FLAG_UNSET_PROTODOWN);
|
||||
|
||||
dplane_intf_update(zif->ifp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -858,6 +916,29 @@ static uint8_t netlink_parse_lacp_bypass(struct rtattr **linkinfo)
|
||||
return bypass;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only called at startup to cleanup leftover protodown reasons we may
|
||||
* have not cleaned up. We leave protodown set though.
|
||||
*/
|
||||
static void if_sweep_protodown(struct zebra_if *zif)
|
||||
{
|
||||
bool protodown;
|
||||
|
||||
protodown = !!ZEBRA_IF_IS_PROTODOWN(zif);
|
||||
|
||||
if (!protodown)
|
||||
return;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug("interface %s sweeping protodown %s reason 0x%x",
|
||||
zif->ifp->name, protodown ? "on" : "off",
|
||||
zif->protodown_rc);
|
||||
|
||||
/* Only clear our reason codes, leave external if it was set */
|
||||
UNSET_FLAG(zif->protodown_rc, ZEBRA_PROTODOWN_ALL);
|
||||
dplane_intf_update(zif->ifp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called from interface_lookup_netlink(). This function is only used
|
||||
* during bootstrap.
|
||||
@ -905,7 +986,8 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
|
||||
/* Looking up interface name. */
|
||||
memset(linkinfo, 0, sizeof(linkinfo));
|
||||
netlink_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
|
||||
netlink_parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len,
|
||||
NLA_F_NESTED);
|
||||
|
||||
/* check for wireless messages to ignore */
|
||||
if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) {
|
||||
@ -1020,10 +1102,8 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
zebra_l2if_update_bond_slave(ifp, bond_ifindex, !!bypass);
|
||||
|
||||
if (tb[IFLA_PROTO_DOWN]) {
|
||||
uint8_t protodown;
|
||||
|
||||
protodown = *(uint8_t *)RTA_DATA(tb[IFLA_PROTO_DOWN]);
|
||||
netlink_proc_dplane_if_protodown(zif, !!protodown);
|
||||
netlink_proc_dplane_if_protodown(zif, tb);
|
||||
if_sweep_protodown(zif);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1244,6 +1324,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;
|
||||
@ -1716,7 +1831,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
|
||||
/* Looking up interface name. */
|
||||
memset(linkinfo, 0, sizeof(linkinfo));
|
||||
netlink_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
|
||||
netlink_parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len,
|
||||
NLA_F_NESTED);
|
||||
|
||||
/* check for wireless messages to ignore */
|
||||
if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) {
|
||||
@ -1856,14 +1972,9 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
zebra_l2if_update_bond_slave(ifp, bond_ifindex,
|
||||
!!bypass);
|
||||
|
||||
if (tb[IFLA_PROTO_DOWN]) {
|
||||
uint8_t protodown;
|
||||
if (tb[IFLA_PROTO_DOWN])
|
||||
netlink_proc_dplane_if_protodown(ifp->info, tb);
|
||||
|
||||
protodown = *(uint8_t *)RTA_DATA(
|
||||
tb[IFLA_PROTO_DOWN]);
|
||||
netlink_proc_dplane_if_protodown(ifp->info,
|
||||
!!protodown);
|
||||
}
|
||||
} else if (ifp->vrf->vrf_id != vrf_id) {
|
||||
/* VRF change for an interface. */
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
@ -1910,14 +2021,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
netlink_to_zebra_link_type(ifi->ifi_type);
|
||||
netlink_interface_update_hw_addr(tb, ifp);
|
||||
|
||||
if (tb[IFLA_PROTO_DOWN]) {
|
||||
uint8_t protodown;
|
||||
|
||||
protodown = *(uint8_t *)RTA_DATA(
|
||||
tb[IFLA_PROTO_DOWN]);
|
||||
netlink_proc_dplane_if_protodown(zif,
|
||||
!!protodown);
|
||||
}
|
||||
if (tb[IFLA_PROTO_DOWN])
|
||||
netlink_proc_dplane_if_protodown(ifp->info, tb);
|
||||
|
||||
if (if_is_no_ptm_operative(ifp)) {
|
||||
bool is_up = if_is_operative(ifp);
|
||||
@ -2049,30 +2154,72 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netlink_protodown(struct interface *ifp, bool down)
|
||||
{
|
||||
struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
|
||||
/**
|
||||
* 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[NL_PKT_BUF_SIZE];
|
||||
} req;
|
||||
char buf[];
|
||||
} *req = buf;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
struct rtattr *nest_protodown_reason;
|
||||
ifindex_t ifindex = dplane_ctx_get_ifindex(ctx);
|
||||
bool down = dplane_ctx_intf_is_protodown(ctx);
|
||||
bool pd_reason_val = dplane_ctx_get_intf_pd_reason_val(ctx);
|
||||
struct nlsock *nl =
|
||||
kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx));
|
||||
|
||||
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||
req.n.nlmsg_flags = NLM_F_REQUEST;
|
||||
req.n.nlmsg_type = RTM_SETLINK;
|
||||
req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
|
||||
if (buflen < sizeof(*req))
|
||||
return 0;
|
||||
|
||||
req.ifa.ifi_index = ifp->ifindex;
|
||||
memset(req, 0, sizeof(*req));
|
||||
|
||||
nl_attr_put(&req.n, sizeof(req), IFLA_PROTO_DOWN, &down, sizeof(down));
|
||||
nl_attr_put32(&req.n, sizeof(req), IFLA_LINK, ifp->ifindex);
|
||||
if (cmd != RTM_SETLINK)
|
||||
flog_err(
|
||||
EC_ZEBRA_INTF_UPDATE_FAILURE,
|
||||
"Only RTM_SETLINK message type currently supported in dplane pthread");
|
||||
|
||||
return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
|
||||
false);
|
||||
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);
|
||||
|
||||
/* Reason info nest */
|
||||
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)pd_reason_val) << frr_protodown_r_bit);
|
||||
|
||||
nl_attr_nest_end(&req->n, nest_protodown_reason);
|
||||
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug("%s: %s, protodown=%d reason_val=%d ifindex=%u",
|
||||
__func__, nl_msg_type_to_str(cmd), down,
|
||||
pd_reason_val, ifindex);
|
||||
|
||||
return NLMSG_ALIGN(req->n.nlmsg_len);
|
||||
}
|
||||
|
||||
/* Interface information read by netlink. */
|
||||
@ -2088,4 +2235,35 @@ void interface_list(struct zebra_ns *zns)
|
||||
interface_addr_lookup_netlink(zns);
|
||||
}
|
||||
|
||||
void if_netlink_set_frr_protodown_r_bit(uint8_t bit)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug(
|
||||
"Protodown reason bit index changed: bit-index %u -> bit-index %u",
|
||||
frr_protodown_r_bit, bit);
|
||||
|
||||
frr_protodown_r_bit = bit;
|
||||
}
|
||||
|
||||
void if_netlink_unset_frr_protodown_r_bit(void)
|
||||
{
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug(
|
||||
"Protodown reason bit index changed: bit-index %u -> bit-index %u",
|
||||
frr_protodown_r_bit, FRR_PROTODOWN_REASON_DEFAULT_BIT);
|
||||
|
||||
frr_protodown_r_bit = FRR_PROTODOWN_REASON_DEFAULT_BIT;
|
||||
}
|
||||
|
||||
|
||||
bool if_netlink_frr_protodown_r_bit_is_set(void)
|
||||
{
|
||||
return (frr_protodown_r_bit != FRR_PROTODOWN_REASON_DEFAULT_BIT);
|
||||
}
|
||||
|
||||
uint8_t if_netlink_get_frr_protodown_r_bit(void)
|
||||
{
|
||||
return frr_protodown_r_bit;
|
||||
}
|
||||
|
||||
#endif /* GNU_LINUX */
|
||||
|
@ -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,19 +50,19 @@ extern enum netlink_msg_status
|
||||
netlink_put_address_update_msg(struct nl_batch *bth,
|
||||
struct zebra_dplane_ctx *ctx);
|
||||
|
||||
/*
|
||||
* Set protodown status of interface.
|
||||
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
|
||||
/* Protodown bit setter/getter
|
||||
*
|
||||
* ifp
|
||||
* Interface to set protodown on.
|
||||
*
|
||||
* down
|
||||
* If true, set protodown on. If false, set protodown off.
|
||||
*
|
||||
* Returns:
|
||||
* 0
|
||||
* Allow users to change the bit if it conflicts with another
|
||||
* on their system.
|
||||
*/
|
||||
int netlink_protodown(struct interface *ifp, bool down);
|
||||
extern void if_netlink_set_frr_protodown_r_bit(uint8_t bit);
|
||||
extern void if_netlink_unset_frr_protodown_r_bit(void);
|
||||
extern bool if_netlink_frr_protodown_r_bit_is_set(void);
|
||||
extern uint8_t if_netlink_get_frr_protodown_r_bit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
41
zebra/if_socket.c
Normal file
41
zebra/if_socket.c
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Zebra Interface interaction with the kernel using socket.
|
||||
* Copyright (C) 2022 NVIDIA CORPORATION & AFFILIATES
|
||||
* Stephen Worley
|
||||
*
|
||||
* This file is part of FRR.
|
||||
*
|
||||
* FRR is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* FRR is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with FRR; see the file COPYING. If not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#ifndef HAVE_NETLINK
|
||||
|
||||
#include "lib_errors.h"
|
||||
|
||||
#include "zebra/rt.h"
|
||||
#include "zebra/zebra_dplane.h"
|
||||
#include "zebra/zebra_errors.h"
|
||||
|
||||
enum zebra_dplane_result kernel_intf_update(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
flog_err(EC_LIB_UNAVAILABLE, "%s not Implemented for this platform",
|
||||
__func__);
|
||||
return ZEBRA_DPLANE_REQUEST_FAILURE;
|
||||
}
|
||||
|
||||
#endif
|
@ -261,6 +261,13 @@ static int if_zebra_delete_hook(struct interface *ifp)
|
||||
if (ifp->info) {
|
||||
zebra_if = ifp->info;
|
||||
|
||||
/* If we set protodown, clear our reason now from the kernel */
|
||||
if (ZEBRA_IF_IS_PROTODOWN(zebra_if) && zebra_if->protodown_rc &&
|
||||
!ZEBRA_IF_IS_PROTODOWN_ONLY_EXTERNAL(zebra_if))
|
||||
zebra_if_update_protodown_rc(ifp, true,
|
||||
(zebra_if->protodown_rc &
|
||||
~ZEBRA_PROTODOWN_ALL));
|
||||
|
||||
/* Free installed address chains tree. */
|
||||
if (zebra_if->ipv4_subnets)
|
||||
route_table_finish(zebra_if->ipv4_subnets);
|
||||
@ -1229,58 +1236,130 @@ void zebra_if_update_all_links(struct zebra_ns *zns)
|
||||
}
|
||||
}
|
||||
|
||||
void zebra_if_set_protodown(struct interface *ifp, bool down)
|
||||
static bool if_ignore_set_protodown(const struct interface *ifp, bool new_down,
|
||||
uint32_t new_protodown_rc)
|
||||
{
|
||||
struct zebra_if *zif;
|
||||
bool old_down, old_set_down, old_unset_down;
|
||||
|
||||
zif = ifp->info;
|
||||
|
||||
/* Current state as we know it */
|
||||
old_down = !!(ZEBRA_IF_IS_PROTODOWN(zif));
|
||||
old_set_down = !!CHECK_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN);
|
||||
old_unset_down = !!CHECK_FLAG(zif->flags, ZIF_FLAG_UNSET_PROTODOWN);
|
||||
|
||||
if (new_protodown_rc == zif->protodown_rc) {
|
||||
/* Early return if already down & reason bitfield matches */
|
||||
if (new_down == old_down) {
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug(
|
||||
"Ignoring request to set protodown %s for interface %s (%u): protodown %s is already set (reason bitfield: old 0x%x new 0x%x)",
|
||||
new_down ? "on" : "off", ifp->name,
|
||||
ifp->ifindex, new_down ? "on" : "off",
|
||||
zif->protodown_rc, new_protodown_rc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Early return if already set queued & reason bitfield matches
|
||||
*/
|
||||
if (new_down && old_set_down) {
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug(
|
||||
"Ignoring request to set protodown %s for interface %s (%u): protodown %s is already queued to dplane (reason bitfield: old 0x%x new 0x%x)",
|
||||
new_down ? "on" : "off", ifp->name,
|
||||
ifp->ifindex, new_down ? "on" : "off",
|
||||
zif->protodown_rc, new_protodown_rc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Early return if already unset queued & reason bitfield
|
||||
* matches */
|
||||
if (!new_down && old_unset_down) {
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug(
|
||||
"Ignoring request to set protodown %s for interface %s (%u): protodown %s is already queued to dplane (reason bitfield: old 0x%x new 0x%x)",
|
||||
new_down ? "on" : "off", ifp->name,
|
||||
ifp->ifindex, new_down ? "on" : "off",
|
||||
zif->protodown_rc, new_protodown_rc);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int zebra_if_update_protodown_rc(struct interface *ifp, bool new_down,
|
||||
uint32_t new_protodown_rc)
|
||||
{
|
||||
struct zebra_if *zif;
|
||||
|
||||
zif = ifp->info;
|
||||
|
||||
/* Check if we already have this state or it's queued */
|
||||
if (if_ignore_set_protodown(ifp, new_down, new_protodown_rc))
|
||||
return 1;
|
||||
|
||||
zlog_info(
|
||||
"Setting protodown %s - interface %s (%u): reason bitfield change from 0x%x --> 0x%x",
|
||||
new_down ? "on" : "off", ifp->name, ifp->ifindex,
|
||||
zif->protodown_rc, new_protodown_rc);
|
||||
|
||||
zif->protodown_rc = new_protodown_rc;
|
||||
|
||||
if (new_down)
|
||||
SET_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN);
|
||||
else
|
||||
SET_FLAG(zif->flags, ZIF_FLAG_UNSET_PROTODOWN);
|
||||
|
||||
#ifdef HAVE_NETLINK
|
||||
netlink_protodown(ifp, down);
|
||||
dplane_intf_update(ifp);
|
||||
#else
|
||||
zlog_warn("Protodown is not supported on this platform");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zebra_if_set_protodown(struct interface *ifp, bool new_down,
|
||||
enum protodown_reasons new_reason)
|
||||
{
|
||||
struct zebra_if *zif;
|
||||
uint32_t new_protodown_rc;
|
||||
|
||||
zif = ifp->info;
|
||||
|
||||
if (new_down)
|
||||
new_protodown_rc = zif->protodown_rc | new_reason;
|
||||
else
|
||||
new_protodown_rc = zif->protodown_rc & ~new_reason;
|
||||
|
||||
return zebra_if_update_protodown_rc(ifp, new_down, new_protodown_rc);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 +1414,66 @@ void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx)
|
||||
*/
|
||||
if (op != DPLANE_OP_INTF_ADDR_ADD)
|
||||
rib_update(RIB_UPDATE_KERNEL);
|
||||
}
|
||||
|
||||
static void zebra_if_update_ctx(struct zebra_dplane_ctx *ctx,
|
||||
struct interface *ifp)
|
||||
{
|
||||
enum zebra_dplane_result dp_res;
|
||||
struct zebra_if *zif;
|
||||
bool pd_reason_val;
|
||||
bool down;
|
||||
|
||||
dp_res = dplane_ctx_get_status(ctx);
|
||||
pd_reason_val = dplane_ctx_get_intf_pd_reason_val(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 %d",
|
||||
__func__, dplane_op2str(dplane_ctx_get_op(ctx)),
|
||||
ifp->name, ifp->ifindex, down ? "on" : "off",
|
||||
pd_reason_val);
|
||||
|
||||
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);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Update our info */
|
||||
COND_FLAG(zif->flags, ZIF_FLAG_PROTODOWN, down);
|
||||
|
||||
done:
|
||||
/* We're responsible for the ctx object */
|
||||
dplane_ctx_fini(&ctx);
|
||||
/* Clear our dplane flags */
|
||||
UNSET_FLAG(zif->flags, ZIF_FLAG_SET_PROTODOWN);
|
||||
UNSET_FLAG(zif->flags, ZIF_FLAG_UNSET_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 +1487,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,28 +1848,34 @@ 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;
|
||||
|
||||
pd_buf[0] = '\0';
|
||||
size_t len;
|
||||
|
||||
strlcat(pd_buf, "(", pd_buf_len);
|
||||
|
||||
if (protodown_rc & ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
strlcat(pd_buf, ",", pd_buf_len);
|
||||
strlcat(pd_buf, "startup-delay", pd_buf_len);
|
||||
}
|
||||
if (CHECK_FLAG(protodown_rc, ZEBRA_PROTODOWN_EXTERNAL))
|
||||
strlcat(pd_buf, "external,", pd_buf_len);
|
||||
|
||||
if (protodown_rc & ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN) {
|
||||
if (!first)
|
||||
strlcat(pd_buf, ",", pd_buf_len);
|
||||
strlcat(pd_buf, "uplinks-down", pd_buf_len);
|
||||
}
|
||||
if (CHECK_FLAG(protodown_rc, ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY))
|
||||
strlcat(pd_buf, "startup-delay,", pd_buf_len);
|
||||
|
||||
if (CHECK_FLAG(protodown_rc, ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN))
|
||||
strlcat(pd_buf, "uplinks-down,", pd_buf_len);
|
||||
|
||||
if (CHECK_FLAG(protodown_rc, ZEBRA_PROTODOWN_VRRP))
|
||||
strlcat(pd_buf, "vrrp,", pd_buf_len);
|
||||
|
||||
if (CHECK_FLAG(protodown_rc, ZEBRA_PROTODOWN_SHARP))
|
||||
strlcat(pd_buf, "sharp,", pd_buf_len);
|
||||
|
||||
len = strnlen(pd_buf, pd_buf_len);
|
||||
|
||||
/* Remove trailing comma */
|
||||
if (pd_buf[len - 1] == ',')
|
||||
pd_buf[len - 1] = '\0';
|
||||
|
||||
strlcat(pd_buf, ")", pd_buf_len);
|
||||
|
||||
@ -1878,7 +2081,7 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
|
||||
|
||||
zebra_evpn_if_es_print(vty, NULL, zebra_if);
|
||||
vty_out(vty, " protodown: %s %s\n",
|
||||
(zebra_if->flags & ZIF_FLAG_PROTODOWN) ? "on" : "off",
|
||||
(ZEBRA_IF_IS_PROTODOWN(zebra_if)) ? "on" : "off",
|
||||
if_is_protodown_applicable(ifp) ? "" : "(n/a)");
|
||||
if (zebra_if->protodown_rc)
|
||||
vty_out(vty, " protodown reasons: %s\n",
|
||||
@ -2229,7 +2432,7 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp,
|
||||
if (if_is_protodown_applicable(ifp)) {
|
||||
json_object_string_add(
|
||||
json_if, "protodown",
|
||||
(zebra_if->flags & ZIF_FLAG_PROTODOWN) ? "on" : "off");
|
||||
(ZEBRA_IF_IS_PROTODOWN(zebra_if)) ? "on" : "off");
|
||||
if (zebra_if->protodown_rc)
|
||||
json_object_string_add(
|
||||
json_if, "protodownReason",
|
||||
|
@ -308,14 +308,22 @@ enum zebra_if_flags {
|
||||
|
||||
/* Dataplane protodown-on */
|
||||
ZIF_FLAG_PROTODOWN = (1 << 2),
|
||||
/* Dataplane protodown-on Queued to the dplane */
|
||||
ZIF_FLAG_SET_PROTODOWN = (1 << 3),
|
||||
/* Dataplane protodown-off Queued to the dplane */
|
||||
ZIF_FLAG_UNSET_PROTODOWN = (1 << 4),
|
||||
|
||||
/* LACP bypass state is set by the dataplane on a bond member
|
||||
* and inherited by the bond (if one or more bond members are in
|
||||
* a bypass state the bond is placed in a bypass state)
|
||||
*/
|
||||
ZIF_FLAG_LACP_BYPASS = (1 << 3)
|
||||
ZIF_FLAG_LACP_BYPASS = (1 << 5)
|
||||
};
|
||||
|
||||
#define ZEBRA_IF_IS_PROTODOWN(zif) ((zif)->flags & ZIF_FLAG_PROTODOWN)
|
||||
#define ZEBRA_IF_IS_PROTODOWN_ONLY_EXTERNAL(zif) \
|
||||
((zif)->protodown_rc == ZEBRA_PROTODOWN_EXTERNAL)
|
||||
|
||||
/* `zebra' daemon local interface structure. */
|
||||
struct zebra_if {
|
||||
/* back pointer to the interface */
|
||||
@ -403,7 +411,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 +505,16 @@ 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);
|
||||
/**
|
||||
* Directly update entire protodown & reason code bitfield.
|
||||
*/
|
||||
extern int zebra_if_update_protodown_rc(struct interface *ifp, bool new_down,
|
||||
uint32_t new_protodown_rc);
|
||||
/**
|
||||
* Set protodown with single reason.
|
||||
*/
|
||||
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 +538,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);
|
||||
|
@ -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"},
|
||||
@ -209,6 +210,10 @@ int netlink_config_write_helper(struct vty *vty)
|
||||
vty_out(vty, "zebra kernel netlink batch-tx-buf %u %u\n", size,
|
||||
threshold);
|
||||
|
||||
if (if_netlink_frr_protodown_r_bit_is_set())
|
||||
vty_out(vty, "zebra protodown reason-bit %u\n",
|
||||
if_netlink_get_frr_protodown_r_bit());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1491,6 +1496,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;
|
||||
|
@ -1577,6 +1577,12 @@ void kernel_update_multi(struct dplane_ctx_q *ctx_list)
|
||||
res = kernel_pbr_rule_update(ctx);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_INTF_INSTALL:
|
||||
case DPLANE_OP_INTF_UPDATE:
|
||||
case DPLANE_OP_INTF_DELETE:
|
||||
res = kernel_intf_update(ctx);
|
||||
break;
|
||||
|
||||
/* Ignore 'notifications' - no-op */
|
||||
case DPLANE_OP_SYS_ROUTE_ADD:
|
||||
case DPLANE_OP_SYS_ROUTE_DELETE:
|
||||
|
@ -66,6 +66,9 @@ enum zebra_dplane_result kernel_neigh_update_ctx(struct zebra_dplane_ctx *ctx);
|
||||
extern enum zebra_dplane_result
|
||||
kernel_pbr_rule_update(struct zebra_dplane_ctx *ctx);
|
||||
|
||||
extern enum zebra_dplane_result
|
||||
kernel_intf_update(struct zebra_dplane_ctx *ctx);
|
||||
|
||||
#endif /* !HAVE_NETLINK */
|
||||
|
||||
extern int kernel_neigh_update(int cmd, int ifindex, void *addr, char *lla,
|
||||
|
@ -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);
|
||||
|
@ -60,6 +60,7 @@ zebra_zebra_SOURCES = \
|
||||
zebra/debug.c \
|
||||
zebra/if_ioctl.c \
|
||||
zebra/if_netlink.c \
|
||||
zebra/if_socket.c \
|
||||
zebra/if_sysctl.c \
|
||||
zebra/interface.c \
|
||||
zebra/ioctl.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;
|
||||
|
@ -193,6 +193,9 @@ struct dplane_intf_info {
|
||||
uint32_t metric;
|
||||
uint32_t flags;
|
||||
|
||||
bool protodown;
|
||||
bool pd_reason_val;
|
||||
|
||||
#define DPLANE_INTF_CONNECTED (1 << 0) /* Connected peer, p2p */
|
||||
#define DPLANE_INTF_SECONDARY (1 << 1)
|
||||
#define DPLANE_INTF_BROADCAST (1 << 2)
|
||||
@ -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,27 @@ 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_pd_reason_val(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return ctx->u.intf.pd_reason_val;
|
||||
}
|
||||
|
||||
void dplane_ctx_set_intf_pd_reason_val(struct zebra_dplane_ctx *ctx, bool val)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
ctx->u.intf.pd_reason_val = val;
|
||||
}
|
||||
|
||||
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 +2678,73 @@ 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;
|
||||
struct zebra_if *zif;
|
||||
int ret = EINVAL;
|
||||
bool set_pdown, unset_pdown;
|
||||
|
||||
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) {
|
||||
set_pdown = !!(zif->flags & ZIF_FLAG_SET_PROTODOWN);
|
||||
unset_pdown = !!(zif->flags & ZIF_FLAG_UNSET_PROTODOWN);
|
||||
|
||||
if (zif->protodown_rc &&
|
||||
ZEBRA_IF_IS_PROTODOWN_ONLY_EXTERNAL(zif) == false)
|
||||
ctx->u.intf.pd_reason_val = true;
|
||||
|
||||
/*
|
||||
* See if we have new protodown state to set, otherwise keep
|
||||
* current state
|
||||
*/
|
||||
if (set_pdown)
|
||||
ctx->u.intf.protodown = true;
|
||||
else if (unset_pdown)
|
||||
ctx->u.intf.protodown = false;
|
||||
else
|
||||
ctx->u.intf.protodown = !!ZEBRA_IF_IS_PROTODOWN(zif);
|
||||
}
|
||||
|
||||
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 +3931,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 +5427,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 +5570,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:
|
||||
|
@ -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,9 @@ 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_pd_reason_val(const struct zebra_dplane_ctx *ctx);
|
||||
void dplane_ctx_set_intf_pd_reason_val(struct zebra_dplane_ctx *ctx, bool val);
|
||||
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);
|
||||
@ -676,6 +684,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,
|
||||
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.
|
||||
*/
|
||||
@ -814,6 +829,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);
|
||||
|
||||
|
@ -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.",
|
||||
.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,
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -3463,11 +3463,13 @@ void zebra_evpn_mh_json(json_object *json)
|
||||
|
||||
if (zmh_info->protodown_rc) {
|
||||
json_array = json_object_new_array();
|
||||
if (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY)
|
||||
if (CHECK_FLAG(zmh_info->protodown_rc,
|
||||
ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY))
|
||||
json_object_array_add(
|
||||
json_array,
|
||||
json_object_new_string("startupDelay"));
|
||||
if (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN)
|
||||
if (CHECK_FLAG(zmh_info->protodown_rc,
|
||||
ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN))
|
||||
json_object_array_add(
|
||||
json_array,
|
||||
json_object_new_string("uplinkDown"));
|
||||
@ -3623,10 +3625,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 +3637,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 = (old_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);
|
||||
new_protodown_rc);
|
||||
|
||||
if (old_protodown == new_protodown)
|
||||
return;
|
||||
|
||||
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_update_protodown_rc(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 +3676,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 +3707,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 +3735,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)
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -68,19 +68,27 @@ 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),
|
||||
/* Just used to clear our fields on shutdown, externel not included */
|
||||
ZEBRA_PROTODOWN_ALL = (ZEBRA_PROTODOWN_EVPN_ALL | ZEBRA_PROTODOWN_VRRP |
|
||||
ZEBRA_PROTODOWN_SHARP)
|
||||
};
|
||||
#define ZEBRA_PROTODOWN_RC_STR_LEN 80
|
||||
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include "northbound_cli.h"
|
||||
#include "zebra/zebra_nb.h"
|
||||
#include "zebra/kernel_netlink.h"
|
||||
#include "zebra/if_netlink.h"
|
||||
#include "zebra/table_manager.h"
|
||||
#include "zebra/zebra_script.h"
|
||||
#include "zebra/rtadv.h"
|
||||
@ -4357,6 +4358,31 @@ DEFUN_HIDDEN(no_zebra_kernel_netlink_batch_tx_buf,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY (zebra_protodown_bit,
|
||||
zebra_protodown_bit_cmd,
|
||||
"zebra protodown reason-bit (0-31)$bit",
|
||||
ZEBRA_STR
|
||||
"Protodown Configuration\n"
|
||||
"Reason Bit used in the kernel for application\n"
|
||||
"Reason Bit range\n")
|
||||
{
|
||||
if_netlink_set_frr_protodown_r_bit(bit);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY (no_zebra_protodown_bit,
|
||||
no_zebra_protodown_bit_cmd,
|
||||
"no zebra protodown reason-bit [(0-31)$bit]",
|
||||
NO_STR
|
||||
ZEBRA_STR
|
||||
"Protodown Configuration\n"
|
||||
"Reason Bit used in the kernel for setting protodown\n"
|
||||
"Reason Bit Range\n")
|
||||
{
|
||||
if_netlink_unset_frr_protodown_r_bit();
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* HAVE_NETLINK */
|
||||
|
||||
DEFUN(ip_table_range, ip_table_range_cmd,
|
||||
@ -4562,6 +4588,8 @@ void zebra_vty_init(void)
|
||||
#ifdef HAVE_NETLINK
|
||||
install_element(CONFIG_NODE, &zebra_kernel_netlink_batch_tx_buf_cmd);
|
||||
install_element(CONFIG_NODE, &no_zebra_kernel_netlink_batch_tx_buf_cmd);
|
||||
install_element(CONFIG_NODE, &zebra_protodown_bit_cmd);
|
||||
install_element(CONFIG_NODE, &no_zebra_protodown_bit_cmd);
|
||||
#endif /* HAVE_NETLINK */
|
||||
|
||||
#ifdef HAVE_SCRIPTING
|
||||
|
Loading…
Reference in New Issue
Block a user