diff options
70 files changed, 1802 insertions, 614 deletions
diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h index 7c3b23ab54..49821061b1 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 f12d0dd3ee..62e0430c96 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 ee1f74989b..cebabb9fd0 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 32436861f4..cd5cf5be54 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 90e0074e35..830883872e 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 46f7f9b22f..f0c5de074d 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 7a0d328c6a..d4c6ecfdbb 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 33884d0452..31524e2221 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 a105b6de3f..4955e4c3df 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 0db0ac4873..1172514e52 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 4696e4dc44..396c8335f8 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 b8517199af..8fc52652a2 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 a0360525a8..0f69095323 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 d9fd920c7c..8da41e6d34 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 e557d3a84a..2404ffe2a7 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 3e3bd2dd21..3af4048ed4 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 86d7c402ed..53dc551ca3 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 18a261d940..791762aa7b 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 9b9b4061ed..5a49806581 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 6427705e90..fc46a11c0b 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 6530022db8..286555c564 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 d144ebc728..361899fc1d 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 a0b1bd18c5..d74773194c 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 9279122deb..e9f2db9b6e 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 0358a0f377..8809ec2ad8 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 b9b9a71167..74bc034ccd 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) { @@ -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 adf2ba2ab0..ff7df0b379 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 4ed0a39ba4..9c221445cd 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 aba02e4653..d85d87b4b6 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 001da7680b..ec8e773354 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 02a308f328..7e3ded8209 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 df2a1d852d..664f42f4ba 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 3eaa9567ab..1624c6e4f9 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 88628999ab..be909c862a 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 d82c2146c7..df0b3b9081 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 24a850c737..5d2d65658f 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 c6aaf3f5a0..99326b41b3 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 467cb0504d..e26fe6f53a 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 d203b5ef4d..9ba9a7659d 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 e00888acf3..c63e0f35d4 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 45c4df0e7e..556d25b822 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 4e0926e294..62649cd949 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 */ @@ -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 ebc5ea16cc..6be598434d 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 db3fc32fd8..cba38183bb 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 d88ed29364..2e2e4986c3 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 a635cccb09..c4efc14a9d 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 9247ac3358..82314ccc04 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 28047f7b2d..217657d358 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 95b1e5bdc1..87d7214972 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 d44a8a9088..785dbc6ce5 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 0000000000..80dc9ca86f --- /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 0000000000..ed793aeb43 --- /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 0416148b27..a12204f240 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 9f78447255..2ce936b291 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 03dfbf9322..f52f56b0e0 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 35038557df..4de9e895a2 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 fb67953fe3..f62c5cd211 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 fd7ffff17c..ef813e9541 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 2f923e398c..c85e7ba795 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 ca9ca77bf5..248375dc6c 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 70ae987894..d7d31434c6 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 1495c88936..6ab1bb8f92 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 41c18df7d3..49dd34d650 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 0000000000..bb373b962a --- /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 0000000000..97c0800133 --- /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 4cb46b87a5..f90f8983d4 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 888f6a8c21..c207e4d427 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 6080048976..34ef79f155 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 */  };  | 
