summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_advertise.h6
-rw-r--r--bgpd/bgp_ecommunity.h6
-rw-r--r--bgpd/bgp_evpn_mh.h5
-rw-r--r--bgpd/bgp_mplsvpn.c19
-rw-r--r--bgpd/bgp_nexthop.h25
-rw-r--r--bgpd/bgp_route.c35
-rw-r--r--bgpd/bgp_updgrp.h21
-rw-r--r--bgpd/bgp_vty.c45
-rw-r--r--bgpd/bgp_vty.h2
-rw-r--r--bgpd/bgp_zebra.c19
-rw-r--r--bgpd/bgp_zebra.h2
-rw-r--r--bgpd/bgpd.c6
-rw-r--r--bgpd/bgpd.h11
-rw-r--r--configure.ac2
-rw-r--r--doc/developer/mgmtd-dev.rst7
-rw-r--r--doc/developer/topotests.rst13
-rw-r--r--doc/user/bgp.rst13
-rw-r--r--doc/user/routemap.rst8
-rw-r--r--docker/ubuntu-ci/Dockerfile8
-rw-r--r--lib/event.c9
-rw-r--r--lib/mgmt_be_client.c47
-rw-r--r--lib/mgmt_be_client.h12
-rw-r--r--lib/northbound.c21
-rw-r--r--lib/northbound.h27
-rw-r--r--lib/northbound_cli.c12
-rw-r--r--lib/sockopt.c3
-rw-r--r--lib/vty.h4
-rw-r--r--lib/yang.c46
-rw-r--r--lib/yang.h13
-rw-r--r--mgmtd/mgmt_be_adapter.c29
-rw-r--r--mgmtd/mgmt_fe_adapter.c3
-rw-r--r--mgmtd/mgmt_testc.c49
-rw-r--r--mgmtd/mgmt_txn.c28
-rw-r--r--mgmtd/subdir.am1
-rw-r--r--nhrpd/netlink_arp.c5
-rw-r--r--ospfd/ospf_ext.c231
-rw-r--r--ospfd/ospf_opaque.c17
-rw-r--r--ospfd/ospf_ri.c307
-rw-r--r--ospfd/ospf_sr.c1
-rw-r--r--ospfd/ospf_te.c475
-rw-r--r--pimd/pim_mroute.c2
-rw-r--r--pimd/pim_upstream.c36
-rw-r--r--pimd/pim_upstream.h2
-rw-r--r--qpb/qpb.h1
-rw-r--r--staticd/static_nht.c34
-rw-r--r--staticd/static_routes.c63
-rw-r--r--staticd/static_routes.h1
-rw-r--r--staticd/static_zebra.c2
-rw-r--r--tests/lib/subdir.am2
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py7
-rw-r--r--tests/topotests/bgp_rpki_topo1/r2/bgpd.conf6
-rw-r--r--tests/topotests/bgp_rpki_topo1/r2/zebra.conf3
-rw-r--r--tests/topotests/bgp_rpki_topo1/r4/bgpd.conf6
-rw-r--r--tests/topotests/bgp_rpki_topo1/r4/zebra.conf4
-rw-r--r--tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py48
-rw-r--r--tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json2
-rw-r--r--tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf17
-rw-r--r--tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf10
-rw-r--r--tests/topotests/bgp_vrf_route_leak_basic/setup_vrfs1
-rw-r--r--tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py313
-rw-r--r--tests/topotests/mgmt_notif/test_notif.py2
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt2
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt2
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt4
-rw-r--r--tests/topotests/ospfapi/test_ospf_clientapi.py64
-rw-r--r--tests/topotests/static_vrf/r1/frr.conf18
-rw-r--r--tests/topotests/static_vrf/test_static_vrf.py126
-rw-r--r--vtysh/vtysh.c33
-rw-r--r--vtysh/vtysh_config.c10
-rw-r--r--zebra/zebra_evpn_mh.h2
70 files changed, 1802 insertions, 614 deletions
diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h
index 7c3b23ab5..49821061b 100644
--- a/bgpd/bgp_advertise.h
+++ b/bgpd/bgp_advertise.h
@@ -69,14 +69,14 @@ struct bgp_adj_out {
uint32_t addpath_tx_id;
+ /* Attribute hash */
+ uint32_t attr_hash;
+
/* Advertised attribute. */
struct attr *attr;
/* Advertisement information. */
struct bgp_advertise *adv;
-
- /* Attribute hash */
- uint32_t attr_hash;
};
RB_HEAD(bgp_adj_out_rb, bgp_adj_out);
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
index f12d0dd3e..62e0430c9 100644
--- a/bgpd/bgp_ecommunity.h
+++ b/bgpd/bgp_ecommunity.h
@@ -117,6 +117,9 @@ struct ecommunity {
*/
uint8_t unit_size;
+ /* Disable IEEE floating-point encoding for extended community */
+ bool disable_ieee_floating;
+
/* Size of Extended Communities attribute. */
uint32_t size;
@@ -125,9 +128,6 @@ struct ecommunity {
/* Human readable format string. */
char *str;
-
- /* Disable IEEE floating-point encoding for extended community */
- bool disable_ieee_floating;
};
struct ecommunity_as {
diff --git a/bgpd/bgp_evpn_mh.h b/bgpd/bgp_evpn_mh.h
index ee1f74989..cebabb9fd 100644
--- a/bgpd/bgp_evpn_mh.h
+++ b/bgpd/bgp_evpn_mh.h
@@ -388,11 +388,6 @@ static inline bool bgp_evpn_attr_is_local_es(struct attr *attr)
return attr ? !!(attr->es_flags & ATTR_ES_IS_LOCAL) : false;
}
-static inline uint32_t bgp_evpn_attr_get_df_pref(struct attr *attr)
-{
- return (attr) ? attr->df_pref : 0;
-}
-
static inline bool bgp_evpn_local_es_is_active(struct bgp_evpn_es *es)
{
return (es->flags & BGP_EVPNES_OPER_UP)
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 32436861f..cd5cf5be5 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -2209,12 +2209,22 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
/* If the path has accept-own community and the source VRF
* is valid, reset next-hop to self, to allow importing own
* routes between different VRFs on the same node.
- * Set the nh ifindex to VRF's interface, not the real interface.
+ */
+
+ if (src_bgp)
+ subgroup_announce_reset_nhop(nhfamily, &static_attr);
+
+ bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn);
+
+ /* The nh ifindex may not be defined (when the route is
+ * imported from the network statement => BGP_ROUTE_STATIC)
+ * or to the real interface.
+ * Rewrite the nh ifindex to VRF's interface.
* Let the kernel to decide with double lookup the real next-hop
* interface when installing the route.
*/
- if (src_bgp) {
- subgroup_announce_reset_nhop(nhfamily, &static_attr);
+ if (src_bgp || bpi_ultimate->sub_type == BGP_ROUTE_STATIC ||
+ bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE) {
ifp = if_get_vrf_loopback(src_vrf->vrf_id);
if (ifp)
static_attr.nh_ifindex = ifp->ifindex;
@@ -2300,9 +2310,6 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
*/
if (!CHECK_FLAG(to_bgp->af_flags[afi][safi],
BGP_CONFIG_VRF_TO_VRF_IMPORT)) {
- /* work back to original route */
- bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn);
-
/*
* if original route was unicast,
* then it did not arrive over vpn
diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h
index 90e0074e3..830883872 100644
--- a/bgpd/bgp_nexthop.h
+++ b/bgpd/bgp_nexthop.h
@@ -39,6 +39,18 @@ struct bgp_nexthop_cache {
/* Nexthop number and nexthop linked list.*/
uint8_t nexthop_num;
+
+ /* This flag is set to TRUE for a bnc that is gateway IP overlay index
+ * nexthop.
+ */
+ bool is_evpn_gwip_nexthop;
+
+ uint16_t change_flags;
+#define BGP_NEXTHOP_CHANGED (1 << 0)
+#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1)
+#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2)
+#define BGP_NEXTHOP_MACIP_CHANGED (1 << 3)
+
struct nexthop *nexthop;
time_t last_update;
uint16_t flags;
@@ -72,27 +84,16 @@ struct bgp_nexthop_cache {
*/
#define BGP_NEXTHOP_EVPN_INCOMPLETE (1 << 7)
- uint16_t change_flags;
-
-#define BGP_NEXTHOP_CHANGED (1 << 0)
-#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1)
-#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2)
-#define BGP_NEXTHOP_MACIP_CHANGED (1 << 3)
+ uint32_t srte_color;
/* Back pointer to the cache tree this entry belongs to. */
struct bgp_nexthop_cache_head *tree;
- uint32_t srte_color;
struct prefix prefix;
void *nht_info; /* In BGP, peer session */
LIST_HEAD(path_list, bgp_path_info) paths;
unsigned int path_count;
struct bgp *bgp;
-
- /* This flag is set to TRUE for a bnc that is gateway IP overlay index
- * nexthop.
- */
- bool is_evpn_gwip_nexthop;
};
extern int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a,
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 46f7f9b22..f0c5de074 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -2670,16 +2670,20 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
* defined as non-transitive in [RFC8097], can be advertised to
* peers in the same OAD.
*/
- if (peer->sort == BGP_PEER_IBGP || peer->sub_sort == BGP_PEER_EBGP_OAD) {
+ if ((peer->sort == BGP_PEER_IBGP ||
+ peer->sub_sort == BGP_PEER_EBGP_OAD) &&
+ peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_SEND_EXT_COMMUNITY_RPKI)) {
enum rpki_states rpki_state = RPKI_NOT_BEING_USED;
rpki_state = hook_call(bgp_rpki_prefix_status, peer, attr, p);
if (rpki_state != RPKI_NOT_BEING_USED)
- bgp_attr_set_ecommunity(
- attr, ecommunity_add_origin_validation_state(
- rpki_state,
- bgp_attr_get_ecommunity(attr)));
+ bgp_attr_set_ecommunity(attr,
+ ecommunity_add_origin_validation_state(
+ rpki_state,
+ bgp_attr_get_ecommunity(
+ attr)));
}
/*
@@ -3520,7 +3524,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
*/
if (old_select &&
is_route_parent_evpn(old_select))
- bgp_zebra_withdraw(p, old_select, bgp, safi);
+ bgp_zebra_withdraw(p, old_select, bgp, afi,
+ safi);
bgp_zebra_announce(dest, p, new_select, bgp, afi, safi);
} else {
@@ -3530,7 +3535,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
|| old_select->sub_type == BGP_ROUTE_AGGREGATE
|| old_select->sub_type == BGP_ROUTE_IMPORTED))
- bgp_zebra_withdraw(p, old_select, bgp, safi);
+ bgp_zebra_withdraw(p, old_select, bgp, afi,
+ safi);
}
}
@@ -4427,7 +4433,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
if (pi && pi->attr->rmap_table_id != new_attr.rmap_table_id) {
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
/* remove from RIB previous entry */
- bgp_zebra_withdraw(p, pi, bgp, safi);
+ bgp_zebra_withdraw(p, pi, bgp, afi, safi);
}
if (peer->sort == BGP_PEER_EBGP) {
@@ -6029,7 +6035,7 @@ bool bgp_inbound_policy_exists(struct peer *peer, struct bgp_filter *filter)
}
static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table,
- safi_t safi)
+ afi_t afi, safi_t safi)
{
struct bgp_dest *dest;
struct bgp_path_info *pi;
@@ -6053,7 +6059,8 @@ static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table,
|| pi->sub_type == BGP_ROUTE_IMPORTED)) {
if (bgp_fibupd_safi(safi))
- bgp_zebra_withdraw(p, pi, bgp, safi);
+ bgp_zebra_withdraw(p, pi, bgp, afi,
+ safi);
}
dest = bgp_path_info_reap(dest, pi);
@@ -6071,7 +6078,7 @@ void bgp_cleanup_routes(struct bgp *bgp)
for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
if (afi == AFI_L2VPN)
continue;
- bgp_cleanup_table(bgp, bgp->rib[afi][SAFI_UNICAST],
+ bgp_cleanup_table(bgp, bgp->rib[afi][SAFI_UNICAST], afi,
SAFI_UNICAST);
/*
* VPN and ENCAP and EVPN tables are two-level (RD is top level)
@@ -6083,7 +6090,7 @@ void bgp_cleanup_routes(struct bgp *bgp)
dest = bgp_route_next(dest)) {
table = bgp_dest_get_bgp_table_info(dest);
if (table != NULL) {
- bgp_cleanup_table(bgp, table, safi);
+ bgp_cleanup_table(bgp, table, afi, safi);
bgp_table_finish(&table);
bgp_dest_set_bgp_table_info(dest, NULL);
dest = bgp_dest_unlock_node(dest);
@@ -6096,7 +6103,7 @@ void bgp_cleanup_routes(struct bgp *bgp)
dest = bgp_route_next(dest)) {
table = bgp_dest_get_bgp_table_info(dest);
if (table != NULL) {
- bgp_cleanup_table(bgp, table, safi);
+ bgp_cleanup_table(bgp, table, afi, safi);
bgp_table_finish(&table);
bgp_dest_set_bgp_table_info(dest, NULL);
dest = bgp_dest_unlock_node(dest);
@@ -6110,7 +6117,7 @@ void bgp_cleanup_routes(struct bgp *bgp)
dest = bgp_route_next(dest)) {
table = bgp_dest_get_bgp_table_info(dest);
if (table != NULL) {
- bgp_cleanup_table(bgp, table, SAFI_EVPN);
+ bgp_cleanup_table(bgp, table, afi, SAFI_EVPN);
bgp_table_finish(&table);
bgp_dest_set_bgp_table_info(dest, NULL);
dest = bgp_dest_unlock_node(dest);
diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h
index 7a0d328c6..d4c6ecfdb 100644
--- a/bgpd/bgp_updgrp.h
+++ b/bgpd/bgp_updgrp.h
@@ -40,17 +40,16 @@
(PEER_FLAG_LOCAL_AS_NO_PREPEND | PEER_FLAG_LOCAL_AS_REPLACE_AS)
#define PEER_UPDGRP_AF_FLAGS \
- (PEER_FLAG_SEND_COMMUNITY | PEER_FLAG_SEND_EXT_COMMUNITY \
- | PEER_FLAG_SEND_LARGE_COMMUNITY \
- | PEER_FLAG_DEFAULT_ORIGINATE | PEER_FLAG_REFLECTOR_CLIENT \
- | PEER_FLAG_RSERVER_CLIENT | PEER_FLAG_NEXTHOP_SELF \
- | PEER_FLAG_NEXTHOP_UNCHANGED | PEER_FLAG_FORCE_NEXTHOP_SELF \
- | PEER_FLAG_AS_PATH_UNCHANGED | PEER_FLAG_MED_UNCHANGED \
- | PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED | PEER_FLAG_REMOVE_PRIVATE_AS \
- | PEER_FLAG_REMOVE_PRIVATE_AS_ALL \
- | PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE \
- | PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE \
- | PEER_FLAG_AS_OVERRIDE)
+ (PEER_FLAG_SEND_COMMUNITY | PEER_FLAG_SEND_EXT_COMMUNITY | \
+ PEER_FLAG_SEND_EXT_COMMUNITY_RPKI | PEER_FLAG_SEND_LARGE_COMMUNITY | \
+ PEER_FLAG_DEFAULT_ORIGINATE | PEER_FLAG_REFLECTOR_CLIENT | \
+ PEER_FLAG_RSERVER_CLIENT | PEER_FLAG_NEXTHOP_SELF | \
+ PEER_FLAG_NEXTHOP_UNCHANGED | PEER_FLAG_FORCE_NEXTHOP_SELF | \
+ PEER_FLAG_AS_PATH_UNCHANGED | PEER_FLAG_MED_UNCHANGED | \
+ PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED | PEER_FLAG_REMOVE_PRIVATE_AS | \
+ PEER_FLAG_REMOVE_PRIVATE_AS_ALL | \
+ PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE | \
+ PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE | PEER_FLAG_AS_OVERRIDE)
#define PEER_UPDGRP_CAP_FLAGS (PEER_CAP_AS4_RCV)
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 33884d045..31524e222 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -6473,6 +6473,32 @@ ALIAS_HIDDEN(
"Send Standard Community attributes\n"
"Send Large Community attributes\n")
+DEFPY (neighbor_ecommunity_rpki,
+ neighbor_ecommunity_rpki_cmd,
+ "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor send-community extended rpki",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Send Community attribute to this neighbor\n"
+ "Send Extended Community attributes\n"
+ "Send RPKI Extended Community attributes\n")
+{
+ struct peer *peer;
+ afi_t afi = bgp_node_afi(vty);
+ safi_t safi = bgp_node_safi(vty);
+
+ peer = peer_and_group_lookup_vty(vty, neighbor);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (no)
+ return peer_af_flag_unset_vty(vty, neighbor, afi, safi,
+ PEER_FLAG_SEND_EXT_COMMUNITY_RPKI);
+ else
+ return peer_af_flag_set_vty(vty, neighbor, afi, safi,
+ PEER_FLAG_SEND_EXT_COMMUNITY_RPKI);
+}
+
/* neighbor soft-reconfig. */
DEFUN (neighbor_soft_reconfiguration,
neighbor_soft_reconfiguration_cmd,
@@ -17665,8 +17691,8 @@ bool peergroup_flag_check(struct peer *peer, uint64_t flag)
return !!CHECK_FLAG(peer->flags_override, flag);
}
-static bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi,
- uint64_t flag)
+bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi,
+ uint64_t flag)
{
if (!peer_group_active(peer)) {
if (CHECK_FLAG(peer->af_flags_invert[afi][safi], flag))
@@ -18442,6 +18468,12 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
if (flag_slcomm)
vty_out(vty, " no neighbor %s send-community large\n",
addr);
+
+ if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_SEND_EXT_COMMUNITY_RPKI))
+ vty_out(vty,
+ " no neighbor %s send-community extended rpki\n",
+ addr);
}
/* Default information */
@@ -20327,6 +20359,15 @@ void bgp_vty_init(void)
install_element(BGP_VPNV6_NODE, &neighbor_send_community_type_cmd);
install_element(BGP_VPNV6_NODE, &no_neighbor_send_community_cmd);
install_element(BGP_VPNV6_NODE, &no_neighbor_send_community_type_cmd);
+ install_element(BGP_NODE, &neighbor_ecommunity_rpki_cmd);
+ install_element(BGP_IPV4_NODE, &neighbor_ecommunity_rpki_cmd);
+ install_element(BGP_IPV4M_NODE, &neighbor_ecommunity_rpki_cmd);
+ install_element(BGP_IPV4L_NODE, &neighbor_ecommunity_rpki_cmd);
+ install_element(BGP_IPV6_NODE, &neighbor_ecommunity_rpki_cmd);
+ install_element(BGP_IPV6M_NODE, &neighbor_ecommunity_rpki_cmd);
+ install_element(BGP_IPV6L_NODE, &neighbor_ecommunity_rpki_cmd);
+ install_element(BGP_VPNV4_NODE, &neighbor_ecommunity_rpki_cmd);
+ install_element(BGP_VPNV6_NODE, &neighbor_ecommunity_rpki_cmd);
/* "neighbor route-reflector" commands.*/
install_element(BGP_NODE, &neighbor_route_reflector_client_hidden_cmd);
diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h
index a105b6de3..4955e4c3d 100644
--- a/bgpd/bgp_vty.h
+++ b/bgpd/bgp_vty.h
@@ -171,5 +171,7 @@ extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
safi_t safi, const char *neighbor, int as_type,
as_t as, uint16_t show_flags);
extern bool peergroup_flag_check(struct peer *peer, uint64_t flag);
+extern bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi,
+ uint64_t flag);
#endif /* _QUAGGA_BGP_VTY_H */
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 0db0ac487..1172514e5 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1511,6 +1511,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
struct bgp_path_info *info, struct bgp *bgp, afi_t afi,
safi_t safi)
{
+ struct bgp_path_info *bpi_ultimate;
struct zapi_route api = { 0 };
unsigned int valid_nh_count = 0;
bool allow_recursion = false;
@@ -1554,15 +1555,9 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
peer = info->peer;
- if (info->type == ZEBRA_ROUTE_BGP
- && info->sub_type == BGP_ROUTE_IMPORTED) {
-
- /* Obtain peer from parent */
- if (info->extra && info->extra->vrfleak &&
- info->extra->vrfleak->parent)
- peer = ((struct bgp_path_info *)(info->extra->vrfleak
- ->parent))
- ->peer;
+ if (info->type == ZEBRA_ROUTE_BGP) {
+ bpi_ultimate = bgp_get_imported_bpi_ultimate(info);
+ peer = bpi_ultimate->peer;
}
tag = info->attr->tag;
@@ -1724,7 +1719,7 @@ void bgp_zebra_announce_table_all_subtypes(struct bgp *bgp, afi_t afi,
}
void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info,
- struct bgp *bgp, safi_t safi)
+ struct bgp *bgp, afi_t afi, safi_t safi)
{
struct zapi_route api;
struct peer *peer;
@@ -1743,7 +1738,7 @@ void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info,
if (safi == SAFI_FLOWSPEC) {
peer = info->peer;
- bgp_pbr_update_entry(peer->bgp, p, info, AFI_IP, safi, false);
+ bgp_pbr_update_entry(peer->bgp, p, info, afi, safi, false);
return;
}
@@ -1784,7 +1779,7 @@ void bgp_zebra_withdraw_table_all_subtypes(struct bgp *bgp, afi_t afi, safi_t sa
if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
&& (pi->type == ZEBRA_ROUTE_BGP))
bgp_zebra_withdraw(bgp_dest_get_prefix(dest),
- pi, bgp, safi);
+ pi, bgp, afi, safi);
}
}
}
diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h
index 4696e4dc4..396c8335f 100644
--- a/bgpd/bgp_zebra.h
+++ b/bgpd/bgp_zebra.h
@@ -34,7 +34,7 @@ extern void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
extern void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi);
extern void bgp_zebra_withdraw(const struct prefix *p,
struct bgp_path_info *path, struct bgp *bgp,
- safi_t safi);
+ afi_t afi, safi_t safi);
/* Announce routes of any bgp subtype of a table to zebra */
extern void bgp_zebra_announce_table_all_subtypes(struct bgp *bgp, afi_t afi,
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index b8517199a..8fc52652a 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1513,6 +1513,8 @@ struct peer *peer_new(struct bgp *bgp)
SET_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_SEND_EXT_COMMUNITY);
SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_SEND_EXT_COMMUNITY_RPKI);
+ SET_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_SEND_LARGE_COMMUNITY);
SET_FLAG(peer->af_flags_invert[afi][safi],
@@ -1520,6 +1522,8 @@ struct peer *peer_new(struct bgp *bgp)
SET_FLAG(peer->af_flags_invert[afi][safi],
PEER_FLAG_SEND_EXT_COMMUNITY);
SET_FLAG(peer->af_flags_invert[afi][safi],
+ PEER_FLAG_SEND_EXT_COMMUNITY_RPKI);
+ SET_FLAG(peer->af_flags_invert[afi][safi],
PEER_FLAG_SEND_LARGE_COMMUNITY);
peer->addpath_type[afi][safi] = BGP_ADDPATH_NONE;
peer->addpath_best_selected[afi][safi] = 0;
@@ -1650,6 +1654,7 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
XSTRDUP(MTYPE_BGP_PEER_IFNAME, peer_src->ifname);
}
peer_dst->ttl = peer_src->ttl;
+ peer_dst->gtsm_hops = peer_src->gtsm_hops;
}
static int bgp_peer_conf_if_to_su_update_v4(struct peer_connection *connection,
@@ -4608,6 +4613,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] = {
{PEER_FLAG_DISABLE_ADDPATH_RX, 0, peer_change_none},
{PEER_FLAG_SOO, 0, peer_change_reset},
{PEER_FLAG_ACCEPT_OWN, 0, peer_change_reset},
+ {PEER_FLAG_SEND_EXT_COMMUNITY_RPKI, 1, peer_change_reset_out},
{0, 0, 0}};
/* Proper action set. */
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index a0360525a..0f6909532 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -1149,6 +1149,11 @@ struct peer_connection {
int fd;
+ /* Thread flags */
+ _Atomic uint32_t thread_flags;
+#define PEER_THREAD_WRITES_ON (1U << 0)
+#define PEER_THREAD_READS_ON (1U << 1)
+
/* Packet receive and send buffer. */
pthread_mutex_t io_mtx; // guards ibuf, obuf
struct stream_fifo *ibuf; // packets waiting to be processed
@@ -1179,11 +1184,6 @@ struct peer_connection {
union sockunion su;
#define BGP_CONNECTION_SU_UNSPEC(connection) \
(connection->su.sa.sa_family == AF_UNSPEC)
-
- /* Thread flags */
- _Atomic uint32_t thread_flags;
-#define PEER_THREAD_WRITES_ON (1U << 0)
-#define PEER_THREAD_READS_ON (1U << 1)
};
extern struct peer_connection *bgp_peer_connection_new(struct peer *peer);
extern void bgp_peer_connection_free(struct peer_connection **connection);
@@ -1527,6 +1527,7 @@ struct peer {
#define PEER_FLAG_MAX_PREFIX_FORCE (1ULL << 26)
#define PEER_FLAG_DISABLE_ADDPATH_RX (1ULL << 27)
#define PEER_FLAG_SOO (1ULL << 28)
+#define PEER_FLAG_SEND_EXT_COMMUNITY_RPKI (1ULL << 29)
#define PEER_FLAG_ACCEPT_OWN (1ULL << 63)
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
diff --git a/configure.ac b/configure.ac
index d9fd920c7..8da41e6d3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2905,7 +2905,7 @@ compiler flags : ${CFLAGS} ${WERROR} ${AC_CFLAGS} ${SAN_FLAGS}
make : ${MAKE-make}
linker flags : ${LDFLAGS} ${SAN_FLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM}
state file directory : ${e_frr_runstatedir}
-config file directory : ${e_sysconfdir}
+config file directory : ${e_frr_sysconfdir}
module directory : ${e_moduledir}
script directory : ${e_scriptdir}
user to run as : ${enable_user}
diff --git a/doc/developer/mgmtd-dev.rst b/doc/developer/mgmtd-dev.rst
index e557d3a84..2404ffe2a 100644
--- a/doc/developer/mgmtd-dev.rst
+++ b/doc/developer/mgmtd-dev.rst
@@ -43,19 +43,20 @@ Fully Converted To MGMTD
- lib/filter
- lib/if_rmap
- lib/routemap
+- lib/affinitymap
+- lib/if
+- lib/vrf
- ripd
+- ripngd
- staticd
- zebra (* - partial)
Converted To Northbound
"""""""""""""""""""""""
- bfdd
-- lib/affinitymap
-- lib/if
- pathd
- pbrd
- pimd
-- ripngd
Converted To Northbound With Issues
"""""""""""""""""""""""""""""""""""
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
index 3e3bd2dd2..3af4048ed 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -10,7 +10,10 @@ Installation and Setup
Topotests run under python3.
-Tested with Ubuntu 20.04,Ubuntu 18.04, and Debian 11.
+Tested with Ubuntu 22.04,Ubuntu 20.04, and Debian 12.
+
+Python protobuf version < 4 is required b/c python protobuf >= 4 requires a
+protoc >= 3.19, and older package versions are shipped by in the above distros.
Instructions are the same for all setups. However, ExaBGP is only used for
BGP tests.
@@ -33,16 +36,16 @@ Installing Topotest Requirements
tshark \
valgrind
python3 -m pip install wheel
- python3 -m pip install protobuf
- python3 -m pip install 'pytest>=6.2.4'
- python3 -m pip install 'pytest-xdist>=2.3.0'
+ python3 -m pip install 'protobuf<4'
+ python3 -m pip install 'pytest>=6.2.4' 'pytest-xdist>=2.3.0'
python3 -m pip install 'scapy>=2.4.5'
python3 -m pip install xmltodict
python3 -m pip install git+https://github.com/Exa-Networks/exabgp@0659057837cd6c6351579e9f0fa47e9fb7de7311
useradd -d /var/run/exabgp/ -s /bin/false exabgp
# To enable the gRPC topotest install:
- python3 -m pip install grpcio grpcio-tools
+ # It's important to include 'protobuf<4' here to avoid incompatible grpcio-tools versions.
+ python3 -m pip install 'protobuf<4' grpcio grpcio-tools
Enable Coredumps
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 86d7c402e..53dc551ca 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1674,7 +1674,18 @@ Configuring Peers
modifying the `net.core.optmem_max` sysctl to a larger value to
avoid out of memory errors from the linux kernel.
-.. clicmd:: neighbor PEER send-community
+.. clicmd:: neighbor PEER send-community <both|all|extended|standard|large>
+
+ Send the communities to the peer.
+
+ Default: enabled.
+
+.. clicmd:: neighbor PEER send-community extended rpki
+
+ Send the extended RPKI communities to the peer. RPKI extended community
+ can be send only to iBGP and eBGP-OAD peers.
+
+ Default: enabled.
.. clicmd:: neighbor PEER weight WEIGHT
diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst
index 18a261d94..791762aa7 100644
--- a/doc/user/routemap.rst
+++ b/doc/user/routemap.rst
@@ -380,13 +380,13 @@ Route Map Exit Action Command
.. clicmd:: on-match next
-.. clicmd:: continue
-
Proceed on to the next entry in the route-map.
-.. clicmd:: on-match goto N
+.. clicmd:: continue (1-65535)
-.. clicmd:: continue N
+ Proceed to the specified sequence in the route-map.
+
+.. clicmd:: on-match goto N
Proceed processing the route-map at the first entry whose order is >= N
diff --git a/docker/ubuntu-ci/Dockerfile b/docker/ubuntu-ci/Dockerfile
index 9b9b4061e..5a4980658 100644
--- a/docker/ubuntu-ci/Dockerfile
+++ b/docker/ubuntu-ci/Dockerfile
@@ -74,12 +74,10 @@ RUN apt update && apt upgrade -y && \
wget https://raw.githubusercontent.com/FRRouting/frr-mibs/main/ietf/SNMPv2-PDU -O /usr/share/snmp/mibs/ietf/SNMPv2-PDU && \
wget https://raw.githubusercontent.com/FRRouting/frr-mibs/main/ietf/IPATM-IPMC-MIB -O /usr/share/snmp/mibs/ietf/IPATM-IPMC-MIB && \
python3 -m pip install wheel && \
- python3 -m pip install pytest && \
- python3 -m pip install pytest-sugar && \
- python3 -m pip install pytest-xdist && \
- python3 -m pip install "scapy>=2.4.2" && \
+ python3 -m pip install 'protobuf<4' grpcio grpcio-tools && \
+ python3 -m pip install 'pytest>=6.2.4' 'pytest-xdist>=2.3.0' && \
+ python3 -m pip install 'scapy>=2.4.5' && \
python3 -m pip install xmltodict && \
- python3 -m pip install grpcio grpcio-tools && \
python3 -m pip install git+https://github.com/Exa-Networks/exabgp@0659057837cd6c6351579e9f0fa47e9fb7de7311
RUN groupadd -r -g 92 frr && \
diff --git a/lib/event.c b/lib/event.c
index 6427705e9..fc46a11c0 100644
--- a/lib/event.c
+++ b/lib/event.c
@@ -570,9 +570,12 @@ struct event_loop *event_master_create(const char *name)
rv->fd_limit = (int)limit.rlim_cur;
}
- if (rv->fd_limit > STUPIDLY_LARGE_FD_SIZE)
- zlog_warn("FD Limit set: %u is stupidly large. Is this what you intended? Consider using --limit-fds",
- rv->fd_limit);
+ if (rv->fd_limit > STUPIDLY_LARGE_FD_SIZE) {
+ zlog_warn("FD Limit set: %u is stupidly large. Is this what you intended? Consider using --limit-fds also limiting size to %u",
+ rv->fd_limit, STUPIDLY_LARGE_FD_SIZE);
+
+ rv->fd_limit = STUPIDLY_LARGE_FD_SIZE;
+ }
rv->read = XCALLOC(MTYPE_EVENT_POLL,
sizeof(struct event *) * rv->fd_limit);
diff --git a/lib/mgmt_be_client.c b/lib/mgmt_be_client.c
index 6530022db..286555c56 100644
--- a/lib/mgmt_be_client.c
+++ b/lib/mgmt_be_client.c
@@ -963,22 +963,29 @@ static void be_client_handle_notify(struct mgmt_be_client *client, void *msgbuf,
size_t msg_len)
{
struct mgmt_msg_notify_data *notif_msg = msgbuf;
- struct mgmt_be_client_notification_cb *cb;
- const char *notif;
- uint i;
+ struct nb_node *nb_node;
+ char notif[XPATH_MAXLEN];
+ struct lyd_node *dnode;
+ LY_ERR err;
debug_be_client("Received notification for client %s", client->name);
- /* "{\"modname:notification-name\": ...}" */
- notif = (const char *)notif_msg->result + 2;
+ err = yang_parse_notification(notif_msg->result_type,
+ (char *)notif_msg->result, &dnode);
+ if (err)
+ return;
- for (i = 0; i < client->cbs.nnotify_cbs; i++) {
- cb = &client->cbs.notify_cbs[i];
- if (strncmp(cb->xpath, notif, strlen(cb->xpath)))
- continue;
- cb->callback(client, client->user_data, cb,
- (const char *)notif_msg->result);
+ lysc_path(dnode->schema, LYSC_PATH_DATA, notif, sizeof(notif));
+
+ nb_node = nb_node_find(notif);
+ if (!nb_node || !nb_node->cbs.notify) {
+ debug_be_client("No notification callback for %s", notif);
+ goto cleanup;
}
+
+ nb_callback_notify(nb_node, notif, dnode);
+cleanup:
+ lyd_free_all(dnode);
}
/*
@@ -1049,8 +1056,6 @@ int mgmt_be_send_subscr_req(struct mgmt_be_client *client_ctx,
{
Mgmtd__BeMessage be_msg;
Mgmtd__BeSubscribeReq subscr_req;
- const char **notif_xpaths = NULL;
- int ret;
mgmtd__be_subscribe_req__init(&subscr_req);
subscr_req.client_name = client_ctx->name;
@@ -1060,16 +1065,8 @@ int mgmt_be_send_subscr_req(struct mgmt_be_client *client_ctx,
subscr_req.oper_xpaths = oper_xpaths;
/* See if we should register for notifications */
- subscr_req.n_notif_xpaths = client_ctx->cbs.nnotify_cbs;
- if (client_ctx->cbs.nnotify_cbs) {
- struct mgmt_be_client_notification_cb *cb, *ecb;
-
- cb = client_ctx->cbs.notify_cbs;
- ecb = cb + client_ctx->cbs.nnotify_cbs;
- for (; cb < ecb; cb++)
- *darr_append(notif_xpaths) = cb->xpath;
- }
- subscr_req.notif_xpaths = (char **)notif_xpaths;
+ subscr_req.n_notif_xpaths = client_ctx->cbs.nnotif_xpaths;
+ subscr_req.notif_xpaths = (char **)client_ctx->cbs.notif_xpaths;
mgmtd__be_message__init(&be_msg);
be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REQ;
@@ -1079,9 +1076,7 @@ int mgmt_be_send_subscr_req(struct mgmt_be_client *client_ctx,
subscr_req.client_name, subscr_req.n_config_xpaths,
subscr_req.n_oper_xpaths, subscr_req.n_notif_xpaths);
- ret = mgmt_be_client_send_msg(client_ctx, &be_msg);
- darr_free(notif_xpaths);
- return ret;
+ return mgmt_be_client_send_msg(client_ctx, &be_msg);
}
static int _notify_conenct_disconnect(struct msg_client *msg_client,
diff --git a/lib/mgmt_be_client.h b/lib/mgmt_be_client.h
index d144ebc72..361899fc1 100644
--- a/lib/mgmt_be_client.h
+++ b/lib/mgmt_be_client.h
@@ -73,16 +73,8 @@ struct mgmt_be_client_cbs {
struct mgmt_be_client_txn_ctx *txn_ctx,
bool destroyed);
- struct mgmt_be_client_notification_cb *notify_cbs;
- uint nnotify_cbs;
-};
-
-struct mgmt_be_client_notification_cb {
- const char *xpath; /* the notification */
- uint8_t format; /* currently only LYD_JSON supported */
- void (*callback)(struct mgmt_be_client *client, uintptr_t usr_data,
- struct mgmt_be_client_notification_cb *this,
- const char *notif_data);
+ const char **notif_xpaths;
+ uint nnotif_xpaths;
};
/***************************************************************
diff --git a/lib/northbound.c b/lib/northbound.c
index a0b1bd18c..d74773194 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -284,6 +284,8 @@ static unsigned int nb_node_validate_cbs(const struct nb_node *nb_node)
!!nb_node->cbs.lookup_entry, false);
error += nb_node_validate_cb(nb_node, NB_CB_RPC, !!nb_node->cbs.rpc,
false);
+ error += nb_node_validate_cb(nb_node, NB_CB_NOTIFY,
+ !!nb_node->cbs.notify, true);
return error;
}
@@ -1605,6 +1607,18 @@ int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath,
return nb_node->cbs.rpc(&args);
}
+void nb_callback_notify(const struct nb_node *nb_node, const char *xpath,
+ struct lyd_node *dnode)
+{
+ struct nb_cb_notify_args args = {};
+
+ DEBUGD(&nb_dbg_cbs_notify, "northbound notify: %s", xpath);
+
+ args.xpath = xpath;
+ args.dnode = dnode;
+ nb_node->cbs.notify(&args);
+}
+
/*
* Call the northbound configuration callback associated to a given
* configuration change.
@@ -1653,6 +1667,7 @@ static int nb_callback_configuration(struct nb_context *context,
case NB_CB_GET_KEYS:
case NB_CB_LOOKUP_ENTRY:
case NB_CB_RPC:
+ case NB_CB_NOTIFY:
yang_dnode_get_path(dnode, xpath, sizeof(xpath));
flog_err(EC_LIB_DEVELOPMENT,
"%s: unknown operation (%u) [xpath %s]", __func__,
@@ -2047,6 +2062,10 @@ bool nb_cb_operation_is_valid(enum nb_cb_operation operation,
return false;
}
return true;
+ case NB_CB_NOTIFY:
+ if (snode->nodetype != LYS_NOTIF)
+ return false;
+ return true;
default:
return false;
}
@@ -2279,6 +2298,8 @@ const char *nb_cb_operation_name(enum nb_cb_operation operation)
return "lookup_entry";
case NB_CB_RPC:
return "rpc";
+ case NB_CB_NOTIFY:
+ return "notify";
}
assert(!"Reached end of function we should never hit");
diff --git a/lib/northbound.h b/lib/northbound.h
index 9279122de..e9f2db9b6 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -99,6 +99,7 @@ enum nb_cb_operation {
NB_CB_GET_KEYS,
NB_CB_LOOKUP_ENTRY,
NB_CB_RPC,
+ NB_CB_NOTIFY,
};
union nb_resource {
@@ -286,6 +287,18 @@ struct nb_cb_rpc_args {
size_t errmsg_len;
};
+struct nb_cb_notify_args {
+ /* XPath of the notification. */
+ const char *xpath;
+
+ /*
+ * libyang data node representing the notification. If the notification
+ * is not top-level, it still points to the notification node, but it's
+ * part of the full data tree with all its parents.
+ */
+ struct lyd_node *dnode;
+};
+
/*
* Set of configuration callbacks that can be associated to a northbound node.
*/
@@ -510,6 +523,17 @@ struct nb_callbacks {
int (*rpc)(struct nb_cb_rpc_args *args);
/*
+ * Notification callback.
+ *
+ * The callback is called when a YANG notification is received.
+ *
+ * args
+ * Refer to the documentation comments of nb_cb_notify_args for
+ * details.
+ */
+ void (*notify)(struct nb_cb_notify_args *args);
+
+ /*
* Optional callback to compare the data nodes when printing
* the CLI commands associated with them.
*
@@ -786,6 +810,7 @@ DECLARE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set));
extern struct debug nb_dbg_cbs_config;
extern struct debug nb_dbg_cbs_state;
extern struct debug nb_dbg_cbs_rpc;
+extern struct debug nb_dbg_cbs_notify;
extern struct debug nb_dbg_notif;
extern struct debug nb_dbg_events;
extern struct debug nb_dbg_libyang;
@@ -814,6 +839,8 @@ extern const void *nb_callback_lookup_next(const struct nb_node *nb_node,
extern int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath,
const struct list *input, struct list *output,
char *errmsg, size_t errmsg_len);
+extern void nb_callback_notify(const struct nb_node *nb_node, const char *xpath,
+ struct lyd_node *dnode);
/*
* Create a northbound node for all YANG schema nodes.
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index 0358a0f37..8809ec2ad 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -25,6 +25,7 @@
struct debug nb_dbg_cbs_config = {0, "Northbound callbacks: configuration"};
struct debug nb_dbg_cbs_state = {0, "Northbound callbacks: state"};
struct debug nb_dbg_cbs_rpc = {0, "Northbound callbacks: RPCs"};
+struct debug nb_dbg_cbs_notify = {0, "Northbound callbacks: notifications"};
struct debug nb_dbg_notif = {0, "Northbound notifications"};
struct debug nb_dbg_events = {0, "Northbound events"};
struct debug nb_dbg_libyang = {0, "libyang debugging"};
@@ -1772,13 +1773,15 @@ DEFPY (rollback_config,
/* Debug CLI commands. */
static struct debug *nb_debugs[] = {
&nb_dbg_cbs_config, &nb_dbg_cbs_state, &nb_dbg_cbs_rpc,
- &nb_dbg_notif, &nb_dbg_events, &nb_dbg_libyang,
+ &nb_dbg_cbs_notify, &nb_dbg_notif, &nb_dbg_events,
+ &nb_dbg_libyang,
};
static const char *const nb_debugs_conflines[] = {
"debug northbound callbacks configuration",
"debug northbound callbacks state",
"debug northbound callbacks rpc",
+ "debug northbound callbacks notify",
"debug northbound notifications",
"debug northbound events",
"debug northbound libyang",
@@ -1803,7 +1806,7 @@ DEFPY (debug_nb,
debug_nb_cmd,
"[no] debug northbound\
[<\
- callbacks$cbs [{configuration$cbs_cfg|state$cbs_state|rpc$cbs_rpc}]\
+ callbacks$cbs [{configuration$cbs_cfg|state$cbs_state|rpc$cbs_rpc|notify$cbs_notify}]\
|notifications$notifications\
|events$events\
|libyang$libyang\
@@ -1816,13 +1819,14 @@ DEFPY (debug_nb,
"State\n"
"RPC\n"
"Notifications\n"
+ "Notifications\n"
"Events\n"
"libyang debugging\n")
{
uint32_t mode = DEBUG_NODE2MODE(vty->node);
if (cbs) {
- bool none = (!cbs_cfg && !cbs_state && !cbs_rpc);
+ bool none = (!cbs_cfg && !cbs_state && !cbs_rpc && !cbs_notify);
if (none || cbs_cfg)
DEBUG_MODE_SET(&nb_dbg_cbs_config, mode, !no);
@@ -1830,6 +1834,8 @@ DEFPY (debug_nb,
DEBUG_MODE_SET(&nb_dbg_cbs_state, mode, !no);
if (none || cbs_rpc)
DEBUG_MODE_SET(&nb_dbg_cbs_rpc, mode, !no);
+ if (none || cbs_notify)
+ DEBUG_MODE_SET(&nb_dbg_cbs_notify, mode, !no);
}
if (notifications)
DEBUG_MODE_SET(&nb_dbg_notif, mode, !no);
diff --git a/lib/sockopt.c b/lib/sockopt.c
index b9b9a7116..74bc034cc 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -672,6 +672,9 @@ int sockopt_tcp_mss_get(int sock)
int tcp_maxseg = 0;
socklen_t tcp_maxseg_len = sizeof(tcp_maxseg);
+ if (sock < 0)
+ return 0;
+
ret = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg,
&tcp_maxseg_len);
if (ret != 0) {
diff --git a/lib/vty.h b/lib/vty.h
index 06973da91..a59ac7a65 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -232,10 +232,6 @@ struct vty {
uintptr_t mgmt_req_pending_data;
bool mgmt_locked_candidate_ds;
bool mgmt_locked_running_ds;
- /* Need to track when we file-lock in vtysh to re-lock on end/conf t
- * workaround
- */
- bool vtysh_file_locked;
};
static inline void vty_push_context(struct vty *vty, int node, uint64_t id)
diff --git a/lib/yang.c b/lib/yang.c
index adf2ba2ab..ff7df0b37 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -714,6 +714,52 @@ static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
zlog(priority, "libyang: %s", msg);
}
+LY_ERR yang_parse_notification(LYD_FORMAT format, const char *data,
+ struct lyd_node **notif)
+{
+ struct lyd_node *tree, *dnode;
+ struct ly_in *in = NULL;
+ bool found = false;
+ LY_ERR err;
+
+ err = ly_in_new_memory(data, &in);
+ if (err) {
+ zlog_err("Failed to initialize ly_in: %s", ly_last_errmsg());
+ return err;
+ }
+
+ err = lyd_parse_op(ly_native_ctx, NULL, in, format, LYD_TYPE_NOTIF_YANG,
+ &tree, NULL);
+ if (err) {
+ zlog_err("Failed to parse notification: %s", ly_last_errmsg());
+ ly_in_free(in, 0);
+ return err;
+ }
+
+ /*
+ * Notification can be a child of some data node, so traverse the tree
+ * until we find the notification.
+ */
+ LYD_TREE_DFS_BEGIN (tree, dnode) {
+ if (dnode->schema->nodetype == LYS_NOTIF) {
+ found = true;
+ break;
+ }
+ LYD_TREE_DFS_END(tree, dnode);
+ }
+
+ if (!found) {
+ zlog_err("Notification not found in the parsed tree");
+ lyd_free_all(tree);
+ ly_in_free(in, 0);
+ return LY_ENOTFOUND;
+ }
+
+ *notif = dnode;
+
+ return LY_SUCCESS;
+}
+
static ssize_t yang_print_darr(void *arg, const void *buf, size_t count)
{
uint8_t *dst = darr_append_n(*(uint8_t **)arg, count);
diff --git a/lib/yang.h b/lib/yang.h
index 4ed0a39ba..9c221445c 100644
--- a/lib/yang.h
+++ b/lib/yang.h
@@ -607,6 +607,19 @@ extern struct ly_ctx *yang_ctx_new_setup(bool embedded_modules,
*/
extern void yang_debugging_set(bool enable);
+/*
+ * Parse a YANG notification.
+ *
+ * Args:
+ * format: LYD_FORMAT of input data.
+ * data: input data.
+ * notif: pointer to the libyang data tree to store the parsed notification.
+ * If the notification is not on the top level of the yang model,
+ * the pointer to the notification node is still returned, but it's
+ * part of the full data tree with all its parents.
+ */
+extern LY_ERR yang_parse_notification(LYD_FORMAT format, const char *data,
+ struct lyd_node **notif);
/*
* "Print" the yang tree in `root` into dynamic sized array.
diff --git a/mgmtd/mgmt_be_adapter.c b/mgmtd/mgmt_be_adapter.c
index aba02e465..d85d87b4b 100644
--- a/mgmtd/mgmt_be_adapter.c
+++ b/mgmtd/mgmt_be_adapter.c
@@ -592,14 +592,22 @@ static void mgmt_be_adapter_send_notify(struct mgmt_msg_notify_data *msg,
{
struct mgmt_be_client_adapter *adapter;
struct mgmt_be_xpath_map *map;
- const char *notif;
+ char notif[XPATH_MAXLEN];
+ struct lyd_node *dnode;
+ LY_ERR err;
uint id;
if (!darr_len(be_notif_xpath_map))
return;
- /* "{\"modname:notification-name\": ...}" */
- notif = (const char *)msg->result + 2;
+ err = yang_parse_notification(msg->result_type, (char *)msg->result,
+ &dnode);
+ if (err)
+ return;
+
+ lysc_path(dnode->schema, LYSC_PATH_DATA, notif, sizeof(notif));
+
+ lyd_free_all(dnode);
darr_foreach_p (be_notif_xpath_map, map) {
if (strncmp(map->xpath_prefix, notif, strlen(map->xpath_prefix)))
@@ -917,22 +925,17 @@ uint64_t mgmt_be_interested_clients(const char *xpath, bool config)
static bool be_is_client_interested(const char *xpath,
enum mgmt_be_client_id id, bool config)
{
- const char *const *xpaths;
+ uint64_t clients;
assert(id < MGMTD_BE_CLIENT_ID_MAX);
__dbg("Checking client: %s for xpath: '%s'", mgmt_be_client_id2name(id),
xpath);
- xpaths = config ? be_client_config_xpaths[id]
- : be_client_oper_xpaths[id];
- if (xpaths) {
- for (; *xpaths; xpaths++) {
- if (mgmt_be_xpath_prefix(*xpaths, xpath)) {
- __dbg("xpath: %s: matched: %s", *xpaths, xpath);
- return true;
- }
- }
+ clients = mgmt_be_interested_clients(xpath, config);
+ if (IS_IDBIT_SET(clients, id)) {
+ __dbg("client: %s: interested", mgmt_be_client_id2name(id));
+ return true;
}
__dbg("client: %s: not interested", mgmt_be_client_id2name(id));
diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c
index 001da7680..ec8e77335 100644
--- a/mgmtd/mgmt_fe_adapter.c
+++ b/mgmtd/mgmt_fe_adapter.c
@@ -711,9 +711,6 @@ mgmt_fe_session_handle_setcfg_req_msg(struct mgmt_fe_session_ctx *session,
}
if (session->cfg_txn_id == MGMTD_TXN_ID_NONE) {
- /* as we have the lock no-one else should have a config txn */
- assert(!mgmt_config_txn_in_progress());
-
/* Start a CONFIG Transaction (if not started already) */
session->cfg_txn_id = mgmt_create_txn(session->session_id,
MGMTD_TXN_TYPE_CONFIG);
diff --git a/mgmtd/mgmt_testc.c b/mgmtd/mgmt_testc.c
index 02a308f32..7e3ded820 100644
--- a/mgmtd/mgmt_testc.c
+++ b/mgmtd/mgmt_testc.c
@@ -11,14 +11,13 @@
#include "darr.h"
#include "libfrr.h"
#include "mgmt_be_client.h"
+#include "northbound.h"
/* ---------------- */
/* Local Prototypes */
/* ---------------- */
-static void async_notification(struct mgmt_be_client *client, uintptr_t usr_data,
- struct mgmt_be_client_notification_cb *this,
- const char *notif_data);
+static void async_notification(struct nb_cb_notify_args *args);
static void sigusr1(void);
static void sigint(void);
@@ -79,6 +78,24 @@ struct frr_signal_t __signals[] = {
#define MGMTD_TESTC_VTY_PORT 2624
/* clang-format off */
+static const struct frr_yang_module_info frr_ripd_info = {
+ .name = "frr-ripd",
+ .ignore_cfg_cbs = true,
+ .nodes = {
+ {
+ .xpath = "/frr-ripd:authentication-failure",
+ .cbs.notify = async_notification,
+ },
+ {
+ .xpath = NULL,
+ }
+ }
+};
+
+static const struct frr_yang_module_info *const mgmt_yang_modules[] = {
+ &frr_ripd_info,
+};
+
FRR_DAEMON_INFO(mgmtd_testc, MGMTD_TESTC,
.proghelp = "FRR Management Daemon Test Client.",
@@ -87,15 +104,15 @@ FRR_DAEMON_INFO(mgmtd_testc, MGMTD_TESTC,
.privs = &__privs,
- // .yang_modules = mgmt_yang_modules,
- // .n_yang_modules = array_size(mgmt_yang_modules),
+ .yang_modules = mgmt_yang_modules,
+ .n_yang_modules = array_size(mgmt_yang_modules),
/* avoid libfrr trying to read our config file for us */
.flags = FRR_MANUAL_VTY_START,
);
/* clang-format on */
-struct mgmt_be_client_notification_cb *__notify_cbs;
+const char **__notif_xpaths;
struct mgmt_be_client_cbs __client_cbs = {};
struct event *event_timeout;
@@ -117,7 +134,7 @@ static void quit(int exit_code)
{
EVENT_OFF(event_timeout);
frr_fini();
- darr_free(__client_cbs.notify_cbs);
+ darr_free(__client_cbs.notif_xpaths);
exit(exit_code);
}
@@ -133,13 +150,12 @@ static void timeout(struct event *event)
quit(1);
}
-static void async_notification(struct mgmt_be_client *client, uintptr_t usr_data,
- struct mgmt_be_client_notification_cb *this,
- const char *notif_data)
+static void async_notification(struct nb_cb_notify_args *args)
{
zlog_notice("Received YANG notification");
- printf("%s\n", notif_data);
+ printf("{\"frr-ripd:authentication-failure\": {\"interface-name\": \"%s\"}}\n",
+ yang_dnode_get_string(args->dnode, "interface-name"));
if (o_notif_count && !--o_notif_count)
quit(0);
@@ -191,17 +207,12 @@ int main(int argc, char **argv)
exit(1);
}
if (argc && f_listen) {
- struct mgmt_be_client_notification_cb *cb;
-
for (i = 0; i < argc; i++) {
zlog_notice("Listen on xpath: %s", argv[i]);
- cb = darr_append(__notify_cbs);
- cb->xpath = argv[i];
- cb->format = LYD_JSON;
- cb->callback = async_notification;
+ darr_push(__notif_xpaths, argv[i]);
}
- __client_cbs.notify_cbs = __notify_cbs;
- __client_cbs.nnotify_cbs = darr_len(__notify_cbs);
+ __client_cbs.notif_xpaths = __notif_xpaths;
+ __client_cbs.nnotif_xpaths = darr_len(__notif_xpaths);
}
mgmt_be_client = mgmt_be_client_create("mgmtd-testc", &__client_cbs, 0,
diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c
index df2a1d852..664f42f4b 100644
--- a/mgmtd/mgmt_txn.c
+++ b/mgmtd/mgmt_txn.c
@@ -105,6 +105,7 @@ struct mgmt_commit_cfg_req {
uint8_t abort : 1;
uint8_t implicit : 1;
uint8_t rollback : 1;
+ uint8_t init : 1;
/* Track commit phases */
enum mgmt_commit_phase phase;
@@ -750,6 +751,14 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn,
mgmt_history_rollback_complete(success);
}
+ if (txn->commit_cfg_req->req.commit_cfg.init) {
+ /*
+ * This is the backend init request.
+ * We need to unlock the running datastore.
+ */
+ mgmt_ds_unlock(txn->commit_cfg_req->req.commit_cfg.dst_ds_ctx);
+ }
+
txn->commit_cfg_req->req.commit_cfg.cmt_stats = NULL;
mgmt_txn_req_free(&txn->commit_cfg_req);
@@ -2081,15 +2090,26 @@ int mgmt_txn_notify_be_adapter_conn(struct mgmt_be_client_adapter *adapter,
struct mgmt_commit_cfg_req *cmtcfg_req;
static struct mgmt_commit_stats dummy_stats;
struct nb_config_cbs *adapter_cfgs = NULL;
+ struct mgmt_ds_ctx *ds_ctx;
memset(&dummy_stats, 0, sizeof(dummy_stats));
if (connect) {
- /* Get config for this single backend client */
+ ds_ctx = mgmt_ds_get_ctx_by_id(mm, MGMTD_DS_RUNNING);
+ assert(ds_ctx);
+
+ /*
+ * Lock the running datastore to prevent any changes while we
+ * are initializing the backend.
+ */
+ if (mgmt_ds_lock(ds_ctx, 0) != 0)
+ return -1;
+ /* Get config for this single backend client */
mgmt_be_get_adapter_config(adapter, &adapter_cfgs);
if (!adapter_cfgs || RB_EMPTY(nb_config_cbs, adapter_cfgs)) {
SET_FLAG(adapter->flags,
MGMTD_BE_ADAPTER_FLAGS_CFG_SYNCED);
+ mgmt_ds_unlock(ds_ctx);
return 0;
}
@@ -2101,6 +2121,7 @@ int mgmt_txn_notify_be_adapter_conn(struct mgmt_be_client_adapter *adapter,
if (!txn) {
__log_err("Failed to create CONFIG Transaction for downloading CONFIGs for client '%s'",
adapter->name);
+ mgmt_ds_unlock(ds_ctx);
nb_config_diff_del_changes(adapter_cfgs);
return -1;
}
@@ -2114,10 +2135,11 @@ int mgmt_txn_notify_be_adapter_conn(struct mgmt_be_client_adapter *adapter,
txn_req = mgmt_txn_req_alloc(txn, 0, MGMTD_TXN_PROC_COMMITCFG);
txn_req->req.commit_cfg.src_ds_id = MGMTD_DS_NONE;
txn_req->req.commit_cfg.src_ds_ctx = 0;
- txn_req->req.commit_cfg.dst_ds_id = MGMTD_DS_NONE;
- txn_req->req.commit_cfg.dst_ds_ctx = 0;
+ txn_req->req.commit_cfg.dst_ds_id = MGMTD_DS_RUNNING;
+ txn_req->req.commit_cfg.dst_ds_ctx = ds_ctx;
txn_req->req.commit_cfg.validate_only = false;
txn_req->req.commit_cfg.abort = false;
+ txn_req->req.commit_cfg.init = true;
txn_req->req.commit_cfg.cmt_stats = &dummy_stats;
txn_req->req.commit_cfg.cfg_chgs = adapter_cfgs;
diff --git a/mgmtd/subdir.am b/mgmtd/subdir.am
index 3eaa9567a..1624c6e4f 100644
--- a/mgmtd/subdir.am
+++ b/mgmtd/subdir.am
@@ -19,7 +19,6 @@ mgmtd_libmgmt_be_nb_la_SOURCES = \
zebra/zebra_cli.c \
# end
nodist_mgmtd_libmgmt_be_nb_la_SOURCES = \
- lib/affinitymap_cli.c \
# end
mgmtd_libmgmt_be_nb_la_CFLAGS = $(AM_CFLAGS) -DINCLUDE_MGMTD_CMDDEFS_ONLY
mgmtd_libmgmt_be_nb_la_CPPFLAGS = $(AM_CPPFLAGS) -DINCLUDE_MGMTD_CMDDEFS_ONLY
diff --git a/nhrpd/netlink_arp.c b/nhrpd/netlink_arp.c
index 88628999a..be909c862 100644
--- a/nhrpd/netlink_arp.c
+++ b/nhrpd/netlink_arp.c
@@ -191,6 +191,11 @@ int nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS)
"Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU",
&addr, ifp->name, &c->cur.remote_nbma_natoa,
&c->cur.peer->vc->remote.nbma, &lladdr);
+
+ if (lladdr.sa.sa_family == AF_UNSPEC)
+ /* nothing from zebra, so use nhrp peer */
+ lladdr = c->cur.peer->vc->remote.nbma;
+
/* In case of shortcuts, nbma is given by lladdr, not
* vc->remote.nbma.
*/
diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c
index d82c2146c..df0b3b908 100644
--- a/ospfd/ospf_ext.c
+++ b/ospfd/ospf_ext.c
@@ -31,6 +31,7 @@
#include "network.h"
#include "if.h"
#include "libospf.h" /* for ospf interface types */
+#include <lib/json.h>
#include "ospfd/ospfd.h"
#include "ospfd/ospf_interface.h"
@@ -1715,23 +1716,29 @@ static void ospf_ext_lsa_schedule(struct ext_itf *exti, enum lsa_opcode op)
/* Cisco experimental SubTLV */
static uint16_t show_vty_ext_link_rmt_itf_addr(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct ext_subtlv_rmt_itf_addr *top =
(struct ext_subtlv_rmt_itf_addr *)tlvh;
check_tlv_size(EXT_SUBTLV_RMT_ITF_ADDR_SIZE, "Remote Itf. Address");
- vty_out(vty,
- " Remote Interface Address Sub-TLV: Length %u\n Address: %pI4\n",
- ntohs(top->header.length), &top->value);
+ if (!json)
+ vty_out(vty,
+ " Remote Interface Address Sub-TLV: Length %u\n Address: %pI4\n",
+ ntohs(top->header.length), &top->value);
+ else
+ json_object_string_addf(json, "remoteInterfaceAddress", "%pI4",
+ &top->value);
return TLV_SIZE(tlvh);
}
/* Adjacency SID SubTLV */
static uint16_t show_vty_ext_link_adj_sid(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct ext_subtlv_adj_sid *top = (struct ext_subtlv_adj_sid *)tlvh;
uint8_t tlv_size;
@@ -1741,21 +1748,35 @@ static uint16_t show_vty_ext_link_adj_sid(struct vty *vty,
: SID_INDEX_SIZE(EXT_SUBTLV_ADJ_SID_SIZE);
check_tlv_size(tlv_size, "Adjacency SID");
- vty_out(vty,
- " Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\t%s: %u\n",
- ntohs(top->header.length), top->flags, top->mtid, top->weight,
- CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label"
- : "Index",
- CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
- ? GET_LABEL(ntohl(top->value))
- : ntohl(top->value));
+ if (!json)
+ vty_out(vty,
+ " Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\t%s: %u\n",
+ ntohs(top->header.length), top->flags, top->mtid,
+ top->weight,
+ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
+ ? "Label"
+ : "Index",
+ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
+ ? GET_LABEL(ntohl(top->value))
+ : ntohl(top->value));
+ else {
+ json_object_string_addf(json, "flags", "0x%x", top->flags);
+ json_object_string_addf(json, "mtID", "0x%x", top->mtid);
+ json_object_string_addf(json, "weight", "0x%x", top->weight);
+ if (CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG))
+ json_object_int_add(json, "label",
+ GET_LABEL(ntohl(top->value)));
+ else
+ json_object_int_add(json, "index", ntohl(top->value));
+ }
return TLV_SIZE(tlvh);
}
/* LAN Adjacency SubTLV */
static uint16_t show_vty_ext_link_lan_adj_sid(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct ext_subtlv_lan_adj_sid *top =
(struct ext_subtlv_lan_adj_sid *)tlvh;
@@ -1766,42 +1787,67 @@ static uint16_t show_vty_ext_link_lan_adj_sid(struct vty *vty,
: SID_INDEX_SIZE(EXT_SUBTLV_LAN_ADJ_SID_SIZE);
check_tlv_size(tlv_size, "LAN-Adjacency SID");
- vty_out(vty,
- " LAN-Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\tNeighbor ID: %pI4\n\t%s: %u\n",
- ntohs(top->header.length), top->flags, top->mtid, top->weight,
- &top->neighbor_id,
- CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label"
- : "Index",
- CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
- ? GET_LABEL(ntohl(top->value))
- : ntohl(top->value));
+ if (!json)
+ vty_out(vty,
+ " LAN-Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\tNeighbor ID: %pI4\n\t%s: %u\n",
+ ntohs(top->header.length), top->flags, top->mtid,
+ top->weight, &top->neighbor_id,
+ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
+ ? "Label"
+ : "Index",
+ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
+ ? GET_LABEL(ntohl(top->value))
+ : ntohl(top->value));
+ else {
+ json_object_string_addf(json, "flags", "0x%x", top->flags);
+ json_object_string_addf(json, "mtID", "0x%x", top->mtid);
+ json_object_string_addf(json, "weight", "0x%x", top->weight);
+ json_object_string_addf(json, "neighborID", "%pI4",
+ &top->neighbor_id);
+ if (CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG))
+ json_object_int_add(json, "label",
+ GET_LABEL(ntohl(top->value)));
+ else
+ json_object_int_add(json, "index", ntohl(top->value));
+ }
return TLV_SIZE(tlvh);
}
static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
- size_t buf_size)
+ size_t buf_size, json_object *json)
{
+ json_object *obj;
+
if (TLV_SIZE(tlvh) > buf_size) {
vty_out(vty, " TLV size %d exceeds buffer size. Abort!",
TLV_SIZE(tlvh));
return buf_size;
}
-
- vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n",
- ntohs(tlvh->type), ntohs(tlvh->length));
+ if (!json)
+ vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n",
+ ntohs(tlvh->type), ntohs(tlvh->length));
+ else {
+ obj = json_object_new_object();
+ json_object_string_addf(obj, "type", "0x%x",
+ ntohs(tlvh->type));
+ json_object_string_addf(obj, "length", "0x%x",
+ ntohs(tlvh->length));
+ json_object_object_add(json, "unknownTLV", obj);
+ }
return TLV_SIZE(tlvh);
}
/* Extended Link Sub TLVs */
static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext,
- size_t buf_size)
+ size_t buf_size, json_object *json)
{
struct ext_tlv_link *top = (struct ext_tlv_link *)ext;
struct tlv_header *tlvh;
uint16_t length = ntohs(top->header.length);
uint16_t sum = 0;
+ json_object *jadj = NULL, *obj = NULL;
/* Verify that TLV length is valid against remaining buffer size */
if (length > buf_size) {
@@ -1811,12 +1857,22 @@ static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext,
return buf_size;
}
- vty_out(vty,
- " Extended Link TLV: Length %u\n Link Type: 0x%x\n"
- " Link ID: %pI4\n",
- ntohs(top->header.length), top->link_type,
- &top->link_id);
- vty_out(vty, " Link data: %pI4\n", &top->link_data);
+ if (!json) {
+ vty_out(vty,
+ " Extended Link TLV: Length %u\n Link Type: 0x%x\n"
+ " Link ID: %pI4\n",
+ ntohs(top->header.length), top->link_type,
+ &top->link_id);
+ vty_out(vty, " Link data: %pI4\n", &top->link_data);
+ } else {
+ json_object_string_addf(json, "linkType", "0x%x",
+ top->link_type);
+ json_object_string_addf(json, "linkID", "%pI4", &top->link_id);
+ json_object_string_addf(json, "linkData", "%pI4",
+ &top->link_data);
+ jadj = json_object_new_array();
+ json_object_object_add(json, "adjacencySID", jadj);
+ }
/* Skip Extended TLV and parse sub-TLVs */
length -= EXT_TLV_LINK_SIZE;
@@ -1825,16 +1881,27 @@ static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext,
for (; sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) {
switch (ntohs(tlvh->type)) {
case EXT_SUBTLV_ADJ_SID:
- sum += show_vty_ext_link_adj_sid(vty, tlvh);
+ if (json) {
+ obj = json_object_new_object();
+ json_object_array_add(jadj, obj);
+ } else
+ obj = NULL;
+ sum += show_vty_ext_link_adj_sid(vty, tlvh, obj);
break;
case EXT_SUBTLV_LAN_ADJ_SID:
- sum += show_vty_ext_link_lan_adj_sid(vty, tlvh);
+ if (json) {
+ obj = json_object_new_object();
+ json_object_array_add(jadj, obj);
+ } else
+ obj = NULL;
+ sum += show_vty_ext_link_lan_adj_sid(vty, tlvh, obj);
break;
case EXT_SUBTLV_RMT_ITF_ADDR:
- sum += show_vty_ext_link_rmt_itf_addr(vty, tlvh);
+ sum += show_vty_ext_link_rmt_itf_addr(vty, tlvh, json);
break;
default:
- sum += show_vty_unknown_tlv(vty, tlvh, length - sum);
+ sum += show_vty_unknown_tlv(vty, tlvh, length - sum,
+ json);
break;
}
}
@@ -1849,9 +1916,12 @@ static void ospf_ext_link_show_info(struct vty *vty, struct json_object *json,
struct lsa_header *lsah = lsa->data;
struct tlv_header *tlvh;
uint16_t length = 0, sum = 0;
+ json_object *jlink = NULL;
- if (json)
- return;
+ if (json) {
+ jlink = json_object_new_object();
+ json_object_object_add(json, "extendedLink", jlink);
+ }
/* Initialize TLV browsing */
length = lsa->size - OSPF_LSA_HEADER_SIZE;
@@ -1860,10 +1930,12 @@ static void ospf_ext_link_show_info(struct vty *vty, struct json_object *json,
tlvh = TLV_HDR_NEXT(tlvh)) {
switch (ntohs(tlvh->type)) {
case EXT_TLV_LINK:
- sum += show_vty_link_info(vty, tlvh, length - sum);
+ sum += show_vty_link_info(vty, tlvh, length - sum,
+ jlink);
break;
default:
- sum += show_vty_unknown_tlv(vty, tlvh, length - sum);
+ sum += show_vty_unknown_tlv(vty, tlvh, length - sum,
+ jlink);
break;
}
}
@@ -1871,7 +1943,8 @@ static void ospf_ext_link_show_info(struct vty *vty, struct json_object *json,
/* Prefix SID SubTLV */
static uint16_t show_vty_ext_pref_pref_sid(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct ext_subtlv_prefix_sid *top =
(struct ext_subtlv_prefix_sid *)tlvh;
@@ -1882,27 +1955,39 @@ static uint16_t show_vty_ext_pref_pref_sid(struct vty *vty,
: SID_INDEX_SIZE(EXT_SUBTLV_PREFIX_SID_SIZE);
check_tlv_size(tlv_size, "Prefix SID");
- vty_out(vty,
- " Prefix SID Sub-TLV: Length %u\n\tAlgorithm: %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\t%s: %u\n",
- ntohs(top->header.length), top->algorithm, top->flags,
- top->mtid,
- CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) ? "Label"
- : "Index",
- CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG)
- ? GET_LABEL(ntohl(top->value))
- : ntohl(top->value));
-
+ if (!json)
+ vty_out(vty,
+ " Prefix SID Sub-TLV: Length %u\n\tAlgorithm: %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\t%s: %u\n",
+ ntohs(top->header.length), top->algorithm, top->flags,
+ top->mtid,
+ CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG)
+ ? "Label"
+ : "Index",
+ CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG)
+ ? GET_LABEL(ntohl(top->value))
+ : ntohl(top->value));
+ else {
+ json_object_int_add(json, "algorithm", top->algorithm);
+ json_object_string_addf(json, "flags", "0x%x", top->flags);
+ json_object_string_addf(json, "mtID", "0x%x", top->mtid);
+ if (CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG))
+ json_object_int_add(json, "label",
+ GET_LABEL(ntohl(top->value)));
+ else
+ json_object_int_add(json, "index", ntohl(top->value));
+ }
return TLV_SIZE(tlvh);
}
/* Extended Prefix SubTLVs */
static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext,
- size_t buf_size)
+ size_t buf_size, json_object *json)
{
struct ext_tlv_prefix *top = (struct ext_tlv_prefix *)ext;
struct tlv_header *tlvh;
uint16_t length = ntohs(top->header.length);
uint16_t sum = 0;
+ json_object *jsid = NULL;
/* Verify that TLV length is valid against remaining buffer size */
if (length > buf_size) {
@@ -1912,11 +1997,21 @@ static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext,
return buf_size;
}
- vty_out(vty,
- " Extended Prefix TLV: Length %u\n\tRoute Type: %u\n"
- "\tAddress Family: 0x%x\n\tFlags: 0x%x\n\tAddress: %pI4/%u\n",
- ntohs(top->header.length), top->route_type, top->af, top->flags,
- &top->address, top->pref_length);
+ if (!json)
+ vty_out(vty,
+ " Extended Prefix TLV: Length %u\n\tRoute Type: %u\n"
+ "\tAddress Family: 0x%x\n\tFlags: 0x%x\n\tAddress: %pI4/%u\n",
+ ntohs(top->header.length), top->route_type, top->af,
+ top->flags, &top->address, top->pref_length);
+ else {
+ json_object_int_add(json, "routeType", top->route_type);
+ json_object_string_addf(json, "addressFamily", "0x%x", top->af);
+ json_object_string_addf(json, "flags", "0x%x", top->flags);
+ json_object_string_addf(json, "address", "%pI4", &top->address);
+ json_object_int_add(json, "prefixLength", top->pref_length);
+ jsid = json_object_new_object();
+ json_object_object_add(json, "prefixSID", jsid);
+ }
/* Skip Extended Prefix TLV and parse sub-TLVs */
length -= EXT_TLV_PREFIX_SIZE;
@@ -1925,10 +2020,11 @@ static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext,
for (; sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) {
switch (ntohs(tlvh->type)) {
case EXT_SUBTLV_PREFIX_SID:
- sum += show_vty_ext_pref_pref_sid(vty, tlvh);
+ sum += show_vty_ext_pref_pref_sid(vty, tlvh, jsid);
break;
default:
- sum += show_vty_unknown_tlv(vty, tlvh, length - sum);
+ sum += show_vty_unknown_tlv(vty, tlvh, length - sum,
+ json);
break;
}
}
@@ -1943,9 +2039,12 @@ static void ospf_ext_pref_show_info(struct vty *vty, struct json_object *json,
struct lsa_header *lsah = lsa->data;
struct tlv_header *tlvh;
uint16_t length = 0, sum = 0;
+ json_object *jpref = NULL;
- if (json)
- return;
+ if (json) {
+ jpref = json_object_new_object();
+ json_object_object_add(json, "extendedPrefix", jpref);
+ }
/* Initialize TLV browsing */
length = lsa->size - OSPF_LSA_HEADER_SIZE;
@@ -1954,10 +2053,12 @@ static void ospf_ext_pref_show_info(struct vty *vty, struct json_object *json,
tlvh = TLV_HDR_NEXT(tlvh)) {
switch (ntohs(tlvh->type)) {
case EXT_TLV_PREFIX:
- sum += show_vty_pref_info(vty, tlvh, length - sum);
+ sum += show_vty_pref_info(vty, tlvh, length - sum,
+ jpref);
break;
default:
- sum += show_vty_unknown_tlv(vty, tlvh, length - sum);
+ sum += show_vty_unknown_tlv(vty, tlvh, length - sum,
+ jpref);
break;
}
}
diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c
index 24a850c73..5d2d65658 100644
--- a/ospfd/ospf_opaque.c
+++ b/ospfd/ospf_opaque.c
@@ -1251,12 +1251,12 @@ void ospf_opaque_config_write_debug(struct vty *vty)
void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa,
json_object *json)
{
- char buf[128], *bp;
struct lsa_header *lsah = lsa->data;
uint32_t lsid = ntohl(lsah->id.s_addr);
uint8_t opaque_type = GET_OPAQUE_TYPE(lsid);
uint32_t opaque_id = GET_OPAQUE_ID(lsid);
struct ospf_opaque_functab *functab;
+ json_object *jopaque = NULL;
int len, lenValid;
/* Switch output functionality by vty address. */
@@ -1277,17 +1277,14 @@ void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa,
ospf_opaque_type_name(opaque_type));
json_object_int_add(json, "opaqueId", opaque_id);
len = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE;
- json_object_int_add(json, "opaqueDataLength", len);
+ json_object_int_add(json, "opaqueLength", len);
lenValid = VALID_OPAQUE_INFO_LEN(lsah);
- json_object_boolean_add(json, "opaqueDataLengthValid",
+ json_object_boolean_add(json, "opaqueLengthValid",
lenValid);
if (lenValid) {
- bp = asnprintfrr(MTYPE_TMP, buf, sizeof(buf),
- "%*pHXn", (int)len,
- (lsah + 1));
- json_object_string_add(json, "opaqueData", buf);
- if (bp != buf)
- XFREE(MTYPE_TMP, bp);
+ jopaque = json_object_new_object();
+ json_object_object_add(json, "opaqueValues",
+ jopaque);
}
}
} else {
@@ -1304,7 +1301,7 @@ void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa,
/* Call individual output functions. */
if ((functab = ospf_opaque_functab_lookup(lsa)) != NULL)
if (functab->show_opaque_info != NULL)
- (*functab->show_opaque_info)(vty, json, lsa);
+ (*functab->show_opaque_info)(vty, jopaque, lsa);
return;
}
diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c
index c6aaf3f5a..99326b41b 100644
--- a/ospfd/ospf_ri.c
+++ b/ospfd/ospf_ri.c
@@ -24,6 +24,7 @@
#include "hash.h"
#include "sockunion.h" /* for inet_aton() */
#include "mpls.h"
+#include <lib/json.h>
#include "ospfd/ospfd.h"
#include "ospfd/ospf_interface.h"
@@ -1216,15 +1217,20 @@ static int ospf_router_info_lsa_update(struct ospf_lsa *lsa)
} \
} while (0)
-static uint16_t show_vty_router_cap(struct vty *vty, struct tlv_header *tlvh)
+static uint16_t show_vty_router_cap(struct vty *vty, struct tlv_header *tlvh,
+ json_object *json)
{
struct ri_tlv_router_cap *top = (struct ri_tlv_router_cap *)tlvh;
check_tlv_size(RI_TLV_CAPABILITIES_SIZE, "Router Capabilities");
if (vty != NULL)
- vty_out(vty, " Router Capabilities: 0x%x\n",
- ntohl(top->value));
+ if (!json)
+ vty_out(vty, " Router Capabilities: 0x%x\n",
+ ntohl(top->value));
+ else
+ json_object_string_addf(json, "routerCapabilities",
+ "0x%x", ntohl(top->value));
else
zlog_debug(" Router Capabilities: 0x%x", ntohl(top->value));
@@ -1232,7 +1238,8 @@ static uint16_t show_vty_router_cap(struct vty *vty, struct tlv_header *tlvh)
}
static uint16_t show_vty_pce_subtlv_address(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct ri_pce_subtlv_address *top =
(struct ri_pce_subtlv_address *)tlvh;
@@ -1240,20 +1247,28 @@ static uint16_t show_vty_pce_subtlv_address(struct vty *vty,
if (ntohs(top->address.type) == PCE_ADDRESS_IPV4) {
check_tlv_size(PCE_ADDRESS_IPV4_SIZE, "PCE Address");
if (vty != NULL)
- vty_out(vty, " PCE Address: %pI4\n",
- &top->address.value);
+ if (!json)
+ vty_out(vty, " PCE Address: %pI4\n",
+ &top->address.value);
+ else
+ json_object_string_addf(json, "pceAddress",
+ "%pI4",
+ &top->address.value);
else
zlog_debug(" PCE Address: %pI4",
&top->address.value);
} else if (ntohs(top->address.type) == PCE_ADDRESS_IPV6) {
- /* TODO: Add support to IPv6 with inet_ntop() */
check_tlv_size(PCE_ADDRESS_IPV6_SIZE, "PCE Address");
if (vty != NULL)
- vty_out(vty, " PCE Address: 0x%x\n",
- ntohl(top->address.value.s_addr));
+ if (!json)
+ vty_out(vty,
+ " PCE Address: unsupported IPv6\n");
+ else
+ json_object_string_add(json, "pceAddress",
+ "unsupported IPv6");
+
else
- zlog_debug(" PCE Address: 0x%x",
- ntohl(top->address.value.s_addr));
+ zlog_debug(" PCE Address: unsupported IPv6");
} else {
if (vty != NULL)
vty_out(vty, " Wrong PCE Address type: 0x%x\n",
@@ -1267,7 +1282,8 @@ static uint16_t show_vty_pce_subtlv_address(struct vty *vty,
}
static uint16_t show_vty_pce_subtlv_path_scope(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct ri_pce_subtlv_path_scope *top =
(struct ri_pce_subtlv_path_scope *)tlvh;
@@ -1275,7 +1291,12 @@ static uint16_t show_vty_pce_subtlv_path_scope(struct vty *vty,
check_tlv_size(RI_PCE_SUBTLV_PATH_SCOPE_SIZE, "PCE Path Scope");
if (vty != NULL)
- vty_out(vty, " PCE Path Scope: 0x%x\n", ntohl(top->value));
+ if (!json)
+ vty_out(vty, " PCE Path Scope: 0x%x\n",
+ ntohl(top->value));
+ else
+ json_object_string_addf(json, "pcePathScope", "0x%x",
+ ntohl(top->value));
else
zlog_debug(" PCE Path Scope: 0x%x", ntohl(top->value));
@@ -1283,7 +1304,8 @@ static uint16_t show_vty_pce_subtlv_path_scope(struct vty *vty,
}
static uint16_t show_vty_pce_subtlv_domain(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct ri_pce_subtlv_domain *top = (struct ri_pce_subtlv_domain *)tlvh;
struct in_addr tmp;
@@ -1293,13 +1315,21 @@ static uint16_t show_vty_pce_subtlv_domain(struct vty *vty,
if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) {
tmp.s_addr = top->value;
if (vty != NULL)
- vty_out(vty, " PCE Domain Area: %pI4\n", &tmp);
+ if (!json)
+ vty_out(vty, " PCE Domain Area: %pI4\n", &tmp);
+ else
+ json_object_string_addf(json, "pceDomainArea",
+ "%pI4", &tmp);
else
zlog_debug(" PCE Domain Area: %pI4", &tmp);
} else if (ntohs(top->type) == PCE_DOMAIN_TYPE_AS) {
if (vty != NULL)
- vty_out(vty, " PCE Domain AS: %d\n",
- ntohl(top->value));
+ if (!json)
+ vty_out(vty, " PCE Domain AS: %d\n",
+ ntohl(top->value));
+ else
+ json_object_int_add(json, "pceDomainAS",
+ ntohl(top->value));
else
zlog_debug(" PCE Domain AS: %d", ntohl(top->value));
} else {
@@ -1315,7 +1345,8 @@ static uint16_t show_vty_pce_subtlv_domain(struct vty *vty,
}
static uint16_t show_vty_pce_subtlv_neighbor(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct ri_pce_subtlv_neighbor *top =
@@ -1327,13 +1358,22 @@ static uint16_t show_vty_pce_subtlv_neighbor(struct vty *vty,
if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) {
tmp.s_addr = top->value;
if (vty != NULL)
- vty_out(vty, " PCE Neighbor Area: %pI4\n", &tmp);
+ if (!json)
+ vty_out(vty, " PCE Neighbor Area: %pI4\n",
+ &tmp);
+ else
+ json_object_string_addf(json, "pceNeighborArea",
+ "%pI4", &tmp);
else
zlog_debug(" PCE Neighbor Area: %pI4", &tmp);
} else if (ntohs(top->type) == PCE_DOMAIN_TYPE_AS) {
if (vty != NULL)
- vty_out(vty, " PCE Neighbor AS: %d\n",
- ntohl(top->value));
+ if (!json)
+ vty_out(vty, " PCE Neighbor AS: %d\n",
+ ntohl(top->value));
+ else
+ json_object_int_add(json, "pceNeighborAS",
+ ntohl(top->value));
else
zlog_debug(" PCE Neighbor AS: %d",
ntohl(top->value));
@@ -1350,7 +1390,8 @@ static uint16_t show_vty_pce_subtlv_neighbor(struct vty *vty,
}
static uint16_t show_vty_pce_subtlv_cap_flag(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct ri_pce_subtlv_cap_flag *top =
(struct ri_pce_subtlv_cap_flag *)tlvh;
@@ -1358,8 +1399,12 @@ static uint16_t show_vty_pce_subtlv_cap_flag(struct vty *vty,
check_tlv_size(RI_PCE_SUBTLV_CAP_FLAG_SIZE, "PCE Capabilities");
if (vty != NULL)
- vty_out(vty, " PCE Capabilities Flag: 0x%x\n",
- ntohl(top->value));
+ if (!json)
+ vty_out(vty, " PCE Capabilities Flag: 0x%x\n",
+ ntohl(top->value));
+ else
+ json_object_string_addf(json, "pceCapabilities",
+ "0x%x", ntohl(top->value));
else
zlog_debug(" PCE Capabilities Flag: 0x%x",
ntohl(top->value));
@@ -1368,8 +1413,10 @@ static uint16_t show_vty_pce_subtlv_cap_flag(struct vty *vty,
}
static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
- size_t buf_size)
+ size_t buf_size, json_object *json)
{
+ json_object *obj;
+
if (TLV_SIZE(tlvh) > buf_size) {
if (vty != NULL)
vty_out(vty,
@@ -1383,8 +1430,18 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
}
if (vty != NULL)
- vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n",
- ntohs(tlvh->type), ntohs(tlvh->length));
+ if (!json)
+ vty_out(vty,
+ " Unknown TLV: [type(0x%x), length(0x%x)]\n",
+ ntohs(tlvh->type), ntohs(tlvh->length));
+ else {
+ obj = json_object_new_object();
+ json_object_string_addf(obj, "type", "0x%x",
+ ntohs(tlvh->type));
+ json_object_string_addf(obj, "length", "0x%x",
+ ntohs(tlvh->length));
+ json_object_object_add(json, "unknownTLV", obj);
+ }
else
zlog_debug(" Unknown TLV: [type(0x%x), length(0x%x)]",
ntohs(tlvh->type), ntohs(tlvh->length));
@@ -1393,7 +1450,7 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
}
static uint16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri,
- size_t buf_size)
+ size_t buf_size, json_object *json)
{
struct tlv_header *tlvh;
uint16_t length = ntohs(ri->length);
@@ -1410,22 +1467,23 @@ static uint16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri,
for (tlvh = ri; sum < length; tlvh = TLV_HDR_NEXT(tlvh)) {
switch (ntohs(tlvh->type)) {
case RI_PCE_SUBTLV_ADDRESS:
- sum += show_vty_pce_subtlv_address(vty, tlvh);
+ sum += show_vty_pce_subtlv_address(vty, tlvh, json);
break;
case RI_PCE_SUBTLV_PATH_SCOPE:
- sum += show_vty_pce_subtlv_path_scope(vty, tlvh);
+ sum += show_vty_pce_subtlv_path_scope(vty, tlvh, json);
break;
case RI_PCE_SUBTLV_DOMAIN:
- sum += show_vty_pce_subtlv_domain(vty, tlvh);
+ sum += show_vty_pce_subtlv_domain(vty, tlvh, json);
break;
case RI_PCE_SUBTLV_NEIGHBOR:
- sum += show_vty_pce_subtlv_neighbor(vty, tlvh);
+ sum += show_vty_pce_subtlv_neighbor(vty, tlvh, json);
break;
case RI_PCE_SUBTLV_CAP_FLAG:
- sum += show_vty_pce_subtlv_cap_flag(vty, tlvh);
+ sum += show_vty_pce_subtlv_cap_flag(vty, tlvh, json);
break;
default:
- sum += show_vty_unknown_tlv(vty, tlvh, length - sum);
+ sum += show_vty_unknown_tlv(vty, tlvh, length - sum,
+ json);
break;
}
}
@@ -1433,33 +1491,62 @@ static uint16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri,
}
/* Display Segment Routing Algorithm TLV information */
-static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh)
+static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh,
+ json_object *json)
{
struct ri_sr_tlv_sr_algorithm *algo =
(struct ri_sr_tlv_sr_algorithm *)tlvh;
int i;
+ json_object *json_algo, *obj;
+ char buf[2];
check_tlv_size(ALGORITHM_COUNT, "Segment Routing Algorithm");
- if (vty != NULL) {
- vty_out(vty, " Segment Routing Algorithm TLV:\n");
- for (i = 0; i < ntohs(algo->header.length); i++) {
- switch (algo->value[i]) {
- case 0:
- vty_out(vty, " Algorithm %d: SPF\n", i);
- break;
- case 1:
- vty_out(vty, " Algorithm %d: Strict SPF\n",
- i);
- break;
- default:
- vty_out(vty,
- " Algorithm %d: Unknown value %d\n", i,
- algo->value[i]);
- break;
+ if (vty != NULL)
+ if (!json) {
+ vty_out(vty, " Segment Routing Algorithm TLV:\n");
+ for (i = 0; i < ntohs(algo->header.length); i++) {
+ switch (algo->value[i]) {
+ case 0:
+ vty_out(vty,
+ " Algorithm %d: SPF\n", i);
+ break;
+ case 1:
+ vty_out(vty,
+ " Algorithm %d: Strict SPF\n",
+ i);
+ break;
+ default:
+ vty_out(vty,
+ " Algorithm %d: Unknown value %d\n", i,
+ algo->value[i]);
+ break;
+ }
+ }
+ } else {
+ json_algo = json_object_new_array();
+ json_object_object_add(json, "algorithms",
+ json_algo);
+ for (i = 0; i < ntohs(algo->header.length); i++) {
+ obj = json_object_new_object();
+ snprintfrr(buf, 2, "%d", i);
+ switch (algo->value[i]) {
+ case 0:
+ json_object_string_add(obj, buf, "SPF");
+ break;
+ case 1:
+ json_object_string_add(obj, buf,
+ "strictSPF");
+ break;
+ default:
+ json_object_string_add(obj, buf,
+ "unknown");
+ break;
+ }
+ json_object_array_add(json_algo, obj);
}
}
- } else {
+ else {
zlog_debug(" Segment Routing Algorithm TLV:");
for (i = 0; i < ntohs(algo->header.length); i++)
switch (algo->value[i]) {
@@ -1480,24 +1567,47 @@ static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh)
}
/* Display Segment Routing SID/Label Range TLV information */
-static uint16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh)
+static uint16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh,
+ json_object *json)
{
struct ri_sr_tlv_sid_label_range *range =
(struct ri_sr_tlv_sid_label_range *)tlvh;
+ json_object *obj;
+ uint32_t upper;
check_tlv_size(RI_SR_TLV_LABEL_RANGE_SIZE, "SR Label Range");
- if (vty != NULL) {
- vty_out(vty,
- " Segment Routing %s Range TLV:\n"
- " Range Size = %d\n"
- " SID Label = %d\n\n",
- ntohs(range->header.type) == RI_SR_TLV_SRGB_LABEL_RANGE
- ? "Global"
- : "Local",
- GET_RANGE_SIZE(ntohl(range->size)),
- GET_LABEL(ntohl(range->lower.value)));
- } else {
+ if (vty != NULL)
+ if (!json) {
+ vty_out(vty,
+ " Segment Routing %s Range TLV:\n"
+ " Range Size = %d\n"
+ " SID Label = %d\n\n",
+ ntohs(range->header.type) ==
+ RI_SR_TLV_SRGB_LABEL_RANGE
+ ? "Global"
+ : "Local",
+ GET_RANGE_SIZE(ntohl(range->size)),
+ GET_LABEL(ntohl(range->lower.value)));
+ } else {
+ /*
+ * According to draft-ietf-teas-yang-sr-te-topo, SRGB
+ * and SRLB are describe with lower and upper bounds
+ */
+ upper = GET_LABEL(ntohl(range->lower.value)) +
+ GET_RANGE_SIZE(ntohl(range->size)) - 1;
+ obj = json_object_new_object();
+ json_object_int_add(obj, "upperBound", upper);
+ json_object_int_add(obj, "lowerBound",
+ GET_LABEL(ntohl(range->lower.value)));
+ json_object_object_add(json,
+ ntohs(range->header.type) ==
+ RI_SR_TLV_SRGB_LABEL_RANGE
+ ? "srgb"
+ : "srlb",
+ obj);
+ }
+ else {
zlog_debug(
" Segment Routing %s Range TLV: Range Size = %d SID Label = %d",
ntohs(range->header.type) == RI_SR_TLV_SRGB_LABEL_RANGE
@@ -1511,22 +1621,25 @@ static uint16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh)
}
/* Display Segment Routing Maximum Stack Depth TLV information */
-static uint16_t show_vty_sr_msd(struct vty *vty, struct tlv_header *tlvh)
+static uint16_t show_vty_sr_msd(struct vty *vty, struct tlv_header *tlvh,
+ json_object *json)
{
struct ri_sr_tlv_node_msd *msd = (struct ri_sr_tlv_node_msd *)tlvh;
check_tlv_size(RI_SR_TLV_NODE_MSD_SIZE, "Node Maximum Stack Depth");
- if (vty != NULL) {
- vty_out(vty,
- " Segment Routing MSD TLV:\n"
- " Node Maximum Stack Depth = %d\n",
- msd->value);
- } else {
+ if (vty != NULL)
+ if (!json)
+ vty_out(vty,
+ " Segment Routing MSD TLV:\n"
+ " Node Maximum Stack Depth = %d\n",
+ msd->value);
+ else
+ json_object_int_add(json, "nodeMsd", msd->value);
+ else
zlog_debug(
" Segment Routing MSD TLV: Node Maximum Stack Depth = %d",
msd->value);
- }
return TLV_SIZE(tlvh);
}
@@ -1538,9 +1651,14 @@ static void ospf_router_info_show_info(struct vty *vty,
struct lsa_header *lsah = lsa->data;
struct tlv_header *tlvh;
uint16_t length = 0, sum = 0;
+ json_object *jri = NULL, *jpce = NULL, *jsr = NULL;
- if (json)
- return;
+ if (json) {
+ jri = json_object_new_object();
+ json_object_object_add(json, "routerInformation", jri);
+ jpce = json_object_new_object();
+ jsr = json_object_new_object();
+ }
/* Initialize TLV browsing */
length = lsa->size - OSPF_LSA_HEADER_SIZE;
@@ -1549,30 +1667,36 @@ static void ospf_router_info_show_info(struct vty *vty,
tlvh = TLV_HDR_NEXT(tlvh)) {
switch (ntohs(tlvh->type)) {
case RI_TLV_CAPABILITIES:
- sum += show_vty_router_cap(vty, tlvh);
+ sum += show_vty_router_cap(vty, tlvh, jri);
break;
case RI_TLV_PCE:
tlvh++;
sum += TLV_HDR_SIZE;
- sum += show_vty_pce_info(vty, tlvh, length - sum);
+ sum += show_vty_pce_info(vty, tlvh, length - sum, jpce);
break;
case RI_SR_TLV_SR_ALGORITHM:
- sum += show_vty_sr_algorithm(vty, tlvh);
+ sum += show_vty_sr_algorithm(vty, tlvh, jsr);
break;
case RI_SR_TLV_SRGB_LABEL_RANGE:
case RI_SR_TLV_SRLB_LABEL_RANGE:
- sum += show_vty_sr_range(vty, tlvh);
+ sum += show_vty_sr_range(vty, tlvh, jsr);
break;
case RI_SR_TLV_NODE_MSD:
- sum += show_vty_sr_msd(vty, tlvh);
+ sum += show_vty_sr_msd(vty, tlvh, jsr);
break;
default:
- sum += show_vty_unknown_tlv(vty, tlvh, length);
+ sum += show_vty_unknown_tlv(vty, tlvh, length, jri);
break;
}
}
+ if (json) {
+ if (json_object_object_length(jpce) > 1)
+ json_object_object_add(jri, "pceInformation", jpce);
+ if (json_object_object_length(jsr) > 1)
+ json_object_object_add(jri, "segmentRouting", jsr);
+ }
return;
}
@@ -1723,9 +1847,11 @@ DEFUN (router_info,
DEFUN (no_router_info,
no_router_info_cmd,
- "no router-info",
+ "no router-info [<area|as>]",
NO_STR
- "Disable the Router Information functionality\n")
+ "Disable the Router Information functionality\n"
+ "Disable the Router Information functionality with AS flooding scope\n"
+ "Disable the Router Information functionality with Area flooding scope\n")
{
if (!OspfRI.enabled)
@@ -2043,7 +2169,7 @@ DEFUN (show_ip_ospf_router_info,
if (OspfRI.enabled) {
vty_out(vty, "--- Router Information parameters ---\n");
- show_vty_router_cap(vty, &OspfRI.router_cap.header);
+ show_vty_router_cap(vty, &OspfRI.router_cap.header, NULL);
} else {
if (vty != NULL)
vty_out(vty,
@@ -2072,27 +2198,32 @@ DEFUN (show_ip_opsf_router_info_pce,
if (pce->pce_address.header.type != 0)
show_vty_pce_subtlv_address(vty,
- &pce->pce_address.header);
+ &pce->pce_address.header,
+ NULL);
if (pce->pce_scope.header.type != 0)
show_vty_pce_subtlv_path_scope(vty,
- &pce->pce_scope.header);
+ &pce->pce_scope.header,
+ NULL);
for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) {
if (domain->header.type != 0)
show_vty_pce_subtlv_domain(vty,
- &domain->header);
+ &domain->header,
+ NULL);
}
for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) {
if (neighbor->header.type != 0)
show_vty_pce_subtlv_neighbor(vty,
- &neighbor->header);
+ &neighbor->header,
+ NULL);
}
if (pce->pce_cap_flag.header.type != 0)
show_vty_pce_subtlv_cap_flag(vty,
- &pce->pce_cap_flag.header);
+ &pce->pce_cap_flag.header,
+ NULL);
} else {
vty_out(vty, " PCE info is disabled on this router\n");
diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c
index 467cb0504..e26fe6f53 100644
--- a/ospfd/ospf_sr.c
+++ b/ospfd/ospf_sr.c
@@ -580,6 +580,7 @@ static void ospf_sr_stop(void)
hash_clean(OspfSR.neighbors, (void *)sr_node_del);
OspfSR.self = NULL;
OspfSR.status = SR_OFF;
+ OspfSR.msd = 0;
}
/*
diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c
index d203b5ef4..9ba9a7659 100644
--- a/ospfd/ospf_te.c
+++ b/ospfd/ospf_te.c
@@ -31,6 +31,7 @@
#include "link_state.h"
#include "zclient.h"
#include "printfrr.h"
+#include <lib/json.h>
#include "ospfd/ospfd.h"
#include "ospfd/ospf_interface.h"
@@ -3141,14 +3142,19 @@ static void ospf_te_init_ted(struct ls_ted *ted, struct ospf *ospf)
} \
} while (0)
-static uint16_t show_vty_router_addr(struct vty *vty, struct tlv_header *tlvh)
+static uint16_t show_vty_router_addr(struct vty *vty, struct tlv_header *tlvh,
+ json_object *json)
{
struct te_tlv_router_addr *top = (struct te_tlv_router_addr *)tlvh;
check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Router Address");
if (vty != NULL)
- vty_out(vty, " Router-Address: %pI4\n", &top->value);
+ if (!json)
+ vty_out(vty, " Router-Address: %pI4\n", &top->value);
+ else
+ json_object_string_addf(json, "routerAddress", "%pI4",
+ &top->value);
else
zlog_debug(" Router-Address: %pI4", &top->value);
@@ -3156,7 +3162,7 @@ static uint16_t show_vty_router_addr(struct vty *vty, struct tlv_header *tlvh)
}
static uint16_t show_vty_link_header(struct vty *vty, struct tlv_header *tlvh,
- size_t buf_size)
+ size_t buf_size, json_object *json)
{
struct te_tlv_link *top = (struct te_tlv_link *)tlvh;
@@ -3173,8 +3179,12 @@ static uint16_t show_vty_link_header(struct vty *vty, struct tlv_header *tlvh,
}
if (vty != NULL)
- vty_out(vty, " Link: %u octets of data\n",
- ntohs(top->header.length));
+ if (!json)
+ vty_out(vty, " Link: %u octets of data\n",
+ ntohs(top->header.length));
+ else
+ json_object_int_add(json, "teLinkDataLength",
+ ntohs(top->header.length));
else
zlog_debug(" Link: %u octets of data",
ntohs(top->header.length));
@@ -3183,7 +3193,8 @@ static uint16_t show_vty_link_header(struct vty *vty, struct tlv_header *tlvh,
}
static uint16_t show_vty_link_subtlv_link_type(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_link_type *top;
const char *cp = "Unknown";
@@ -3203,8 +3214,11 @@ static uint16_t show_vty_link_subtlv_link_type(struct vty *vty,
}
if (vty != NULL)
- vty_out(vty, " Link-Type: %s (%u)\n", cp,
- top->link_type.value);
+ if (!json)
+ vty_out(vty, " Link-Type: %s (%u)\n", cp,
+ top->link_type.value);
+ else
+ json_object_string_add(json, "accessType", cp);
else
zlog_debug(" Link-Type: %s (%u)", cp, top->link_type.value);
@@ -3212,7 +3226,8 @@ static uint16_t show_vty_link_subtlv_link_type(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_link_id(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_link_id *top;
@@ -3220,7 +3235,11 @@ static uint16_t show_vty_link_subtlv_link_id(struct vty *vty,
top = (struct te_link_subtlv_link_id *)tlvh;
if (vty != NULL)
- vty_out(vty, " Link-ID: %pI4\n", &top->value);
+ if (!json)
+ vty_out(vty, " Link-ID: %pI4\n", &top->value);
+ else
+ json_object_string_addf(json, "linkID", "%pI4",
+ &top->value);
else
zlog_debug(" Link-ID: %pI4", &top->value);
@@ -3229,9 +3248,12 @@ static uint16_t show_vty_link_subtlv_link_id(struct vty *vty,
static uint16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty,
struct tlv_header *tlvh,
- size_t buf_size)
+ size_t buf_size,
+ json_object *json)
{
struct te_link_subtlv_lclif_ipaddr *top;
+ json_object *json_addr, *json_obj;
+ char buf[4];
int i, n;
if (TLV_SIZE(tlvh) > buf_size) {
@@ -3250,13 +3272,29 @@ static uint16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty,
n = ntohs(tlvh->length) / sizeof(top->value[0]);
if (vty != NULL)
- vty_out(vty, " Local Interface IP Address(es): %d\n", n);
+ if (!json)
+ vty_out(vty, " Local Interface IP Address(es): %d\n",
+ n);
+ else {
+ json_addr = json_object_new_array();
+ json_object_object_add(json, "localIPAddresses",
+ json_addr);
+ }
else
zlog_debug(" Local Interface IP Address(es): %d", n);
for (i = 0; i < n; i++) {
if (vty != NULL)
- vty_out(vty, " #%d: %pI4\n", i, &top->value[i]);
+ if (!json)
+ vty_out(vty, " #%d: %pI4\n", i,
+ &top->value[i]);
+ else {
+ json_obj = json_object_new_object();
+ snprintfrr(buf, 2, "%d", i);
+ json_object_string_addf(json_obj, buf, "%pI4",
+ &top->value[i]);
+ json_object_array_add(json_addr, json_obj);
+ }
else
zlog_debug(" #%d: %pI4", i, &top->value[i]);
}
@@ -3265,9 +3303,12 @@ static uint16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty,
static uint16_t show_vty_link_subtlv_rmtif_ipaddr(struct vty *vty,
struct tlv_header *tlvh,
- size_t buf_size)
+ size_t buf_size,
+ json_object *json)
{
struct te_link_subtlv_rmtif_ipaddr *top;
+ json_object *json_addr, *json_obj;
+ char buf[4];
int i, n;
if (TLV_SIZE(tlvh) > buf_size) {
@@ -3285,13 +3326,29 @@ static uint16_t show_vty_link_subtlv_rmtif_ipaddr(struct vty *vty,
top = (struct te_link_subtlv_rmtif_ipaddr *)tlvh;
n = ntohs(tlvh->length) / sizeof(top->value[0]);
if (vty != NULL)
- vty_out(vty, " Remote Interface IP Address(es): %d\n", n);
+ if (!json)
+ vty_out(vty, " Remote Interface IP Address(es): %d\n",
+ n);
+ else {
+ json_addr = json_object_new_array();
+ json_object_object_add(json, "remoteIPAddresses",
+ json_addr);
+ }
else
zlog_debug(" Remote Interface IP Address(es): %d", n);
for (i = 0; i < n; i++) {
if (vty != NULL)
- vty_out(vty, " #%d: %pI4\n", i, &top->value[i]);
+ if (!json)
+ vty_out(vty, " #%d: %pI4\n", i,
+ &top->value[i]);
+ else {
+ json_obj = json_object_new_object();
+ snprintfrr(buf, 2, "%d", i);
+ json_object_string_addf(json_obj, buf, "%pI4",
+ &top->value[i]);
+ json_object_array_add(json_addr, json_obj);
+ }
else
zlog_debug(" #%d: %pI4", i, &top->value[i]);
}
@@ -3299,7 +3356,8 @@ static uint16_t show_vty_link_subtlv_rmtif_ipaddr(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_te_metric(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_te_metric *top;
@@ -3307,8 +3365,12 @@ static uint16_t show_vty_link_subtlv_te_metric(struct vty *vty,
top = (struct te_link_subtlv_te_metric *)tlvh;
if (vty != NULL)
- vty_out(vty, " Traffic Engineering Metric: %u\n",
- (uint32_t)ntohl(top->value));
+ if (!json)
+ vty_out(vty, " Traffic Engineering Metric: %u\n",
+ (uint32_t)ntohl(top->value));
+ else
+ json_object_int_add(json, "teDefaultMetric",
+ (uint32_t)ntohl(top->value));
else
zlog_debug(" Traffic Engineering Metric: %u",
(uint32_t)ntohl(top->value));
@@ -3317,7 +3379,8 @@ static uint16_t show_vty_link_subtlv_te_metric(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_max_bw(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_max_bw *top;
float fval;
@@ -3328,7 +3391,11 @@ static uint16_t show_vty_link_subtlv_max_bw(struct vty *vty,
fval = ntohf(top->value);
if (vty != NULL)
- vty_out(vty, " Maximum Bandwidth: %g (Bytes/sec)\n", fval);
+ if (!json)
+ vty_out(vty, " Maximum Bandwidth: %g (Bytes/sec)\n",
+ fval);
+ else
+ json_object_double_add(json, "maxLinkBandwidth", fval);
else
zlog_debug(" Maximum Bandwidth: %g (Bytes/sec)", fval);
@@ -3336,7 +3403,8 @@ static uint16_t show_vty_link_subtlv_max_bw(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_max_rsv_bw(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_max_rsv_bw *top;
float fval;
@@ -3347,8 +3415,12 @@ static uint16_t show_vty_link_subtlv_max_rsv_bw(struct vty *vty,
fval = ntohf(top->value);
if (vty != NULL)
- vty_out(vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
- fval);
+ if (!json)
+ vty_out(vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
+ fval);
+ else
+ json_object_double_add(json, "maxResvLinkBandwidth",
+ fval);
else
zlog_debug(" Maximum Reservable Bandwidth: %g (Bytes/sec)",
fval);
@@ -3357,18 +3429,27 @@ static uint16_t show_vty_link_subtlv_max_rsv_bw(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_unrsv_bw *top;
+ json_object *json_bw, *json_obj;
float fval1, fval2;
+ char buf[16];
int i;
check_tlv_size(TE_LINK_SUBTLV_UNRSV_SIZE, "Unreserved Bandwidth");
top = (struct te_link_subtlv_unrsv_bw *)tlvh;
if (vty != NULL)
- vty_out(vty,
- " Unreserved Bandwidth per Class Type in Byte/s:\n");
+ if (!json)
+ vty_out(vty,
+ " Unreserved Bandwidth per Class Type in Byte/s:\n");
+ else {
+ json_bw = json_object_new_array();
+ json_object_object_add(json, "unreservedBandwidth",
+ json_bw);
+ }
else
zlog_debug(
" Unreserved Bandwidth per Class Type in Byte/s:");
@@ -3377,9 +3458,20 @@ static uint16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty,
fval2 = ntohf(top->value[i + 1]);
if (vty != NULL)
- vty_out(vty,
- " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
- i, fval1, i + 1, fval2);
+ if (!json)
+ vty_out(vty,
+ " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
+ i, fval1, i + 1, fval2);
+ else {
+ json_obj = json_object_new_object();
+ snprintfrr(buf, 12, "classType-%u", i);
+ json_object_double_add(json_obj, buf, fval1);
+ json_object_array_add(json_bw, json_obj);
+ json_obj = json_object_new_object();
+ snprintfrr(buf, 12, "classType-%u", i + 1);
+ json_object_double_add(json_obj, buf, fval2);
+ json_object_array_add(json_bw, json_obj);
+ }
else
zlog_debug(
" [%d]: %g (Bytes/sec), [%d]: %g (Bytes/sec)",
@@ -3390,7 +3482,8 @@ static uint16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_rsc_clsclr(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_rsc_clsclr *top;
@@ -3398,8 +3491,13 @@ static uint16_t show_vty_link_subtlv_rsc_clsclr(struct vty *vty,
top = (struct te_link_subtlv_rsc_clsclr *)tlvh;
if (vty != NULL)
- vty_out(vty, " Resource class/color: 0x%x\n",
- (uint32_t)ntohl(top->value));
+ if (!json)
+ vty_out(vty, " Resource class/color: 0x%x\n",
+ (uint32_t)ntohl(top->value));
+ else
+ json_object_string_addf(json, "administrativeGroup",
+ "0x%x",
+ (uint32_t)ntohl(top->value));
else
zlog_debug(" Resource Class/Color: 0x%x",
(uint32_t)ntohl(top->value));
@@ -3408,7 +3506,8 @@ static uint16_t show_vty_link_subtlv_rsc_clsclr(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_lrrid(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_lrrid *top;
@@ -3417,10 +3516,17 @@ static uint16_t show_vty_link_subtlv_lrrid(struct vty *vty,
top = (struct te_link_subtlv_lrrid *)tlvh;
if (vty != NULL) {
- vty_out(vty, " Local TE Router ID: %pI4\n",
- &top->local);
- vty_out(vty, " Remote TE Router ID: %pI4\n",
- &top->remote);
+ if (!json) {
+ vty_out(vty, " Local TE Router ID: %pI4\n",
+ &top->local);
+ vty_out(vty, " Remote TE Router ID: %pI4\n",
+ &top->remote);
+ } else {
+ json_object_string_addf(json, "localTeRouterID", "%pI4",
+ &top->local);
+ json_object_string_addf(json, "remoteTeRouterID",
+ "%pI4", &top->remote);
+ }
} else {
zlog_debug(" Local TE Router ID: %pI4",
&top->local);
@@ -3432,7 +3538,8 @@ static uint16_t show_vty_link_subtlv_lrrid(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_llri(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_llri *top;
@@ -3441,10 +3548,17 @@ static uint16_t show_vty_link_subtlv_llri(struct vty *vty,
top = (struct te_link_subtlv_llri *)tlvh;
if (vty != NULL) {
- vty_out(vty, " Link Local ID: %d\n",
- (uint32_t)ntohl(top->local));
- vty_out(vty, " Link Remote ID: %d\n",
- (uint32_t)ntohl(top->remote));
+ if (!json) {
+ vty_out(vty, " Link Local ID: %d\n",
+ (uint32_t)ntohl(top->local));
+ vty_out(vty, " Link Remote ID: %d\n",
+ (uint32_t)ntohl(top->remote));
+ } else {
+ json_object_int_add(json, "localLinkID",
+ (uint32_t)ntohl(top->local));
+ json_object_int_add(json, "remoteLinkID",
+ (uint32_t)ntohl(top->remote));
+ }
} else {
zlog_debug(" Link Local ID: %d",
(uint32_t)ntohl(top->local));
@@ -3456,7 +3570,8 @@ static uint16_t show_vty_link_subtlv_llri(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_rip(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_rip *top;
@@ -3465,8 +3580,12 @@ static uint16_t show_vty_link_subtlv_rip(struct vty *vty,
top = (struct te_link_subtlv_rip *)tlvh;
if (vty != NULL)
- vty_out(vty, " Inter-AS TE Remote ASBR IP address: %pI4\n",
- &top->value);
+ if (!json)
+ vty_out(vty, " Inter-AS TE Remote ASBR IP address: %pI4\n",
+ &top->value);
+ else
+ json_object_string_addf(json, "remoteAsbrAddress",
+ "%pI4", &top->value);
else
zlog_debug(" Inter-AS TE Remote ASBR IP address: %pI4",
&top->value);
@@ -3475,7 +3594,8 @@ static uint16_t show_vty_link_subtlv_rip(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_ras(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_ras *top;
@@ -3484,8 +3604,12 @@ static uint16_t show_vty_link_subtlv_ras(struct vty *vty,
top = (struct te_link_subtlv_ras *)tlvh;
if (vty != NULL)
- vty_out(vty, " Inter-AS TE Remote AS number: %u\n",
- ntohl(top->value));
+ if (!json)
+ vty_out(vty, " Inter-AS TE Remote AS number: %u\n",
+ ntohl(top->value));
+ else
+ json_object_int_add(json, "remoteAsbrNumber",
+ ntohl(top->value));
else
zlog_debug(" Inter-AS TE Remote AS number: %u",
ntohl(top->value));
@@ -3494,7 +3618,8 @@ static uint16_t show_vty_link_subtlv_ras(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_av_delay(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_av_delay *top;
uint32_t delay;
@@ -3507,8 +3632,15 @@ static uint16_t show_vty_link_subtlv_av_delay(struct vty *vty,
anomalous = (uint32_t)ntohl(top->value) & TE_EXT_ANORMAL;
if (vty != NULL)
- vty_out(vty, " %s Average Link Delay: %d (micro-sec)\n",
- anomalous ? "Anomalous" : "Normal", delay);
+ if (!json)
+ vty_out(vty, " %s Average Link Delay: %d (micro-sec)\n",
+ anomalous ? "Anomalous" : "Normal", delay);
+ else {
+ json_object_int_add(json, "oneWayDelay", delay);
+ json_object_string_add(json, "oneWayDelayNormality",
+ anomalous ? "abnormal"
+ : "normal");
+ }
else
zlog_debug(" %s Average Link Delay: %d (micro-sec)",
anomalous ? "Anomalous" : "Normal", delay);
@@ -3517,7 +3649,8 @@ static uint16_t show_vty_link_subtlv_av_delay(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_mm_delay(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_mm_delay *top;
uint32_t low, high;
@@ -3531,8 +3664,20 @@ static uint16_t show_vty_link_subtlv_mm_delay(struct vty *vty,
high = (uint32_t)ntohl(top->high);
if (vty != NULL)
- vty_out(vty, " %s Min/Max Link Delay: %d/%d (micro-sec)\n",
- anomalous ? "Anomalous" : "Normal", low, high);
+ if (!json)
+ vty_out(vty,
+ " %s Min/Max Link Delay: %d/%d (micro-sec)\n",
+ anomalous ? "Anomalous" : "Normal", low, high);
+ else {
+ json_object_int_add(json, "oneWayMinDelay", low);
+ json_object_string_add(json, "oneWayMinDelayNormality",
+ anomalous ? "abnormal"
+ : "normal");
+ json_object_int_add(json, "oneWayMaxDelay", high);
+ json_object_string_add(json, "oneWayMaxDelayNormality",
+ anomalous ? "abnormal"
+ : "normal");
+ }
else
zlog_debug(" %s Min/Max Link Delay: %d/%d (micro-sec)",
anomalous ? "Anomalous" : "Normal", low, high);
@@ -3541,7 +3686,8 @@ static uint16_t show_vty_link_subtlv_mm_delay(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_delay_var(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_delay_var *top;
uint32_t jitter;
@@ -3552,7 +3698,12 @@ static uint16_t show_vty_link_subtlv_delay_var(struct vty *vty,
jitter = (uint32_t)ntohl(top->value) & TE_EXT_MASK;
if (vty != NULL)
- vty_out(vty, " Delay Variation: %d (micro-sec)\n", jitter);
+ if (!json)
+ vty_out(vty, " Delay Variation: %d (micro-sec)\n",
+ jitter);
+ else
+ json_object_int_add(json, "oneWayDelayVariation",
+ jitter);
else
zlog_debug(" Delay Variation: %d (micro-sec)", jitter);
@@ -3560,7 +3711,8 @@ static uint16_t show_vty_link_subtlv_delay_var(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_pkt_loss(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_pkt_loss *top;
uint32_t loss;
@@ -3575,8 +3727,16 @@ static uint16_t show_vty_link_subtlv_pkt_loss(struct vty *vty,
anomalous = (uint32_t)ntohl(top->value) & TE_EXT_ANORMAL;
if (vty != NULL)
- vty_out(vty, " %s Link Loss: %g (%%)\n",
- anomalous ? "Anomalous" : "Normal", fval);
+ if (!json)
+ vty_out(vty, " %s Link Loss: %g (%%)\n",
+ anomalous ? "Anomalous" : "Normal", fval);
+ else {
+ json_object_double_add(json, "oneWayPacketLoss", fval);
+ json_object_string_add(json,
+ "oneWayPacketLossNormality",
+ anomalous ? "abnormal"
+ : "normal");
+ }
else
zlog_debug(" %s Link Loss: %g (%%)",
anomalous ? "Anomalous" : "Normal", fval);
@@ -3585,7 +3745,8 @@ static uint16_t show_vty_link_subtlv_pkt_loss(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_res_bw(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_res_bw *top;
float fval;
@@ -3596,9 +3757,13 @@ static uint16_t show_vty_link_subtlv_res_bw(struct vty *vty,
fval = ntohf(top->value);
if (vty != NULL)
- vty_out(vty,
- " Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
- fval);
+ if (!json)
+ vty_out(vty,
+ " Unidirectional Residual Bandwidth: %g (Bytes/sec)\n",
+ fval);
+ else
+ json_object_double_add(json, "oneWayResidualBandwidth",
+ fval);
else
zlog_debug(
" Unidirectional Residual Bandwidth: %g (Bytes/sec)",
@@ -3608,7 +3773,8 @@ static uint16_t show_vty_link_subtlv_res_bw(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_ava_bw(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_ava_bw *top;
float fval;
@@ -3619,9 +3785,13 @@ static uint16_t show_vty_link_subtlv_ava_bw(struct vty *vty,
fval = ntohf(top->value);
if (vty != NULL)
- vty_out(vty,
- " Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
- fval);
+ if (!json)
+ vty_out(vty,
+ " Unidirectional Available Bandwidth: %g (Bytes/sec)\n",
+ fval);
+ else
+ json_object_double_add(json, "oneWayAvailableBandwidth",
+ fval);
else
zlog_debug(
" Unidirectional Available Bandwidth: %g (Bytes/sec)",
@@ -3631,7 +3801,8 @@ static uint16_t show_vty_link_subtlv_ava_bw(struct vty *vty,
}
static uint16_t show_vty_link_subtlv_use_bw(struct vty *vty,
- struct tlv_header *tlvh)
+ struct tlv_header *tlvh,
+ json_object *json)
{
struct te_link_subtlv_use_bw *top;
float fval;
@@ -3642,9 +3813,13 @@ static uint16_t show_vty_link_subtlv_use_bw(struct vty *vty,
fval = ntohf(top->value);
if (vty != NULL)
- vty_out(vty,
- " Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
- fval);
+ if (!json)
+ vty_out(vty,
+ " Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n",
+ fval);
+ else
+ json_object_double_add(json, "oneWayUtilizedBandwidth",
+ fval);
else
zlog_debug(
" Unidirectional Utilized Bandwidth: %g (Bytes/sec)",
@@ -3654,8 +3829,10 @@ static uint16_t show_vty_link_subtlv_use_bw(struct vty *vty,
}
static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
- size_t buf_size)
+ size_t buf_size, json_object *json)
{
+ json_object *obj;
+
if (TLV_SIZE(tlvh) > buf_size) {
if (vty != NULL)
vty_out(vty,
@@ -3669,8 +3846,17 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
}
if (vty != NULL)
- vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n",
- ntohs(tlvh->type), ntohs(tlvh->length));
+ if (!json)
+ vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n",
+ ntohs(tlvh->type), ntohs(tlvh->length));
+ else {
+ obj = json_object_new_object();
+ json_object_string_addf(obj, "type", "0x%x",
+ ntohs(tlvh->type));
+ json_object_string_addf(obj, "length", "0x%x",
+ ntohs(tlvh->length));
+ json_object_object_add(json, "unknownTLV", obj);
+ }
else
zlog_debug(" Unknown TLV: [type(0x%x), length(0x%x)]",
ntohs(tlvh->type), ntohs(tlvh->length));
@@ -3680,7 +3866,8 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty,
struct tlv_header *tlvh0,
- uint16_t subtotal, uint16_t total)
+ uint16_t subtotal, uint16_t total,
+ json_object *json)
{
struct tlv_header *tlvh;
uint16_t sum = subtotal;
@@ -3688,69 +3875,72 @@ static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty,
for (tlvh = tlvh0; sum < total; tlvh = TLV_HDR_NEXT(tlvh)) {
switch (ntohs(tlvh->type)) {
case TE_LINK_SUBTLV_LINK_TYPE:
- sum += show_vty_link_subtlv_link_type(vty, tlvh);
+ sum += show_vty_link_subtlv_link_type(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_LINK_ID:
- sum += show_vty_link_subtlv_link_id(vty, tlvh);
+ sum += show_vty_link_subtlv_link_id(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_LCLIF_IPADDR:
sum += show_vty_link_subtlv_lclif_ipaddr(vty, tlvh,
- total - sum);
+ total - sum,
+ json);
break;
case TE_LINK_SUBTLV_RMTIF_IPADDR:
sum += show_vty_link_subtlv_rmtif_ipaddr(vty, tlvh,
- total - sum);
+ total - sum,
+ json);
break;
case TE_LINK_SUBTLV_TE_METRIC:
- sum += show_vty_link_subtlv_te_metric(vty, tlvh);
+ sum += show_vty_link_subtlv_te_metric(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_MAX_BW:
- sum += show_vty_link_subtlv_max_bw(vty, tlvh);
+ sum += show_vty_link_subtlv_max_bw(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_MAX_RSV_BW:
- sum += show_vty_link_subtlv_max_rsv_bw(vty, tlvh);
+ sum += show_vty_link_subtlv_max_rsv_bw(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_UNRSV_BW:
- sum += show_vty_link_subtlv_unrsv_bw(vty, tlvh);
+ sum += show_vty_link_subtlv_unrsv_bw(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_RSC_CLSCLR:
- sum += show_vty_link_subtlv_rsc_clsclr(vty, tlvh);
+ sum += show_vty_link_subtlv_rsc_clsclr(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_LRRID:
- sum += show_vty_link_subtlv_lrrid(vty, tlvh);
+ sum += show_vty_link_subtlv_lrrid(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_LLRI:
- sum += show_vty_link_subtlv_llri(vty, tlvh);
+ sum += show_vty_link_subtlv_llri(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_RIP:
- sum += show_vty_link_subtlv_rip(vty, tlvh);
+ sum += show_vty_link_subtlv_rip(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_RAS:
- sum += show_vty_link_subtlv_ras(vty, tlvh);
+ sum += show_vty_link_subtlv_ras(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_AV_DELAY:
- sum += show_vty_link_subtlv_av_delay(vty, tlvh);
+ sum += show_vty_link_subtlv_av_delay(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_MM_DELAY:
- sum += show_vty_link_subtlv_mm_delay(vty, tlvh);
+ sum += show_vty_link_subtlv_mm_delay(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_DELAY_VAR:
- sum += show_vty_link_subtlv_delay_var(vty, tlvh);
+ sum += show_vty_link_subtlv_delay_var(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_PKT_LOSS:
- sum += show_vty_link_subtlv_pkt_loss(vty, tlvh);
+ sum += show_vty_link_subtlv_pkt_loss(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_RES_BW:
- sum += show_vty_link_subtlv_res_bw(vty, tlvh);
+ sum += show_vty_link_subtlv_res_bw(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_AVA_BW:
- sum += show_vty_link_subtlv_ava_bw(vty, tlvh);
+ sum += show_vty_link_subtlv_ava_bw(vty, tlvh, json);
break;
case TE_LINK_SUBTLV_USE_BW:
- sum += show_vty_link_subtlv_use_bw(vty, tlvh);
+ sum += show_vty_link_subtlv_use_bw(vty, tlvh, json);
break;
default:
- sum += show_vty_unknown_tlv(vty, tlvh, total - sum);
+ sum += show_vty_unknown_tlv(vty, tlvh, total - sum,
+ json);
break;
}
}
@@ -3762,37 +3952,47 @@ static void ospf_mpls_te_show_info(struct vty *vty, struct json_object *json,
{
struct lsa_header *lsah = lsa->data;
struct tlv_header *tlvh, *next;
- uint16_t sum, total;
+ uint16_t sum, sub, total;
uint16_t (*subfunc)(struct vty * vty, struct tlv_header * tlvh,
- uint16_t subtotal, uint16_t total) = NULL;
-
- if (json)
- return;
+ uint16_t subtotal, uint16_t total,
+ struct json_object *json) = NULL;
+ json_object *jobj = NULL;
sum = 0;
+ sub = 0;
total = lsa->size - OSPF_LSA_HEADER_SIZE;
for (tlvh = TLV_HDR_TOP(lsah); sum < total && tlvh;
tlvh = (next ? next : TLV_HDR_NEXT(tlvh))) {
if (subfunc != NULL) {
- sum = (*subfunc)(vty, tlvh, sum, total);
+ sum = (*subfunc)(vty, tlvh, sum, total, jobj);
next = (struct tlv_header *)((char *)tlvh + sum);
subfunc = NULL;
continue;
}
next = NULL;
+ sub = total - sum;
switch (ntohs(tlvh->type)) {
case TE_TLV_ROUTER_ADDR:
- sum += show_vty_router_addr(vty, tlvh);
+ if (json) {
+ jobj = json_object_new_object();
+ json_object_object_add(json, "teRouterAddress",
+ jobj);
+ }
+ sum += show_vty_router_addr(vty, tlvh, jobj);
break;
case TE_TLV_LINK:
- sum += show_vty_link_header(vty, tlvh, total - sum);
+ if (json) {
+ jobj = json_object_new_object();
+ json_object_object_add(json, "teLink", jobj);
+ }
+ sum += show_vty_link_header(vty, tlvh, sub, jobj);
subfunc = ospf_mpls_te_show_link_subtlv;
next = TLV_DATA(tlvh);
break;
default:
- sum += show_vty_unknown_tlv(vty, tlvh, total - sum);
+ sum += show_vty_unknown_tlv(vty, tlvh, sub, json);
break;
}
}
@@ -4126,7 +4326,8 @@ DEFUN (show_ip_ospf_mpls_te_router,
if (ntohs(OspfMplsTE.router_addr.header.type) != 0)
show_vty_router_addr(vty,
- &OspfMplsTE.router_addr.header);
+ &OspfMplsTE.router_addr.header,
+ NULL);
else
vty_out(vty, " Router address is not set\n");
vty_out(vty, " Link State distribution is %s\n",
@@ -4135,7 +4336,8 @@ DEFUN (show_ip_ospf_mpls_te_router,
return CMD_SUCCESS;
}
-static void show_mpls_te_link_sub(struct vty *vty, struct interface *ifp)
+static void show_mpls_te_link_sub(struct vty *vty, struct interface *ifp,
+ json_object *json)
{
struct mpls_te_link *lp;
@@ -4165,53 +4367,69 @@ static void show_mpls_te_link_sub(struct vty *vty, struct interface *ifp)
if (TLV_TYPE(lp->link_type) != 0)
show_vty_link_subtlv_link_type(vty,
- &lp->link_type.header);
+ &lp->link_type.header,
+ json);
if (TLV_TYPE(lp->link_id) != 0)
- show_vty_link_subtlv_link_id(vty, &lp->link_id.header);
+ show_vty_link_subtlv_link_id(vty, &lp->link_id.header,
+ json);
if (TLV_TYPE(lp->lclif_ipaddr) != 0)
show_vty_link_subtlv_lclif_ipaddr(
vty, &lp->lclif_ipaddr.header,
- lp->lclif_ipaddr.header.length);
+ lp->lclif_ipaddr.header.length,
+ json);
if (TLV_TYPE(lp->rmtif_ipaddr) != 0)
show_vty_link_subtlv_rmtif_ipaddr(
vty, &lp->rmtif_ipaddr.header,
- lp->rmtif_ipaddr.header.length);
+ lp->rmtif_ipaddr.header.length,
+ json);
if (TLV_TYPE(lp->rip) != 0)
- show_vty_link_subtlv_rip(vty, &lp->rip.header);
+ show_vty_link_subtlv_rip(vty, &lp->rip.header, json);
if (TLV_TYPE(lp->ras) != 0)
- show_vty_link_subtlv_ras(vty, &lp->ras.header);
+ show_vty_link_subtlv_ras(vty, &lp->ras.header, json);
if (TLV_TYPE(lp->te_metric) != 0)
show_vty_link_subtlv_te_metric(vty,
- &lp->te_metric.header);
+ &lp->te_metric.header,
+ json);
if (TLV_TYPE(lp->max_bw) != 0)
- show_vty_link_subtlv_max_bw(vty, &lp->max_bw.header);
+ show_vty_link_subtlv_max_bw(vty, &lp->max_bw.header,
+ json);
if (TLV_TYPE(lp->max_rsv_bw) != 0)
show_vty_link_subtlv_max_rsv_bw(vty,
- &lp->max_rsv_bw.header);
+ &lp->max_rsv_bw.header,
+ json);
if (TLV_TYPE(lp->unrsv_bw) != 0)
show_vty_link_subtlv_unrsv_bw(vty,
- &lp->unrsv_bw.header);
+ &lp->unrsv_bw.header,
+ json);
if (TLV_TYPE(lp->rsc_clsclr) != 0)
show_vty_link_subtlv_rsc_clsclr(vty,
- &lp->rsc_clsclr.header);
+ &lp->rsc_clsclr.header,
+ json);
if (TLV_TYPE(lp->av_delay) != 0)
show_vty_link_subtlv_av_delay(vty,
- &lp->av_delay.header);
+ &lp->av_delay.header,
+ json);
if (TLV_TYPE(lp->mm_delay) != 0)
show_vty_link_subtlv_mm_delay(vty,
- &lp->mm_delay.header);
+ &lp->mm_delay.header,
+ json);
if (TLV_TYPE(lp->delay_var) != 0)
show_vty_link_subtlv_delay_var(vty,
- &lp->delay_var.header);
+ &lp->delay_var.header,
+ json);
if (TLV_TYPE(lp->pkt_loss) != 0)
show_vty_link_subtlv_pkt_loss(vty,
- &lp->pkt_loss.header);
+ &lp->pkt_loss.header,
+ json);
if (TLV_TYPE(lp->res_bw) != 0)
- show_vty_link_subtlv_res_bw(vty, &lp->res_bw.header);
+ show_vty_link_subtlv_res_bw(vty, &lp->res_bw.header,
+ json);
if (TLV_TYPE(lp->ava_bw) != 0)
- show_vty_link_subtlv_ava_bw(vty, &lp->ava_bw.header);
+ show_vty_link_subtlv_ava_bw(vty, &lp->ava_bw.header,
+ json);
if (TLV_TYPE(lp->use_bw) != 0)
- show_vty_link_subtlv_use_bw(vty, &lp->use_bw.header);
+ show_vty_link_subtlv_use_bw(vty, &lp->use_bw.header,
+ json);
vty_out(vty, "---------------\n\n");
} else {
vty_out(vty, " %s: MPLS-TE is disabled on this interface\n",
@@ -4240,7 +4458,6 @@ DEFUN (show_ip_ospf_mpls_te_link,
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
if (ospf == NULL || !ospf->oi_running)
return CMD_SUCCESS;
-
vrf = vrf_lookup_by_id(VRF_DEFAULT);
if (!vrf)
return CMD_SUCCESS;
@@ -4254,11 +4471,11 @@ DEFUN (show_ip_ospf_mpls_te_link,
}
if (!ifp) {
FOR_ALL_INTERFACES (vrf, ifp)
- show_mpls_te_link_sub(vty, ifp);
+ show_mpls_te_link_sub(vty, ifp, NULL);
return CMD_SUCCESS;
}
- show_mpls_te_link_sub(vty, ifp);
+ show_mpls_te_link_sub(vty, ifp, NULL);
return CMD_SUCCESS;
}
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index e00888acf..c63e0f35d 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -1219,7 +1219,7 @@ int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name)
return pim_upstream_mroute_update(c_oil, name);
}
-/* Look for IIF changes and update the dateplane entry only if the IIF
+/* Look for IIF changes and update the dataplane entry only if the IIF
* has changed.
*/
int pim_upstream_mroute_iif_update(struct channel_oil *c_oil, const char *name)
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index 45c4df0e7..556d25b82 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -1944,6 +1944,40 @@ void pim_upstream_terminate(struct pim_instance *pim)
wheel_delete(pim->upstream_sg_wheel);
pim->upstream_sg_wheel = NULL;
}
+bool pim_sg_is_reevaluate_oil_req(struct pim_instance *pim,
+ struct pim_upstream *up)
+{
+ struct pim_interface *pim_ifp = NULL;
+
+ /*
+ * Attempt to retrieve the PIM interface information if the RPF
+ * interface is present
+ */
+ if (up->rpf.source_nexthop.interface) {
+ pim_ifp = up->rpf.source_nexthop.interface->info;
+ } else {
+ if (PIM_DEBUG_PIM_TRACE) {
+ zlog_debug("%s: up %s RPF is not present", __func__,
+ up->sg_str);
+ }
+ }
+
+ /*
+ * Determine if a reevaluation of the outgoing interface list (OIL) is
+ * required. This may be necessary in scenarios such as MSDP where the
+ * RP role for a group changes from secondary to primary. In such cases,
+ * SGRpt may receive a prune, resulting in an S,G entry with a NULL OIL.
+ * The S,G upstream should then inherit the OIL from *,G, which is
+ * particularly important for VXLAN setups.
+ */
+ if (up->channel_oil->oil_inherited_rescan ||
+ (pim_ifp && I_am_RP(pim_ifp->pim, up->sg.grp)) ||
+ pim_upstream_empty_inherited_olist(up)) {
+ return true;
+ }
+
+ return false;
+}
bool pim_upstream_equal(const void *arg1, const void *arg2)
{
@@ -2079,7 +2113,7 @@ static void pim_upstream_sg_running(void *arg)
* only doing this at this point in time
* to get us up and working for the moment
*/
- if (up->channel_oil->oil_inherited_rescan) {
+ if (pim_sg_is_reevaluate_oil_req(pim, up)) {
if (PIM_DEBUG_TRACE)
zlog_debug(
"%s: Handling unscanned inherited_olist for %s[%s]",
diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h
index 4e0926e29..62649cd94 100644
--- a/pimd/pim_upstream.h
+++ b/pimd/pim_upstream.h
@@ -383,4 +383,6 @@ uint32_t pim_up_mlag_local_cost(struct pim_upstream *up);
uint32_t pim_up_mlag_peer_cost(struct pim_upstream *up);
void pim_upstream_reeval_use_rpt(struct pim_instance *pim);
int pim_upstream_could_register(struct pim_upstream *up);
+bool pim_sg_is_reevaluate_oil_req(struct pim_instance *pim,
+ struct pim_upstream *up);
#endif /* PIM_UPSTREAM_H */
diff --git a/qpb/qpb.h b/qpb/qpb.h
index d52528f41..280461447 100644
--- a/qpb/qpb.h
+++ b/qpb/qpb.h
@@ -14,6 +14,7 @@
#ifndef _QPB_H
#define _QPB_H
+#include "nexthop.h"
#include "prefix.h"
#include "qpb/qpb.pb-c.h"
diff --git a/staticd/static_nht.c b/staticd/static_nht.c
index ebc5ea16c..6be598434 100644
--- a/staticd/static_nht.c
+++ b/staticd/static_nht.c
@@ -18,8 +18,7 @@
#include "static_nht.h"
static void static_nht_update_path(struct static_path *pn, struct prefix *nhp,
- uint32_t nh_num, vrf_id_t nh_vrf_id,
- struct vrf *vrf)
+ uint32_t nh_num, vrf_id_t nh_vrf_id)
{
struct static_nexthop *nh;
@@ -49,18 +48,13 @@ static void static_nht_update_path(struct static_path *pn, struct prefix *nhp,
static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp,
uint32_t nh_num, afi_t afi, safi_t safi,
- struct vrf *vrf, vrf_id_t nh_vrf_id)
+ struct static_vrf *svrf, vrf_id_t nh_vrf_id)
{
struct route_table *stable;
- struct static_vrf *svrf;
struct route_node *rn;
struct static_path *pn;
struct static_route_info *si;
- svrf = vrf->info;
- if (!svrf)
- return;
-
stable = static_vrf_static_table(afi, safi, svrf);
if (!stable)
return;
@@ -71,7 +65,7 @@ static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp,
si = static_route_info_from_rnode(rn);
frr_each(static_path_list, &si->path_list, pn) {
static_nht_update_path(pn, nhp, nh_num,
- nh_vrf_id, vrf);
+ nh_vrf_id);
}
route_unlock_node(rn);
}
@@ -83,7 +77,7 @@ static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp,
if (!si)
continue;
frr_each(static_path_list, &si->path_list, pn) {
- static_nht_update_path(pn, nhp, nh_num, nh_vrf_id, vrf);
+ static_nht_update_path(pn, nhp, nh_num, nh_vrf_id);
}
}
}
@@ -91,29 +85,23 @@ static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp,
void static_nht_update(struct prefix *sp, struct prefix *nhp, uint32_t nh_num,
afi_t afi, safi_t safi, vrf_id_t nh_vrf_id)
{
+ struct static_vrf *svrf;
- struct vrf *vrf;
-
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
- static_nht_update_safi(sp, nhp, nh_num, afi, safi, vrf,
+ RB_FOREACH (svrf, svrf_name_head, &svrfs)
+ static_nht_update_safi(sp, nhp, nh_num, afi, safi, svrf,
nh_vrf_id);
}
static void static_nht_reset_start_safi(struct prefix *nhp, afi_t afi,
- safi_t safi, struct vrf *vrf,
+ safi_t safi, struct static_vrf *svrf,
vrf_id_t nh_vrf_id)
{
- struct static_vrf *svrf;
struct route_table *stable;
struct static_nexthop *nh;
struct static_path *pn;
struct route_node *rn;
struct static_route_info *si;
- svrf = vrf->info;
- if (!svrf)
- return;
-
stable = static_vrf_static_table(afi, safi, svrf);
if (!stable)
return;
@@ -153,10 +141,10 @@ static void static_nht_reset_start_safi(struct prefix *nhp, afi_t afi,
void static_nht_reset_start(struct prefix *nhp, afi_t afi, safi_t safi,
vrf_id_t nh_vrf_id)
{
- struct vrf *vrf;
+ struct static_vrf *svrf;
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
- static_nht_reset_start_safi(nhp, afi, safi, vrf, nh_vrf_id);
+ RB_FOREACH (svrf, svrf_name_head, &svrfs)
+ static_nht_reset_start_safi(nhp, afi, safi, svrf, nh_vrf_id);
}
static void static_nht_mark_state_safi(struct prefix *sp, afi_t afi,
diff --git a/staticd/static_routes.c b/staticd/static_routes.c
index db3fc32fd..cba38183b 100644
--- a/staticd/static_routes.c
+++ b/staticd/static_routes.c
@@ -87,11 +87,6 @@ void zebra_stable_node_cleanup(struct route_table *table,
/* Install static path into rib. */
void static_install_path(struct static_path *pn)
{
- struct static_nexthop *nh;
-
- frr_each(static_nexthop_list, &pn->nexthop_list, nh)
- static_zebra_nht_register(nh, true);
-
if (static_nexthop_list_count(&pn->nexthop_list))
static_zebra_route_add(pn, true);
}
@@ -377,6 +372,17 @@ void static_install_nexthop(struct static_nexthop *nh)
}
}
+void static_uninstall_nexthop(struct static_nexthop *nh)
+{
+ struct static_path *pn = nh->pn;
+
+ if (nh->nh_vrf_id == VRF_UNKNOWN)
+ return;
+
+ static_zebra_nht_register(nh, false);
+ static_uninstall_path(pn);
+}
+
void static_delete_nexthop(struct static_nexthop *nh)
{
struct static_path *pn = nh->pn;
@@ -386,17 +392,8 @@ void static_delete_nexthop(struct static_nexthop *nh)
/* Remove BFD session/configuration if any. */
bfd_sess_free(&nh->bsp);
- if (nh->nh_vrf_id == VRF_UNKNOWN)
- goto EXIT;
+ static_uninstall_nexthop(nh);
- static_zebra_nht_register(nh, false);
- /*
- * If we have other si nodes then route replace
- * else delete the route
- */
- static_uninstall_path(pn);
-
-EXIT:
route_unlock_node(rn);
/* Free static route configuration. */
XFREE(MTYPE_STATIC_NEXTHOP, nh);
@@ -490,7 +487,6 @@ static void static_fixup_vrf(struct vrf *vrf, struct route_table *stable,
continue;
nh->nh_vrf_id = vrf->vrf_id;
- nh->nh_registered = false;
if (nh->ifname[0]) {
ifp = if_lookup_by_name(nh->ifname,
nh->nh_vrf_id);
@@ -500,7 +496,7 @@ static void static_fixup_vrf(struct vrf *vrf, struct route_table *stable,
continue;
}
- static_install_path(pn);
+ static_install_nexthop(nh);
}
}
}
@@ -518,8 +514,6 @@ static void static_fixup_vrf(struct vrf *vrf, struct route_table *stable,
static void static_enable_vrf(struct route_table *stable, afi_t afi, safi_t safi)
{
struct route_node *rn;
- struct static_nexthop *nh;
- struct interface *ifp;
struct static_path *pn;
struct static_route_info *si;
@@ -527,22 +521,8 @@ static void static_enable_vrf(struct route_table *stable, afi_t afi, safi_t safi
si = static_route_info_from_rnode(rn);
if (!si)
continue;
- frr_each(static_path_list, &si->path_list, pn) {
- frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
- if (nh->nh_vrf_id == VRF_UNKNOWN)
- continue;
- if (nh->ifname[0]) {
- ifp = if_lookup_by_name(nh->ifname,
- nh->nh_vrf_id);
- if (ifp)
- nh->ifindex = ifp->ifindex;
- else
- continue;
- }
-
- static_install_path(pn);
- }
- }
+ frr_each(static_path_list, &si->path_list, pn)
+ static_install_path(pn);
}
}
@@ -604,7 +584,7 @@ static void static_cleanup_vrf(struct vrf *vrf, struct route_table *stable,
if (strcmp(vrf->name, nh->nh_vrfname) != 0)
continue;
- static_uninstall_path(pn);
+ static_uninstall_nexthop(nh);
nh->nh_vrf_id = VRF_UNKNOWN;
nh->ifindex = IFINDEX_INTERNAL;
@@ -625,7 +605,6 @@ static void static_disable_vrf(struct route_table *stable,
afi_t afi, safi_t safi)
{
struct route_node *rn;
- struct static_nexthop *nh;
struct static_path *pn;
struct static_route_info *si;
@@ -633,14 +612,8 @@ static void static_disable_vrf(struct route_table *stable,
si = static_route_info_from_rnode(rn);
if (!si)
continue;
- frr_each(static_path_list, &si->path_list, pn) {
- frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
- if (nh->nh_vrf_id == VRF_UNKNOWN)
- continue;
-
- static_uninstall_path(pn);
- }
- }
+ frr_each(static_path_list, &si->path_list, pn)
+ static_uninstall_path(pn);
}
}
diff --git a/staticd/static_routes.h b/staticd/static_routes.h
index d88ed2936..2e2e4986c 100644
--- a/staticd/static_routes.h
+++ b/staticd/static_routes.h
@@ -207,6 +207,7 @@ static_add_nexthop(struct static_path *pn, enum static_nh_type type,
struct ipaddr *ipaddr, const char *ifname,
const char *nh_vrf, uint32_t color);
extern void static_install_nexthop(struct static_nexthop *nh);
+extern void static_uninstall_nexthop(struct static_nexthop *nh);
extern void static_delete_nexthop(struct static_nexthop *nh);
diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c
index a635cccb0..c4efc14a9 100644
--- a/staticd/static_zebra.c
+++ b/staticd/static_zebra.c
@@ -390,7 +390,7 @@ extern void static_zebra_route_add(struct static_path *pn, bool install)
struct zapi_route api;
uint32_t nh_num = 0;
- if (!si->svrf->vrf)
+ if (!si->svrf->vrf || si->svrf->vrf->vrf_id == VRF_UNKNOWN)
return;
p = src_pp = NULL;
diff --git a/tests/lib/subdir.am b/tests/lib/subdir.am
index 9247ac335..82314ccc0 100644
--- a/tests/lib/subdir.am
+++ b/tests/lib/subdir.am
@@ -25,7 +25,7 @@ copy_script: tests/lib/script1.lua
$(INSTALL_SCRIPT) $< tests/lib/script1.lua
##############################################################################
-GRPC_TESTS_LDADD = staticd/libstatic.a grpc/libfrrgrpc_pb.la -lgrpc++ -lprotobuf $(ALL_TESTS_LDADD) $(LIBYANG_LIBS) -lm
+GRPC_TESTS_LDADD = mgmtd/libmgmt_be_nb.la staticd/libstatic.a grpc/libfrrgrpc_pb.la -lgrpc++ -lprotobuf $(ALL_TESTS_LDADD) $(LIBYANG_LIBS) -lm
if GRPC
check_PROGRAMS += tests/lib/test_grpc
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py
index 28047f7b2..217657d35 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py
@@ -891,4 +891,11 @@ luCommand(
"pass",
"Redundant route 2 details",
)
+luCommand(
+ "r1",
+ 'vtysh -c "show ip route vrf r1-cust5 5.1.0.0/24"',
+ "Known via .bgp., distance 200, .* vrf r1-cust5, best",
+ "pass",
+ "Recursive route leak details",
+)
# done
diff --git a/tests/topotests/bgp_rpki_topo1/r2/bgpd.conf b/tests/topotests/bgp_rpki_topo1/r2/bgpd.conf
index 95b1e5bdc..87d721497 100644
--- a/tests/topotests/bgp_rpki_topo1/r2/bgpd.conf
+++ b/tests/topotests/bgp_rpki_topo1/r2/bgpd.conf
@@ -4,6 +4,12 @@ router bgp 65002
neighbor 192.0.2.1 timers connect 1
neighbor 192.0.2.1 ebgp-multihop 3
neighbor 192.0.2.1 update-source 192.0.2.2
+ neighbor 192.168.4.4 remote-as internal
+ neighbor 192.168.4.4 timers 1 3
+ neighbor 192.168.4.4 timers connect 1
+ address-family ipv4 unicast
+ neighbor 192.168.4.4 next-hop-self
+ exit-address-family
!
router bgp 65002 vrf vrf10
no bgp ebgp-requires-policy
diff --git a/tests/topotests/bgp_rpki_topo1/r2/zebra.conf b/tests/topotests/bgp_rpki_topo1/r2/zebra.conf
index d44a8a908..785dbc6ce 100644
--- a/tests/topotests/bgp_rpki_topo1/r2/zebra.conf
+++ b/tests/topotests/bgp_rpki_topo1/r2/zebra.conf
@@ -10,3 +10,6 @@ interface r2-eth0
interface r2-eth1 vrf vrf10
ip address 192.168.2.2/24
!
+interface r2-eth2
+ ip address 192.168.4.2/24
+!
diff --git a/tests/topotests/bgp_rpki_topo1/r4/bgpd.conf b/tests/topotests/bgp_rpki_topo1/r4/bgpd.conf
new file mode 100644
index 000000000..80dc9ca86
--- /dev/null
+++ b/tests/topotests/bgp_rpki_topo1/r4/bgpd.conf
@@ -0,0 +1,6 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.4.2 remote-as internal
+ neighbor 192.168.4.2 timers 1 3
+ neighbor 192.168.4.2 timers connect 1
+!
diff --git a/tests/topotests/bgp_rpki_topo1/r4/zebra.conf b/tests/topotests/bgp_rpki_topo1/r4/zebra.conf
new file mode 100644
index 000000000..ed793aeb4
--- /dev/null
+++ b/tests/topotests/bgp_rpki_topo1/r4/zebra.conf
@@ -0,0 +1,4 @@
+!
+interface r4-eth0
+ ip address 192.168.4.4/24
+!
diff --git a/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py
index 0416148b2..a12204f24 100644
--- a/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py
+++ b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py
@@ -22,7 +22,7 @@ pytestmark = [pytest.mark.bgpd]
def build_topo(tgen):
- for routern in range(1, 4):
+ for routern in range(1, 5):
tgen.add_router("r{}".format(routern))
switch = tgen.add_switch("s1")
@@ -33,6 +33,10 @@ def build_topo(tgen):
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r3"])
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r4"])
+
def setup_module(mod):
tgen = Topogen(build_topo, mod.__name__)
@@ -402,6 +406,48 @@ router bgp 65002 vrf vrf10
assert result is None, "Unexpected prefixes RPKI state on {}".format(rname)
+def test_bgp_ecommunity_rpki():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r2 = tgen.gears["r2"]
+ r4 = tgen.gears["r4"]
+
+ # Flush all the states what was before and try sending out the prefixes
+ # with RPKI extended community.
+ r2.vtysh_cmd("clear ip bgp 192.168.4.4 soft out")
+
+ def _bgp_check_ecommunity_rpki(community=None):
+ output = json.loads(r4.vtysh_cmd("show bgp ipv4 unicast 198.51.100.0/24 json"))
+ expected = {
+ "paths": [
+ {
+ "extendedCommunity": community,
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_ecommunity_rpki, {"string": "OVS:valid"})
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Didn't receive RPKI extended community"
+
+ r2.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65002
+ address-family ipv4 unicast
+ no neighbor 192.168.4.4 send-community extended rpki
+ """
+ )
+
+ test_func = functools.partial(_bgp_check_ecommunity_rpki)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Received RPKI extended community"
+
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
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
index 9f7844725..2ce936b29 100644
--- a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json
+++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json
@@ -12,7 +12,7 @@
{
"fib": true,
"directlyConnected": true,
- "interfaceName": "eth0",
+ "interfaceName": "vrf10",
"vrf": "vrf10",
"active": true
}
diff --git a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf
index 03dfbf932..f52f56b0e 100644
--- a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf
+++ b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf
@@ -1,10 +1,19 @@
hostname r1
+router bgp 99
+ no bgp ebgp-requires-policy
+ address-family ipv4 unicast
+ redistribute connected
+ import vrf DONNA
+ !
+!
router bgp 99 vrf DONNA
no bgp ebgp-requires-policy
address-family ipv4 unicast
redistribute connected
import vrf EVA
+ import vrf NOTEXISTING
+ import vrf default
!
!
router bgp 99 vrf EVA
@@ -12,5 +21,13 @@ router bgp 99 vrf EVA
address-family ipv4 unicast
redistribute connected
import vrf DONNA
+ import vrf NOTEXISTING
+ !
+!
+router bgp 99 vrf NOTEXISTING
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ address-family ipv4 unicast
+ network 172.16.101.0/24
!
!
diff --git a/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf b/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf
index 35038557d..4de9e895a 100644
--- a/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf
+++ b/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf
@@ -1,5 +1,9 @@
hostname r1
+int dummy0
+ ip address 10.0.4.1/24
+ no shut
+!
int dummy1
ip address 10.0.0.1/24
no shut
@@ -16,3 +20,9 @@ int dummy4
ip address 10.0.3.1/24
no shut
!
+int EVA
+ no shut
+!
+int DONNA
+ no shut
+!
diff --git a/tests/topotests/bgp_vrf_route_leak_basic/setup_vrfs b/tests/topotests/bgp_vrf_route_leak_basic/setup_vrfs
index fb67953fe..f62c5cd21 100644
--- a/tests/topotests/bgp_vrf_route_leak_basic/setup_vrfs
+++ b/tests/topotests/bgp_vrf_route_leak_basic/setup_vrfs
@@ -3,6 +3,7 @@
ip link add DONNA type vrf table 1001
ip link add EVA type vrf table 1002
+ip link add dummy0 type dummy # vrf default
ip link add dummy1 type dummy
ip link add dummy2 type dummy
ip link add dummy3 type dummy
diff --git a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py
index fd7ffff17..ef813e954 100644
--- a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py
+++ b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py
@@ -64,7 +64,7 @@ def teardown_module(mod):
tgen.stop_topology()
-def test_vrf_route_leak():
+def test_vrf_route_leak_donna():
logger.info("Ensure that routes are leaked back and forth")
tgen = get_topogen()
# Don't run this test if we have any failure.
@@ -81,11 +81,59 @@ def test_vrf_route_leak():
}
],
"10.0.1.0/24": [
- {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "EVA",
+ "vrf": "EVA",
+ "active": True,
+ },
+ ],
+ },
],
"10.0.2.0/24": [{"protocol": "connected"}],
"10.0.3.0/24": [
- {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "EVA",
+ "vrf": "EVA",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "10.0.4.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "lo",
+ "vrf": "default",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "172.16.101.0/24": [
+ {
+ "protocol": "bgp",
+ "nexthops": [
+ {
+ "interfaceIndex": 0,
+ "interfaceName": "unknown",
+ "vrf": "Unknown",
+ },
+ ],
+ },
],
}
@@ -95,10 +143,31 @@ def test_vrf_route_leak():
result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
+
+def test_vrf_route_leak_eva():
+ logger.info("Ensure that routes are leaked back and forth")
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
# Test EVA VRF.
expect = {
"10.0.0.0/24": [
- {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
+ "active": True,
+ },
+ ],
+ },
],
"10.0.1.0/24": [
{
@@ -106,13 +175,36 @@ def test_vrf_route_leak():
}
],
"10.0.2.0/24": [
- {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
+ "active": True,
+ },
+ ],
+ },
],
"10.0.3.0/24": [
{
"protocol": "connected",
}
],
+ "172.16.101.0/24": [
+ {
+ "protocol": "bgp",
+ "nexthops": [
+ {
+ "interfaceIndex": 0,
+ "interfaceName": "unknown",
+ "vrf": "Unknown",
+ },
+ ],
+ },
+ ],
}
test_func = partial(
@@ -122,6 +214,217 @@ def test_vrf_route_leak():
assert result, "BGP VRF EVA check failed:\n{}".format(diff)
+def test_vrf_route_leak_donna():
+ logger.info("Ensure that routes are leaked back and forth")
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ # Test DONNA VRF.
+ expect = {
+ "10.0.0.0/24": [
+ {
+ "protocol": "connected",
+ }
+ ],
+ "10.0.1.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "EVA",
+ "vrf": "EVA",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "10.0.2.0/24": [{"protocol": "connected"}],
+ "10.0.3.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "EVA",
+ "vrf": "EVA",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "10.0.4.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "lo",
+ "vrf": "default",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "172.16.101.0/24": [
+ {
+ "protocol": "bgp",
+ "nexthops": [
+ {
+ "interfaceIndex": 0,
+ "interfaceName": "unknown",
+ "vrf": "Unknown",
+ },
+ ],
+ },
+ ],
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect
+ )
+ result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assert result, "BGP VRF DONNA check failed:\n{}".format(diff)
+
+
+def test_vrf_route_leak_eva():
+ logger.info("Ensure that routes are leaked back and forth")
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ # Test EVA VRF.
+ expect = {
+ "10.0.0.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "10.0.1.0/24": [
+ {
+ "protocol": "connected",
+ }
+ ],
+ "10.0.2.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "10.0.3.0/24": [
+ {
+ "protocol": "connected",
+ }
+ ],
+ "172.16.101.0/24": [
+ {
+ "protocol": "bgp",
+ "nexthops": [
+ {
+ "interfaceIndex": 0,
+ "interfaceName": "unknown",
+ "vrf": "Unknown",
+ },
+ ],
+ },
+ ],
+ }
+
+
+def test_vrf_route_leak_default():
+ logger.info("Ensure that routes are leaked back and forth")
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ # Test default VRF.
+ expect = {
+ "10.0.0.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "10.0.2.0/24": [
+ {
+ "protocol": "bgp",
+ "selected": True,
+ "nexthops": [
+ {
+ "fib": True,
+ "interfaceName": "DONNA",
+ "vrf": "DONNA",
+ "active": True,
+ },
+ ],
+ },
+ ],
+ "10.0.4.0/24": [
+ {
+ "protocol": "connected",
+ }
+ ],
+ }
+
+ test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect)
+ result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assert result, "BGP VRF default check failed:\n{}".format(diff)
+
+
+def test_ping():
+ "Simple ping tests"
+
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ logger.info("Ping from default to DONNA")
+ output = r1.run("ping -c 4 -w 4 -I 10.0.4.1 10.0.0.1")
+ assert " 0% packet loss" in output, "Ping default->DONNA FAILED"
+
+
def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()
diff --git a/tests/topotests/mgmt_notif/test_notif.py b/tests/topotests/mgmt_notif/test_notif.py
index 2f923e398..c85e7ba79 100644
--- a/tests/topotests/mgmt_notif/test_notif.py
+++ b/tests/topotests/mgmt_notif/test_notif.py
@@ -92,7 +92,7 @@ def test_backend_notification(tgen):
pytest.skip("No mgmtd_testc")
output = r1.cmd_raises(
- be_client_path + " --timeout 20 --log file:mgmt_testc.log --listen frr-ripd"
+ be_client_path + " --timeout 20 --log file:mgmt_testc.log --listen /frr-ripd"
)
jsout = json.loads(output)
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt
index ca9ca77bf..248375dc6 100644
--- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt
@@ -7,5 +7,5 @@ O>* 10.0.4.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX
O 10.0.20.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX
C>* 10.0.20.0/24 is directly connected, r1-eth1, XX:XX:XX
L>* 10.0.20.1/32 is directly connected, r1-eth1, XX:XX:XX
-B>* 10.0.30.0/24 [20/0] is directly connected, r1-eth2 (vrf neno), weight 1, XX:XX:XX
+B>* 10.0.30.0/24 [20/0] is directly connected, neno (vrf neno), weight 1, XX:XX:XX
O>* 10.0.40.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt
index 70ae98789..d7d31434c 100644
--- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt
@@ -9,4 +9,4 @@ O 10.0.20.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX
C>* 10.0.20.0/24 is directly connected, r2-eth1, XX:XX:XX
L>* 10.0.20.2/32 is directly connected, r2-eth1, XX:XX:XX
O>* 10.0.30.0/24 [110/20] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX
-B>* 10.0.40.0/24 [20/0] is directly connected, r2-eth2 (vrf ray), weight 1, XX:XX:XX
+B>* 10.0.40.0/24 [20/0] is directly connected, ray (vrf ray), weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt
index 1495c8893..6ab1bb8f9 100644
--- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt
@@ -1,9 +1,9 @@
VRF ray:
B 10.0.1.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX
-B 10.0.2.0/24 [20/0] is directly connected, r2-eth0 (vrf default) inactive, weight 1, XX:XX:XX
+B 10.0.2.0/24 [20/0] is directly connected, lo (vrf default) inactive, weight 1, XX:XX:XX
B>* 10.0.3.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX
O>* 10.0.4.0/24 [110/20] via 10.0.40.4, r2-eth2, weight 1, XX:XX:XX
-B 10.0.20.0/24 [20/0] is directly connected, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX
+B 10.0.20.0/24 [20/0] is directly connected, lo (vrf default) inactive, weight 1, XX:XX:XX
B>* 10.0.30.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX
O 10.0.40.0/24 [110/10] is directly connected, r2-eth2, weight 1, XX:XX:XX
C>* 10.0.40.0/24 is directly connected, r2-eth2, XX:XX:XX
diff --git a/tests/topotests/ospfapi/test_ospf_clientapi.py b/tests/topotests/ospfapi/test_ospf_clientapi.py
index 41c18df7d..49dd34d65 100644
--- a/tests/topotests/ospfapi/test_ospf_clientapi.py
+++ b/tests/topotests/ospfapi/test_ospf_clientapi.py
@@ -277,7 +277,9 @@ def _test_add_data(tgen, apibin):
"linkStateId": "230.0.0.2",
"advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
- "opaqueData": "00000202",
+ "opaqueValues": {
+ "opaqueData": "00000202"
+ }
},
],
}
@@ -327,7 +329,9 @@ def _test_add_data(tgen, apibin):
"linkStateId": "231.0.0.1",
"advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
- "opaqueData": "00010101",
+ "opaqueValues": {
+ "opaqueData": "00010101",
+ }
},
],
}
@@ -376,7 +380,9 @@ def _test_add_data(tgen, apibin):
"linkStateId": "232.0.0.3",
"advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
- "opaqueData": "deadbeaf01234567",
+ "opaqueValues": {
+ "opaqueData": "deadbeaf01234567",
+ }
},
]
}
@@ -427,7 +433,9 @@ def _test_add_data(tgen, apibin):
"linkStateId": "232.0.0.3",
"advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000002",
- "opaqueData": "ebadf00d",
+ "opaqueValues": {
+ "opaqueData": "ebadf00d",
+ }
},
]
}
@@ -574,7 +582,7 @@ def _test_opaque_add_del(tgen, apibin):
"lsaSeqNumber": "80000001",
"checksum": "76bf",
"length": 20,
- "opaqueDataLength": 0,
+ "opaqueLength": 0,
},
{
"linkStateId": "230.0.0.2",
@@ -583,7 +591,7 @@ def _test_opaque_add_del(tgen, apibin):
"checksum": "8aa2",
"length": 24,
"opaqueId": 2,
- "opaqueDataLength": 4,
+ "opaqueLength": 4,
},
]
}
@@ -599,7 +607,7 @@ def _test_opaque_add_del(tgen, apibin):
"lsaSeqNumber": "80000001",
"checksum": "5bd8",
"length": 20,
- "opaqueDataLength": 0,
+ "opaqueLength": 0,
},
{
"linkStateId": "231.0.0.2",
@@ -607,7 +615,7 @@ def _test_opaque_add_del(tgen, apibin):
"lsaSeqNumber": "80000001",
"checksum": "7690",
"length": 28,
- "opaqueDataLength": 8,
+ "opaqueLength": 8,
},
],
},
@@ -621,7 +629,7 @@ def _test_opaque_add_del(tgen, apibin):
"lsaSeqNumber": "80000001",
"checksum": "5ed5",
"length": 20,
- "opaqueDataLength": 0,
+ "opaqueLength": 0,
},
{
"linkStateId": "232.0.0.2",
@@ -629,7 +637,7 @@ def _test_opaque_add_del(tgen, apibin):
"lsaSeqNumber": "80000001",
"checksum": "d9bd",
"length": 24,
- "opaqueDataLength": 4,
+ "opaqueLength": 4,
},
],
},
@@ -734,7 +742,7 @@ def _test_opaque_add_del(tgen, apibin):
"lsaSeqNumber": "80000001",
"checksum": "76bf",
"length": 20,
- "opaqueDataLength": 0,
+ "opaqueLength": 0,
},
{
"linkStateId": "230.0.0.2",
@@ -744,7 +752,7 @@ def _test_opaque_add_del(tgen, apibin):
"checksum": "8aa2",
"length": 24,
"opaqueId": 2,
- "opaqueDataLength": 4,
+ "opaqueLength": 4,
},
]
}
@@ -760,7 +768,7 @@ def _test_opaque_add_del(tgen, apibin):
"lsaSeqNumber": "80000001",
"checksum": "5bd8",
"length": 20,
- "opaqueDataLength": 0,
+ "opaqueLength": 0,
},
{
"lsaAge": 3600,
@@ -770,7 +778,7 @@ def _test_opaque_add_del(tgen, apibin):
"checksum": "4fe2",
# data removed
"length": 20,
- "opaqueDataLength": 0,
+ "opaqueLength": 0,
},
],
},
@@ -785,7 +793,7 @@ def _test_opaque_add_del(tgen, apibin):
"lsaSeqNumber": "80000001",
"checksum": "5ed5",
"length": 20,
- "opaqueDataLength": 0,
+ "opaqueLength": 0,
},
{
"linkStateId": "232.0.0.2",
@@ -793,7 +801,7 @@ def _test_opaque_add_del(tgen, apibin):
"lsaSeqNumber": "80000001",
"checksum": "d9bd",
"length": 24,
- "opaqueDataLength": 4,
+ "opaqueLength": 4,
},
],
},
@@ -827,7 +835,7 @@ def _test_opaque_add_del(tgen, apibin):
"lsaSeqNumber": "80000001",
"checksum": "76bf",
"length": 20,
- "opaqueDataLength": 0,
+ "opaqueLength": 0,
},
{
"linkStateId": "230.0.0.2",
@@ -837,7 +845,7 @@ def _test_opaque_add_del(tgen, apibin):
"checksum": "8aa2",
"length": 24,
"opaqueId": 2,
- "opaqueDataLength": 4,
+ "opaqueLength": 4,
},
]
}
@@ -854,7 +862,7 @@ def _test_opaque_add_del(tgen, apibin):
"lsaSeqNumber": "80000001",
"checksum": "5bd8",
"length": 20,
- "opaqueDataLength": 0,
+ "opaqueLength": 0,
},
{
"lsaAge": 3600,
@@ -864,7 +872,7 @@ def _test_opaque_add_del(tgen, apibin):
"checksum": "4fe2",
# data removed
"length": 20,
- "opaqueDataLength": 0,
+ "opaqueLength": 0,
},
],
},
@@ -879,7 +887,7 @@ def _test_opaque_add_del(tgen, apibin):
"lsaSeqNumber": "80000001",
"checksum": "5ed5",
"length": 20,
- "opaqueDataLength": 0,
+ "opaqueLength": 0,
},
{
"linkStateId": "232.0.0.2",
@@ -888,7 +896,7 @@ def _test_opaque_add_del(tgen, apibin):
"lsaSeqNumber": "80000001",
"checksum": "d9bd",
"length": 24,
- "opaqueDataLength": 4,
+ "opaqueLength": 4,
},
],
},
@@ -1044,7 +1052,7 @@ def _test_opaque_add_restart_add(tgen, apibin):
"lsaSeqNumber": "80000001",
"checksum": "b07a",
"length": 28,
- "opaqueDataLength": 8,
+ "opaqueLength": 8,
},
],
},
@@ -1100,7 +1108,7 @@ def _test_opaque_add_restart_add(tgen, apibin):
"lsaSeqNumber": "80000003",
"checksum": "cb27",
"length": 28,
- "opaqueDataLength": 8,
+ "opaqueLength": 8,
},
],
},
@@ -1655,7 +1663,9 @@ def _test_opaque_link_local_lsa_crash(tgen, apibin):
"linkStateId": "230.0.0.1",
"advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
- "opaqueData": "feedaceedeadbeef",
+ "opaqueValues": {
+ "opaqueData": "feedaceedeadbeef",
+ }
},
],
}
@@ -1684,7 +1694,9 @@ def _test_opaque_link_local_lsa_crash(tgen, apibin):
"linkStateId": "230.0.0.1",
"advertisingRouter": "1.0.0.0",
"lsaSeqNumber": "80000001",
- "opaqueData": "feedaceecafebeef",
+ "opaqueValues": {
+ "opaqueData": "feedaceecafebeef",
+ }
},
],
}
diff --git a/tests/topotests/static_vrf/r1/frr.conf b/tests/topotests/static_vrf/r1/frr.conf
new file mode 100644
index 000000000..bb373b962
--- /dev/null
+++ b/tests/topotests/static_vrf/r1/frr.conf
@@ -0,0 +1,18 @@
+interface r1-eth0 vrf red
+ ip address 192.0.2.1/23
+exit
+
+interface r1-eth1 vrf blue
+ ip address 192.0.2.129/24
+exit
+
+ip route 198.51.100.1/32 192.0.2.2 nexthop-vrf red
+ip route 198.51.100.1/32 192.0.2.130 nexthop-vrf blue
+ip route 198.51.100.2/32 r1-eth0 nexthop-vrf red
+ip route 198.51.100.2/32 r1-eth1 nexthop-vrf blue
+
+ip route 203.0.113.1/32 192.0.2.130 vrf red nexthop-vrf blue
+ip route 203.0.113.2/32 r1-eth1 vrf red nexthop-vrf blue
+
+ip route 203.0.113.129/32 192.0.2.2 vrf blue nexthop-vrf red
+ip route 203.0.113.130/32 r1-eth0 vrf blue nexthop-vrf red
diff --git a/tests/topotests/static_vrf/test_static_vrf.py b/tests/topotests/static_vrf/test_static_vrf.py
new file mode 100644
index 000000000..97c080013
--- /dev/null
+++ b/tests/topotests/static_vrf/test_static_vrf.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 eval: (blacken-mode 1) -*-
+# SPDX-License-Identifier: ISC
+#
+# Copyright (c) 2024 NFWare Inc.
+#
+# noqa: E501
+#
+"""
+Test static route functionality
+"""
+
+import ipaddress
+
+import pytest
+from lib.topogen import Topogen
+from lib.common_config import retry
+
+pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd]
+
+
+@pytest.fixture(scope="module")
+def tgen(request):
+ "Setup/Teardown the environment and provide tgen argument to tests"
+
+ topodef = {"s1": ("r1",), "s2": ("r1",)}
+
+ tgen = Topogen(topodef, request.module.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ # Setup VRF red
+ router.net.add_l3vrf("red", 10)
+ router.net.attach_iface_to_l3vrf(rname + "-eth0", "red")
+ # Setup VRF blue
+ router.net.add_l3vrf("blue", 20)
+ router.net.attach_iface_to_l3vrf(rname + "-eth1", "blue")
+ # Load configuration
+ router.load_frr_config("frr.conf")
+
+ tgen.start_router()
+ yield tgen
+ tgen.stop_topology()
+
+
+@retry(retry_timeout=1, initial_wait=0.1)
+def check_kernel(r1, prefix, nexthops, vrf, expected_p=True, expected_nh=True):
+ vrfstr = f" vrf {vrf}" if vrf else ""
+
+ net = ipaddress.ip_network(prefix)
+ if net.version == 6:
+ kernel = r1.run(f"ip -6 route show{vrfstr} {prefix}")
+ else:
+ kernel = r1.run(f"ip -4 route show{vrfstr} {prefix}")
+
+ if expected_p:
+ assert prefix in kernel, f"Failed to find \n'{prefix}'\n in \n'{kernel:.1920}'"
+ else:
+ assert (
+ prefix not in kernel
+ ), f"Failed found \n'{prefix}'\n in \n'{kernel:.1920}'"
+
+ if not expected_p:
+ return
+
+ for nh in nexthops:
+ if expected_nh:
+ assert f"{nh}" in kernel, f"Failed to find \n'{nh}'\n in \n'{kernel:.1920}'"
+ else:
+ assert (
+ f"{nh}" not in kernel
+ ), f"Failed found \n'{nh}'\n in \n'{kernel:.1920}'"
+
+
+def test_static_vrf(tgen):
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ # Check initial configuration
+ check_kernel(r1, "198.51.100.1", ["192.0.2.2", "192.0.2.130"], None)
+ check_kernel(r1, "198.51.100.2", ["r1-eth0", "r1-eth1"], None)
+ check_kernel(r1, "203.0.113.1", ["192.0.2.130"], "red")
+ check_kernel(r1, "203.0.113.2", ["r1-eth1"], "red")
+ check_kernel(r1, "203.0.113.129", ["192.0.2.2"], "blue")
+ check_kernel(r1, "203.0.113.130", ["r1-eth0"], "blue")
+
+ # Delete VRF red
+ r1.net.del_iface("red")
+
+ # Check that "red" nexthops are removed, "blue" nexthops are still there
+ check_kernel(r1, "198.51.100.1", ["192.0.2.2"], None, expected_nh=False)
+ check_kernel(r1, "198.51.100.1", ["192.0.2.130"], None)
+ check_kernel(r1, "198.51.100.2", ["r1-eth0"], None, expected_nh=False)
+ check_kernel(r1, "198.51.100.2", ["r1-eth1"], None)
+ check_kernel(r1, "203.0.113.129", ["192.0.2.2"], "blue", expected_p=False)
+ check_kernel(r1, "203.0.113.130", ["r1-eth0"], "blue", expected_p=False)
+
+ # Delete VRF blue
+ r1.net.del_iface("blue")
+
+ # Check that "blue" nexthops are removed
+ check_kernel(r1, "198.51.100.1", ["192.0.2.130"], None, expected_p=False)
+ check_kernel(r1, "198.51.100.2", ["r1-eth1"], None, expected_p=False)
+
+ # Add VRF red back, attach "eth0" to it
+ r1.net.add_l3vrf("red", 10)
+ r1.net.attach_iface_to_l3vrf("r1-eth0", "red")
+
+ # Check that "red" nexthops are restored
+ check_kernel(r1, "198.51.100.1", ["192.0.2.2"], None)
+ check_kernel(r1, "198.51.100.2", ["r1-eth0"], None)
+
+ # Add VRF blue back, attach "eth1" to it
+ r1.net.add_l3vrf("blue", 20)
+ r1.net.attach_iface_to_l3vrf("r1-eth1", "blue")
+
+ # Check that everything is restored
+ check_kernel(r1, "198.51.100.1", ["192.0.2.2", "192.0.2.130"], None)
+ check_kernel(r1, "198.51.100.2", ["r1-eth0", "r1-eth1"], None)
+ check_kernel(r1, "203.0.113.1", ["192.0.2.130"], "red")
+ check_kernel(r1, "203.0.113.2", ["r1-eth1"], "red")
+ check_kernel(r1, "203.0.113.129", ["192.0.2.2"], "blue")
+ check_kernel(r1, "203.0.113.130", ["r1-eth0"], "blue")
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 4cb46b87a..f90f8983d 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -1669,7 +1669,6 @@ static int vtysh_end(void)
/* Nothing to do. */
break;
default:
- vty->vtysh_file_locked = false;
vty->node = ENABLE_NODE;
break;
}
@@ -2393,23 +2392,12 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_disable, vtysh_disable_cmd, "disable",
}
DEFUNSH(VTYSH_REALLYALL, vtysh_config_terminal, vtysh_config_terminal_cmd,
- "configure [terminal]",
- "Configuration from vty interface\n"
- "Configuration terminal\n")
-{
- vty->node = CONFIG_NODE;
- return CMD_SUCCESS;
-}
-
-DEFUNSH(VTYSH_REALLYALL, vtysh_config_terminal_file_lock,
- vtysh_config_terminal_file_lock_cmd,
- "configure terminal file-lock",
+ "configure [terminal [file-lock]]",
"Configuration from vty interface\n"
"Configuration terminal\n"
"Configuration with locked datastores\n")
{
vty->node = CONFIG_NODE;
- vty->vtysh_file_locked = true;
return CMD_SUCCESS;
}
@@ -2424,21 +2412,6 @@ static int vtysh_exit(struct vty *vty)
if (cnode->parent_node)
vty->node = cnode->parent_node;
- if (vty->node == CONFIG_NODE) {
- bool locked = vty->vtysh_file_locked;
-
- /* resync in case one of the daemons is somewhere else */
- vtysh_execute("end");
- /* NOTE: a rather expensive thing to do, can we avoid it? */
-
- if (locked)
- vtysh_execute("configure terminal file-lock");
- else
- vtysh_execute("configure terminal");
- } else if (vty->node == ENABLE_NODE) {
- vty->vtysh_file_locked = false;
- }
-
return CMD_SUCCESS;
}
@@ -3196,7 +3169,7 @@ DEFUNSH(VTYSH_ALL, debug_nb,
debug_nb_cmd,
"[no] debug northbound\
[<\
- callbacks [{configuration|state|rpc}]\
+ callbacks [{configuration|state|rpc|notify}]\
|notifications\
|events\
|libyang\
@@ -3209,6 +3182,7 @@ DEFUNSH(VTYSH_ALL, debug_nb,
"State\n"
"RPC\n"
"Notifications\n"
+ "Notifications\n"
"Events\n"
"libyang debugging\n")
{
@@ -5125,7 +5099,6 @@ void vtysh_init_vty(void)
if (!user_mode)
install_element(VIEW_NODE, &vtysh_enable_cmd);
install_element(ENABLE_NODE, &vtysh_config_terminal_cmd);
- install_element(ENABLE_NODE, &vtysh_config_terminal_file_lock_cmd);
install_element(ENABLE_NODE, &vtysh_disable_cmd);
/* "exit" command. */
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index 888f6a8c2..c207e4d42 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -616,8 +616,13 @@ static int vtysh_read_file(FILE *confp, bool dry_run)
vty->node = CONFIG_NODE;
vtysh_execute_no_pager("enable");
- vtysh_execute_no_pager("conf term file-lock");
- vty->vtysh_file_locked = true;
+ /*
+ * When reading the config, we need to wait until the lock is acquired.
+ * If we ignore the failure and continue without the lock, the config
+ * will be fully ignored.
+ */
+ while (vtysh_execute_no_pager("conf term file-lock") == CMD_WARNING_CONFIG_FAILED)
+ usleep(100000);
if (!dry_run)
vtysh_execute_no_pager("XFRR_start_configuration");
@@ -629,7 +634,6 @@ static int vtysh_read_file(FILE *confp, bool dry_run)
vtysh_execute_no_pager("XFRR_end_configuration");
vtysh_execute_no_pager("end");
- vty->vtysh_file_locked = false;
vtysh_execute_no_pager("disable");
vty_close(vty);
diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h
index 608004897..34ef79f15 100644
--- a/zebra/zebra_evpn_mh.h
+++ b/zebra/zebra_evpn_mh.h
@@ -154,7 +154,7 @@ struct zebra_evpn_es_vtep {
/* Parameters for DF election */
uint8_t df_alg;
- uint32_t df_pref;
+ uint16_t df_pref;
/* XXX - maintain a backpointer to struct zebra_vtep */
};