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