diff options
43 files changed, 778 insertions, 320 deletions
diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 0e341a8c6b..add999bd44 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -304,15 +304,3 @@ extern int bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag, return -1; return 0; } - -extern bool is_zero_gw_ip(const union gw_addr *gw_ip, const afi_t afi) -{ - if (afi == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&gw_ip->ipv6)) - return true; - - if (afi == AF_INET && gw_ip->ipv4.s_addr == INADDR_ANY) - return true; - - return false; -} - diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index 102509fdd7..64f0e7c51a 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -25,11 +25,6 @@ struct attr; -union gw_addr { - struct in_addr ipv4; - struct in6_addr ipv6; -}; - enum overlay_index_type { OVERLAY_INDEX_TYPE_NONE, OVERLAY_INDEX_GATEWAY_IP, @@ -45,7 +40,7 @@ enum overlay_index_type { struct bgp_route_evpn { enum overlay_index_type type; esi_t eth_s_id; - union gw_addr gw_ip; + struct ipaddr gw_ip; }; extern bool str2esi(const char *str, esi_t *id); @@ -64,6 +59,4 @@ extern void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag, bool *proxy); extern uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg); -extern bool is_zero_gw_ip(const union gw_addr *gw_ip, afi_t afi); - #endif /* _QUAGGA_BGP_ATTR_EVPN_H */ diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index ea54c14222..ffa4aca3fb 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1335,7 +1335,8 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, if (src_attr && !IN6_IS_ADDR_UNSPECIFIED(&src_attr->mp_nexthop_global)) { attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP; - memcpy(&attr.evpn_overlay.gw_ip.ipv6, + SET_IPADDR_V6(&attr.evpn_overlay.gw_ip); + memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v6, &src_attr->mp_nexthop_global, sizeof(struct in6_addr)); } @@ -1344,7 +1345,8 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP)) { if (src_attr && src_attr->nexthop.s_addr != 0) { attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP; - memcpy(&attr.evpn_overlay.gw_ip.ipv4, + SET_IPADDR_V4(&attr.evpn_overlay.gw_ip); + memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v4, &src_attr->nexthop, sizeof(struct in_addr)); } } @@ -2470,11 +2472,11 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, if (afi == AFI_IP6) { memcpy(&attr.mp_nexthop_global, - &attr.evpn_overlay.gw_ip.ipv6, + &attr.evpn_overlay.gw_ip.ipaddr_v6, sizeof(struct in6_addr)); attr.mp_nexthop_len = IPV6_MAX_BYTELEN; } else { - attr.nexthop = attr.evpn_overlay.gw_ip.ipv4; + attr.nexthop = attr.evpn_overlay.gw_ip.ipaddr_v4; attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); } } @@ -4041,7 +4043,6 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, uint32_t eth_tag; mpls_label_t label; /* holds the VNI as in the packet */ int ret; - afi_t gw_afi; bool is_valid_update = true; /* Type-5 route should be 34 or 58 bytes: @@ -4100,17 +4101,17 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, SET_IPADDR_V4(&p.prefix.prefix_addr.ip); memcpy(&p.prefix.prefix_addr.ip.ipaddr_v4, pfx, 4); pfx += 4; - memcpy(&evpn.gw_ip.ipv4, pfx, 4); + SET_IPADDR_V4(&evpn.gw_ip); + memcpy(&evpn.gw_ip.ipaddr_v4, pfx, 4); pfx += 4; - gw_afi = AF_INET; } else { SET_IPADDR_V6(&p.prefix.prefix_addr.ip); memcpy(&p.prefix.prefix_addr.ip.ipaddr_v6, pfx, IPV6_MAX_BYTELEN); pfx += IPV6_MAX_BYTELEN; - memcpy(&evpn.gw_ip.ipv6, pfx, IPV6_MAX_BYTELEN); + SET_IPADDR_V6(&evpn.gw_ip); + memcpy(&evpn.gw_ip.ipaddr_v6, pfx, IPV6_MAX_BYTELEN); pfx += IPV6_MAX_BYTELEN; - gw_afi = AF_INET6; } /* Get the VNI (in MPLS label field). Stored as bytes here. */ @@ -4127,20 +4128,20 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, * An update containing a non-zero gateway IP and a non-zero ESI * at the same time is should be treated as withdraw */ - if (bgp_evpn_is_esi_valid(&evpn.eth_s_id) - && !is_zero_gw_ip(&evpn.gw_ip, gw_afi)) { + if (bgp_evpn_is_esi_valid(&evpn.eth_s_id) && + !ipaddr_is_zero(&evpn.gw_ip)) { flog_err(EC_BGP_EVPN_ROUTE_INVALID, "%s - Rx EVPN Type-5 ESI and gateway-IP both non-zero.", peer->host); is_valid_update = false; } else if (bgp_evpn_is_esi_valid(&evpn.eth_s_id)) evpn.type = OVERLAY_INDEX_ESI; - else if (!is_zero_gw_ip(&evpn.gw_ip, gw_afi)) + else if (!ipaddr_is_zero(&evpn.gw_ip)) evpn.type = OVERLAY_INDEX_GATEWAY_IP; if (attr) { - if (is_zero_mac(&attr->rmac) - && !bgp_evpn_is_esi_valid(&evpn.eth_s_id) - && is_zero_gw_ip(&evpn.gw_ip, gw_afi) && label == 0) { + if (is_zero_mac(&attr->rmac) && + !bgp_evpn_is_esi_valid(&evpn.eth_s_id) && + ipaddr_is_zero(&evpn.gw_ip) && label == 0) { flog_err(EC_BGP_EVPN_ROUTE_INVALID, "%s - Rx EVPN Type-5 ESI, gateway-IP, RMAC and label all zero", peer->host); @@ -4213,9 +4214,10 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p, bgp_attr_get_evpn_overlay(attr); if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip)) - stream_put_ipv4(s, evpn_overlay->gw_ip.ipv4.s_addr); + stream_put_ipv4(s, + evpn_overlay->gw_ip.ipaddr_v4.s_addr); else - stream_put(s, &(evpn_overlay->gw_ip.ipv6), 16); + stream_put(s, &(evpn_overlay->gw_ip.ipaddr_v6), 16); } else { if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip)) stream_put_ipv4(s, 0); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 45e9aad1ba..672fa4512a 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -662,6 +662,15 @@ static void bgp_graceful_restart_timer_off(struct peer *peer) UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); BGP_TIMER_OFF(peer->t_gr_stale); + + if (peer_dynamic_neighbor(peer) && + !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s (dynamic neighbor) deleted (%s)", + peer->host, __func__); + peer_delete(peer); + } + bgp_timer_set(peer); } @@ -1380,10 +1389,11 @@ int bgp_stop(struct peer *peer) && peer->last_reset == PEER_DOWN_UPDATE_SOURCE_CHANGE) bfd_sess_uninstall(peer->bfd_config->session); - if (peer_dynamic_neighbor(peer) - && !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) { + if (peer_dynamic_neighbor_no_nsf(peer) && + !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) { if (bgp_debug_neighbor_events(peer)) - zlog_debug("%s (dynamic neighbor) deleted", peer->host); + zlog_debug("%s (dynamic neighbor) deleted (%s)", + peer->host, __func__); peer_delete(peer); return -1; } @@ -1602,9 +1612,10 @@ static int bgp_stop_with_error(struct peer *peer) if (peer->v_start >= (60 * 2)) peer->v_start = (60 * 2); - if (peer_dynamic_neighbor(peer)) { + if (peer_dynamic_neighbor_no_nsf(peer)) { if (bgp_debug_neighbor_events(peer)) - zlog_debug("%s (dynamic neighbor) deleted", peer->host); + zlog_debug("%s (dynamic neighbor) deleted (%s)", + peer->host, __func__); peer_delete(peer); return -1; } @@ -1620,9 +1631,10 @@ static int bgp_stop_with_notify(struct peer *peer, uint8_t code, /* Send notify to remote peer */ bgp_notify_send(peer, code, sub_code); - if (peer_dynamic_neighbor(peer)) { + if (peer_dynamic_neighbor_no_nsf(peer)) { if (bgp_debug_neighbor_events(peer)) - zlog_debug("%s (dynamic neighbor) deleted", peer->host); + zlog_debug("%s (dynamic neighbor) deleted (%s)", + peer->host, __func__); peer_delete(peer); return -1; } @@ -1781,9 +1793,10 @@ static int bgp_connect_success_w_delayopen(struct peer *peer) /* TCP connect fail */ static int bgp_connect_fail(struct peer *peer) { - if (peer_dynamic_neighbor(peer)) { + if (peer_dynamic_neighbor_no_nsf(peer)) { if (bgp_debug_neighbor_events(peer)) - zlog_debug("%s (dynamic neighbor) deleted", peer->host); + zlog_debug("%s (dynamic neighbor) deleted (%s)", + peer->host, __func__); peer_delete(peer); return -1; } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 8569cbc102..309699fdf4 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3571,30 +3571,6 @@ struct bgp_path_info *info_make(int type, int sub_type, unsigned short instance, return new; } -static bool overlay_index_equal(afi_t afi, struct bgp_path_info *path, - union gw_addr *gw_ip) -{ - const struct bgp_route_evpn *eo = bgp_attr_get_evpn_overlay(path->attr); - union gw_addr path_gw_ip, *path_gw_ip_remote; - union { - esi_t esi; - union gw_addr ip; - } temp; - - if (afi != AFI_L2VPN) - return true; - - path_gw_ip = eo->gw_ip; - - if (gw_ip == NULL) { - memset(&temp, 0, sizeof(temp)); - path_gw_ip_remote = &temp.ip; - } else - path_gw_ip_remote = gw_ip; - - return !!memcmp(&path_gw_ip, path_gw_ip_remote, sizeof(union gw_addr)); -} - /* Check if received nexthop is valid or not. */ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, uint8_t type, uint8_t stype, struct attr *attr, @@ -6096,7 +6072,6 @@ static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p, mpls_label_t label = 0; #endif uint32_t num_labels = 0; - union gw_addr add; assert(bgp_static); @@ -6119,12 +6094,17 @@ static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p, } } if (afi == AFI_L2VPN) { - if (bgp_static->gatewayIp.family == AF_INET) - add.ipv4.s_addr = - bgp_static->gatewayIp.u.prefix4.s_addr; - else if (bgp_static->gatewayIp.family == AF_INET6) - memcpy(&(add.ipv6), &(bgp_static->gatewayIp.u.prefix6), - sizeof(struct in6_addr)); + if (bgp_static->gatewayIp.family == AF_INET) { + SET_IPADDR_V4(&attr.evpn_overlay.gw_ip); + memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v4, + &bgp_static->gatewayIp.u.prefix4, + IPV4_MAX_BYTELEN); + } else if (bgp_static->gatewayIp.family == AF_INET6) { + SET_IPADDR_V6(&attr.evpn_overlay.gw_ip); + memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v6, + &bgp_static->gatewayIp.u.prefix6, + IPV6_MAX_BYTELEN); + } memcpy(&attr.esi, bgp_static->eth_s_id, sizeof(esi_t)); if (bgp_static->encap_tunneltype == BGP_ENCAP_TYPE_VXLAN) { struct bgp_encap_type_vxlan bet; @@ -6173,9 +6153,7 @@ static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p, break; if (pi) { - memset(&add, 0, sizeof(union gw_addr)); if (attrhash_cmp(pi->attr, attr_new) - && overlay_index_equal(afi, pi, &add) && !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) { bgp_dest_unlock_node(dest); bgp_attr_unintern(&attr_new); @@ -9519,10 +9497,7 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p, const struct bgp_route_evpn *eo = bgp_attr_get_evpn_overlay(attr); - if (is_evpn_prefix_ipaddr_v4((struct prefix_evpn *)p)) - inet_ntop(AF_INET, &eo->gw_ip.ipv4, buf, BUFSIZ); - else if (is_evpn_prefix_ipaddr_v6((struct prefix_evpn *)p)) - inet_ntop(AF_INET6, &eo->gw_ip.ipv6, buf, BUFSIZ); + ipaddr2str(&eo->gw_ip, buf, BUFSIZ); if (!json_path) vty_out(vty, "/%s", buf); @@ -9935,12 +9910,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, && attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) { char gwip_buf[INET6_ADDRSTRLEN]; - if (is_evpn_prefix_ipaddr_v4((struct prefix_evpn *)&bn->p)) - inet_ntop(AF_INET, &attr->evpn_overlay.gw_ip.ipv4, - gwip_buf, sizeof(gwip_buf)); - else - inet_ntop(AF_INET6, &attr->evpn_overlay.gw_ip.ipv6, - gwip_buf, sizeof(gwip_buf)); + ipaddr2str(&attr->evpn_overlay.gw_ip, gwip_buf, + sizeof(gwip_buf)); if (json_paths) json_object_string_add(json_path, "gatewayIP", @@ -10725,10 +10696,26 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, str, label2vni(&attr->label)); } + if (path->peer->t_gr_restart && + CHECK_FLAG(path->flags, BGP_PATH_STALE)) { + unsigned long gr_remaining = + thread_timer_remain_second(path->peer->t_gr_restart); + + if (json_paths) { + json_object_int_add(json_path, + "gracefulRestartSecondsRemaining", + gr_remaining); + } else + vty_out(vty, + " Time until Graceful Restart stale route deleted: %lu\n", + gr_remaining); + } + if (path->peer->t_llgr_stale[afi][safi] && attr->community && community_include(attr->community, COMMUNITY_LLGR_STALE)) { unsigned long llgr_remaining = thread_timer_remain_second( path->peer->t_llgr_stale[afi][safi]); + if (json_paths) { json_object_int_add(json_path, "llgrSecondsRemaining", llgr_remaining); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e07883865a..e3f1abe748 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9430,7 +9430,7 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name, /* one clear bgp command to rule them all */ DEFUN (clear_ip_bgp_all, clear_ip_bgp_all_cmd, - "clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|(1-4294967295)|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out>]", + "clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|(1-4294967295)|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out|message-stats>]", CLEAR_STR IP_STR BGP_STR @@ -9452,7 +9452,8 @@ DEFUN (clear_ip_bgp_all, BGP_SOFT_OUT_STR BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n" - BGP_SOFT_OUT_STR) + BGP_SOFT_OUT_STR + "Reset message statistics\n") { char *vrf = NULL; @@ -9509,7 +9510,7 @@ DEFUN (clear_ip_bgp_all, clr_sort = clear_external; } - /* [<soft [<in|out>]|in [prefix-filter]|out>] */ + /* [<soft [<in|out>]|in [prefix-filter]|out|message-stats>] */ if (argv_find(argv, argc, "soft", &idx)) { if (argv_find(argv, argc, "in", &idx) || argv_find(argv, argc, "out", &idx)) @@ -9524,6 +9525,8 @@ DEFUN (clear_ip_bgp_all, : BGP_CLEAR_SOFT_IN; } else if (argv_find(argv, argc, "out", &idx)) { clr_type = BGP_CLEAR_SOFT_OUT; + } else if (argv_find(argv, argc, "message-stats", &idx)) { + clr_type = BGP_CLEAR_MESSAGE_STATS; } else clr_type = BGP_CLEAR_SOFT_NONE; @@ -16547,17 +16550,14 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, /* capability extended-nexthop */ if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_ENHE)) { - if (!peer->conf_if) { - if (CHECK_FLAG(peer->flags_invert, - PEER_FLAG_CAPABILITY_ENHE)) - vty_out(vty, - " no neighbor %s capability extended-nexthop\n", - addr); - else - vty_out(vty, - " neighbor %s capability extended-nexthop\n", - addr); - } + if (CHECK_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE)) + vty_out(vty, + " no neighbor %s capability extended-nexthop\n", + addr); + else if (!peer->conf_if) + vty_out(vty, + " neighbor %s capability extended-nexthop\n", + addr); } /* dont-capability-negotiation */ @@ -17495,7 +17495,20 @@ static struct cmd_node bgp_srv6_node = { static void community_list_vty(void); -static void bgp_ac_neighbor(vector comps, struct cmd_token *token) +static void bgp_ac_peergroup(vector comps, struct cmd_token *token) +{ + struct bgp *bgp; + struct peer_group *group; + struct listnode *lnbgp, *lnpeer; + + for (ALL_LIST_ELEMENTS_RO(bm->bgp, lnbgp, bgp)) { + for (ALL_LIST_ELEMENTS_RO(bgp->group, lnpeer, group)) + vector_set(comps, + XSTRDUP(MTYPE_COMPLETION, group->name)); + } +} + +static void bgp_ac_peer(vector comps, struct cmd_token *token) { struct bgp *bgp; struct peer *peer; @@ -17525,25 +17538,20 @@ static void bgp_ac_neighbor(vector comps, struct cmd_token *token) } } +static void bgp_ac_neighbor(vector comps, struct cmd_token *token) +{ + bgp_ac_peer(comps, token); + + if (token->type == VARIABLE_TKN) + bgp_ac_peergroup(comps, token); +} + static const struct cmd_variable_handler bgp_var_neighbor[] = { {.varname = "neighbor", .completions = bgp_ac_neighbor}, {.varname = "neighbors", .completions = bgp_ac_neighbor}, {.varname = "peer", .completions = bgp_ac_neighbor}, {.completions = NULL}}; -static void bgp_ac_peergroup(vector comps, struct cmd_token *token) -{ - struct bgp *bgp; - struct peer_group *group; - struct listnode *lnbgp, *lnpeer; - - for (ALL_LIST_ELEMENTS_RO(bm->bgp, lnbgp, bgp)) { - for (ALL_LIST_ELEMENTS_RO(bgp->group, lnpeer, group)) - vector_set(comps, XSTRDUP(MTYPE_COMPLETION, - group->name)); - } -} - static const struct cmd_variable_handler bgp_var_peergroup[] = { {.tokenname = "PGNAME", .completions = bgp_ac_peergroup}, {.completions = NULL} }; diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index b592724d27..72e7a936c6 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -7509,6 +7509,34 @@ int peer_ttl_security_hops_unset(struct peer *peer) return ret; } +static void peer_reset_message_stats(struct peer *peer) +{ + if (peer) { + atomic_store_explicit(&peer->open_in, 0, memory_order_relaxed); + atomic_store_explicit(&peer->open_out, 0, memory_order_relaxed); + atomic_store_explicit(&peer->update_in, 0, + memory_order_relaxed); + atomic_store_explicit(&peer->update_out, 0, + memory_order_relaxed); + atomic_store_explicit(&peer->keepalive_in, 0, + memory_order_relaxed); + atomic_store_explicit(&peer->keepalive_out, 0, + memory_order_relaxed); + atomic_store_explicit(&peer->notify_in, 0, + memory_order_relaxed); + atomic_store_explicit(&peer->notify_out, 0, + memory_order_relaxed); + atomic_store_explicit(&peer->refresh_in, 0, + memory_order_relaxed); + atomic_store_explicit(&peer->refresh_out, 0, + memory_order_relaxed); + atomic_store_explicit(&peer->dynamic_cap_in, 0, + memory_order_relaxed); + atomic_store_explicit(&peer->dynamic_cap_out, 0, + memory_order_relaxed); + } +} + /* * If peer clear is invoked in a loop for all peers on the BGP instance, * it may end up freeing the doppelganger, and if this was the next node @@ -7621,6 +7649,10 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi, return BGP_ERR_SOFT_RECONFIG_UNCONFIGURED; } } + + if (stype == BGP_CLEAR_MESSAGE_STATS) + peer_reset_message_stats(peer); + return 0; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 747c185e39..45ccf014f8 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1905,7 +1905,8 @@ enum bgp_clear_type { BGP_CLEAR_SOFT_OUT, BGP_CLEAR_SOFT_IN, BGP_CLEAR_SOFT_BOTH, - BGP_CLEAR_SOFT_IN_ORF_PREFIX + BGP_CLEAR_SOFT_IN_ORF_PREFIX, + BGP_CLEAR_MESSAGE_STATS }; /* Macros. */ @@ -2380,9 +2381,15 @@ static inline bool peer_established(struct peer *peer) return peer->status == Established; } -static inline int peer_dynamic_neighbor(struct peer *peer) +static inline bool peer_dynamic_neighbor(struct peer *peer) { - return (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR)) ? 1 : 0; + return CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR); +} + +static inline bool peer_dynamic_neighbor_no_nsf(struct peer *peer) +{ + return (peer_dynamic_neighbor(peer) && + !CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)); } static inline int peer_cap_enhe(struct peer *peer, afi_t afi, safi_t safi) diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 0fb5fa8482..004b1723ee 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -3392,6 +3392,11 @@ The following are available in the top level *enable* mode: Clear peer using soft reconfiguration in this address-family and sub-address-family. +.. clicmd:: clear bgp [ipv4|ipv6] [unicast] PEER|\* message-stats + + Clear BGP message statistics for a specified peer or for all peers, + optionally filtered by activated address-family and sub-address-family. + The following are available in the ``router bgp`` mode: .. clicmd:: write-quanta (1-64) diff --git a/lib/ipaddr.h b/lib/ipaddr.h index 730c7ce130..a334ea969e 100644 --- a/lib/ipaddr.h +++ b/lib/ipaddr.h @@ -170,6 +170,19 @@ static inline int ipaddr_cmp(const struct ipaddr *a, const struct ipaddr *b) } } +static inline bool ipaddr_is_zero(const struct ipaddr *ip) +{ + switch (ip->ipa_type) { + case IPADDR_NONE: + return true; + case IPADDR_V4: + return ip->ipaddr_v4.s_addr == INADDR_ANY; + case IPADDR_V6: + return IN6_IS_ADDR_UNSPECIFIED(&ip->ipaddr_v6); + } + return true; +} + #ifdef _FRR_ATTRIBUTE_PRINTFRR #pragma FRR printfrr_ext "%pIA" (struct ipaddr *) #endif diff --git a/lib/lib_errors.c b/lib/lib_errors.c index a139b9a14c..acc9a05c33 100644 --- a/lib/lib_errors.c +++ b/lib/lib_errors.c @@ -57,6 +57,12 @@ static struct log_ref ferr_lib_warn[] = { .suggestion = "Gather log data and open an Issue", }, { + .code = EC_LIB_STARVE_THREAD, + .title = "The Event subsystem has detected a thread starvation issue", + .description = "The event subsystem has detected a thread starvation issue. This typically indicates that the system FRR is running on is heavily loaded and this load might be impacting FRR's ability to handle events in a timely fashion", + .suggestion = "Gather log data and open an Issue", + }, + { .code = EC_LIB_NO_THREAD, .title = "The Event subsystem has detected an internal FD problem", .description = "The Event subsystem has detected a file descriptor read/write event without an associated handling function. This is a bug, please collect log data and open an issue.", diff --git a/lib/lib_errors.h b/lib/lib_errors.h index 9f0f58d20b..64ac6c1ceb 100644 --- a/lib/lib_errors.h +++ b/lib/lib_errors.h @@ -46,6 +46,7 @@ enum lib_log_refs { EC_LIB_LINUX_NS, EC_LIB_SLOW_THREAD_CPU, EC_LIB_SLOW_THREAD_WALL, + EC_LIB_STARVE_THREAD, EC_LIB_NO_THREAD, EC_LIB_RMAP_RECURSION_LIMIT, EC_LIB_BACKUP_CONFIG, diff --git a/lib/thread.c b/lib/thread.c index 77e34f48f3..376f61c247 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -787,6 +787,7 @@ static struct thread *thread_get(struct thread_master *m, uint8_t type, thread->arg = arg; thread->yield = THREAD_YIELD_TIME_SLOT; /* default */ thread->ref = NULL; + thread->ignore_timer_late = false; /* * So if the passed in funcname is not what we have @@ -1651,12 +1652,31 @@ static void thread_process_io(struct thread_master *m, unsigned int num) static unsigned int thread_process_timers(struct thread_master *m, struct timeval *timenow) { + struct timeval prev = *timenow; + bool displayed = false; struct thread *thread; unsigned int ready = 0; while ((thread = thread_timer_list_first(&m->timer))) { if (timercmp(timenow, &thread->u.sands, <)) break; + prev = thread->u.sands; + prev.tv_sec += 4; + /* + * If the timer would have popped 4 seconds in the + * past then we are in a situation where we are + * really getting behind on handling of events. + * Let's log it and do the right thing with it. + */ + if (!displayed && !thread->ignore_timer_late && + timercmp(timenow, &prev, >)) { + flog_warn( + EC_LIB_STARVE_THREAD, + "Thread Starvation: %pTHD was scheduled to pop greater than 4s ago", + thread); + displayed = true; + } + thread_timer_list_pop(&m->timer); thread->type = THREAD_READY; thread_list_add_tail(&m->ready, thread); diff --git a/lib/thread.h b/lib/thread.h index 49a70696d0..660f8bd28e 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -126,6 +126,7 @@ struct thread { unsigned long yield; /* yield time in microseconds */ const struct xref_threadsched *xref; /* origin location */ pthread_mutex_t mtx; /* mutex for thread.c functions */ + bool ignore_timer_late; }; #ifdef _FRR_ATTRIBUTE_PRINTFRR @@ -285,6 +286,11 @@ extern bool thread_is_scheduled(struct thread *thread); /* Debug signal mask */ void debug_signals(const sigset_t *sigs); +static inline void thread_ignore_late_timer(struct thread *thread) +{ + thread->ignore_timer_late = true; +} + #ifdef __cplusplus } #endif diff --git a/lib/workqueue.c b/lib/workqueue.c index 2a8326c056..86afe4082e 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -135,10 +135,11 @@ static int work_queue_schedule(struct work_queue *wq, unsigned int delay) /* Schedule timer if there's a delay, otherwise just schedule * as an 'event' */ - if (delay > 0) + if (delay > 0) { thread_add_timer_msec(wq->master, work_queue_run, wq, delay, &wq->thread); - else + thread_ignore_late_timer(wq->thread); + } else thread_add_event(wq->master, work_queue_run, wq, 0, &wq->thread); diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 6588d70208..c169996e01 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2090,8 +2090,7 @@ static struct external_info *ospf_default_external_info(struct ospf *ospf) p.prefix.s_addr = 0; p.prefixlen = 0; - default_ei = ospf_external_info_lookup(ospf, DEFAULT_ROUTE, - ospf->instance, &p); + default_ei = ospf_external_info_lookup(ospf, DEFAULT_ROUTE, 0, &p); if (!default_ei) return NULL; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 3d0804b018..36cb0673e0 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -2223,6 +2223,9 @@ static void ospf_table_reinstall_routes(struct ospf *ospf, { struct route_node *rn; + if (!rt) + return; + for (rn = route_top(rt); rn; rn = route_next(rn)) { struct ospf_route *or; @@ -5939,7 +5942,7 @@ static int show_lsa_summary(struct vty *vty, struct ospf_lsa *lsa, int self, struct as_external_lsa *asel; struct prefix_ipv4 p; - if (lsa != NULL) + if (lsa != NULL) { /* If self option is set, check LSA self flag. */ if (self == 0 || IS_LSA_SELF(lsa)) { @@ -6047,6 +6050,9 @@ static int show_lsa_summary(struct vty *vty, struct ospf_lsa *lsa, int self, vty_out(vty, "\n"); } + return 1; + } + return 0; } @@ -6080,6 +6086,21 @@ static const char * const show_database_desc_json[] = { "asExternalOpaqueLsa", }; +static const char *const show_database_desc_count_json[] = { + "unknownCount", + "routerLinkStatesCount", + "networkLinkStatesCount", + "summaryLinkStatesCount", + "asbrSummaryLinkStatesCount", + "asExternalLinkStatesCount", + "groupMembershipLsaCount", + "nssaExternalLinkStatesCount", + "type8LsaCount", + "linkLocalOpaqueLsaCount", + "areaLocalOpaqueLsaCount", + "asExternalOpaqueLsaCount", +}; + static const char *const show_database_header[] = { "", "Link ID ADV Router Age Seq# CkSum Link count", @@ -6752,6 +6773,7 @@ void show_ip_ospf_database_summary(struct vty *vty, struct ospf *ospf, int self, json_object *json_lsa = NULL; int type; json_object *json_lsa_array = NULL; + uint32_t count; if (json) json_areas = json_object_new_object(); @@ -6761,6 +6783,7 @@ void show_ip_ospf_database_summary(struct vty *vty, struct ospf *ospf, int self, json_area = json_object_new_object(); for (type = OSPF_MIN_LSA; type < OSPF_MAX_LSA; type++) { + count = 0; switch (type) { case OSPF_AS_EXTERNAL_LSA: case OSPF_OPAQUE_AS_LSA: @@ -6797,12 +6820,19 @@ void show_ip_ospf_database_summary(struct vty *vty, struct ospf *ospf, int self, json_lsa); } - show_lsa_summary(vty, lsa, self, - json_lsa); + count += show_lsa_summary( + vty, lsa, self, json_lsa); } if (!json) vty_out(vty, "\n"); + else + json_object_int_add( + json_area, + + show_database_desc_count_json + [type], + count); } } if (json) @@ -6817,6 +6847,7 @@ void show_ip_ospf_database_summary(struct vty *vty, struct ospf *ospf, int self, json_object_object_add(json, "areas", json_areas); for (type = OSPF_MIN_LSA; type < OSPF_MAX_LSA; type++) { + count = 0; switch (type) { case OSPF_AS_EXTERNAL_LSA: case OSPF_OPAQUE_AS_LSA: @@ -6845,11 +6876,17 @@ void show_ip_ospf_database_summary(struct vty *vty, struct ospf *ospf, int self, json_lsa); } - show_lsa_summary(vty, lsa, self, json_lsa); + count += show_lsa_summary(vty, lsa, self, + json_lsa); } if (!json) vty_out(vty, "\n"); + else + json_object_int_add( + json, + show_database_desc_count_json[type], + count); } } diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index a67206d3d6..e2ac777304 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -11272,6 +11272,10 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &no_debug_pim_events_cmd); install_element(CONFIG_NODE, &debug_pim_packets_cmd); install_element(CONFIG_NODE, &no_debug_pim_packets_cmd); + install_element(CONFIG_NODE, &debug_pim_packetdump_send_cmd); + install_element(CONFIG_NODE, &no_debug_pim_packetdump_send_cmd); + install_element(CONFIG_NODE, &debug_pim_packetdump_recv_cmd); + install_element(CONFIG_NODE, &no_debug_pim_packetdump_recv_cmd); install_element(CONFIG_NODE, &debug_pim_trace_cmd); install_element(CONFIG_NODE, &no_debug_pim_trace_cmd); install_element(CONFIG_NODE, &debug_pim_trace_detail_cmd); diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 99d25caffc..81e1ac4e30 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -161,6 +161,11 @@ int pim_debug_config_write(struct vty *vty) ++writes; } + if (PIM_DEBUG_PIM_NHT_RP) { + vty_out(vty, "debug pim nht rp\n"); + ++writes; + } + return writes; } diff --git a/redhat/frr.logrotate b/redhat/frr.logrotate index b488ad08dc..22b2332b7c 100644 --- a/redhat/frr.logrotate +++ b/redhat/frr.logrotate @@ -138,7 +138,7 @@ notifempty missingok postrotate - /bin/kill -USR1 `cat /var/run/frr/static.pid 2> /dev/null` 2> /dev/null || true + /bin/kill -USR1 `cat /var/run/frr/staticd.pid 2> /dev/null` 2> /dev/null || true endscript } diff --git a/tests/topotests/bgp_llgr/r0/bgpd.conf b/tests/topotests/bgp_llgr/r0/bgpd.conf index d93ee193bc..a20e64fa42 100644 --- a/tests/topotests/bgp_llgr/r0/bgpd.conf +++ b/tests/topotests/bgp_llgr/r0/bgpd.conf @@ -4,6 +4,8 @@ router bgp 65000 bgp graceful-restart restart-time 0 bgp long-lived-graceful-restart stale-time 20 neighbor 192.168.0.2 remote-as external + neighbor 192.168.0.2 timers 3 10 + neighbor 192.168.0.2 timers connect 1 address-family ipv4 unicast redistribute connected exit-address-family diff --git a/tests/topotests/bgp_llgr/r1/bgpd.conf b/tests/topotests/bgp_llgr/r1/bgpd.conf index f8c9877730..bf33eebc51 100644 --- a/tests/topotests/bgp_llgr/r1/bgpd.conf +++ b/tests/topotests/bgp_llgr/r1/bgpd.conf @@ -4,6 +4,8 @@ router bgp 65001 bgp graceful-restart restart-time 0 bgp long-lived-graceful-restart stale-time 20 neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 3 10 + neighbor 192.168.1.2 timers connect 1 address-family ipv4 unicast redistribute connected exit-address-family diff --git a/tests/topotests/bgp_llgr/r2/bgpd.conf b/tests/topotests/bgp_llgr/r2/bgpd.conf index ea8e6beef1..6515ef83a0 100644 --- a/tests/topotests/bgp_llgr/r2/bgpd.conf +++ b/tests/topotests/bgp_llgr/r2/bgpd.conf @@ -3,7 +3,16 @@ router bgp 65002 bgp graceful-restart bgp long-lived-graceful-restart stale-time 20 neighbor 192.168.0.1 remote-as external + neighbor 192.168.0.1 timers 3 10 + neighbor 192.168.0.1 timers connect 1 neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 3 10 + neighbor 192.168.1.1 timers connect 1 neighbor 192.168.2.1 remote-as external + neighbor 192.168.2.1 timers 3 10 + neighbor 192.168.2.1 timers connect 1 + neighbor PG peer-group + neighbor PG remote-as external + bgp listen range 192.168.3.0/24 peer-group PG address-family ipv4 unicast neighbor 192.168.1.1 weight 100 diff --git a/tests/topotests/bgp_llgr/r2/zebra.conf b/tests/topotests/bgp_llgr/r2/zebra.conf index 0fa589f3a9..e5e88d4773 100644 --- a/tests/topotests/bgp_llgr/r2/zebra.conf +++ b/tests/topotests/bgp_llgr/r2/zebra.conf @@ -8,3 +8,6 @@ int r2-eth1 int r2-eth2 ip address 192.168.2.2/24 ! +int r2-eth3 + ip address 192.168.3.2/24 +! diff --git a/tests/topotests/bgp_llgr/r3/bgpd.conf b/tests/topotests/bgp_llgr/r3/bgpd.conf index d73fdccb1d..dfe20c1069 100644 --- a/tests/topotests/bgp_llgr/r3/bgpd.conf +++ b/tests/topotests/bgp_llgr/r3/bgpd.conf @@ -4,3 +4,5 @@ router bgp 65003 bgp graceful-restart bgp long-lived-graceful-restart stale-time 20 neighbor 192.168.2.2 remote-as external + neighbor 192.168.2.2 timers 3 10 + neighbor 192.168.2.2 timers connect 1 diff --git a/tests/topotests/bgp_llgr/r4/bgpd.conf b/tests/topotests/bgp_llgr/r4/bgpd.conf new file mode 100644 index 0000000000..49ce387392 --- /dev/null +++ b/tests/topotests/bgp_llgr/r4/bgpd.conf @@ -0,0 +1,13 @@ +router bgp 65004 + bgp router-id 192.168.3.1 + no bgp ebgp-requires-policy + bgp graceful-restart + bgp graceful-restart restart-time 0 + bgp long-lived-graceful-restart stale-time 30 + neighbor 192.168.3.2 remote-as external + neighbor 192.168.3.2 timers 3 10 + neighbor 192.168.3.2 timers connect 1 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_llgr/r4/zebra.conf b/tests/topotests/bgp_llgr/r4/zebra.conf new file mode 100644 index 0000000000..7ec20be8bb --- /dev/null +++ b/tests/topotests/bgp_llgr/r4/zebra.conf @@ -0,0 +1,7 @@ +! +int lo + ip address 172.16.1.2/32 +! +int r4-eth0 + ip address 192.168.3.1/24 +! diff --git a/tests/topotests/bgp_llgr/test_bgp_llgr.py b/tests/topotests/bgp_llgr/test_bgp_llgr.py index df4f401d02..fa57f66400 100644 --- a/tests/topotests/bgp_llgr/test_bgp_llgr.py +++ b/tests/topotests/bgp_llgr/test_bgp_llgr.py @@ -53,7 +53,7 @@ pytestmark = [pytest.mark.bgpd] def build_topo(tgen): - for routern in range(0, 5): + for routern in range(0, 6): tgen.add_router("r{}".format(routern)) switch = tgen.add_switch("s0") @@ -68,6 +68,11 @@ def build_topo(tgen): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r3"]) + # Dynamic neighbor + 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__) @@ -104,14 +109,15 @@ def test_bgp_llgr(): output = json.loads(router.vtysh_cmd("show ip bgp json")) expected = { "routes": { - "172.16.1.1/32": [{"nexthops": [{"ip": "192.168.2.2", "used": True}]}] + "172.16.1.1/32": [{"nexthops": [{"ip": "192.168.2.2", "used": True}]}], + "172.16.1.2/32": [{"nexthops": [{"ip": "192.168.2.2", "used": True}]}], } } return topotest.json_cmp(output, expected) step("Check if we can see 172.16.1.1/32 after initial converge in R3") test_func = functools.partial(_bgp_converge, r3) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Cannot see 172.16.1.1/32 in r3" def _bgp_weight_prefered_route(router): @@ -134,7 +140,7 @@ def test_bgp_llgr(): "Check if we can see 172.16.1.1/32 as best selected due to higher weigth in R2" ) test_func = functools.partial(_bgp_weight_prefered_route, r2) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert ( result is None ), "Prefix 172.16.1.1/32 is not selected as bests path due to weight" @@ -142,14 +148,14 @@ def test_bgp_llgr(): step("Kill bgpd in R1") kill_router_daemons(tgen, "r1", ["bgpd"]) - def _bgp_stale_route(router): - output = json.loads(router.vtysh_cmd("show ip bgp 172.16.1.1/32 json")) + def _bgp_stale_route(router, prefix): + output = json.loads(router.vtysh_cmd("show ip bgp {} json".format(prefix))) expected = {"paths": [{"community": {"string": "llgr-stale"}, "stale": True}]} return topotest.json_cmp(output, expected) step("Check if we can see 172.16.1.1/32 as stale in R2") - test_func = functools.partial(_bgp_stale_route, r2) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + test_func = functools.partial(_bgp_stale_route, r2, "172.16.1.1/32") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Prefix 172.16.1.1/32 is not stale" def _bgp_llgr_depreference_route(router): @@ -170,14 +176,22 @@ def test_bgp_llgr(): step("Check if we can see 172.16.1.1/32 depreferenced due to LLGR_STALE in R2") test_func = functools.partial(_bgp_llgr_depreference_route, r2) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Prefix 172.16.1.1/32 is not depreferenced due to LLGR_STALE" step("Check if we can see 172.16.1.1/32 after R1 was killed in R3") test_func = functools.partial(_bgp_converge, r3) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Cannot see 172.16.1.1/32 in r3" + step("Kill bgpd in R4 (dynamic peer)") + kill_router_daemons(tgen, "r4", ["bgpd"]) + + step("Check if we can see 172.16.1.2/32 after R4 (dynamic peer) was killed") + test_func = functools.partial(_bgp_stale_route, r2, "172.16.1.2/32") + _, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + assert result is None, "Cannot see 172.16.1.2/32 in r2" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/ospf_instance_redistribute/r1/ospf_default_information.json b/tests/topotests/ospf_instance_redistribute/r1/ospf_default_information.json new file mode 100644 index 0000000000..c0f71bb05d --- /dev/null +++ b/tests/topotests/ospf_instance_redistribute/r1/ospf_default_information.json @@ -0,0 +1,33 @@ +{ + "ospfInstance":3, + "routerId":"192.168.100.1", + "areas":{ + }, + "asExternalLinkStates":[ + { + "lsId":"0.0.0.0", + "advertisedRouter":"192.168.100.1", + "sequenceNumber":"80000001", + "metricType":"E2", + "route":"0.0.0.0/0", + "tag":0 + }, + { + "lsId":"4.5.6.7", + "advertisedRouter":"192.168.100.1", + "sequenceNumber":"80000001", + "metricType":"E2", + "route":"4.5.6.7/32", + "tag":0 + }, + { + "lsId":"4.5.6.10", + "advertisedRouter":"192.168.100.1", + "sequenceNumber":"80000001", + "metricType":"E2", + "route":"4.5.6.10/32", + "tag":0 + } + ], + "asExternalLinkStatesCount":3 +} diff --git a/tests/topotests/ospf_instance_redistribute/r1/ospf_instance_lsa.json b/tests/topotests/ospf_instance_redistribute/r1/ospf_instance_lsa.json new file mode 100644 index 0000000000..fc8e349d2e --- /dev/null +++ b/tests/topotests/ospf_instance_redistribute/r1/ospf_instance_lsa.json @@ -0,0 +1,17 @@ +{ + "ospfInstance":3, + "routerId":"192.168.100.1", + "areas":{ + }, + "asExternalLinkStates":[ + { + "lsId":"4.5.6.7", + "advertisedRouter":"192.168.100.1", + "sequenceNumber":"80000001", + "metricType":"E2", + "route":"4.5.6.7/32", + "tag":0 + } + ], + "asExternalLinkStatesCount":1 +} diff --git a/tests/topotests/ospf_instance_redistribute/r1/ospf_instance_lsa2.json b/tests/topotests/ospf_instance_redistribute/r1/ospf_instance_lsa2.json new file mode 100644 index 0000000000..b7d6f7c0c4 --- /dev/null +++ b/tests/topotests/ospf_instance_redistribute/r1/ospf_instance_lsa2.json @@ -0,0 +1,25 @@ +{ + "ospfInstance":3, + "routerId":"192.168.100.1", + "areas":{ + }, + "asExternalLinkStates":[ + { + "lsId":"4.5.6.7", + "advertisedRouter":"192.168.100.1", + "sequenceNumber":"80000001", + "metricType":"E2", + "route":"4.5.6.7/32", + "tag":0 + }, + { + "lsId":"4.5.6.10", + "advertisedRouter":"192.168.100.1", + "sequenceNumber":"80000001", + "metricType":"E2", + "route":"4.5.6.10/32", + "tag":0 + } + ], + "asExternalLinkStatesCount":2 +} diff --git a/tests/topotests/ospf_instance_redistribute/r1/ospfd-3.conf b/tests/topotests/ospf_instance_redistribute/r1/ospfd-3.conf new file mode 100644 index 0000000000..88432fed63 --- /dev/null +++ b/tests/topotests/ospf_instance_redistribute/r1/ospfd-3.conf @@ -0,0 +1,2 @@ +router ospf 3 + redistribute sharp diff --git a/tests/topotests/ospf_instance_redistribute/r1/sharp_installed.json b/tests/topotests/ospf_instance_redistribute/r1/sharp_installed.json new file mode 100644 index 0000000000..c0a1f6ac00 --- /dev/null +++ b/tests/topotests/ospf_instance_redistribute/r1/sharp_installed.json @@ -0,0 +1,13 @@ +{ + "routes":[ + { + "fib":3, + "rib":3, + "fibOffLoaded":0, + "fibTrapped":0, + "type":"sharp" + } + ], + "routesTotal":4, + "routesTotalFib":4 +} diff --git a/tests/topotests/ospf_instance_redistribute/r1/zebra.conf b/tests/topotests/ospf_instance_redistribute/r1/zebra.conf new file mode 100644 index 0000000000..6bb2a65eaf --- /dev/null +++ b/tests/topotests/ospf_instance_redistribute/r1/zebra.conf @@ -0,0 +1,2 @@ +interface lo + ip address 192.168.100.1/24 diff --git a/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py b/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py new file mode 100644 index 0000000000..88c236d7a0 --- /dev/null +++ b/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python + +# +# test_ospf_instance_redistribute.py +# +# Copyright (c) 2022 by +# Nvidia, Inc. +# Donald Sharp +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_ospf_instance_redistribute + +""" + +import os +import re +import sys +import pytest +import json + +pytestmark = [pytest.mark.ospfd, pytest.mark.sharpd] + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from functools import partial + +# Required to instantiate the topology builder class. + +##################################################### +## +## Network Topology Definition +## +##################################################### + + +def build_topo(tgen): + tgen.add_router("r1") + + # Connect r1 and r2 through the eth0 interface + switch = tgen.add_switch("sw1") + switch.add_link(tgen.gears["r1"]) + + +##################################################### +## +## Tests starting +## +##################################################### + + +def setup_module(module): + "Setup topology" + tgen = Topogen(build_topo, module.__name__) + tgen.start_topology() + + # This is a sample of configuration loading. + r1 = tgen.gears["r1"] + r1.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "r1/zebra.conf") + ) + r1.load_config( + TopoRouter.RD_OSPF, os.path.join(CWD, "r1/ospfd-3.conf"), + "-n 3" + ) + r1.load_config( + TopoRouter.RD_SHARP, os.path.join(CWD, "r1/sharpd.conf") + ) + + tgen.start_router() + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def test_install_sharp_instance_routes(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Installing sharp routes") + r1 = tgen.gears["r1"] + r1.vtysh_cmd("sharp install route 4.5.6.7 nexthop 192.168.100.2 1") + r1.vtysh_cmd("sharp install route 4.5.6.8 nexthop 192.168.100.2 1 instance 3") + r1.vtysh_cmd("sharp install route 4.5.6.9 nexthop 192.168.100.3 1 instance 4") + r1.vtysh_cmd("conf\nrouter ospf 3\nredistribute sharp") + + json_file = "{}/r1/sharp_installed.json".format(CWD) + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route summ json", expected) + + logger.info("Ensuring that they exist in the rib/fib") + _, result = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertmsg = '"r1" sharp routes are not installed' + assert result is None, assertmsg + +def test_ospf_instance_redistribute(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Testing that ospf instance 3 has the redistributed sharp route") + r1 = tgen.gears["r1"] + r1.vtysh_cmd("conf\nrouter ospf 3\nredistribute sharp") + + json_file = "{}/r1/ospf_instance_lsa.json".format(CWD) + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf 3 data json", expected) + + _, result = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertmsg = '"r1" ospf instance 3 does not have the proper redistributed routes' + assert result is None, assertmsg + + r1.vtysh_cmd("sharp install route 4.5.6.10 nexthop 192.168.100.2 1") + r1.vtysh_cmd("sharp install route 4.5.6.11 nexthop 192.168.100.2 1 instance 3") + r1.vtysh_cmd("sharp install route 4.5.6.12 nexthop 192.168.100.2 1 instance 4") + + logger.info("Added new sharp routes let's see if we pick up only the .10") + json_file = "{}/r1/ospf_instance_lsa2.json".format(CWD) + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf 3 data json", expected) + + _, result = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertmsg = '"r1" ospf instance 3 does not have the proper redistributed routes' + assert result is None, assertmsg + + +def test_ospf_instance_default_information(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Testing the using default information originate") + r1 = tgen.gears["r1"] + r1.vtysh_cmd("conf\nrouter ospf 3\ndefault-information originate") + + r1.vtysh_cmd("conf\nip route 0.0.0.0/0 192.168.100.2") + json_file = "{}/r1/ospf_default_information.json".format(CWD) + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf 3 data json", expected) + + _, result = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertmsg = '"r1" ospf instance 3 does not properly redistribute the default route' + assert result is None, assertmsg + + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) + diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 1c6c70ae84..141e4074d5 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1761,16 +1761,16 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) desc = (char *)RTA_DATA(tb[IFLA_IFALIAS]); } - /* If VRF, create or update the VRF structure itself. */ - if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) { - netlink_vrf_change(h, tb[IFLA_LINKINFO], ns_id, name); - vrf_id = (vrf_id_t)ifi->ifi_index; - } - /* See if interface is present. */ ifp = if_lookup_by_name_per_ns(zns, name); if (h->nlmsg_type == RTM_NEWLINK) { + /* If VRF, create or update the VRF structure itself. */ + if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) { + netlink_vrf_change(h, tb[IFLA_LINKINFO], ns_id, name); + vrf_id = (vrf_id_t)ifi->ifi_index; + } + if (tb[IFLA_MASTER]) { if (slave_kind && (strcmp(slave_kind, "vrf") == 0) && !vrf_is_backend_netns()) { @@ -2032,6 +2032,10 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) zebra_l2_vxlanif_del(ifp); if_delete_update(ifp); + + /* If VRF, delete the VRF structure itself. */ + if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) + netlink_vrf_change(h, tb[IFLA_LINKINFO], ns_id, name); } return 0; diff --git a/zebra/interface.c b/zebra/interface.c index 8b5dbabb92..534953d903 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -91,9 +91,12 @@ static int if_zebra_speed_update(struct thread *thread) changed = true; } - if (changed || new_speed == UINT32_MAX) + if (changed || new_speed == UINT32_MAX) { thread_add_timer(zrouter.master, if_zebra_speed_update, ifp, 5, &zif->speed_update); + thread_ignore_late_timer(zif->speed_update); + } + return 1; } @@ -187,6 +190,8 @@ static int if_zebra_new_hook(struct interface *ifp) */ thread_add_timer(zrouter.master, if_zebra_speed_update, ifp, 15, &zebra_if->speed_update); + thread_ignore_late_timer(zebra_if->speed_update); + return 0; } @@ -1074,6 +1079,7 @@ void if_up(struct interface *ifp) thread_add_timer(zrouter.master, if_zebra_speed_update, ifp, 0, &zif->speed_update); + thread_ignore_late_timer(zif->speed_update); } /* Interface goes down. We have to manage different behavior of based diff --git a/zebra/redistribute.c b/zebra/redistribute.c index c59ff1bbec..fdd2c8405f 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -94,7 +94,7 @@ static void zebra_redistribute_default(struct zserv *client, vrf_id_t vrf_id) if (CHECK_FLAG(newre->flags, ZEBRA_FLAG_SELECTED)) zsend_redistribute_route( ZEBRA_REDISTRIBUTE_ROUTE_ADD, client, - &rn->p, NULL, newre); + rn, newre); } route_unlock_node(rn); @@ -116,20 +116,17 @@ static void zebra_redistribute(struct zserv *client, int type, for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) RNODE_FOREACH_RE (rn, newre) { - const struct prefix *dst_p, *src_p; - - srcdest_rnode_prefixes(rn, &dst_p, &src_p); - if (IS_ZEBRA_DEBUG_RIB) zlog_debug( - "%s: client %s %pFX(%u) checking: selected=%d, type=%d, distance=%d, metric=%d zebra_check_addr=%d", + "%s: client %s %pRN(%u:%u) checking: selected=%d, type=%d, distance=%d, metric=%d zebra_check_addr=%d", __func__, - zebra_route_string(client->proto), - dst_p, vrf_id, - CHECK_FLAG(newre->flags, - ZEBRA_FLAG_SELECTED), + zebra_route_string(client->proto), rn, + vrf_id, newre->instance, + !!CHECK_FLAG(newre->flags, + ZEBRA_FLAG_SELECTED), newre->type, newre->distance, - newre->metric, zebra_check_addr(dst_p)); + newre->metric, + zebra_check_addr(&rn->p)); if (!CHECK_FLAG(newre->flags, ZEBRA_FLAG_SELECTED)) continue; @@ -137,11 +134,11 @@ static void zebra_redistribute(struct zserv *client, int type, && (newre->type != type || newre->instance != instance))) continue; - if (!zebra_check_addr(dst_p)) + if (!zebra_check_addr(&rn->p)) continue; zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, - client, dst_p, src_p, newre); + client, rn, newre); } } @@ -149,23 +146,25 @@ static void zebra_redistribute(struct zserv *client, int type, * Function to check if prefix is candidate for * redistribute. */ -static bool zebra_redistribute_check(const struct route_entry *re, - struct zserv *client, - const struct prefix *p, int afi) +static bool zebra_redistribute_check(const struct route_node *rn, + const struct route_entry *re, + struct zserv *client) { struct zebra_vrf *zvrf; + afi_t afi; /* Process only if there is valid re */ if (!re) return false; + afi = family2afi(rn->p.family); zvrf = vrf_info_lookup(re->vrf_id); if (re->vrf_id == VRF_DEFAULT && zvrf->table_id != re->table) return false; /* If default route and redistributed */ - if (is_default_prefix(p) - && vrf_bitmap_check(client->redist_default[afi], re->vrf_id)) + if (is_default_prefix(&rn->p) && + vrf_bitmap_check(client->redist_default[afi], re->vrf_id)) return true; /* If redistribute in enabled for zebra route all */ @@ -176,10 +175,13 @@ static bool zebra_redistribute_check(const struct route_entry *re, * If multi-instance then check for route * redistribution for given instance. */ - if (re->instance - && redist_check_instance(&client->mi_redist[afi][re->type], - re->instance)) - return true; + if (re->instance) { + if (redist_check_instance(&client->mi_redist[afi][re->type], + re->instance)) + return true; + else + return false; + } /* If redistribution is enabled for give route type. */ if (vrf_bitmap_check(client->redist[afi][re->type], re->vrf_id)) @@ -190,49 +192,42 @@ static bool zebra_redistribute_check(const struct route_entry *re, /* Either advertise a route for redistribution to registered clients or */ /* withdraw redistribution if add cannot be done for client */ -void redistribute_update(const struct prefix *p, const struct prefix *src_p, +void redistribute_update(const struct route_node *rn, const struct route_entry *re, const struct route_entry *prev_re) { struct listnode *node, *nnode; struct zserv *client; - int afi; if (IS_ZEBRA_DEBUG_RIB) zlog_debug( - "(%u:%u):%pFX: Redist update re %p (%s), old %p (%s)", - re->vrf_id, re->table, p, re, + "(%u:%u):%pRN(%u): Redist update re %p (%s), old %p (%s)", + re->vrf_id, re->table, rn, re->instance, re, zebra_route_string(re->type), prev_re, prev_re ? zebra_route_string(prev_re->type) : "None"); - afi = family2afi(p->family); - if (!afi) { - flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF, - "%s: Unknown AFI/SAFI prefix received", __func__); - return; - } - if (!zebra_check_addr(p)) { + if (!zebra_check_addr(&rn->p)) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug("Redist update filter prefix %pFX", p); + zlog_debug("Redist update filter prefix %pRN", rn); return; } for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { - if (zebra_redistribute_check(re, client, p, afi)) { + if (zebra_redistribute_check(rn, re, client)) { if (IS_ZEBRA_DEBUG_RIB) { zlog_debug( - "%s: client %s %pFX(%u:%u), type=%d, distance=%d, metric=%d", + "%s: client %s %pRN(%u:%u), type=%d, distance=%d, metric=%d", __func__, - zebra_route_string(client->proto), p, + zebra_route_string(client->proto), rn, re->vrf_id, re->table, re->type, re->distance, re->metric); } zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, - client, p, src_p, re); - } else if (zebra_redistribute_check(prev_re, client, p, afi)) + client, rn, re); + } else if (zebra_redistribute_check(rn, prev_re, client)) zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL, - client, p, src_p, prev_re); + client, rn, prev_re); } } @@ -244,13 +239,12 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p, * may have seen a redist for 'old_re', but will not see * the redist for 'new_re'. */ -void redistribute_delete(const struct prefix *p, const struct prefix *src_p, +void redistribute_delete(const struct route_node *rn, const struct route_entry *old_re, const struct route_entry *new_re) { struct listnode *node, *nnode; struct zserv *client; - int afi; vrf_id_t vrfid; if (old_re) @@ -261,27 +255,34 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p, return; if (IS_ZEBRA_DEBUG_RIB) { - zlog_debug("%u:%pFX: Redist del: re %p (%s), new re %p (%s)", - vrfid, p, old_re, - old_re ? zebra_route_string(old_re->type) : "None", - new_re, - new_re ? zebra_route_string(new_re->type) : "None"); - } + uint8_t old_inst, new_inst; + uint32_t table = 0; - afi = family2afi(p->family); - if (!afi) { - flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF, - "%s: Unknown AFI/SAFI prefix received", - __func__); - return; + old_inst = new_inst = 0; + + if (old_re) { + old_inst = old_re->instance; + table = old_re->table; + } + if (new_re) { + new_inst = new_re->instance; + table = new_re->table; + } + + zlog_debug( + "%u:%u%pRN: Redist del: re %p (%u:%s), new re %p (%u:%s)", + vrfid, table, rn, old_re, old_inst, + old_re ? zebra_route_string(old_re->type) : "None", + new_re, new_inst, + new_re ? zebra_route_string(new_re->type) : "None"); } /* Skip invalid (e.g. linklocal) prefix */ - if (!zebra_check_addr(p)) { + if (!zebra_check_addr(&rn->p)) { if (IS_ZEBRA_DEBUG_RIB) { zlog_debug( - "%u:%pFX: Redist del old: skipping invalid prefix", - vrfid, p); + "%u:%pRN: Redist del old: skipping invalid prefix", + vrfid, rn); } return; } @@ -294,13 +295,13 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p, * Skip this client if it will receive an update for the * 'new' re */ - if (zebra_redistribute_check(new_re, client, p, afi)) + if (zebra_redistribute_check(rn, new_re, client)) continue; /* Send a delete for the 'old' re to any subscribed client. */ - if (zebra_redistribute_check(old_re, client, p, afi)) + if (zebra_redistribute_check(rn, old_re, client)) zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL, - client, p, src_p, old_re); + client, rn, old_re); } } @@ -533,14 +534,12 @@ void zebra_interface_address_add_update(struct interface *ifp, { struct listnode *node, *nnode; struct zserv *client; - struct prefix *p; - if (IS_ZEBRA_DEBUG_EVENT) { - p = ifc->address; + if (IS_ZEBRA_DEBUG_EVENT) zlog_debug( "MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %pFX on %s vrf %s(%u)", - p, ifp->name, ifp->vrf->name, ifp->vrf->vrf_id); - } + ifc->address, ifp->name, ifp->vrf->name, + ifp->vrf->vrf_id); if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) flog_warn( @@ -570,14 +569,12 @@ void zebra_interface_address_delete_update(struct interface *ifp, { struct listnode *node, *nnode; struct zserv *client; - struct prefix *p; - if (IS_ZEBRA_DEBUG_EVENT) { - p = ifc->address; + if (IS_ZEBRA_DEBUG_EVENT) zlog_debug( "MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %pFX on %s vrf %s(%u)", - p, ifp->name, ifp->vrf->name, ifp->vrf->vrf_id); - } + ifc->address, ifp->name, ifp->vrf->name, + ifp->vrf->vrf_id); zebra_vxlan_add_del_gw_macip(ifp, ifc->address, 0); diff --git a/zebra/redistribute.h b/zebra/redistribute.h index 2685458f96..ac257d6389 100644 --- a/zebra/redistribute.h +++ b/zebra/redistribute.h @@ -40,8 +40,7 @@ extern void zebra_redistribute_default_add(ZAPI_HANDLER_ARGS); extern void zebra_redistribute_default_delete(ZAPI_HANDLER_ARGS); /* ----------------- */ -extern void redistribute_update(const struct prefix *p, - const struct prefix *src_p, +extern void redistribute_update(const struct route_node *rn, const struct route_entry *re, const struct route_entry *prev_re); /* @@ -52,24 +51,24 @@ extern void redistribute_update(const struct prefix *p, * may have seen a redist for 'old_re', but will not see * the redist for 'new_re'. */ -void redistribute_delete(const struct prefix *p, const struct prefix *src_p, +void redistribute_delete(const struct route_node *rn, const struct route_entry *old_re, const struct route_entry *new_re); -extern void zebra_interface_up_update(struct interface *); -extern void zebra_interface_down_update(struct interface *); +extern void zebra_interface_up_update(struct interface *ifp); +extern void zebra_interface_down_update(struct interface *ifp); -extern void zebra_interface_add_update(struct interface *); -extern void zebra_interface_delete_update(struct interface *); +extern void zebra_interface_add_update(struct interface *ifp); +extern void zebra_interface_delete_update(struct interface *ifp); -extern void zebra_interface_address_add_update(struct interface *, - struct connected *); -extern void zebra_interface_address_delete_update(struct interface *, +extern void zebra_interface_address_add_update(struct interface *ifp, + struct connected *c); +extern void zebra_interface_address_delete_update(struct interface *ifp, struct connected *c); -extern void zebra_interface_parameters_update(struct interface *); -extern void zebra_interface_vrf_update_del(struct interface *, +extern void zebra_interface_parameters_update(struct interface *ifp); +extern void zebra_interface_vrf_update_del(struct interface *ifp, vrf_id_t new_vrf_id); -extern void zebra_interface_vrf_update_add(struct interface *, +extern void zebra_interface_vrf_update_add(struct interface *ifp, vrf_id_t old_vrf_id); extern int zebra_import_table(afi_t afi, vrf_id_t vrf_id, diff --git a/zebra/rib.h b/zebra/rib.h index b7416322f9..a0ec1f0e4f 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -493,6 +493,9 @@ extern uint8_t route_distance(int type); extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq, bool rt_delete); +extern struct route_node * +rib_find_rn_from_ctx(const struct zebra_dplane_ctx *ctx); + /* * Inline functions. */ diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 421438a051..c3d7bcd909 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -546,18 +546,19 @@ int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp) } int zsend_redistribute_route(int cmd, struct zserv *client, - const struct prefix *p, - const struct prefix *src_p, + const struct route_node *rn, const struct route_entry *re) { struct zapi_route api; struct zapi_nexthop *api_nh; struct nexthop *nexthop; + const struct prefix *p, *src_p; uint8_t count = 0; afi_t afi; size_t stream_size = MAX(ZEBRA_MAX_PACKET_SIZ, sizeof(struct zapi_route)); + srcdest_rnode_prefixes(rn, &p, &src_p); memset(&api, 0, sizeof(api)); api.vrf_id = re->vrf_id; api.type = re->type; @@ -742,11 +743,11 @@ int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id, * Common utility send route notification, called from a path using a * route_entry and from a path using a dataplane context. */ -static int route_notify_internal(const struct prefix *p, int type, +static int route_notify_internal(const struct route_node *rn, int type, uint16_t instance, vrf_id_t vrf_id, uint32_t table_id, - enum zapi_route_notify_owner note, - afi_t afi, safi_t safi) + enum zapi_route_notify_owner note, afi_t afi, + safi_t safi) { struct zserv *client; struct stream *s; @@ -756,16 +757,16 @@ static int route_notify_internal(const struct prefix *p, int type, if (!client || !client->notify_owner) { if (IS_ZEBRA_DEBUG_PACKET) zlog_debug( - "Not Notifying Owner: %s about prefix %pFX(%u) %d vrf: %u", - zebra_route_string(type), p, table_id, note, + "Not Notifying Owner: %s about prefix %pRN(%u) %d vrf: %u", + zebra_route_string(type), rn, table_id, note, vrf_id); return 0; } if (IS_ZEBRA_DEBUG_PACKET) zlog_debug( - "Notifying Owner: %s about prefix %pFX(%u) %d vrf: %u", - zebra_route_string(type), p, table_id, note, vrf_id); + "Notifying Owner: %s about prefix %pRN(%u) %d vrf: %u", + zebra_route_string(type), rn, table_id, note, vrf_id); /* We're just allocating a small-ish buffer here, since we only * encode a small amount of data. @@ -778,11 +779,11 @@ static int route_notify_internal(const struct prefix *p, int type, stream_put(s, ¬e, sizeof(note)); - stream_putc(s, p->family); + stream_putc(s, rn->p.family); - blen = prefix_blen(p); - stream_putc(s, p->prefixlen); - stream_put(s, &p->u.prefix, blen); + blen = prefix_blen(&rn->p); + stream_putc(s, rn->p.prefixlen); + stream_put(s, &rn->p.u.prefix, blen); stream_putl(s, table_id); @@ -795,11 +796,12 @@ static int route_notify_internal(const struct prefix *p, int type, return zserv_send_message(client, s); } -int zsend_route_notify_owner(struct route_entry *re, const struct prefix *p, - enum zapi_route_notify_owner note, - afi_t afi, safi_t safi) +int zsend_route_notify_owner(const struct route_node *rn, + struct route_entry *re, + enum zapi_route_notify_owner note, afi_t afi, + safi_t safi) { - return (route_notify_internal(p, re->type, re->instance, re->vrf_id, + return (route_notify_internal(rn, re->type, re->instance, re->vrf_id, re->table, note, afi, safi)); } @@ -809,14 +811,11 @@ int zsend_route_notify_owner(struct route_entry *re, const struct prefix *p, int zsend_route_notify_owner_ctx(const struct zebra_dplane_ctx *ctx, enum zapi_route_notify_owner note) { - return (route_notify_internal(dplane_ctx_get_dest(ctx), - dplane_ctx_get_type(ctx), - dplane_ctx_get_instance(ctx), - dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), - note, - dplane_ctx_get_afi(ctx), - dplane_ctx_get_safi(ctx))); + return (route_notify_internal( + rib_find_rn_from_ctx(ctx), dplane_ctx_get_type(ctx), + dplane_ctx_get_instance(ctx), dplane_ctx_get_vrf(ctx), + dplane_ctx_get_table(ctx), note, dplane_ctx_get_afi(ctx), + dplane_ctx_get_safi(ctx))); } static void zread_route_notify_request(ZAPI_HANDLER_ARGS) @@ -2093,6 +2092,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__); nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); + XFREE(MTYPE_OPAQUE, re->opaque); XFREE(MTYPE_RE, re); return; } @@ -2105,6 +2105,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__, api.safi); nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); + XFREE(MTYPE_OPAQUE, re->opaque); XFREE(MTYPE_RE, re); return; } @@ -2133,6 +2134,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) */ if (ret == -1) { client->error_cnt++; + XFREE(MTYPE_OPAQUE, re->opaque); XFREE(MTYPE_RE, re); } diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index dad40c200d..b3fe7318f9 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -65,8 +65,7 @@ extern void nbr_connected_delete_ipv6(struct interface *ifp, extern int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp); extern int zsend_redistribute_route(int cmd, struct zserv *zclient, - const struct prefix *p, - const struct prefix *src_p, + const struct route_node *rn, const struct route_entry *re); extern int zsend_router_id_update(struct zserv *zclient, afi_t afi, @@ -76,8 +75,8 @@ extern int zsend_interface_vrf_update(struct zserv *zclient, extern int zsend_interface_link_params(struct zserv *zclient, struct interface *ifp); extern int zsend_pw_update(struct zserv *client, struct zebra_pw *pw); -extern int zsend_route_notify_owner(struct route_entry *re, - const struct prefix *p, +extern int zsend_route_notify_owner(const struct route_node *rn, + struct route_entry *re, enum zapi_route_notify_owner note, afi_t afi, safi_t safi); extern int zsend_route_notify_owner_ctx(const struct zebra_dplane_ctx *ctx, diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 1279c7c9a9..1374b932ae 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -575,7 +575,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, * know that they've lost */ if (old && (old != re) && (old->type != re->type)) - zsend_route_notify_owner(old, p, ZAPI_ROUTE_BETTER_ADMIN_WON, + zsend_route_notify_owner(rn, old, ZAPI_ROUTE_BETTER_ADMIN_WON, info->afi, info->safi); /* Update fib selection */ @@ -745,9 +745,9 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq, if (IS_ZEBRA_DEBUG_NHT_DETAILED) zlog_debug( - "%s(%u):%pRN has Nexthop(%pFX) depending on it, evaluating %u:%u", - zvrf_name(zvrf), zvrf_id(zvrf), rn, p, - seq, rnh->seqno); + "%s(%u):%pRN has Nexthop(%pRN) depending on it, evaluating %u:%u", + zvrf_name(zvrf), zvrf_id(zvrf), rn, + rnh->node, seq, rnh->seqno); /* * If we have evaluated this node on this pass @@ -1088,9 +1088,7 @@ static void rib_process(struct route_node *rn) rib_dest_t *dest; struct zebra_vrf *zvrf = NULL; struct vrf *vrf; - const struct prefix *p, *src_p; - srcdest_rnode_prefixes(rn, &p, &src_p); vrf_id_t vrf_id = VRF_UNKNOWN; assert(rn); @@ -1194,9 +1192,9 @@ static void rib_process(struct route_node *rn) info = srcdest_rnode_table_info(rn); srcdest_rnode_prefixes(rn, &p, NULL); - zsend_route_notify_owner(re, p, - ZAPI_ROUTE_FAIL_INSTALL, - info->afi, info->safi); + zsend_route_notify_owner( + rn, re, ZAPI_ROUTE_FAIL_INSTALL, + info->afi, info->safi); continue; } } else { @@ -1288,8 +1286,7 @@ static void rib_process(struct route_node *rn) */ if (!new_selected || CHECK_FLAG(old_selected->status, ROUTE_ENTRY_REMOVED)) - redistribute_delete(p, src_p, - old_selected, + redistribute_delete(rn, old_selected, new_selected); if (old_selected != new_selected) @@ -1758,8 +1755,7 @@ done: * when processing dplane results, e.g. Note well: the route-node is returned * with a ref held - route_unlock_node() must be called eventually. */ -static struct route_node * -rib_find_rn_from_ctx(const struct zebra_dplane_ctx *ctx) +struct route_node *rib_find_rn_from_ctx(const struct zebra_dplane_ctx *ctx) { struct route_table *table = NULL; struct route_node *rn = NULL; @@ -1806,7 +1802,6 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) bool is_update = false; enum dplane_op_e op; enum zebra_dplane_result status; - const struct prefix *dest_pfx, *src_pfx; uint32_t seq; rib_dest_t *dest; bool fib_changed = false; @@ -1815,22 +1810,19 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) zvrf = vrf_info_lookup(dplane_ctx_get_vrf(ctx)); vrf = vrf_lookup_by_id(dplane_ctx_get_vrf(ctx)); - dest_pfx = dplane_ctx_get_dest(ctx); /* Locate rn and re(s) from ctx */ rn = rib_find_rn_from_ctx(ctx); if (rn == NULL) { if (IS_ZEBRA_DEBUG_DPLANE) { zlog_debug( - "Failed to process dplane results: no route for %s(%u):%pFX", - VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dest_pfx); + "Failed to process dplane results: no route for %s(%u):%pRN", + VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), rn); } goto done; } dest = rib_dest_from_rnode(rn); - srcdest_rnode_prefixes(rn, &dest_pfx, &src_pfx); info = srcdest_rnode_table_info(rn); op = dplane_ctx_get_op(ctx); @@ -1838,10 +1830,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) zlog_debug( - "%s(%u:%u):%pFX Processing dplane result ctx %p, op %s result %s", + "%s(%u:%u):%pRN Processing dplane result ctx %p, op %s result %s", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), dest_pfx, ctx, - dplane_op2str(op), dplane_res2str(status)); + dplane_ctx_get_table(ctx), rn, ctx, dplane_op2str(op), + dplane_res2str(status)); /* * Update is a bit of a special case, where we may have both old and new @@ -1880,9 +1872,9 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) if (re->dplane_sequence != seq) { if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) zlog_debug( - "%s(%u):%pFX Stale dplane result for re %p", + "%s(%u):%pRN Stale dplane result for re %p", VRF_LOGNAME(vrf), - dplane_ctx_get_vrf(ctx), dest_pfx, re); + dplane_ctx_get_vrf(ctx), rn, re); } else { if (!zrouter.asic_offloaded || (CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOADED) || @@ -1895,10 +1887,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) if (old_re->dplane_sequence != dplane_ctx_get_old_seq(ctx)) { if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) zlog_debug( - "%s(%u:%u):%pFX Stale dplane result for old_re %p", + "%s(%u:%u):%pRN Stale dplane result for old_re %p", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), old_re->table, - dest_pfx, old_re); + rn, old_re); } else UNSET_FLAG(old_re->status, ROUTE_ENTRY_QUEUED); } @@ -1936,18 +1928,17 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) if (!fib_changed) { if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) zlog_debug( - "%s(%u:%u):%pFX no fib change for re", + "%s(%u:%u):%pRN no fib change for re", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), dplane_ctx_get_table( ctx), - dest_pfx); + rn); } /* Redistribute if this is the selected re */ if (dest && re == dest->selected_fib) - redistribute_update(dest_pfx, src_pfx, - re, old_re); + redistribute_update(rn, re, old_re); } /* @@ -1989,13 +1980,13 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) } if (old_re) SET_FLAG(old_re->status, ROUTE_ENTRY_FAILED); if (re) - zsend_route_notify_owner(re, dest_pfx, - ZAPI_ROUTE_FAIL_INSTALL, - info->afi, info->safi); + zsend_route_notify_owner( + rn, re, ZAPI_ROUTE_FAIL_INSTALL, + info->afi, info->safi); - zlog_warn("%s(%u:%u):%pFX: Route install failed", + zlog_warn("%s(%u:%u):%pRN: Route install failed", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), dest_pfx); + dplane_ctx_get_table(ctx), rn); } break; case DPLANE_OP_ROUTE_DELETE: @@ -2022,9 +2013,9 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_REMOVE_FAIL); - zlog_warn("%s(%u:%u):%pFX: Route Deletion failure", + zlog_warn("%s(%u:%u):%pRN: Route Deletion failure", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), dest_pfx); + dplane_ctx_get_table(ctx), rn); } /* @@ -2099,12 +2090,11 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) struct route_entry *re = NULL; struct vrf *vrf; struct nexthop *nexthop; - const struct prefix *dest_pfx, *src_pfx; rib_dest_t *dest; bool fib_changed = false; bool debug_p = IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_RIB; int start_count, end_count; - dest_pfx = dplane_ctx_get_dest(ctx); + vrf = vrf_lookup_by_id(dplane_ctx_get_vrf(ctx)); /* Locate rn and re(s) from ctx */ @@ -2112,20 +2102,19 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) if (rn == NULL) { if (debug_p) { zlog_debug( - "Failed to process dplane notification: no routes for %s(%u:%u):%pFX", + "Failed to process dplane notification: no routes for %s(%u:%u):%pRN", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), dest_pfx); + dplane_ctx_get_table(ctx), rn); } goto done; } dest = rib_dest_from_rnode(rn); - srcdest_rnode_prefixes(rn, &dest_pfx, &src_pfx); if (debug_p) - zlog_debug("%s(%u:%u):%pFX Processing dplane notif ctx %p", + zlog_debug("%s(%u:%u):%pRN Processing dplane notif ctx %p", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), dest_pfx, ctx); + dplane_ctx_get_table(ctx), rn, ctx); /* * Take a pass through the routes, look for matches with the context @@ -2140,9 +2129,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) if (re == NULL) { if (debug_p) zlog_debug( - "%s(%u:%u):%pFX Unable to process dplane notification: no entry for type %s", + "%s(%u:%u):%pRN Unable to process dplane notification: no entry for type %s", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), dest_pfx, + dplane_ctx_get_table(ctx), rn, zebra_route_string(dplane_ctx_get_type(ctx))); goto done; @@ -2175,20 +2164,20 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); if (debug_p) zlog_debug( - "%s(%u:%u):%pFX dplane notif, uninstalled type %s route", + "%s(%u:%u):%pRN dplane notif, uninstalled type %s route", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), dest_pfx, + dplane_ctx_get_table(ctx), rn, zebra_route_string( dplane_ctx_get_type(ctx))); } else { /* At least report on the event. */ if (debug_p) zlog_debug( - "%s(%u:%u):%pFX dplane notif, but type %s not selected_fib", + "%s(%u:%u):%pRN dplane notif, but type %s not selected_fib", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), dest_pfx, + dplane_ctx_get_table(ctx), rn, zebra_route_string( dplane_ctx_get_type(ctx))); } @@ -2212,9 +2201,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) if (!fib_changed) { if (debug_p) zlog_debug( - "%s(%u:%u):%pFX dplane notification: rib_update returns FALSE", + "%s(%u:%u):%pRN dplane notification: rib_update returns FALSE", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), dest_pfx); + dplane_ctx_get_table(ctx), rn); } /* @@ -2229,9 +2218,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) if (start_count > 0 && end_count > 0) { if (debug_p) zlog_debug( - "%s(%u:%u):%pFX applied nexthop changes from dplane notification", + "%s(%u:%u):%pRN applied nexthop changes from dplane notification", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), dest_pfx); + dplane_ctx_get_table(ctx), rn); /* Changed nexthops - update kernel/others */ dplane_route_notif_update(rn, re, @@ -2240,9 +2229,9 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) } else if (start_count == 0 && end_count > 0) { if (debug_p) zlog_debug( - "%s(%u:%u):%pFX installed transition from dplane notification", + "%s(%u:%u):%pRN installed transition from dplane notification", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), dest_pfx); + dplane_ctx_get_table(ctx), rn); /* We expect this to be the selected route, so we want * to tell others about this transition. @@ -2253,14 +2242,14 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) dplane_route_notif_update(rn, re, DPLANE_OP_ROUTE_UPDATE, ctx); /* Redistribute, lsp, and nht update */ - redistribute_update(dest_pfx, src_pfx, re, NULL); + redistribute_update(rn, re, NULL); } else if (start_count > 0 && end_count == 0) { if (debug_p) zlog_debug( - "%s(%u:%u):%pFX un-installed transition from dplane notification", + "%s(%u:%u):%pRN un-installed transition from dplane notification", VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx), dest_pfx); + dplane_ctx_get_table(ctx), rn); /* Transition from _something_ installed to _nothing_ * installed. @@ -2274,7 +2263,7 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) dplane_route_notif_update(rn, re, DPLANE_OP_ROUTE_DELETE, ctx); /* Redistribute, lsp, and nht update */ - redistribute_delete(dest_pfx, src_pfx, re, NULL); + redistribute_delete(rn, re, NULL); } /* Make any changes visible for lsp and nexthop-tracking processing */ @@ -3522,8 +3511,8 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, else src_buf[0] = '\0'; - zlog_debug("%s[%d]:%pFX%s%s doesn't exist in rib", - vrf->name, table_id, p, + zlog_debug("%s[%d]:%pRN%s%s doesn't exist in rib", + vrf->name, table_id, rn, (src_buf[0] != '\0') ? " from " : "", src_buf); } |
