summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_addpath.c4
-rw-r--r--bgpd/bgp_attr.c90
-rw-r--r--bgpd/bgp_debug.c161
-rw-r--r--bgpd/bgp_fsm.c2
-rw-r--r--bgpd/bgp_fsm.h3
-rw-r--r--bgpd/bgp_snmp_bgp4v2.c42
-rw-r--r--bgpd/bgp_vty.c20
-rw-r--r--bgpd/bgp_zebra.c21
-rw-r--r--debian/changelog6
-rw-r--r--doc/user/evpn.rst2
-rw-r--r--doc/user/ospfd.rst7
-rw-r--r--doc/user/snmp.rst61
-rw-r--r--doc/user/zebra.rst9
-rw-r--r--lib/agentx.c19
-rw-r--r--lib/smux.h5
-rw-r--r--lib/srv6.c9
-rw-r--r--lib/workqueue.c7
-rw-r--r--lib/workqueue.h5
-rw-r--r--lib/zlog_targets.c4
-rw-r--r--ospf6d/ospf6_asbr.c31
-rw-r--r--ospf6d/ospf6_asbr.h2
-rw-r--r--ospf6d/ospf6_interface.c3
-rw-r--r--ospf6d/ospf6_message.c3
-rw-r--r--ospf6d/ospf6_neighbor.c65
-rw-r--r--ospf6d/ospf6_top.c8
-rw-r--r--ospfd/ospf_spf.c10
-rw-r--r--ospfd/ospf_vty.c120
-rw-r--r--ospfd/ospfd.c4
-rw-r--r--pathd/path_pcep_config.c3
-rw-r--r--pimd/pim_oil.c4
-rw-r--r--redhat/frr.spec.in15
-rw-r--r--staticd/static_zebra.c1
-rw-r--r--tests/lib/test_heavy_wq.c6
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf31
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2mib/r1/zebra.conf5
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf23
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf17
-rw-r--r--tests/topotests/bgp_snmp_bgp4v2mib/r2/zebra.conf5
-rwxr-xr-xtests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py248
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/ce1/bgpd.conf0
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/ce1/zebra.conf9
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf41
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/default_ipv4_vpn.json31
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf10_ipv4_unicast.json25
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json22
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4_unicast.json27
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/pe1/zebra.conf27
-rwxr-xr-xtests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py128
-rw-r--r--tests/topotests/config_timing/test_config_timing.py11
-rw-r--r--tests/topotests/lib/snmptest.py7
-rwxr-xr-xtools/frr-reload.py1
-rw-r--r--vtysh/vtysh_main.c7
-rw-r--r--zebra/main.c6
-rw-r--r--zebra/rt_netlink.c6
-rw-r--r--zebra/rtadv.c29
-rw-r--r--zebra/rtadv.h7
-rw-r--r--zebra/zebra_fpm_netlink.c13
-rw-r--r--zebra/zebra_mpls.c1
-rw-r--r--zebra/zebra_rib.c9
-rw-r--r--zebra/zebra_routemap.c129
60 files changed, 1289 insertions, 328 deletions
diff --git a/bgpd/bgp_addpath.c b/bgpd/bgp_addpath.c
index 9784943b4c..461e60dbfc 100644
--- a/bgpd/bgp_addpath.c
+++ b/bgpd/bgp_addpath.c
@@ -406,9 +406,9 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
}
}
- zlog_info("Resetting peer %s%s due to change in addpath config",
+ zlog_info("Resetting peer %s%pBP due to change in addpath config",
CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) ? "group " : "",
- peer->host);
+ peer);
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
group = peer->group;
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 17687e6252..3d93e8a1ac 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -3889,7 +3889,10 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
stream_putc(s, attr->mp_nexthop_len);
stream_put_ipv4(s, attr->nexthop.s_addr);
}
- default:
+ break;
+ case SAFI_UNSPEC:
+ case SAFI_MAX:
+ assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
break;
}
break;
@@ -3940,17 +3943,24 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
break;
case SAFI_FLOWSPEC:
stream_putc(s, 0); /* no nexthop for flowspec */
- default:
+ break;
+ case SAFI_UNSPEC:
+ case SAFI_MAX:
+ assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
break;
}
break;
- default:
+ case AFI_L2VPN:
if (safi != SAFI_FLOWSPEC)
flog_err(
EC_BGP_ATTR_NH_SEND_LEN,
"Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d",
peer->host, afi, safi, attr->mp_nexthop_len);
break;
+ case AFI_UNSPEC:
+ case AFI_MAX:
+ assert(!"DEV ESCAPE: AFI_UNSPEC or AFI_MAX should not be used here");
+ break;
}
/* SNPA */
@@ -3964,7 +3974,12 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
uint32_t num_labels, bool addpath_capable,
uint32_t addpath_tx_id, struct attr *attr)
{
- if (safi == SAFI_MPLS_VPN) {
+ switch (safi) {
+ case SAFI_UNSPEC:
+ case SAFI_MAX:
+ assert(!"Dev escape usage of SAFI_UNSPEC or MAX");
+ break;
+ case SAFI_MPLS_VPN:
if (addpath_capable)
stream_putl(s, addpath_tx_id);
/* Label, RD, Prefix write. */
@@ -3972,35 +3987,74 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
stream_put(s, label, BGP_LABEL_BYTES);
stream_put(s, prd->val, 8);
stream_put(s, &p->u.prefix, PSIZE(p->prefixlen));
- } else if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
- /* EVPN prefix - contents depend on type */
- bgp_evpn_encode_prefix(s, p, prd, label, num_labels, attr,
- addpath_capable, addpath_tx_id);
- } else if (safi == SAFI_LABELED_UNICAST) {
+ break;
+ case SAFI_EVPN:
+ if (afi == AFI_L2VPN)
+ /* EVPN prefix - contents depend on type */
+ bgp_evpn_encode_prefix(s, p, prd, label, num_labels,
+ attr, addpath_capable,
+ addpath_tx_id);
+ else
+ assert(!"Add encoding bits here for other AFI's");
+ break;
+ case SAFI_LABELED_UNICAST:
/* Prefix write with label. */
stream_put_labeled_prefix(s, p, label, addpath_capable,
addpath_tx_id);
- } else if (safi == SAFI_FLOWSPEC) {
+ break;
+ case SAFI_FLOWSPEC:
stream_putc(s, p->u.prefix_flowspec.prefixlen);
stream_put(s, (const void *)p->u.prefix_flowspec.ptr,
p->u.prefix_flowspec.prefixlen);
- } else
+ break;
+
+ case SAFI_UNICAST:
+ case SAFI_MULTICAST:
stream_put_prefix_addpath(s, p, addpath_capable, addpath_tx_id);
+ break;
+ case SAFI_ENCAP:
+ assert(!"Please add proper encoding of SAFI_ENCAP");
+ break;
+ }
}
size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi,
const struct prefix *p)
{
int size = PSIZE(p->prefixlen);
- if (safi == SAFI_MPLS_VPN)
+
+ switch (safi) {
+ case SAFI_UNSPEC:
+ case SAFI_MAX:
+ assert(!"Attempting to figure size for a SAFI_UNSPEC/SAFI_MAX this is a DEV ESCAPE");
+ break;
+ case SAFI_UNICAST:
+ case SAFI_MULTICAST:
+ break;
+ case SAFI_MPLS_VPN:
size += 88;
- else if (safi == SAFI_LABELED_UNICAST)
+ break;
+ case SAFI_ENCAP:
+ /* This has to be wrong, but I don't know what to put here */
+ assert(!"Do we try to use this?");
+ break;
+ case SAFI_LABELED_UNICAST:
size += BGP_LABEL_BYTES;
- else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
- size += 232; // TODO: Maximum possible for type-2, type-3 and
- // type-5
- else if (safi == SAFI_FLOWSPEC)
+ break;
+ case SAFI_EVPN:
+ /*
+ * TODO: Maximum possible for type-2, type-3 and type-5
+ */
+ if (afi == AFI_L2VPN)
+ size += 232;
+ else
+ assert(!"Attempting to figure size for SAFI_EVPN and !AFI_L2VPN and FRR will not have the proper values");
+ break;
+ case SAFI_FLOWSPEC:
size = ((struct prefix_fs *)p)->prefix.prefixlen;
+ break;
+ }
+
return size;
}
@@ -4641,7 +4695,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
}
/* AIGP */
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) &&
+ if (bpi && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) &&
(CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) ||
peer->sort != BGP_PEER_EBGP)) {
/* At the moment only AIGP Metric TLV exists for AIGP
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index bfde1c127e..9e540b63cb 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -51,6 +51,8 @@
#include "bgpd/bgp_flowspec.h"
#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_debug_clippy.c"
+
unsigned long conf_bgp_debug_as4;
unsigned long conf_bgp_debug_neighbor_events;
unsigned long conf_bgp_debug_events;
@@ -324,7 +326,7 @@ static void bgp_debug_list_add_entry(struct list *list, const char *host,
}
static bool bgp_debug_list_remove_entry(struct list *list, const char *host,
- struct prefix *p)
+ const struct prefix *p)
{
struct bgp_debug_filter *filter;
struct listnode *node, *nnode;
@@ -630,17 +632,14 @@ static void bgp_debug_print_evpn_prefix(struct vty *vty, const char *desc,
}
static int bgp_debug_parse_evpn_prefix(struct vty *vty, struct cmd_token **argv,
- int argc, struct prefix **argv_pp)
+ int argc, struct prefix *argv_p)
{
- struct prefix *argv_p;
struct ethaddr mac = {};
struct ipaddr ip = {};
int evpn_type = 0;
int mac_idx = 0;
int ip_idx = 0;
- argv_p = *argv_pp;
-
if (bgp_evpn_cli_parse_type(&evpn_type, argv, argc) < 0)
return CMD_WARNING;
@@ -1023,49 +1022,42 @@ DEFUN (no_debug_bgp_keepalive_peer,
}
/* debug bgp bestpath */
-DEFUN (debug_bgp_bestpath_prefix,
+DEFPY (debug_bgp_bestpath_prefix,
debug_bgp_bestpath_prefix_cmd,
- "debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>",
+ "debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>$prefix",
DEBUG_STR
BGP_STR
"BGP bestpath\n"
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- struct prefix *argv_p;
- int idx_ipv4_ipv6_prefixlen = 3;
-
- argv_p = prefix_new();
- (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p);
- apply_mask(argv_p);
-
if (!bgp_debug_bestpath_prefixes)
bgp_debug_bestpath_prefixes = list_new();
if (bgp_debug_list_has_entry(bgp_debug_bestpath_prefixes, NULL,
- argv_p)) {
+ prefix)) {
vty_out(vty,
"BGP bestpath debugging is already enabled for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
return CMD_SUCCESS;
}
- bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, argv_p);
+ bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, prefix);
if (vty->node == CONFIG_NODE) {
DEBUG_ON(bestpath, BESTPATH);
} else {
TERM_DEBUG_ON(bestpath, BESTPATH);
vty_out(vty, "BGP bestpath debugging is on for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
}
return CMD_SUCCESS;
}
-DEFUN (no_debug_bgp_bestpath_prefix,
+DEFPY (no_debug_bgp_bestpath_prefix,
no_debug_bgp_bestpath_prefix_cmd,
- "no debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>",
+ "no debug bgp bestpath <A.B.C.D/M|X:X::X:X/M>$prefix",
NO_STR
DEBUG_STR
BGP_STR
@@ -1073,18 +1065,12 @@ DEFUN (no_debug_bgp_bestpath_prefix,
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- int idx_ipv4_ipv6_prefixlen = 4;
- struct prefix *argv_p;
- int found_prefix = 0;
-
- argv_p = prefix_new();
- (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p);
- apply_mask(argv_p);
+ bool found_prefix = false;
if (bgp_debug_bestpath_prefixes
&& !list_isempty(bgp_debug_bestpath_prefixes)) {
found_prefix = bgp_debug_list_remove_entry(
- bgp_debug_bestpath_prefixes, NULL, argv_p);
+ bgp_debug_bestpath_prefixes, NULL, prefix);
if (list_isempty(bgp_debug_bestpath_prefixes)) {
if (vty->node == CONFIG_NODE) {
@@ -1099,10 +1085,10 @@ DEFUN (no_debug_bgp_bestpath_prefix,
if (found_prefix)
vty_out(vty, "BGP bestpath debugging is off for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
else
vty_out(vty, "BGP bestpath debugging was not enabled for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
return CMD_SUCCESS;
}
@@ -1410,8 +1396,6 @@ DEFUN (no_debug_bgp_update_direct_peer,
return CMD_SUCCESS;
}
-#include "bgpd/bgp_debug_clippy.c"
-
DEFPY (debug_bgp_update_prefix_afi_safi,
debug_bgp_update_prefix_afi_safi_cmd,
"debug bgp updates prefix l2vpn$afi evpn$safi type <<macip|2> mac <X:X:X:X:X:X|X:X:X:X:X:X/M> [ip <A.B.C.D|X:X::X:X>]|<multicast|3> ip <A.B.C.D|X:X::X:X>|<prefix|5> ip <A.B.C.D/M|X:X::X:X/M>>",
@@ -1439,39 +1423,33 @@ DEFPY (debug_bgp_update_prefix_afi_safi,
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- struct prefix *argv_p;
+ struct prefix argv_p;
int ret = CMD_SUCCESS;
- argv_p = prefix_new();
-
ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p);
- if (ret != CMD_SUCCESS) {
- prefix_free(&argv_p);
+ if (ret != CMD_SUCCESS)
return ret;
- }
if (!bgp_debug_update_prefixes)
bgp_debug_update_prefixes = list_new();
- if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, argv_p)) {
+ if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL,
+ &argv_p)) {
vty_out(vty,
"BGP updates debugging is already enabled for %pFX\n",
- argv_p);
- prefix_free(&argv_p);
+ &argv_p);
return CMD_SUCCESS;
}
- bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, argv_p);
+ bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, &argv_p);
if (vty->node == CONFIG_NODE) {
DEBUG_ON(update, UPDATE_PREFIX);
} else {
TERM_DEBUG_ON(update, UPDATE_PREFIX);
- vty_out(vty, "BGP updates debugging is on for %pFX\n", argv_p);
+ vty_out(vty, "BGP updates debugging is on for %pFX\n", &argv_p);
}
- prefix_free(&argv_p);
-
return CMD_SUCCESS;
}
@@ -1503,22 +1481,18 @@ DEFPY (no_debug_bgp_update_prefix_afi_safi,
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- struct prefix *argv_p;
+ struct prefix argv_p;
bool found_prefix = false;
int ret = CMD_SUCCESS;
- argv_p = prefix_new();
-
ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p);
- if (ret != CMD_SUCCESS) {
- prefix_free(&argv_p);
+ if (ret != CMD_SUCCESS)
return ret;
- }
if (bgp_debug_update_prefixes
&& !list_isempty(bgp_debug_update_prefixes)) {
found_prefix = bgp_debug_list_remove_entry(
- bgp_debug_update_prefixes, NULL, argv_p);
+ bgp_debug_update_prefixes, NULL, &argv_p);
if (list_isempty(bgp_debug_update_prefixes)) {
if (vty->node == CONFIG_NODE) {
@@ -1532,20 +1506,19 @@ DEFPY (no_debug_bgp_update_prefix_afi_safi,
}
if (found_prefix)
- vty_out(vty, "BGP updates debugging is off for %pFX\n", argv_p);
+ vty_out(vty, "BGP updates debugging is off for %pFX\n",
+ &argv_p);
else
vty_out(vty, "BGP updates debugging was not enabled for %pFX\n",
- argv_p);
-
- prefix_free(&argv_p);
+ &argv_p);
return ret;
}
-DEFUN (debug_bgp_update_prefix,
+DEFPY (debug_bgp_update_prefix,
debug_bgp_update_prefix_cmd,
- "debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>",
+ "debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>$prefix",
DEBUG_STR
BGP_STR
"BGP updates\n"
@@ -1553,39 +1526,32 @@ DEFUN (debug_bgp_update_prefix,
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- int idx_ipv4_ipv6_prefixlen = 4;
- struct prefix *argv_p;
-
- argv_p = prefix_new();
- (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p);
- apply_mask(argv_p);
-
if (!bgp_debug_update_prefixes)
bgp_debug_update_prefixes = list_new();
- if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, argv_p)) {
+ if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, prefix)) {
vty_out(vty,
"BGP updates debugging is already enabled for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
return CMD_SUCCESS;
}
- bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, argv_p);
+ bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, prefix);
if (vty->node == CONFIG_NODE) {
DEBUG_ON(update, UPDATE_PREFIX);
} else {
TERM_DEBUG_ON(update, UPDATE_PREFIX);
vty_out(vty, "BGP updates debugging is on for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
}
return CMD_SUCCESS;
}
-DEFUN (no_debug_bgp_update_prefix,
+DEFPY (no_debug_bgp_update_prefix,
no_debug_bgp_update_prefix_cmd,
- "no debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>",
+ "no debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>$prefix",
NO_STR
DEBUG_STR
BGP_STR
@@ -1594,18 +1560,12 @@ DEFUN (no_debug_bgp_update_prefix,
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- int idx_ipv4_ipv6_prefixlen = 5;
- struct prefix *argv_p;
- int found_prefix = 0;
-
- argv_p = prefix_new();
- (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p);
- apply_mask(argv_p);
+ bool found_prefix = false;
if (bgp_debug_update_prefixes
&& !list_isempty(bgp_debug_update_prefixes)) {
found_prefix = bgp_debug_list_remove_entry(
- bgp_debug_update_prefixes, NULL, argv_p);
+ bgp_debug_update_prefixes, NULL, prefix);
if (list_isempty(bgp_debug_update_prefixes)) {
if (vty->node == CONFIG_NODE) {
@@ -1620,10 +1580,10 @@ DEFUN (no_debug_bgp_update_prefix,
if (found_prefix)
vty_out(vty, "BGP updates debugging is off for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
else
vty_out(vty, "BGP updates debugging was not enabled for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
return CMD_SUCCESS;
}
@@ -1693,9 +1653,9 @@ DEFUN (debug_bgp_graceful_restart,
}
-DEFUN (debug_bgp_zebra_prefix,
+DEFPY (debug_bgp_zebra_prefix,
debug_bgp_zebra_prefix_cmd,
- "debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>",
+ "debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>$prefix",
DEBUG_STR
BGP_STR
"BGP Zebra messages\n"
@@ -1703,30 +1663,22 @@ DEFUN (debug_bgp_zebra_prefix,
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- int idx_ipv4_ipv6_prefixlen = 4;
- struct prefix *argv_p;
-
- argv_p = prefix_new();
- (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p);
- apply_mask(argv_p);
-
if (!bgp_debug_zebra_prefixes)
bgp_debug_zebra_prefixes = list_new();
- if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, argv_p)) {
+ if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, prefix)) {
vty_out(vty, "BGP zebra debugging is already enabled for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
return CMD_SUCCESS;
}
- bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, argv_p);
+ bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, prefix);
if (vty->node == CONFIG_NODE)
DEBUG_ON(zebra, ZEBRA);
else {
TERM_DEBUG_ON(zebra, ZEBRA);
- vty_out(vty, "BGP zebra debugging is on for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ vty_out(vty, "BGP zebra debugging is on for %s\n", prefix_str);
}
return CMD_SUCCESS;
@@ -1768,9 +1720,9 @@ DEFUN (no_debug_bgp_graceful_restart,
return CMD_SUCCESS;
}
-DEFUN (no_debug_bgp_zebra_prefix,
+DEFPY (no_debug_bgp_zebra_prefix,
no_debug_bgp_zebra_prefix_cmd,
- "no debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>",
+ "no debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>$prefix",
NO_STR
DEBUG_STR
BGP_STR
@@ -1779,18 +1731,12 @@ DEFUN (no_debug_bgp_zebra_prefix,
"IPv4 prefix\n"
"IPv6 prefix\n")
{
- int idx_ipv4_ipv6_prefixlen = 5;
- struct prefix *argv_p;
- int found_prefix = 0;
-
- argv_p = prefix_new();
- (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p);
- apply_mask(argv_p);
+ bool found_prefix = false;
if (bgp_debug_zebra_prefixes
&& !list_isempty(bgp_debug_zebra_prefixes)) {
found_prefix = bgp_debug_list_remove_entry(
- bgp_debug_zebra_prefixes, NULL, argv_p);
+ bgp_debug_zebra_prefixes, NULL, prefix);
if (list_isempty(bgp_debug_zebra_prefixes)) {
if (vty->node == CONFIG_NODE)
@@ -1803,11 +1749,10 @@ DEFUN (no_debug_bgp_zebra_prefix,
}
if (found_prefix)
- vty_out(vty, "BGP zebra debugging is off for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ vty_out(vty, "BGP zebra debugging is off for %s\n", prefix_str);
else
vty_out(vty, "BGP zebra debugging was not enabled for %s\n",
- argv[idx_ipv4_ipv6_prefixlen]->arg);
+ prefix_str);
return CMD_SUCCESS;
}
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 65de35cbdb..923586f633 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -1245,7 +1245,7 @@ static void bgp_update_delay_process_status_change(struct peer *peer)
/* Called after event occurred, this function change status and reset
read/write and timer thread. */
-void bgp_fsm_change_status(struct peer *peer, int status)
+void bgp_fsm_change_status(struct peer *peer, enum bgp_fsm_status status)
{
struct bgp *bgp;
uint32_t peer_count;
diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h
index 368c2c5001..6418e15b9a 100644
--- a/bgpd/bgp_fsm.h
+++ b/bgpd/bgp_fsm.h
@@ -125,7 +125,8 @@ extern int bgp_event_update(struct peer *, enum bgp_fsm_events event);
extern int bgp_stop(struct peer *peer);
extern void bgp_timer_set(struct peer *);
extern void bgp_routeadv_timer(struct thread *);
-extern void bgp_fsm_change_status(struct peer *peer, int status);
+extern void bgp_fsm_change_status(struct peer *peer,
+ enum bgp_fsm_status status);
extern const char *const peer_down_str[];
extern void bgp_update_delay_end(struct bgp *);
extern void bgp_maxmed_update(struct bgp *);
diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c
index 467a33694a..fe0c33251e 100644
--- a/bgpd/bgp_snmp_bgp4v2.c
+++ b/bgpd/bgp_snmp_bgp4v2.c
@@ -145,10 +145,24 @@ static struct peer *bgpv2PeerTable_lookup(struct variable *v, oid name[],
size_t namelen = v ? v->namelen : BGP4V2_PEER_ENTRY_OFFSET;
oid *offset = name + namelen;
sa_family_t family = name[namelen - 1] == 4 ? AF_INET : AF_INET6;
+ int afi_len = IN_ADDR_SIZE;
+ size_t offsetlen = *length - namelen;
+
+ if (family == AF_INET6)
+ afi_len = IN6_ADDR_SIZE;
+
+ /* Somehow with net-snmp 5.7.3, every OID item in an array
+ * is uninitialized and has a max random value, let's zero it.
+ * With 5.8, 5.9, it works fine even without this hack.
+ */
+ if (!offsetlen) {
+ for (int i = 0; i < afi_len; i++)
+ *(offset + i) = 0;
+ }
if (exact) {
if (family == AF_INET) {
- oid2in_addr(offset, IN_ADDR_SIZE, &addr->ip._v4_addr);
+ oid2in_addr(offset, afi_len, &addr->ip._v4_addr);
peer = peer_lookup_all_vrf(addr);
return peer;
} else if (family == AF_INET6) {
@@ -163,11 +177,11 @@ static struct peer *bgpv2PeerTable_lookup(struct variable *v, oid name[],
switch (sockunion_family(&peer->su)) {
case AF_INET:
oid_copy_in_addr(offset, &peer->su.sin.sin_addr);
- *length = IN_ADDR_SIZE + namelen;
+ *length = afi_len + namelen;
return peer;
case AF_INET6:
oid_copy_in6_addr(offset, &peer->su.sin6.sin6_addr);
- *length = IN6_ADDR_SIZE + namelen;
+ *length = afi_len + namelen;
return peer;
default:
break;
@@ -367,9 +381,10 @@ static uint8_t *bgpv2PeerErrorsTable(struct variable *v, oid name[],
}
return SNMP_STRING("");
case BGP4V2_PEER_LAST_ERROR_SENT_DATA:
- if (peer->last_reset == PEER_DOWN_NOTIFY_SEND ||
- peer->last_reset == PEER_DOWN_RTT_SHUTDOWN ||
- peer->last_reset == PEER_DOWN_USER_SHUTDOWN)
+ if ((peer->last_reset == PEER_DOWN_NOTIFY_SEND ||
+ peer->last_reset == PEER_DOWN_RTT_SHUTDOWN ||
+ peer->last_reset == PEER_DOWN_USER_SHUTDOWN) &&
+ peer->notify.data)
return SNMP_STRING(peer->notify.data);
else
return SNMP_STRING("");
@@ -420,7 +435,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length,
{
oid *offset;
int offsetlen;
- struct bgp_path_info *path;
+ struct bgp_path_info *path, *min;
struct bgp_dest *dest;
union sockunion su;
unsigned int len;
@@ -500,6 +515,8 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length,
else
addr->prefixlen = len * 8;
+ addr->family = family;
+
dest = bgp_node_get(bgp->rib[afi][SAFI_UNICAST], addr);
offset++;
@@ -525,8 +542,8 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length,
if (!dest)
return NULL;
- while ((dest = bgp_route_next(dest))) {
- struct bgp_path_info *min = NULL;
+ do {
+ min = NULL;
for (path = bgp_dest_get_bgp_path_info(dest); path;
path = path->next) {
@@ -564,6 +581,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length,
offset = name + namelen;
+ /* Encode prefix into OID */
if (family == AF_INET)
oid_copy_in_addr(offset, &rn_p->u.prefix4);
else
@@ -573,6 +591,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length,
*offset = rn_p->prefixlen;
offset++;
+ /* Encode peer's IP into OID */
if (family == AF_INET) {
oid_copy_in_addr(offset,
&min->peer->su.sin.sin_addr);
@@ -584,6 +603,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length,
}
addr->prefixlen = rn_p->prefixlen;
+ addr->family = rn_p->family;
bgp_dest_unlock_node(dest);
@@ -594,7 +614,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length,
memset(&paddr.ip._v4_addr, 0, afi_len);
else
memset(&paddr.ip._v6_addr, 0, afi_len);
- }
+ } while ((dest = bgp_route_next(dest)));
return NULL;
}
@@ -735,7 +755,7 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[],
case BGP4V2_NLRI_MED:
if (CHECK_FLAG(path->attr->flag,
ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)))
- return SNMP_INTEGER(path->attr->local_pref);
+ return SNMP_INTEGER(path->attr->med);
else
return SNMP_INTEGER(0);
case BGP4V2_NLRI_ATOMIC_AGGREGATE:
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 219362cd04..8ea9c1996b 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -14693,7 +14693,7 @@ static int bgp_show_neighbor_graceful_restart(struct vty *vty, struct bgp *bgp,
{
struct listnode *node, *nnode;
struct peer *peer;
- int find = 0;
+ bool found = false;
safi_t safi = SAFI_UNICAST;
json_object *json_neighbor = NULL;
@@ -14721,27 +14721,31 @@ static int bgp_show_neighbor_graceful_restart(struct vty *vty, struct bgp *bgp,
&& !strcmp(peer->conf_if, conf_if))
|| (peer->hostname
&& !strcmp(peer->hostname, conf_if))) {
- find = 1;
+ found = true;
bgp_show_peer_gr_status(vty, peer,
json_neighbor);
}
} else {
if (sockunion_same(&peer->su, su)) {
- find = 1;
+ found = true;
bgp_show_peer_gr_status(vty, peer,
json_neighbor);
}
}
- if (json && find)
- json_object_object_add(json, peer->host,
- json_neighbor);
+ if (json) {
+ if (found)
+ json_object_object_add(json, peer->host,
+ json_neighbor);
+ else
+ json_object_free(json_neighbor);
+ }
}
- if (find)
+ if (found)
break;
}
- if (type == show_peer && !find) {
+ if (type == show_peer && !found) {
if (json)
json_object_boolean_true_add(json, "bgpNoSuchNeighbor");
else
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 952b8fcc56..f6e7b444c6 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1589,7 +1589,9 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
api_nh->weight = nh_weight;
- if (mpinfo->extra && !sid_zero(&mpinfo->extra->sid[0].sid) &&
+ if (mpinfo->extra &&
+ bgp_is_valid_label(&mpinfo->extra->label[0]) &&
+ !sid_zero(&mpinfo->extra->sid[0].sid) &&
!CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) {
sid_info = &mpinfo->extra->sid[0];
@@ -1597,12 +1599,16 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
sizeof(api_nh->seg6_segs));
if (sid_info->transposition_len != 0) {
- if (!bgp_is_valid_label(
- &mpinfo->extra->label[0]))
- continue;
-
mpls_lse_decode(mpinfo->extra->label[0], &label,
&ttl, &exp, &bos);
+
+ if (label < MPLS_LABEL_UNRESERVED_MIN) {
+ if (bgp_debug_zebra(&api.prefix))
+ zlog_debug(
+ "skip invalid SRv6 routes: transposition scheme is used, but label is too small");
+ continue;
+ }
+
transpose_sid(&api_nh->seg6_segs, label,
sid_info->transposition_offset,
sid_info->transposition_len);
@@ -1683,9 +1689,8 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
zlog_debug(
"Tx route %s VRF %u %pFX metric %u tag %" ROUTE_TAG_PRI
" count %d nhg %d",
- valid_nh_count ? "add" : "delete", bgp->vrf_id,
- &api.prefix, api.metric, api.tag, api.nexthop_num,
- nhg_id);
+ is_add ? "add" : "delete", bgp->vrf_id, &api.prefix,
+ api.metric, api.tag, api.nexthop_num, nhg_id);
for (i = 0; i < api.nexthop_num; i++) {
api_nh = &api.nexthops[i];
diff --git a/debian/changelog b/debian/changelog
index ad43f13e33..e3b6634594 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -4,11 +4,11 @@ frr (8.5~dev-1) UNRELEASED; urgency=medium
-- Donatas Abraitis <donatas@opensourcerouting.org> Tue, 04 Oct 2022 16:00:00 +0500
-frr (8.4~dev-1) UNRELEASED; urgency=medium
+frr (8.4-0) unstable; urgency=medium
- * FRR Dev 8.4
+ * New upstream release FRR 8.4
- -- Jafar Al-Gharaibeh <jafar@atcorp.com> Wed, 20 Jul 2022 10:00:00 +0500
+ -- Jafar Al-Gharaibeh <jafar@atcorp.com> Tue, 01 Nov 2022 10:00:00 +0500
frr (8.3-0) unstable; urgency=medium
diff --git a/doc/user/evpn.rst b/doc/user/evpn.rst
index 0737ab6f07..c8052803cc 100644
--- a/doc/user/evpn.rst
+++ b/doc/user/evpn.rst
@@ -441,7 +441,7 @@ Here a traditional ``vxlan`` interface is created with the name "vni100" which
uses a VTEP-IP of 100.64.0.1, carries VNI 100, and has Dynamic VTEP learning
disabled. IPv6 address autoconfiguration is disabled for "vni100", then the
interface is enslaved to "br100", ARP/ND suppression is enabled, and Dynamic
-VTEP Learning is disabled.
+MAC Learning is disabled.
.. code-block:: shell
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index 69c1c18d3c..0dff2ea448 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -831,6 +831,13 @@ Showing Information
Show the OSPF routing table, as determined by the most recent SPF
calculation.
+.. clicmd:: show ip ospf [vrf <NAME|all>] border-routers [json]
+
+ Show the list of ABR and ASBR border routers summary learnt via
+ OSPFv2 Type-3 (Summary LSA) and Type-4 (Summary ASBR LSA).
+ User can get that information as JSON format when ``json`` keyword
+ at the end of cli is presented.
+
.. clicmd:: show ip ospf (1-65535) route orr [NAME]
.. clicmd:: show ip ospf [vrf <NAME|all>] route orr [NAME]
diff --git a/doc/user/snmp.rst b/doc/user/snmp.rst
index b9058cc0d3..0bf3565b2e 100644
--- a/doc/user/snmp.rst
+++ b/doc/user/snmp.rst
@@ -115,6 +115,65 @@ Then, you can use the following command to check everything works as expected:
OSPF-MIB::ospfRouterId.0 = IpAddress: 192.168.42.109
[...]
+An example below is how to query SNMP for BGP:
+
+ .. code-block:: shell
+
+ $ # BGP4-MIB (https://www.circitor.fr/Mibs/Mib/B/BGP4-MIB.mib)
+ $ snmpwalk -c public -v2c -On -Ln localhost .1.3.6.1.2.1.15
+
+ $ # BGP4V2-MIB (http://www.circitor.fr/Mibs/Mib/B/BGP4V2-MIB.mib)
+ $ # Information about the peers (bgp4V2PeerTable):
+ $ snmpwalk -c public -v2c -On -Ln localhost .1.3.6.1.3.5.1.1.2
+ ...
+ .1.3.6.1.3.5.1.1.2.1.1.1.4.192.168.10.124 = Gauge32: 0
+ .1.3.6.1.3.5.1.1.2.1.1.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 0
+ .1.3.6.1.3.5.1.1.2.1.2.1.4.192.168.10.124 = INTEGER: 1
+ .1.3.6.1.3.5.1.1.2.1.2.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 2
+ .1.3.6.1.3.5.1.1.2.1.3.1.4.192.168.10.124 = Hex-STRING: C0 A8 0A 11
+ .1.3.6.1.3.5.1.1.2.1.3.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: 2A 02 47 80 0A BC 00 00 00 00 00 00 00 00 00 01
+ .1.3.6.1.3.5.1.1.2.1.4.1.4.192.168.10.124 = INTEGER: 1
+ .1.3.6.1.3.5.1.1.2.1.4.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 2
+ .1.3.6.1.3.5.1.1.2.1.5.1.4.192.168.10.124 = Hex-STRING: C0 A8 0A 7C
+ .1.3.6.1.3.5.1.1.2.1.5.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: 2A 02 47 80 0A BC 00 00 00 00 00 00 00 00 00 02
+ .1.3.6.1.3.5.1.1.2.1.6.1.4.192.168.10.124 = Gauge32: 179
+ .1.3.6.1.3.5.1.1.2.1.6.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 179
+ .1.3.6.1.3.5.1.1.2.1.7.1.4.192.168.10.124 = Gauge32: 65002
+ .1.3.6.1.3.5.1.1.2.1.7.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 65002
+ .1.3.6.1.3.5.1.1.2.1.8.1.4.192.168.10.124 = Hex-STRING: C0 A8 0A 11
+ .1.3.6.1.3.5.1.1.2.1.8.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: C0 A8 0A 11
+ .1.3.6.1.3.5.1.1.2.1.9.1.4.192.168.10.124 = Gauge32: 41894
+ .1.3.6.1.3.5.1.1.2.1.9.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 39960
+ .1.3.6.1.3.5.1.1.2.1.10.1.4.192.168.10.124 = Gauge32: 65001
+ .1.3.6.1.3.5.1.1.2.1.10.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 65001
+ .1.3.6.1.3.5.1.1.2.1.11.1.4.192.168.10.124 = Hex-STRING: C8 C8 C8 CA
+ .1.3.6.1.3.5.1.1.2.1.11.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: C8 C8 C8 CA
+ .1.3.6.1.3.5.1.1.2.1.12.1.4.192.168.10.124 = INTEGER: 2
+ .1.3.6.1.3.5.1.1.2.1.12.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 2
+ .1.3.6.1.3.5.1.1.2.1.13.1.4.192.168.10.124 = INTEGER: 6
+ .1.3.6.1.3.5.1.1.2.1.13.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 6
+
+ $ # Information about the BGP table (bgp4V2NlriTable):
+ $ snmpwalk -c public -v2c -On -Ln localhost .1.3.6.1.3.5.1.1.9
+ ...
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.10.0.2.0.24.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.10.10.100.0.24.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.172.16.31.1.32.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.172.16.31.2.32.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.172.16.31.3.32.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.192.168.0.0.24.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.192.168.1.0.24.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.1.4.192.168.10.0.24.192.168.10.124 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.22.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.0.64.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 1
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.10.0.2.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.10.10.100.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.172.16.31.1.32.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.172.16.31.2.32.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.172.16.31.3.32.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.192.168.0.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.192.168.1.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.1.4.192.168.10.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9
+ .1.3.6.1.3.5.1.1.9.1.24.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.0.64.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: 02 01 FD E9
The AgentX protocol can be transported over a Unix socket or using TCP or UDP.
It usually defaults to a Unix socket and depends on how NetSNMP was built. If
@@ -132,5 +191,7 @@ Here is the syntax for using AgentX:
.. clicmd:: agentx
+ Once enabled, it can't be unconfigured. Only removing from the daemons file
+ the keyword ``agentx`` takes an effect.
.. include:: snmptrap.rst
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index 3608f828e8..c05a29af4e 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -309,6 +309,15 @@ the default route.
User can get that information as JSON string when ``json`` key word
at the end of cli is presented.
+.. clicmd:: show ip nht route-map [vrf <NAME|all>] [json]
+
+ This command displays route-map attach point to nexthop tracking and
+ displays list of protocol with its applied route-map.
+ When zebra considers sending NHT resoultion, the nofification only
+ sent to appropriate client protocol only after applying route-map filter.
+ User can get that information as JSON format when ``json`` keyword
+ at the end of cli is presented.
+
PBR dataplane programming
=========================
diff --git a/lib/agentx.c b/lib/agentx.c
index 6c2923fcf8..5f62459805 100644
--- a/lib/agentx.c
+++ b/lib/agentx.c
@@ -32,13 +32,15 @@
#include "linklist.h"
#include "lib/version.h"
#include "lib_errors.h"
+#include "hook.h"
+#include "libfrr.h"
#include "xref.h"
XREF_SETUP();
DEFINE_HOOK(agentx_enabled, (), ());
-static int agentx_enabled = 0;
+static bool agentx_enabled = false;
static struct thread_master *agentx_tm;
static struct thread *timeout_thr = NULL;
@@ -226,7 +228,7 @@ DEFUN (agentx_enable,
init_snmp(FRR_SMUX_NAME);
events = list_new();
agentx_events_update();
- agentx_enabled = 1;
+ agentx_enabled = true;
hook_call(agentx_enabled);
}
@@ -245,7 +247,14 @@ DEFUN (no_agentx,
return CMD_WARNING_CONFIG_FAILED;
}
-int smux_enabled(void)
+static int smux_disable(void)
+{
+ agentx_enabled = false;
+
+ return 0;
+}
+
+bool smux_enabled(void)
{
return agentx_enabled;
}
@@ -264,6 +273,8 @@ void smux_init(struct thread_master *tm)
install_node(&agentx_node);
install_element(CONFIG_NODE, &agentx_enable_cmd);
install_element(CONFIG_NODE, &no_agentx_cmd);
+
+ hook_register(frr_early_fini, smux_disable);
}
void smux_agentx_enable(void)
@@ -272,7 +283,7 @@ void smux_agentx_enable(void)
init_snmp(FRR_SMUX_NAME);
events = list_new();
agentx_events_update();
- agentx_enabled = 1;
+ agentx_enabled = true;
}
}
diff --git a/lib/smux.h b/lib/smux.h
index 48c3374236..1d73406a28 100644
--- a/lib/smux.h
+++ b/lib/smux.h
@@ -109,7 +109,10 @@ struct index_oid {
#define SNMP_IP6ADDRESS(V) (*var_len = sizeof(struct in6_addr), (uint8_t *)&V)
-extern int smux_enabled(void);
+/*
+ * Check to see if snmp is enabled or not
+ */
+extern bool smux_enabled(void);
extern void smux_init(struct thread_master *tm);
extern void smux_agentx_enable(void);
diff --git a/lib/srv6.c b/lib/srv6.c
index 5cd82080f5..f4077a86d2 100644
--- a/lib/srv6.c
+++ b/lib/srv6.c
@@ -121,6 +121,13 @@ const char *seg6local_context2str(char *str, size_t size,
}
}
+static void srv6_locator_chunk_list_free(void *data)
+{
+ struct srv6_locator_chunk *chunk = data;
+
+ srv6_locator_chunk_free(&chunk);
+}
+
struct srv6_locator *srv6_locator_alloc(const char *name)
{
struct srv6_locator *locator = NULL;
@@ -128,7 +135,7 @@ struct srv6_locator *srv6_locator_alloc(const char *name)
locator = XCALLOC(MTYPE_SRV6_LOCATOR, sizeof(struct srv6_locator));
strlcpy(locator->name, name, sizeof(locator->name));
locator->chunks = list_new();
- locator->chunks->del = (void (*)(void *))srv6_locator_chunk_free;
+ locator->chunks->del = srv6_locator_chunk_list_free;
QOBJ_REG(locator, srv6_locator);
return locator;
diff --git a/lib/workqueue.c b/lib/workqueue.c
index c703de90b3..a5338ba78b 100644
--- a/lib/workqueue.c
+++ b/lib/workqueue.c
@@ -272,9 +272,6 @@ void work_queue_run(struct thread *thread)
/* dont run items which are past their allowed retries */
if (item->ran > wq->spec.max_retries) {
- /* run error handler, if any */
- if (wq->spec.errorfunc)
- wq->spec.errorfunc(wq, item);
work_queue_item_remove(wq, item);
continue;
}
@@ -317,10 +314,6 @@ void work_queue_run(struct thread *thread)
case WQ_RETRY_NOW:
/* a RETRY_NOW that gets here has exceeded max_tries, same as
* ERROR */
- case WQ_ERROR: {
- if (wq->spec.errorfunc)
- wq->spec.errorfunc(wq, item);
- }
/* fallthru */
case WQ_SUCCESS:
default: {
diff --git a/lib/workqueue.h b/lib/workqueue.h
index 27fb1383eb..7866032fc0 100644
--- a/lib/workqueue.h
+++ b/lib/workqueue.h
@@ -41,7 +41,6 @@ DECLARE_MTYPE(WORK_QUEUE);
/* action value, for use by item processor and item error handlers */
typedef enum {
WQ_SUCCESS = 0,
- WQ_ERROR, /* Error, run error handler if provided */
WQ_RETRY_NOW, /* retry immediately */
WQ_RETRY_LATER, /* retry later, cease processing work queue */
WQ_REQUEUE, /* requeue item, continue processing work queue */
@@ -80,10 +79,6 @@ struct work_queue {
*/
wq_item_status (*workfunc)(struct work_queue *, void *);
- /* error handling function, optional */
- void (*errorfunc)(struct work_queue *,
- struct work_queue_item *);
-
/* callback to delete user specific item data */
void (*del_item_data)(struct work_queue *, void *);
diff --git a/lib/zlog_targets.c b/lib/zlog_targets.c
index 31bd8e16eb..f7ea48bf9d 100644
--- a/lib/zlog_targets.c
+++ b/lib/zlog_targets.c
@@ -257,6 +257,7 @@ bool zlog_file_set_filename(struct zlog_cfg_file *zcf, const char *filename)
return zlog_file_cycle(zcf);
}
assert(0);
+ return false;
}
bool zlog_file_set_fd(struct zlog_cfg_file *zcf, int fd)
@@ -271,6 +272,7 @@ bool zlog_file_set_fd(struct zlog_cfg_file *zcf, int fd)
return zlog_file_cycle(zcf);
}
assert(0);
+ return false;
}
struct rcu_close_rotate {
@@ -544,6 +546,7 @@ int zlog_syslog_get_facility(void)
return syslog_facility;
}
assert(0);
+ return 0;
}
void zlog_syslog_set_prio_min(int prio_min)
@@ -581,4 +584,5 @@ int zlog_syslog_get_prio_min(void)
return syslog_prio_min;
}
assert(0);
+ return 0;
}
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 07061b6f57..0fd6e15ed6 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -1585,7 +1585,11 @@ ospf6_asbr_summary_remove_lsa_and_route(struct ospf6 *ospf6,
zlog_debug(
"%s: Remove the blackhole route",
__func__);
+
ospf6_zebra_route_update_remove(aggr->route, ospf6);
+ if (aggr->route->route_option)
+ XFREE(MTYPE_OSPF6_EXTERNAL_INFO,
+ aggr->route->route_option);
ospf6_route_delete(aggr->route);
aggr->route = NULL;
}
@@ -2736,8 +2740,13 @@ ospf6_summary_add_aggr_route_and_blackhole(struct ospf6 *ospf6,
struct ospf6_external_aggr_rt *aggr)
{
struct ospf6_route *rt_aggr;
+ struct ospf6_route *old_rt = NULL;
struct ospf6_external_info *info;
+ /* Check if a route is already present. */
+ if (aggr->route)
+ old_rt = aggr->route;
+
/* Create summary route and save it. */
rt_aggr = ospf6_route_create(ospf6);
rt_aggr->type = OSPF6_DEST_TYPE_NETWORK;
@@ -2756,6 +2765,16 @@ ospf6_summary_add_aggr_route_and_blackhole(struct ospf6 *ospf6,
/* Add next-hop to Null interface. */
ospf6_add_route_nexthop_blackhole(rt_aggr);
+ /* Free the old route, if any. */
+ if (old_rt) {
+ ospf6_zebra_route_update_remove(old_rt, ospf6);
+
+ if (old_rt->route_option)
+ XFREE(MTYPE_OSPF6_EXTERNAL_INFO, old_rt->route_option);
+
+ ospf6_route_delete(old_rt);
+ }
+
ospf6_zebra_route_update_add(rt_aggr, ospf6);
}
@@ -3024,8 +3043,8 @@ static void ospf6_aggr_handle_external_info(void *data)
(void)ospf6_originate_type5_type7_lsas(rt, ospf6);
}
-static void
-ospf6_asbr_summary_config_delete(struct ospf6 *ospf6, struct route_node *rn)
+void ospf6_asbr_summary_config_delete(struct ospf6 *ospf6,
+ struct route_node *rn)
{
struct ospf6_external_aggr_rt *aggr = rn->info;
@@ -3167,14 +3186,6 @@ void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt *aggr)
hash_clean(aggr->match_extnl_hash,
ospf6_aggr_unlink_external_info);
- if (aggr->route) {
- if (aggr->route->route_option)
- XFREE(MTYPE_OSPF6_EXTERNAL_INFO,
- aggr->route->route_option);
-
- ospf6_route_delete(aggr->route);
- }
-
if (IS_OSPF6_DEBUG_AGGR)
zlog_debug("%s: Release the aggregator Address(%pFX)",
__func__,
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
index 0487bb14c3..0d2a98aeba 100644
--- a/ospf6d/ospf6_asbr.h
+++ b/ospf6d/ospf6_asbr.h
@@ -182,4 +182,6 @@ void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt *aggr);
void ospf6_unset_all_aggr_flag(struct ospf6 *ospf6);
void ospf6_fill_aggr_route_details(struct ospf6 *ospf6,
struct ospf6_external_aggr_rt *aggr);
+void ospf6_asbr_summary_config_delete(struct ospf6 *ospf6,
+ struct route_node *rn);
#endif /* OSPF6_ASBR_H */
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 1c045cba07..d3dd5501a4 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -303,6 +303,9 @@ void ospf6_interface_delete(struct ospf6_interface *oi)
/* disable from area list if possible */
ospf6_area_interface_delete(oi);
+ if (oi->at_data.auth_key)
+ XFREE(MTYPE_OSPF6_AUTH_MANUAL_KEY, oi->at_data.auth_key);
+
/* Free BFD allocated data. */
XFREE(MTYPE_TMP, oi->bfd_config.profile);
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index 360a9db0d6..fb54ebab15 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -2015,6 +2015,9 @@ static void ospf6_auth_trailer_copy_keychain_key(struct ospf6_interface *oi)
* these values
*/
oi->at_data.hash_algo = key->hash_algo;
+ if (oi->at_data.auth_key)
+ XFREE(MTYPE_OSPF6_AUTH_MANUAL_KEY,
+ oi->at_data.auth_key);
oi->at_data.auth_key = XSTRDUP(
MTYPE_OSPF6_AUTH_MANUAL_KEY, key->string);
oi->at_data.key_id = key->index;
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
index 439b94c9af..a4ba1fb569 100644
--- a/ospf6d/ospf6_neighbor.c
+++ b/ospf6d/ospf6_neighbor.c
@@ -106,6 +106,23 @@ struct ospf6_neighbor *ospf6_area_neighbor_lookup(struct ospf6_area *area,
return NULL;
}
+static void ospf6_neighbor_clear_ls_lists(struct ospf6_neighbor *on)
+{
+ struct ospf6_lsa *lsa;
+ struct ospf6_lsa *lsanext;
+
+ ospf6_lsdb_remove_all(on->summary_list);
+ if (on->last_ls_req) {
+ ospf6_lsa_unlock(on->last_ls_req);
+ on->last_ls_req = NULL;
+ }
+ ospf6_lsdb_remove_all(on->request_list);
+ for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
+ ospf6_decrement_retrans_count(lsa);
+ ospf6_lsdb_remove(lsa, on->retrans_list);
+ }
+}
+
/* create ospf6_neighbor */
struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
struct ospf6_interface *oi)
@@ -147,14 +164,7 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
void ospf6_neighbor_delete(struct ospf6_neighbor *on)
{
- struct ospf6_lsa *lsa, *lsanext;
-
- ospf6_lsdb_remove_all(on->summary_list);
- ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
- ospf6_decrement_retrans_count(lsa);
- ospf6_lsdb_remove(lsa, on->retrans_list);
- }
+ ospf6_neighbor_clear_ls_lists(on);
ospf6_lsdb_remove_all(on->dbdesc_list);
ospf6_lsdb_remove_all(on->lsupdate_list);
@@ -339,12 +349,7 @@ void negotiation_done(struct thread *thread)
zlog_debug("Neighbor Event %s: *NegotiationDone*", on->name);
/* clear ls-list */
- ospf6_lsdb_remove_all(on->summary_list);
- ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
- ospf6_decrement_retrans_count(lsa);
- ospf6_lsdb_remove(lsa, on->retrans_list);
- }
+ ospf6_neighbor_clear_ls_lists(on);
/* Interface scoped LSAs */
for (ALL_LSDB(on->ospf6_if->lsdb, lsa, lsanext)) {
@@ -464,7 +469,6 @@ void loading_done(struct thread *thread)
void adj_ok(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa, *lsanext;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
assert(on);
@@ -486,19 +490,13 @@ void adj_ok(struct thread *thread)
} else if (on->state >= OSPF6_NEIGHBOR_EXSTART && !need_adjacency(on)) {
ospf6_neighbor_state_change(OSPF6_NEIGHBOR_TWOWAY, on,
OSPF6_NEIGHBOR_EVENT_ADJ_OK);
- ospf6_lsdb_remove_all(on->summary_list);
- ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
- ospf6_decrement_retrans_count(lsa);
- ospf6_lsdb_remove(lsa, on->retrans_list);
- }
+ ospf6_neighbor_clear_ls_lists(on);
}
}
void seqnumber_mismatch(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa, *lsanext;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
assert(on);
@@ -515,12 +513,7 @@ void seqnumber_mismatch(struct thread *thread)
SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT);
SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT);
- ospf6_lsdb_remove_all(on->summary_list);
- ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
- ospf6_decrement_retrans_count(lsa);
- ospf6_lsdb_remove(lsa, on->retrans_list);
- }
+ ospf6_neighbor_clear_ls_lists(on);
THREAD_OFF(on->thread_send_dbdesc);
on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */
@@ -532,7 +525,6 @@ void seqnumber_mismatch(struct thread *thread)
void bad_lsreq(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa, *lsanext;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
assert(on);
@@ -549,12 +541,7 @@ void bad_lsreq(struct thread *thread)
SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT);
SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT);
- ospf6_lsdb_remove_all(on->summary_list);
- ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
- ospf6_decrement_retrans_count(lsa);
- ospf6_lsdb_remove(lsa, on->retrans_list);
- }
+ ospf6_neighbor_clear_ls_lists(on);
THREAD_OFF(on->thread_send_dbdesc);
on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */
@@ -567,7 +554,6 @@ void bad_lsreq(struct thread *thread)
void oneway_received(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa, *lsanext;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
assert(on);
@@ -582,12 +568,7 @@ void oneway_received(struct thread *thread)
OSPF6_NEIGHBOR_EVENT_ONEWAY_RCVD);
thread_add_event(master, neighbor_change, on->ospf6_if, 0, NULL);
- ospf6_lsdb_remove_all(on->summary_list);
- ospf6_lsdb_remove_all(on->request_list);
- for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
- ospf6_decrement_retrans_count(lsa);
- ospf6_lsdb_remove(lsa, on->retrans_list);
- }
+ ospf6_neighbor_clear_ls_lists(on);
THREAD_OFF(on->thread_send_dbdesc);
THREAD_OFF(on->thread_send_lsreq);
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index eb89a14cd3..db45fa5f5c 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -498,6 +498,7 @@ void ospf6_delete(struct ospf6 *o)
struct route_node *rn = NULL;
struct ospf6_area *oa;
struct vrf *vrf;
+ struct ospf6_external_aggr_rt *aggr;
QOBJ_UNREG(o);
@@ -536,8 +537,11 @@ void ospf6_delete(struct ospf6 *o)
}
for (rn = route_top(o->rt_aggr_tbl); rn; rn = route_next(rn))
- if (rn->info)
- ospf6_external_aggregator_free(rn->info);
+ if (rn->info) {
+ aggr = rn->info;
+ ospf6_asbr_summary_config_delete(o, rn);
+ ospf6_external_aggregator_free(aggr);
+ }
route_table_finish(o->rt_aggr_tbl);
XFREE(MTYPE_OSPF6_TOP, o->name);
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
index 4f60ce22a9..58fcbfa4a9 100644
--- a/ospfd/ospf_spf.c
+++ b/ospfd/ospf_spf.c
@@ -1956,9 +1956,10 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
rt_time = monotime_since(&start_time, NULL);
/* Free old all routers routing table */
- if (ospf->oall_rtrs)
- /* ospf_route_delete (ospf->old_rtrs); */
+ if (ospf->oall_rtrs) {
ospf_rtrs_free(ospf->oall_rtrs);
+ ospf->oall_rtrs = NULL;
+ }
/* Update all routers routing table */
ospf->oall_rtrs = ospf->all_rtrs;
@@ -1967,9 +1968,10 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
ospf_apiserver_notify_reachable(ospf->oall_rtrs, ospf->all_rtrs);
#endif
/* Free old ABR/ASBR routing table */
- if (ospf->old_rtrs)
- /* ospf_route_delete (ospf->old_rtrs); */
+ if (ospf->old_rtrs) {
ospf_rtrs_free(ospf->old_rtrs);
+ ospf->old_rtrs = NULL;
+ }
/* Update ABR/ASBR routing table */
ospf->old_rtrs = ospf->new_rtrs;
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 0bab045ef4..43b7de552a 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -6614,14 +6614,17 @@ static void show_lsa_detail_proc(struct vty *vty, struct route_table *rt,
route_lock_node(start);
for (rn = start; rn; rn = route_next_until(rn, start))
if ((lsa = rn->info)) {
- if (json) {
- json_lsa = json_object_new_object();
- json_object_array_add(json, json_lsa);
- }
+ if (show_function[lsa->data->type] != NULL) {
+ if (json) {
+ json_lsa =
+ json_object_new_object();
+ json_object_array_add(json,
+ json_lsa);
+ }
- if (show_function[lsa->data->type] != NULL)
show_function[lsa->data->type](
vty, lsa, json_lsa);
+ }
}
route_unlock_node(start);
}
@@ -6640,9 +6643,6 @@ static void show_lsa_detail(struct vty *vty, struct ospf *ospf, int type,
json_object *json_areas = NULL;
json_object *json_lsa_array = NULL;
- if (json)
- json_lsa_type = json_object_new_object();
-
switch (type) {
case OSPF_AS_EXTERNAL_LSA:
case OSPF_OPAQUE_AS_LSA:
@@ -6685,6 +6685,7 @@ static void show_lsa_detail(struct vty *vty, struct ospf *ospf, int type,
}
if (json) {
+ json_lsa_type = json_object_new_object();
json_object_object_add(json_lsa_type, "areas",
json_areas);
json_object_object_add(json,
@@ -7158,6 +7159,9 @@ DEFUN (show_ip_ospf_database_max,
vty_out(vty,
"%% OSPF is not enabled in vrf %s\n",
vrf_name);
+ if (uj)
+ json_object_free(json);
+
return CMD_SUCCESS;
}
ret = (show_ip_ospf_database_common(
@@ -7169,6 +7173,9 @@ DEFUN (show_ip_ospf_database_max,
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
if (ospf == NULL || !ospf->oi_running) {
vty_out(vty, "%% OSPF is not enabled in vrf default\n");
+ if (uj)
+ json_object_free(json);
+
return CMD_SUCCESS;
}
@@ -11209,15 +11216,37 @@ DEFUN (show_ip_ospf_instance_reachable_routers,
static int show_ip_ospf_border_routers_common(struct vty *vty,
struct ospf *ospf,
- uint8_t use_vrf)
+ uint8_t use_vrf,
+ json_object *json)
{
- if (ospf->instance)
- vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance);
+ json_object *json_vrf = NULL;
+ json_object *json_router = NULL;
- ospf_show_vrf_name(ospf, vty, NULL, use_vrf);
+ if (json) {
+ if (use_vrf)
+ json_vrf = json_object_new_object();
+ else
+ json_vrf = json;
+ json_router = json_object_new_object();
+ }
+
+ if (ospf->instance) {
+ if (!json)
+ vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance);
+ else
+ json_object_int_add(json_vrf, "ospfInstance",
+ ospf->instance);
+ }
+
+ ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf);
if (ospf->new_table == NULL) {
- vty_out(vty, "No OSPF routing information exist\n");
+ if (!json)
+ vty_out(vty, "No OSPF routing information exist\n");
+ else {
+ json_object_free(json_router);
+ json_object_free(json_vrf);
+ }
return CMD_SUCCESS;
}
@@ -11225,22 +11254,35 @@ static int show_ip_ospf_border_routers_common(struct vty *vty,
show_ip_ospf_route_network (vty, ospf->new_table); */
/* Show Router routes. */
- show_ip_ospf_route_router(vty, ospf, ospf->new_rtrs, NULL);
+ show_ip_ospf_route_router(vty, ospf, ospf->new_rtrs, json_router);
- vty_out(vty, "\n");
+ if (json) {
+ json_object_object_add(json_vrf, "routers", json_router);
+ if (use_vrf) {
+ if (ospf->vrf_id == VRF_DEFAULT)
+ json_object_object_add(json, "default",
+ json_vrf);
+ else
+ json_object_object_add(json, ospf->name,
+ json_vrf);
+ }
+ } else {
+ vty_out(vty, "\n");
+ }
return CMD_SUCCESS;
}
-DEFUN (show_ip_ospf_border_routers,
+DEFPY (show_ip_ospf_border_routers,
show_ip_ospf_border_routers_cmd,
- "show ip ospf [vrf <NAME|all>] border-routers",
+ "show ip ospf [vrf <NAME|all>] border-routers [json]",
SHOW_STR
IP_STR
"OSPF information\n"
VRF_CMD_HELP_STR
"All VRFs\n"
- "Show all the ABR's and ASBR's\n")
+ "Show all the ABR's and ASBR's\n"
+ JSON_STR)
{
struct ospf *ospf = NULL;
struct listnode *node = NULL;
@@ -11250,6 +11292,11 @@ DEFUN (show_ip_ospf_border_routers,
int inst = 0;
int idx_vrf = 0;
uint8_t use_vrf = 0;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
+
+ if (uj)
+ json = json_object_new_object();
OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
@@ -11265,32 +11312,47 @@ DEFUN (show_ip_ospf_border_routers,
ospf_output = true;
ret = show_ip_ospf_border_routers_common(
- vty, ospf, use_vrf);
+ vty, ospf, use_vrf, json);
}
- if (!ospf_output)
+ if (uj)
+ vty_json(vty, json);
+ else if (!ospf_output)
vty_out(vty, "%% OSPF is not enabled\n");
+
+ return ret;
} else {
ospf = ospf_lookup_by_inst_name(inst, vrf_name);
if (ospf == NULL || !ospf->oi_running) {
- vty_out(vty,
- "%% OSPF is not enabled in vrf %s\n",
- vrf_name);
+ if (uj)
+ vty_json(vty, json);
+ else
+ vty_out(vty,
+ "%% OSPF is not enabled in vrf %s\n",
+ vrf_name);
+
return CMD_SUCCESS;
}
-
- ret = show_ip_ospf_border_routers_common(vty, ospf,
- use_vrf);
}
} else {
/* Display default ospf (instance 0) info */
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
if (ospf == NULL || !ospf->oi_running) {
- vty_out(vty, "%% OSPF is not enabled in vrf default\n");
+ if (uj)
+ vty_json(vty, json);
+ else
+ vty_out(vty,
+ "%% OSPF is not enabled in vrf default\n");
+
return CMD_SUCCESS;
}
+ }
- ret = show_ip_ospf_border_routers_common(vty, ospf, use_vrf);
+ if (ospf) {
+ ret = show_ip_ospf_border_routers_common(vty, ospf, use_vrf,
+ json);
+ if (uj)
+ vty_json(vty, json);
}
return ret;
@@ -11317,7 +11379,7 @@ DEFUN (show_ip_ospf_instance_border_routers,
if (!ospf || !ospf->oi_running)
return CMD_SUCCESS;
- return show_ip_ospf_border_routers_common(vty, ospf, 0);
+ return show_ip_ospf_border_routers_common(vty, ospf, 0, NULL);
}
static int show_ip_ospf_route_common(struct vty *vty, struct ospf *ospf,
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index 2403b567a5..a5d40ad176 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -852,6 +852,10 @@ static void ospf_finish_final(struct ospf *ospf)
ospf_route_delete(ospf, ospf->new_table);
ospf_route_table_free(ospf->new_table);
}
+ if (ospf->oall_rtrs)
+ ospf_rtrs_free(ospf->oall_rtrs);
+ if (ospf->all_rtrs)
+ ospf_rtrs_free(ospf->all_rtrs);
if (ospf->old_rtrs)
ospf_rtrs_free(ospf->old_rtrs);
if (ospf->new_rtrs)
diff --git a/pathd/path_pcep_config.c b/pathd/path_pcep_config.c
index 99b1c349a9..873b0ccd37 100644
--- a/pathd/path_pcep_config.c
+++ b/pathd/path_pcep_config.c
@@ -453,8 +453,7 @@ int path_pcep_config_update_path(struct path *path)
}
if (number_of_sid_clashed)
- SET_FLAG(segment->segment_list->flags,
- F_SEGMENT_LIST_SID_CONFLICT);
+ SET_FLAG(segment_list->flags, F_SEGMENT_LIST_SID_CONFLICT);
else
srte_apply_changes();
diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c
index 3bfb31e0c6..dff1b4fed4 100644
--- a/pimd/pim_oil.c
+++ b/pimd/pim_oil.c
@@ -166,8 +166,8 @@ struct channel_oil *pim_channel_oil_del(struct channel_oil *c_oil,
const char *name)
{
if (PIM_DEBUG_MROUTE) {
- pim_sgaddr sg = {.src = *oil_mcastgrp(c_oil),
- .grp = *oil_origin(c_oil)};
+ pim_sgaddr sg = {.src = *oil_origin(c_oil),
+ .grp = *oil_mcastgrp(c_oil)};
zlog_debug(
"%s(%s): Del oil for %pSG, Ref Count: %d (Predecrement)",
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index 71e62bf769..a3f5f6b0cd 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -793,9 +793,18 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons
%changelog
-* Wed Jul 20 2022 Martin Winter <mwinter@opensourcerouting.org> - %{version}
-
-* Tue Oct 04 2022 Donatas Abraitis <donatas@opensourcerouting.org> - 8.4
+* Tue Nov 01 2022 Martin Winter <mwinter@opensourcerouting.org> - %{version}
+
+* Tue Nov 01 2022 Jafar Al-Gharaibeh <jafar@atcorp.com> - 8.4
+- New BGP command (neighbor PEER soo) to configure SoO to prevent routing loops and suboptimal routing on dual-homed sites.
+- Command debug bgp allow-martian replaced to bgp allow-martian-nexthop because previously we allowed using martian next-hops when debug is turned on.
+- Implement BGP Prefix Origin Validation State Extended Community rfc8097
+- Implement Route Leak Prevention and Detection Using Roles in UPDATE and OPEN Messages rfc9234
+- BMP L3VPN support
+- PIMv6 support
+- MLD support
+- New command to enable using reserved IPv4 ranges as normal addresses for BGP next-hops, interface addresses, etc.
+- For a full list of bug fixes, please refer to https://frrouting.org/release/
* Wed Jul 13 2022 Jafar Al-Gharaibeh <jafar@atcorp.com> - 8.3
- General:
diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c
index de07ad8ef3..cb36304473 100644
--- a/staticd/static_zebra.c
+++ b/staticd/static_zebra.c
@@ -313,6 +313,7 @@ static bool static_zebra_nht_get_prefix(const struct static_nexthop *nh,
}
assertf(0, "BUG: someone forgot to add nexthop type %u", nh->type);
+ return false;
}
void static_zebra_nht_register(struct static_nexthop *nh, bool reg)
diff --git a/tests/lib/test_heavy_wq.c b/tests/lib/test_heavy_wq.c
index 00aa7b80dd..be47ef4bbc 100644
--- a/tests/lib/test_heavy_wq.c
+++ b/tests/lib/test_heavy_wq.c
@@ -70,11 +70,6 @@ static void heavy_wq_add(struct vty *vty, const char *str, int i)
return;
}
-static void slow_func_err(struct work_queue *wq, struct work_queue_item *item)
-{
- printf("%s: running error function\n", __func__);
-}
-
static void slow_func_del(struct work_queue *wq, void *data)
{
struct heavy_wq_node *hn = data;
@@ -143,7 +138,6 @@ static int heavy_wq_init(void)
heavy_wq = work_queue_new(master, "heavy_work_queue");
heavy_wq->spec.workfunc = &slow_func;
- heavy_wq->spec.errorfunc = &slow_func_err;
heavy_wq->spec.del_item_data = &slow_func_del;
heavy_wq->spec.max_retries = 3;
heavy_wq->spec.hold = 1000;
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf
new file mode 100644
index 0000000000..d82a21e1f9
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf
@@ -0,0 +1,31 @@
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ no bgp default ipv4-unicast
+ neighbor 192.168.12.2 remote-as external
+ neighbor 192.168.12.2 timers 1 3
+ neighbor 192.168.12.2 timers connect 1
+ neighbor 2001:db8::12:2 remote-as external
+ neighbor 2001:db8::12:2 timers 1 3
+ neighbor 2001:db8::12:2 timers connect 1
+ !
+ address-family ipv4 unicast
+ network 10.0.0.0/31 route-map p1
+ network 10.0.0.2/32 route-map p2
+ neighbor 192.168.12.2 activate
+ exit-address-family
+ address-family ipv6 unicast
+ network 2001:db8::1/128 route-map p1
+ network 2001:db8:1::/56 route-map p2
+ neighbor 2001:db8::12:2 activate
+ exit-address-family
+!
+route-map p1 permit 10
+ set metric 1
+exit
+route-map p2 permit 10
+ set metric 2
+ set origin incomplete
+exit
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r1/zebra.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r1/zebra.conf
new file mode 100644
index 0000000000..0807e89d08
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2mib/r1/zebra.conf
@@ -0,0 +1,5 @@
+!
+interface r1-eth0
+ ip address 192.168.12.1/24
+ ipv6 address 2001:db8::12:1/64
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf
new file mode 100644
index 0000000000..3512e66cec
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf
@@ -0,0 +1,23 @@
+!
+debug bgp updates
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ no bgp default ipv4-unicast
+ neighbor 192.168.12.1 remote-as external
+ neighbor 192.168.12.1 timers 1 3
+ neighbor 192.168.12.1 timers connect 1
+ neighbor 2001:db8::12:1 remote-as external
+ neighbor 2001:db8::12:1 timers 1 3
+ neighbor 2001:db8::12:1 timers connect 1
+ !
+ address-family ipv4 unicast
+ neighbor 192.168.12.1 activate
+ exit-address-family
+ address-family ipv6 unicast
+ neighbor 2001:db8::12:1 activate
+ exit-address-family
+!
+agentx
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf
new file mode 100644
index 0000000000..032b93b676
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf
@@ -0,0 +1,17 @@
+agentAddress 127.0.0.1,[::1]
+
+group public_group v1 public
+group public_group v2c public
+access public_group "" any noauth prefix all all none
+
+rocommunity public default
+
+view all included .1
+
+iquerySecName frr
+rouser frr
+
+master agentx
+
+agentXSocket /etc/frr/agentx
+agentXPerms 777 755 root frr
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/zebra.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/zebra.conf
new file mode 100644
index 0000000000..db6d7005a0
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2mib/r2/zebra.conf
@@ -0,0 +1,5 @@
+!
+interface r2-eth0
+ ip address 192.168.12.2/24
+ ipv6 address 2001:db8::12:2/64
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py b/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py
new file mode 100755
index 0000000000..53ca10930b
--- /dev/null
+++ b/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py
@@ -0,0 +1,248 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Test some of the BGP4V2-MIB entries.
+"""
+
+import os
+import sys
+import json
+from time import sleep
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.snmptest import SnmpTester
+from lib import topotest
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.snmp]
+
+
+def build_topo(tgen):
+ tgen.add_router("r1")
+ tgen.add_router("r2")
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+ snmpd = os.system("which snmpd")
+ if snmpd:
+ error_msg = "SNMP not installed - skipping"
+ pytest.skip(error_msg)
+
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ for rname, router in tgen.routers().items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP,
+ os.path.join(CWD, "{}/bgpd.conf".format(rname)),
+ "-M snmp",
+ )
+ router.load_config(
+ TopoRouter.RD_SNMP,
+ os.path.join(CWD, "{}/snmpd.conf".format(rname)),
+ "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX",
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_snmp_bgp4v2():
+ tgen = get_topogen()
+
+ r2 = tgen.gears["r2"]
+
+ def _bgp_converge_summary():
+ output = json.loads(r2.vtysh_cmd("show bgp summary json"))
+ expected = {
+ "ipv4Unicast": {
+ "peers": {
+ "192.168.12.1": {
+ "state": "Established",
+ "pfxRcd": 2,
+ }
+ }
+ },
+ "ipv6Unicast": {
+ "peers": {
+ "2001:db8::12:1": {
+ "state": "Established",
+ "pfxRcd": 2,
+ }
+ }
+ },
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge_summary)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't see connections established"
+
+ def _bgp_converge_prefixes():
+ output = json.loads(r2.vtysh_cmd("show bgp all json"))
+ expected = {
+ "ipv4Unicast": {
+ "routes": {
+ "10.0.0.0/31": [
+ {
+ "metric": 1,
+ "origin": "IGP",
+ }
+ ],
+ "10.0.0.2/32": [
+ {
+ "metric": 2,
+ "origin": "incomplete",
+ }
+ ],
+ }
+ },
+ "ipv6Unicast": {
+ "routes": {
+ "2001:db8::1/128": [
+ {
+ "metric": 1,
+ "origin": "IGP",
+ }
+ ],
+ "2001:db8:1::/56": [
+ {
+ "metric": 2,
+ "origin": "incomplete",
+ }
+ ],
+ }
+ },
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge_prefixes)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't see prefixes from R1"
+
+ snmp = SnmpTester(r2, "localhost", "public", "2c", "-Ln -On")
+
+ def _snmpwalk_remote_addr():
+ expected = {
+ "1.3.6.1.3.5.1.1.2.1.5.1.4.192.168.12.1": "C0 A8 0C 01",
+ "1.3.6.1.3.5.1.1.2.1.5.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "20 01 0D B8 00 00 00 00 00 00 00 00 00 12 00 01",
+ }
+
+ # bgp4V2PeerRemoteAddr
+ output, _ = snmp.walk(".1.3.6.1.3.5.1.1.2.1.5")
+ return output == expected
+
+ _, result = topotest.run_and_expect(_snmpwalk_remote_addr, True, count=10, wait=1)
+ assertmsg = "Can't fetch SNMP for bgp4V2PeerRemoteAddr"
+ assert result, assertmsg
+
+ def _snmpwalk_peer_state():
+ expected = {
+ "1.3.6.1.3.5.1.1.2.1.13.1.4.192.168.12.1": "6",
+ "1.3.6.1.3.5.1.1.2.1.13.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "6",
+ }
+
+ # bgp4V2PeerState
+ output, _ = snmp.walk(".1.3.6.1.3.5.1.1.2.1.13")
+ return output == expected
+
+ _, result = topotest.run_and_expect(_snmpwalk_peer_state, True, count=10, wait=1)
+ assertmsg = "Can't fetch SNMP for bgp4V2PeerState"
+ assert result, assertmsg
+
+ def _snmpwalk_peer_last_error_code_received():
+ expected = {
+ "1.3.6.1.3.5.1.1.3.1.1.1.4.192.168.12.1": "0",
+ "1.3.6.1.3.5.1.1.3.1.1.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "0",
+ }
+
+ # bgp4V2PeerLastErrorCodeReceived
+ output, _ = snmp.walk(".1.3.6.1.3.5.1.1.3.1.1")
+ return output == expected
+
+ _, result = topotest.run_and_expect(
+ _snmpwalk_peer_last_error_code_received, True, count=10, wait=1
+ )
+ assertmsg = "Can't fetch SNMP for bgp4V2PeerLastErrorCodeReceived"
+ assert result, assertmsg
+
+ def _snmpwalk_origin():
+ expected = {
+ "1.3.6.1.3.5.1.1.9.1.9.1.4.10.0.0.0.31.192.168.12.1": "1",
+ "1.3.6.1.3.5.1.1.9.1.9.1.4.10.0.0.2.32.192.168.12.1": "3",
+ "1.3.6.1.3.5.1.1.9.1.9.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "1",
+ "1.3.6.1.3.5.1.1.9.1.9.2.16.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "3",
+ }
+
+ # bgp4V2NlriOrigin
+ output, _ = snmp.walk(".1.3.6.1.3.5.1.1.9.1.9")
+ return output == expected
+
+ _, result = topotest.run_and_expect(_snmpwalk_origin, True, count=10, wait=1)
+ assertmsg = "Can't fetch SNMP for bgp4V2NlriOrigin"
+ assert result, assertmsg
+
+ def _snmpwalk_med():
+ expected = {
+ "1.3.6.1.3.5.1.1.9.1.17.1.4.10.0.0.0.31.192.168.12.1": "1",
+ "1.3.6.1.3.5.1.1.9.1.17.1.4.10.0.0.2.32.192.168.12.1": "2",
+ "1.3.6.1.3.5.1.1.9.1.17.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "1",
+ "1.3.6.1.3.5.1.1.9.1.17.2.16.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "2",
+ }
+
+ # bgp4V2NlriMed
+ output, _ = snmp.walk(".1.3.6.1.3.5.1.1.9.1.17")
+ return output == expected
+
+ _, result = topotest.run_and_expect(_snmpwalk_med, True, count=10, wait=1)
+ assertmsg = "Can't fetch SNMP for bgp4V2NlriMed"
+ assert result, assertmsg
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/bgpd.conf
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/bgpd.conf
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/zebra.conf
new file mode 100644
index 0000000000..823a56d53f
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/ce1/zebra.conf
@@ -0,0 +1,9 @@
+log file zebra.log
+!
+hostname ce1
+!
+interface eth0
+ ip address 172.16.0.1/24
+!
+line vty
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf
new file mode 100644
index 0000000000..15779aa0d5
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf
@@ -0,0 +1,41 @@
+frr defaults traditional
+!
+hostname pe1
+password zebra
+!
+log stdout notifications
+log monitor notifications
+log commands
+!
+router bgp 65001
+ bgp router-id 192.0.2.1
+ !
+ segment-routing srv6
+ locator default
+ exit
+ !
+!
+router bgp 65001 vrf vrf10
+ bgp router-id 192.0.2.1
+ !
+ address-family ipv4 unicast
+ redistribute connected
+ sid vpn export auto
+ rd vpn export 65001:10
+ rt vpn both 0:10
+ import vpn
+ export vpn
+ exit-address-family
+ !
+!
+router bgp 65001 vrf vrf20
+ bgp router-id 192.0.2.1
+ !
+ address-family ipv4 unicast
+ rd vpn export 65001:20
+ rt vpn both 0:10
+ import vpn
+ export vpn
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/default_ipv4_vpn.json b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/default_ipv4_vpn.json
new file mode 100644
index 0000000000..dc86d7c978
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/default_ipv4_vpn.json
@@ -0,0 +1,31 @@
+{
+ "vrfName": "default",
+ "routerId": "192.0.2.1",
+ "localAS": 65001,
+ "routes": {
+ "routeDistinguishers": {
+ "65001:10": {
+ "172.16.0.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "pathFrom": "external",
+ "prefix": "172.16.0.0",
+ "prefixLen": 24,
+ "network": "172.16.0.0\/24",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "hostname": "pe1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf10_ipv4_unicast.json b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf10_ipv4_unicast.json
new file mode 100644
index 0000000000..ce2d5c19c3
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf10_ipv4_unicast.json
@@ -0,0 +1,25 @@
+{
+ "vrfName": "vrf10",
+ "routerId": "192.0.2.1",
+ "localAS": 65001,
+ "routes": {
+ "172.16.0.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "pathFrom": "external",
+ "prefix": "172.16.0.0",
+ "prefixLen": 24,
+ "network": "172.16.0.0\/24",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "hostname": "pe1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json
new file mode 100644
index 0000000000..9f78447255
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json
@@ -0,0 +1,22 @@
+{
+ "172.16.0.0\/24": [
+ {
+ "prefix": "172.16.0.0\/24",
+ "prefixLen": 24,
+ "protocol": "bgp",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "installed": true,
+ "nexthops": [
+ {
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "vrf": "vrf10",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4_unicast.json b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4_unicast.json
new file mode 100644
index 0000000000..6a88d39a8c
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4_unicast.json
@@ -0,0 +1,27 @@
+{
+ "vrfName": "vrf20",
+ "routerId": "192.0.2.1",
+ "localAS": 65001,
+ "routes": {
+ "172.16.0.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "pathFrom": "external",
+ "prefix": "172.16.0.0",
+ "prefixLen": 24,
+ "network": "172.16.0.0\/24",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "hostname": "pe1",
+ "afi": "ipv4",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/zebra.conf
new file mode 100644
index 0000000000..52341fc4fc
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/zebra.conf
@@ -0,0 +1,27 @@
+log file zebra.log
+!
+hostname pe1
+!
+interface lo
+ ip address 10.0.0.1/32
+!
+interface eth0 vrf vrf10
+ ip address 172.16.0.254/24
+!
+line vty
+!
+segment-routing
+ srv6
+ locators
+ locator default
+ prefix 2001:db8:2::/64 block-len 40 node-len 24 func-bits 16
+ exit
+ !
+ exit
+ !
+ exit
+ !
+exit
+!
+end
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py b/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py
new file mode 100755
index 0000000000..16f8adb3c5
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2022, LINE Corporation
+# Authored by Ryoga Saito <ryoga.saito@linecorp.com>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+import os
+import re
+import sys
+import json
+import functools
+import pytest
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from lib.common_config import required_linux_kernel_version
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ tgen.add_router("pe1")
+ tgen.add_router("ce1")
+
+ tgen.add_link(tgen.gears["pe1"], tgen.gears["ce1"], "eth0", "eth0")
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ for rname, router in tgen.routers().items():
+ router.load_config(TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname)))
+ router.load_config(TopoRouter.RD_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname)))
+
+ tgen.gears["pe1"].run("ip link add vrf10 type vrf table 10")
+ tgen.gears["pe1"].run("ip link set vrf10 up")
+ tgen.gears["pe1"].run("ip link add vrf20 type vrf table 20")
+ tgen.gears["pe1"].run("ip link set vrf20 up")
+ tgen.gears["pe1"].run("ip link set eth0 master vrf10")
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def open_json_file(path):
+ try:
+ with open(path, "r") as f:
+ return json.load(f)
+ except IOError:
+ assert False, "Could not read file {}".format(path)
+
+
+def check(name, command, checker):
+ tgen = get_topogen()
+ router = tgen.gears[name]
+
+ def _check():
+ try:
+ return checker(router.vtysh_cmd(command))
+ except:
+ return False
+
+ logger.info('[+] check {} "{}"'.format(name, command))
+ _, result = topotest.run_and_expect(_check, None, count=10, wait=0.5)
+ assert result is None, "Failed"
+
+
+def check_vrf10_bgp_rib(output):
+ expected = open_json_file("%s/pe1/results/vrf10_ipv4_unicast.json" % CWD)
+ actual = json.loads(output)
+ return topotest.json_cmp(actual, expected)
+
+
+def check_default_bgp_vpn_rib(output):
+ expected = open_json_file("%s/pe1/results/default_ipv4_vpn.json" % CWD)
+ actual = json.loads(output)
+ return topotest.json_cmp(actual, expected)
+
+
+def check_vrf20_bgp_rib(output):
+ expected = open_json_file("%s/pe1/results/vrf20_ipv4_unicast.json" % CWD)
+ actual = json.loads(output)
+ return topotest.json_cmp(actual, expected)
+
+
+def check_vrf20_rib(output):
+ expected = open_json_file("%s/pe1/results/vrf20_ipv4.json" % CWD)
+ actual = json.loads(output)
+ return topotest.json_cmp(actual, expected)
+
+
+def test_rib():
+ check("pe1", "show bgp vrf vrf10 ipv4 unicast json", check_vrf10_bgp_rib)
+ check("pe1", "show bgp ipv4 vpn json", check_default_bgp_vpn_rib)
+ check("pe1", "show bgp vrf vrf20 ipv4 unicast json", check_vrf20_bgp_rib)
+ check("pe1", "show ip route vrf vrf20 json", check_vrf20_rib)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/config_timing/test_config_timing.py b/tests/topotests/config_timing/test_config_timing.py
index 7ab8619b01..0e5508b56d 100644
--- a/tests/topotests/config_timing/test_config_timing.py
+++ b/tests/topotests/config_timing/test_config_timing.py
@@ -161,8 +161,17 @@ def test_static_timing():
return tot_delta
+
# Number of static routes
- prefix_count = 10000
+ router = tgen.gears["r1"]
+ output = router.run("vtysh -h | grep address-sanitizer")
+ if output == "":
+ logger.info("No Address Sanitizer, generating 10000 routes")
+ prefix_count = 10000
+ else:
+ logger.info("Address Sanitizer build, only testing 50 routes")
+ prefix_count = 50
+
prefix_base = [
[u"10.0.0.0/8", u"11.0.0.0/8"],
[u"2100:1111:2220::/44", u"2100:3333:4440::/44"],
diff --git a/tests/topotests/lib/snmptest.py b/tests/topotests/lib/snmptest.py
index fe5ff28979..d695443906 100644
--- a/tests/topotests/lib/snmptest.py
+++ b/tests/topotests/lib/snmptest.py
@@ -36,11 +36,12 @@ from lib.topolog import logger
class SnmpTester(object):
"A helper class for testing SNMP"
- def __init__(self, router, iface, community, version):
+ def __init__(self, router, iface, community, version, options=""):
self.community = community
self.version = version
self.router = router
self.iface = iface
+ self.options = options
logger.info(
"created SNMP tester: SNMPv{0} community:{1}".format(
self.version, self.community
@@ -52,7 +53,9 @@ class SnmpTester(object):
Helper function to build a string with SNMP
configuration for commands.
"""
- return "-v {0} -c {1} {2}".format(self.version, self.community, self.iface)
+ return "-v {0} -c {1} {2} {3}".format(
+ self.version, self.community, self.options, self.iface
+ )
@staticmethod
def _get_snmp_value(snmp_output):
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index 7c5d91d4dc..bf402e1bef 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -1514,6 +1514,7 @@ def ignore_unconfigurable_lines(lines_to_add, lines_to_del):
[
ctx_keys[0].startswith(x)
for x in [
+ "agentx",
"frr version",
"frr defaults",
"username",
diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
index a72cb6e809..be7eb3ecdf 100644
--- a/vtysh/vtysh_main.c
+++ b/vtysh/vtysh_main.c
@@ -354,6 +354,7 @@ int main(int argc, char **argv, char **env)
const char *pathspace_arg = NULL;
char pathspace[MAXPATHLEN] = "";
const char *histfile = NULL;
+ const char *histfile_env = getenv("VTYSH_HISTFILE");
/* SUID: drop down to calling user & go back up when needed */
elevuid = geteuid();
@@ -611,10 +612,8 @@ int main(int argc, char **argv, char **env)
* VTYSH_HISTFILE is preferred over command line
* argument (-H/--histfile).
*/
- if (getenv("VTYSH_HISTFILE")) {
- const char *file = getenv("VTYSH_HISTFILE");
-
- strlcpy(history_file, file, sizeof(history_file));
+ if (histfile_env) {
+ strlcpy(history_file, histfile_env, sizeof(history_file));
} else if (histfile) {
strlcpy(history_file, histfile, sizeof(history_file));
} else {
diff --git a/zebra/main.c b/zebra/main.c
index 3de97943fd..e38f9a85e3 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -221,12 +221,12 @@ void zebra_finalize(struct thread *dummy)
{
zlog_info("Zebra final shutdown");
- /* Final shutdown of ns resources */
- ns_walk_func(zebra_ns_final_shutdown, NULL, NULL);
-
/* Stop dplane thread and finish any cleanup */
zebra_dplane_shutdown();
+ /* Final shutdown of ns resources */
+ ns_walk_func(zebra_ns_final_shutdown, NULL, NULL);
+
zebra_router_terminate();
ns_terminate();
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 96ec90e549..33fe8db99e 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -987,10 +987,12 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
}
}
}
- if (nhe_id || ng)
+ if (nhe_id || ng) {
dplane_rib_add_multipath(afi, SAFI_UNICAST, &p, &src_p,
re, ng, startup, ctx);
- else {
+ if (ng)
+ nexthop_group_delete(&ng);
+ } else {
/*
* I really don't see how this is possible
* but since we are testing for it let's
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index a8ec60844c..2b9246515d 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -585,6 +585,28 @@ static void rtadv_process_solicit(struct interface *ifp)
zif->rtadv.AdvIntervalTimer = MIN_DELAY_BETWEEN_RAS;
}
+static const char *rtadv_optionalhdr2str(uint8_t opt_type)
+{
+ switch (opt_type) {
+ case ND_OPT_SOURCE_LINKADDR:
+ return "Optional Source Link Address";
+ case ND_OPT_TARGET_LINKADDR:
+ return "Optional Target Link Address";
+ case ND_OPT_PREFIX_INFORMATION:
+ return "Optional Prefix Information";
+ case ND_OPT_REDIRECTED_HEADER:
+ return "Optional Redirected Header";
+ case ND_OPT_MTU:
+ return "Optional MTU";
+ case ND_OPT_RTR_ADV_INTERVAL:
+ return "Optional Advertisement Interval";
+ case ND_OPT_HOME_AGENT_INFO:
+ return "Optional Home Agent Information";
+ }
+
+ return "Unknown Optional Type";
+}
+
/*
* This function processes optional attributes off of
* end of a RA packet received. At this point in
@@ -609,6 +631,13 @@ static void rtadv_process_optional(uint8_t *optional, unsigned int len,
&addr->sin6_addr, 1);
break;
default:
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug(
+ "%s:Received Packet with optional Header type %s(%u) that is being ignored",
+ __func__,
+ rtadv_optionalhdr2str(
+ opt_hdr->nd_opt_type),
+ opt_hdr->nd_opt_type);
break;
}
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index 26c7823747..2304af19d1 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -308,6 +308,7 @@ struct rtadv_prefix {
#define ND_OPT_HA_INFORMATION 8 /* HA Information Option */
#endif
+
#ifndef HAVE_STRUCT_ND_OPT_ADV_INTERVAL
struct nd_opt_adv_interval { /* Advertisement interval option */
uint8_t nd_opt_ai_type;
@@ -324,6 +325,12 @@ struct nd_opt_adv_interval { /* Advertisement interval option */
#define nd_opt_ai_interval nd_opt_adv_interval_ival
#endif
#endif
+#ifndef ND_OPT_RTR_ADV_INTERVAL
+#define ND_OPT_RTR_ADV_INTERVAL 7
+#endif
+#ifndef ND_OPT_HOME_AGENT_INFO
+#define ND_OPT_HOME_AGENT_INFO 8
+#endif
#ifndef HAVE_STRUCT_ND_OPT_HOMEAGENT_INFO
struct nd_opt_homeagent_info { /* Home Agent info */
diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c
index ca897251e2..5cefa16cdd 100644
--- a/zebra/zebra_fpm_netlink.c
+++ b/zebra/zebra_fpm_netlink.c
@@ -539,10 +539,15 @@ static void zfpm_log_route_info(struct netlink_route_info *ri,
for (i = 0; i < ri->num_nhs; i++) {
nhi = &ri->nhs[i];
- if (ri->af == AF_INET)
- inet_ntop(AF_INET, &nhi->gateway, buf, sizeof(buf));
- else
- inet_ntop(AF_INET6, &nhi->gateway, buf, sizeof(buf));
+ if (nhi->gateway) {
+ if (ri->af == AF_INET)
+ inet_ntop(AF_INET, nhi->gateway, buf,
+ sizeof(buf));
+ else
+ inet_ntop(AF_INET6, nhi->gateway, buf,
+ sizeof(buf));
+ } else
+ strlcpy(buf, "none", sizeof(buf));
zfpm_debug(" Intf: %u, Gateway: %s, Recursive: %s, Type: %s, Encap type: %s",
nhi->if_index, buf, nhi->recursive ? "yes" : "no",
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index 9756d9ba08..fe3f77f3c7 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -1754,7 +1754,6 @@ static void mpls_processq_init(void)
zrouter.lsp_process_q->spec.workfunc = &lsp_process;
zrouter.lsp_process_q->spec.del_item_data = &lsp_processq_del;
- zrouter.lsp_process_q->spec.errorfunc = NULL;
zrouter.lsp_process_q->spec.completion_func = &lsp_processq_complete;
zrouter.lsp_process_q->spec.max_retries = 0;
zrouter.lsp_process_q->spec.hold = 10;
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index b86780276b..9551f26d80 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -3681,14 +3681,14 @@ static void rib_meta_queue_free(struct meta_queue *mq, struct list *l,
static void early_route_meta_queue_free(struct meta_queue *mq, struct list *l,
struct zebra_vrf *zvrf)
{
- struct zebra_early_route *zer;
+ struct zebra_early_route *ere;
struct listnode *node, *nnode;
- for (ALL_LIST_ELEMENTS(l, node, nnode, zer)) {
- if (zvrf && zer->re->vrf_id != zvrf->vrf->vrf_id)
+ for (ALL_LIST_ELEMENTS(l, node, nnode, ere)) {
+ if (zvrf && ere->re->vrf_id != zvrf->vrf->vrf_id)
continue;
- XFREE(MTYPE_RE, zer);
+ early_route_memory_free(ere);
node->data = NULL;
list_delete_node(l, node);
mq->size--;
@@ -3743,7 +3743,6 @@ static void rib_queue_init(void)
/* fill in the work queue spec */
zrouter.ribq->spec.workfunc = &meta_queue_process;
- zrouter.ribq->spec.errorfunc = NULL;
zrouter.ribq->spec.completion_func = NULL;
/* XXX: TODO: These should be runtime configurable via vty */
zrouter.ribq->spec.max_retries = 3;
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 066ef8a8d0..4f43cea493 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -143,26 +143,48 @@ static void show_vrf_proto_rm(struct vty *vty, struct zebra_vrf *zvrf,
}
static void show_vrf_nht_rm(struct vty *vty, struct zebra_vrf *zvrf,
- int af_type)
+ int af_type, json_object *json)
{
int i;
- vty_out(vty, "Protocol : route-map\n");
- vty_out(vty, "-------------------------------------\n");
+ if (!json) {
+ vty_out(vty, "Protocol : route-map\n");
+ vty_out(vty, "-------------------------------------\n");
+ }
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+ if (json) {
+ if (NHT_RM_NAME(zvrf, af_type, i))
+ json_object_string_add(
+ json, zebra_route_string(i),
+ NHT_RM_NAME(zvrf, af_type, i));
+ else
+ json_object_string_add(
+ json, zebra_route_string(i), "none");
+ } else {
+ if (NHT_RM_NAME(zvrf, af_type, i))
+ vty_out(vty, "%-24s : %-10s\n",
+ zebra_route_string(i),
+ NHT_RM_NAME(zvrf, af_type, i));
+ else
+ vty_out(vty, "%-24s : none\n",
+ zebra_route_string(i));
+ }
+ }
+
+ if (json) {
if (NHT_RM_NAME(zvrf, af_type, i))
- vty_out(vty, "%-24s : %-10s\n", zebra_route_string(i),
+ json_object_string_add(json, "any",
+ NHT_RM_NAME(zvrf, af_type, i));
+ else
+ json_object_string_add(json, "any", "none");
+ } else {
+ if (NHT_RM_NAME(zvrf, af_type, i))
+ vty_out(vty, "%-24s : %-10s\n", "any",
NHT_RM_NAME(zvrf, af_type, i));
else
- vty_out(vty, "%-24s : none\n", zebra_route_string(i));
+ vty_out(vty, "%-24s : none\n", "any");
}
-
- if (NHT_RM_NAME(zvrf, af_type, i))
- vty_out(vty, "%-24s : %-10s\n", "any",
- NHT_RM_NAME(zvrf, af_type, i));
- else
- vty_out(vty, "%-24s : none\n", "any");
}
static int show_proto_rm(struct vty *vty, int af_type, const char *vrf_all,
@@ -198,35 +220,78 @@ static int show_proto_rm(struct vty *vty, int af_type, const char *vrf_all,
}
static int show_nht_rm(struct vty *vty, int af_type, const char *vrf_all,
- const char *vrf_name)
+ const char *vrf_name, bool use_json)
{
struct zebra_vrf *zvrf;
+ json_object *json = NULL;
+ json_object *json_vrfs = NULL;
+
+ if (use_json) {
+ json = json_object_new_object();
+ json_vrfs = json_object_new_object();
+ json_object_string_add(json, "afi",
+ (af_type == AFI_IP) ? "ipv4" : "ipv6");
+ }
if (vrf_all) {
struct vrf *vrf;
+ if (use_json)
+ json_object_object_add(json, "vrfs", json_vrfs);
+
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
zvrf = (struct zebra_vrf *)vrf->info;
if (zvrf == NULL)
continue;
- vty_out(vty, "VRF: %s\n", zvrf->vrf->name);
- show_vrf_nht_rm(vty, zvrf, af_type);
+ if (use_json) {
+ json_object *json_proto = NULL;
+ json_object *json_vrf = NULL;
+ json_vrf = json_object_new_object();
+ json_object_object_add(
+ json_vrfs, zvrf->vrf->name, json_vrf);
+ json_proto = json_object_new_object();
+ json_object_object_add(json_vrf, "protocols",
+ json_proto);
+ show_vrf_nht_rm(vty, zvrf, af_type, json_proto);
+ } else {
+ vty_out(vty, "VRF: %s\n", zvrf->vrf->name);
+ show_vrf_nht_rm(vty, zvrf, af_type, NULL);
+ }
}
} else {
+ json_object *json_proto = NULL;
+ json_object *json_vrf = NULL;
vrf_id_t vrf_id = VRF_DEFAULT;
if (vrf_name)
VRF_GET_ID(vrf_id, vrf_name, false);
zvrf = zebra_vrf_lookup_by_id(vrf_id);
- if (!zvrf)
+ if (!zvrf) {
+ json_object_free(json);
+ json_object_free(json_vrfs);
return CMD_SUCCESS;
+ }
- vty_out(vty, "VRF: %s\n", zvrf->vrf->name);
- show_vrf_nht_rm(vty, zvrf, af_type);
+ if (use_json) {
+ json_object_object_add(json, "vrfs", json_vrfs);
+ json_vrf = json_object_new_object();
+ json_object_object_add(json_vrfs, zvrf->vrf->name,
+ json_vrf);
+ json_proto = json_object_new_object();
+ json_object_object_add(json_vrf, "protocols",
+ json_proto);
+ show_vrf_nht_rm(vty, zvrf, af_type, json_proto);
+ } else {
+ vty_out(vty, "VRF: %s\n", zvrf->vrf->name);
+ show_vrf_nht_rm(vty, zvrf, af_type, NULL);
+ }
}
+ if (use_json)
+ vty_json(vty, json);
+
return CMD_SUCCESS;
}
@@ -854,14 +919,19 @@ DEFPY_YANG (no_ip_protocol_nht_rmap,
DEFPY_YANG (show_ip_protocol_nht,
show_ip_protocol_nht_cmd,
- "show ip nht route-map [vrf <NAME$vrf_name|all$vrf_all>]",
+ "show ip nht route-map [vrf <NAME$vrf_name|all$vrf_all>] [json]",
SHOW_STR
IP_STR
- "IP nexthop tracking table\n"
- "IP Next Hop tracking filtering status\n"
- VRF_FULL_CMD_HELP_STR)
+ "IPv4 nexthop tracking table\n"
+ "IPv4 Next Hop tracking filtering status\n"
+ VRF_CMD_HELP_STR
+ "All VRFs\n"
+ JSON_STR)
{
- int ret = show_nht_rm(vty, AFI_IP, vrf_all, vrf_name);
+ int ret;
+ bool uj = use_json(argc, argv);
+
+ ret = show_nht_rm(vty, AFI_IP, vrf_all, vrf_name, uj);
return ret;
}
@@ -936,14 +1006,19 @@ DEFPY_YANG (no_ipv6_protocol_nht_rmap,
DEFPY_YANG (show_ipv6_protocol_nht,
show_ipv6_protocol_nht_cmd,
- "show ipv6 nht route-map [vrf <NAME$vrf_name|all$vrf_all>]",
+ "show ipv6 nht route-map [vrf <NAME$vrf_name|all$vrf_all>] [json]",
SHOW_STR
IP6_STR
- "Next Hop filtering status\n"
- "Route-map\n"
- VRF_FULL_CMD_HELP_STR)
+ "IPv6 nexthop tracking table\n"
+ "IPv6 Next Hop tracking filtering status\n"
+ VRF_CMD_HELP_STR
+ "All VRFs\n"
+ JSON_STR)
{
- int ret = show_nht_rm(vty, AFI_IP6, vrf_all, vrf_name);
+ int ret;
+ bool uj = use_json(argc, argv);
+
+ ret = show_nht_rm(vty, AFI_IP6, vrf_all, vrf_name, uj);
return ret;
}