diff options
149 files changed, 1480 insertions, 986 deletions
diff --git a/Makefile.am b/Makefile.am index 0dff83e505..e4149b62ed 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,9 +1,10 @@ ## Process this file with automake to produce Makefile.in. AUTOMAKE_OPTIONS = subdir-objects 1.12 -ACLOCAL_AMFLAGS = -I m4 +ACLOCAL_AMFLAGS = -I m4 -Wall,no-override AM_CFLAGS = \ + $(AC_CFLAGS) \ $(LIBYANG_CFLAGS) \ $(SQLITE3_CFLAGS) \ $(UNWIND_CFLAGS) \ @@ -12,7 +13,7 @@ AM_CFLAGS = \ # end AM_CPPFLAGS = \ -I$(top_srcdir) -I$(top_srcdir)/include -I$(top_srcdir)/lib \ - -I$(top_builddir) -I$(top_builddir)/include -I$(top_builddir)/lib \ + -I$(top_builddir) \ $(LUA_INCLUDE) \ # end AM_LDFLAGS = \ diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 71ac356585..df1998c4fc 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -28,7 +28,7 @@ THE SOFTWARE. #include "thread.h" #include "privs.h" #include "sigevent.h" -#include "version.h" +#include "lib/version.h" #include "command.h" #include "vty.h" #include "memory.h" diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index 958d7cf0ed..6004070e68 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -308,8 +308,6 @@ void bgp_peer_configure_bfd(struct peer *p, bool manual) if (p->nexthop.ifp) bfd_sess_set_interface(p->bfd_config->session, p->nexthop.ifp->name); - - bfd_sess_enable(p->bfd_config->session, true); } static void bgp_peer_remove_bfd(struct peer *p) diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 0e5f506b3a..abe97571c5 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -34,7 +34,7 @@ #include "lib_errors.h" #include "stream.h" #include "libfrr.h" -#include "version.h" +#include "lib/version.h" #include "jhash.h" #include "termtable.h" diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 7f6f61e141..923c9b0d7e 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -1294,15 +1294,19 @@ bool ecommunity_del_val(struct ecommunity *ecom, struct ecommunity_val *eval) /* Delete the selected value */ ecom->size--; - p = XMALLOC(MTYPE_ECOMMUNITY_VAL, ecom->size * ecom->unit_size); - if (c != 0) - memcpy(p, ecom->val, c * ecom->unit_size); - if ((ecom->size - c) != 0) - memcpy(p + (c)*ecom->unit_size, - ecom->val + (c + 1) * ecom->unit_size, - (ecom->size - c) * ecom->unit_size); - XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val); - ecom->val = p; + if (ecom->size) { + p = XMALLOC(MTYPE_ECOMMUNITY_VAL, ecom->size * ecom->unit_size); + if (c != 0) + memcpy(p, ecom->val, c * ecom->unit_size); + if ((ecom->size - c) != 0) + memcpy(p + (c)*ecom->unit_size, + ecom->val + (c + 1) * ecom->unit_size, + (ecom->size - c) * ecom->unit_size); + XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val); + ecom->val = p; + } else + ecom->val = NULL; + return true; } diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 45a856a459..6bcb31e652 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -101,7 +101,7 @@ static int bgp_delayopen_timer(struct thread *); static int bgp_start(struct peer *); /* Register peer with NHT */ -static int bgp_peer_reg_with_nht(struct peer *peer) +int bgp_peer_reg_with_nht(struct peer *peer) { int connected = 0; @@ -294,7 +294,6 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) } FOREACH_AFI_SAFI (afi, safi) { - peer->af_flags[afi][safi] = from_peer->af_flags[afi][safi]; peer->af_sflags[afi][safi] = from_peer->af_sflags[afi][safi]; peer->af_cap[afi][safi] = from_peer->af_cap[afi][safi]; peer->afc_nego[afi][safi] = from_peer->afc_nego[afi][safi]; @@ -340,6 +339,8 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) * needed, even on a passive connection. */ bgp_peer_reg_with_nht(peer); + if (from_peer) + bgp_replace_nexthop_by_peer(from_peer, peer); bgp_reads_on(peer); bgp_writes_on(peer); diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index bcf697e153..12cbad3eb8 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -179,4 +179,5 @@ const char *print_peer_gr_mode(enum peer_mode pr_mode); const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd); const char *print_global_gr_mode(enum global_mode gl_mode); const char *print_global_gr_cmd(enum global_gr_command gl_gr_cmd); +int bgp_peer_reg_with_nht(struct peer *peer); #endif /* _QUAGGA_BGP_FSM_H */ diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 62fed931f9..eb68d84c06 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -540,6 +540,17 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ if (bpi) { bool labelssame = labels_same(bpi, label, num_labels); + if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED) + && CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { + if (debug) { + zlog_debug( + "%s: ->%s(s_flags: 0x%x b_flags: 0x%x): %pFX: Found route, being removed, not leaking", + __func__, bgp->name_pretty, + source_bpi->flags, bpi->flags, p); + } + return NULL; + } + if (attrhash_cmp(bpi->attr, new_attr) && labelssame && !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { @@ -613,6 +624,16 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ return bpi; } + if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED)) { + if (debug) { + zlog_debug( + "%s: ->%s(s_flags: 0x%x): %pFX: New route, being removed, not leaking", + __func__, bgp->name_pretty, + source_bpi->flags, p); + } + return NULL; + } + new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0, bgp->peer_self, new_attr, bn); @@ -1027,6 +1048,8 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */ if (debug) zlog_debug("%s: deleting it", __func__); + /* withdraw from leak-to vrfs as well */ + vpn_leak_to_vrf_withdraw(bgp_vpn, bpi); bgp_aggregate_decrement( bgp_vpn, bgp_dest_get_prefix(bn), bpi, @@ -1101,7 +1124,10 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ if (!ecom_intersect( bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN], path_vpn->attr->ecommunity)) { - + if (debug) + zlog_debug( + "from vpn to vrf %s, skipping after no intersection of route targets", + bgp_vrf->name_pretty); return; } @@ -1532,7 +1558,8 @@ void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw, bool is_config) { afi_t afi; - int debug; + int debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) + | BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); char *vname; const char *export_name; char buf[RD_ADDRSTRLEN]; @@ -1541,14 +1568,23 @@ void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw, struct ecommunity *ecom; vpn_policy_direction_t idir, edir; + /* + * Router-id change that is not explicitly configured + * (a change from zebra, frr restart for example) + * should not replace a configured vpn RD/RT. + */ + if (!is_config) { + if (debug) + zlog_debug("%s: skipping non explicit router-id change", + __func__); + return; + } + if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT && bgp->inst_type != BGP_INSTANCE_TYPE_VRF) return; export_name = bgp->name ? bgp->name : VRF_DEFAULT_NAME; - debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) | - BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); - idir = BGP_VPN_POLICY_DIR_FROMVPN; edir = BGP_VPN_POLICY_DIR_TOVPN; @@ -1574,26 +1610,12 @@ void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw, if (!bgp_import) continue; - ecommunity_del_val(bgp_import->vpn_policy[afi]. - rtlist[idir], + ecommunity_del_val( + bgp_import->vpn_policy[afi] + .rtlist[idir], (struct ecommunity_val *)ecom->val); - } } else { - /* - * Router-id changes that are not explicit config - * changes should not replace configured RD/RT. - */ - if (!is_config) { - if (CHECK_FLAG(bgp->vpn_policy[afi].flags, - BGP_VPN_POLICY_TOVPN_RD_SET)) { - if (debug) - zlog_debug("%s: auto router-id change skipped", - __func__); - goto postchange; - } - } - /* New router-id derive auto RD and RT and export * to VPN */ @@ -1624,10 +1646,8 @@ void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw, else bgp_import->vpn_policy[afi].rtlist[idir] = ecommunity_dup(ecom); - } -postchange: /* Update routes to VPN */ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi, bgp_get_default(), diff --git a/bgpd/bgp_mplsvpn_snmp.c b/bgpd/bgp_mplsvpn_snmp.c index 6f75856d54..7a2f618ce6 100644 --- a/bgpd/bgp_mplsvpn_snmp.c +++ b/bgpd/bgp_mplsvpn_snmp.c @@ -32,7 +32,7 @@ #include "filter.h" #include "hook.h" #include "libfrr.h" -#include "version.h" +#include "lib/version.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" diff --git a/bgpd/bgp_nb_config.c b/bgpd/bgp_nb_config.c index 5a88bd08d9..94ff362d1a 100644 --- a/bgpd/bgp_nb_config.c +++ b/bgpd/bgp_nb_config.c @@ -123,7 +123,12 @@ int bgp_router_create(struct nb_cb_create_args *args) if (is_new_bgp && inst_type == BGP_INSTANCE_TYPE_DEFAULT) vpn_leak_postchange_all(); - if (inst_type == BGP_INSTANCE_TYPE_VRF) + /* + * Check if we need to export to other VRF(s). + * Leak the routes to importing bgp vrf instances, + * only when new bgp vrf instance is configured. + */ + if (ret != BGP_INSTANCE_EXISTS) bgp_vpn_leak_export(bgp); UNSET_FLAG(bgp->vrf_flags, BGP_VRF_AUTO); diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 4821ce8ddb..8d9024e07c 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -569,6 +569,7 @@ static int bgp_accept(struct thread *thread) peer1->doppelganger = peer; peer->fd = bgp_sock; vrf_bind(peer->bgp->vrf_id, bgp_sock, bgp_get_bound_name(peer)); + bgp_peer_reg_with_nht(peer); bgp_fsm_change_status(peer, Active); BGP_TIMER_OFF(peer->t_start); /* created in peer_create() */ diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 9c8d7878c5..dc2b0b679b 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -60,13 +60,15 @@ static int bgp_nht_ifp_initial(struct thread *thread); static int bgp_isvalid_nexthop(struct bgp_nexthop_cache *bnc) { return (bgp_zebra_num_connects() == 0 - || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID))); + || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) + && bnc->nexthop_num > 0)); } static int bgp_isvalid_labeled_nexthop(struct bgp_nexthop_cache *bnc) { return (bgp_zebra_num_connects() == 0 - || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID))); + || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) + && bnc->nexthop_num > 0)); } static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc) @@ -98,6 +100,31 @@ void bgp_unlink_nexthop(struct bgp_path_info *path) bgp_unlink_nexthop_check(bnc); } +void bgp_replace_nexthop_by_peer(struct peer *from, struct peer *to) +{ + struct prefix pp; + struct prefix pt; + struct bgp_nexthop_cache *bncp, *bnct; + afi_t afi; + + if (!sockunion2hostprefix(&from->su, &pp)) + return; + + afi = family2afi(pp.family); + bncp = bnc_find(&from->bgp->nexthop_cache_table[afi], &pp, 0); + + if (!sockunion2hostprefix(&to->su, &pt)) + return; + + bnct = bnc_find(&to->bgp->nexthop_cache_table[afi], &pt, 0); + + if (bnct != bncp) + return; + + if (bnct) + bnct->nht_info = to; +} + void bgp_unlink_nexthop_by_peer(struct peer *peer) { struct prefix p; @@ -273,8 +300,16 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, (bgp_path_info_extra_get(pi))->igpmetric = bnc->metric; else if (pi->extra) pi->extra->igpmetric = 0; - } else if (peer) - bnc->nht_info = (void *)peer; /* NHT peer reference */ + } else if (peer) { + /* + * Let's not accidently save the peer data for a peer + * we are going to throw away in a second or so. + * When we come back around we'll fix up this + * data properly in replace_nexthop_by_peer + */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) + bnc->nht_info = (void *)peer; /* NHT peer reference */ + } /* * We are cheating here. Views have no associated underlying @@ -444,6 +479,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, bnc->nexthop = nhlist_head; } else { bnc->flags &= ~BGP_NEXTHOP_VALID; + bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; bnc->nexthop_num = nhr->nexthop_num; /* notify bgp fsm if nbr ip goes from valid->invalid */ diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h index a1683e1511..9268b225ca 100644 --- a/bgpd/bgp_nht.h +++ b/bgpd/bgp_nht.h @@ -51,7 +51,7 @@ extern int bgp_find_or_add_nexthop(struct bgp *bgp_route, */ extern void bgp_unlink_nexthop(struct bgp_path_info *p); void bgp_unlink_nexthop_by_peer(struct peer *peer); - +void bgp_replace_nexthop_by_peer(struct peer *from, struct peer *to); /** * bgp_delete_connected_nexthop() - Reset the 'peer' pointer for a connected * nexthop entry. If no paths reference the nexthop, it will be unregistered diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 321397c3af..49b94e6d7c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -10260,7 +10260,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, "\n"); /* Line 4 display Community */ - if (attr->community) { + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) { if (json_paths) { if (!attr->community->json) community_str(attr->community, true); diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index bb85ad393d..816ed88eec 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -57,7 +57,7 @@ #endif #include "hook.h" #include "libfrr.h" -#include "version.h" +#include "lib/version.h" #ifndef VTYSH_EXTRACT_PL #include "bgpd/bgp_rpki_clippy.c" diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 3afdbea908..61a6467ab6 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -32,7 +32,7 @@ #include "filter.h" #include "hook.h" #include "libfrr.h" -#include "version.h" +#include "lib/version.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index d1912db01f..ae0bf7fe92 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1700,9 +1700,6 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type, redist_add_instance(&zclient->mi_redist[afi][type], instance); } else { - if (vrf_bitmap_check(zclient->redist[afi][type], bgp->vrf_id)) - return CMD_WARNING; - #ifdef ENABLE_BGP_VNC if (EVPN_ENABLED(bgp) && type == ZEBRA_ROUTE_VNC_DIRECT) { vnc_export_bgp_enable( diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d37b9fa48c..bad62f9946 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3402,7 +3402,7 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name, return ret; case BGP_SUCCESS: if (*bgp_val) - return ret; + return BGP_INSTANCE_EXISTS; } bgp = bgp_create(as, name, inst_type); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 51134dc8c5..f9aa62c682 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1844,6 +1844,7 @@ enum bgp_clear_type { /* BGP error codes. */ #define BGP_SUCCESS 0 #define BGP_CREATED 1 +#define BGP_INSTANCE_EXISTS 2 #define BGP_ERR_INVALID_VALUE -1 #define BGP_ERR_INVALID_FLAG -2 #define BGP_ERR_INVALID_AS -3 diff --git a/bgpd/rfp-example/rfptest/subdir.am b/bgpd/rfp-example/rfptest/subdir.am index 9f6d33a855..1b5024a30b 100644 --- a/bgpd/rfp-example/rfptest/subdir.am +++ b/bgpd/rfp-example/rfptest/subdir.am @@ -6,7 +6,10 @@ if ENABLE_BGP_VNC noinst_PROGRAMS += bgpd/rfp-example/rfptest/rfptest endif -bgpd_rfp_example_rfptest_rfptest_CFLAGS = -I$(top_srcdir)/bgpd/rfapi +bgpd_rfp_example_rfptest_rfptest_CFLAGS = \ + $(AM_CFLAGS) \ + -I$(top_srcdir)/bgpd/rfapi \ + # end bgpd_rfp_example_rfptest_rfptest_SOURCES = \ bgpd/rfp-example/rfptest/rfptest.c \ # end diff --git a/bgpd/subdir.am b/bgpd/subdir.am index 07e71ba601..2c73f14594 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -211,20 +211,17 @@ noinst_HEADERS += \ bgpd_bgpd_SOURCES = bgpd/bgp_main.c bgpd_bgp_btoa_SOURCES = bgpd/bgp_btoa.c -bgpd_bgpd_CFLAGS = $(AM_CFLAGS) -bgpd_bgp_btoa_CFLAGS = $(AM_CFLAGS) - # RFPLDADD is set in bgpd/rfp-example/librfp/subdir.am bgpd_bgpd_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBCAP) $(LIBM) $(UST_LIBS) bgpd_bgp_btoa_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBCAP) $(LIBM) $(UST_LIBS) bgpd_bgpd_snmp_la_SOURCES = bgpd/bgp_snmp.c bgpd/bgp_mplsvpn_snmp.c -bgpd_bgpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 +bgpd_bgpd_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11 bgpd_bgpd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic bgpd_bgpd_snmp_la_LIBADD = lib/libfrrsnmp.la bgpd_bgpd_rpki_la_SOURCES = bgpd/bgp_rpki.c -bgpd_bgpd_rpki_la_CFLAGS = $(WERROR) $(RTRLIB_CFLAGS) +bgpd_bgpd_rpki_la_CFLAGS = $(AM_CFLAGS) $(RTRLIB_CFLAGS) bgpd_bgpd_rpki_la_LDFLAGS = -avoid-version -module -shared -export-dynamic bgpd_bgpd_rpki_la_LIBADD = $(RTRLIB_LIBS) diff --git a/bootstrap.sh b/bootstrap.sh index c0b95d3dd0..212e7d1d45 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -4,4 +4,4 @@ # and so that those used to the presence of bootstrap.sh or autogen.sh # will have an eaiser time. -autoreconf -i +exec autoreconf -is -Wall,no-override diff --git a/configure.ac b/configure.ac index f9516e559f..a770a78105 100755..100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,7 @@ ## Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro <kunihiro@zebra.org> ## Portions Copyright (c) 2003 Paul Jakma <paul@dishone.st> ## -AC_PREREQ([2.60]) +AC_PREREQ([2.69]) AC_INIT([frr], [7.7-dev], [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" @@ -18,6 +18,7 @@ AC_SUBST([CONFIG_ARGS]) AC_CONFIG_SRCDIR([lib/zebra.h]) AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([m4/ac]) dnl ----------------------------------- dnl Get hostname and other information. @@ -205,6 +206,7 @@ AC_SUBST([SED]) dnl try and enable CFLAGS that are useful for FRR dnl - specifically, options to control warnings +AC_SUBST([AC_CFLAGS]) AC_USE_SYSTEM_EXTENSIONS AC_DEFUN([AC_C_FLAG], [{ m4_pushdef([cachename],[m4_translit([frr_cv_$1],[ =-+/{}$],[________])]) @@ -223,7 +225,7 @@ AC_DEFUN([AC_C_FLAG], [{ AC_LANG_POP([C]) ]) if test "$cachename" = "yes"; then - m4_if([$3], [], [CFLAGS="$CFLAGS $1"], [$3]) + m4_if([$3], [], [AC_CFLAGS="$AC_CFLAGS $1"], [$3]) else : $2 @@ -275,7 +277,7 @@ if test "$enable_gcov" = "yes"; then AC_C_FLAG([-O0]) fi - LDFLAGS="${LDFLAGS} -lgcov" + AC_LDFLAGS="${AC_LDFLAGS} -lgcov" fi if test "$enable_clang_coverage" = "yes"; then @@ -302,17 +304,19 @@ if test "$enable_scripting" = "yes"; then ]) fi +dnl the following flags go in CFLAGS rather than AC_CFLAGS since they make +dnl sense to be overridden by the user if test "$enable_dev_build" = "yes"; then AC_DEFINE([DEV_BUILD], [1], [Build for development]) if test "$orig_cflags" = ""; then - AC_C_FLAG([-g3]) - AC_C_FLAG([-O0]) - AC_C_FLAG([-ggdb3]) + AC_C_FLAG([-O0],,[CFLAGS="$CFLAGS -O0"]) + AC_C_FLAG([-g3],,[CFLAGS="$CFLAGS -g3"]) + AC_C_FLAG([-ggdb3],,[CFLAGS="$CFLAGS -ggdb3"]) fi else if test "$orig_cflags" = ""; then - AC_C_FLAG([-g]) - AC_C_FLAG([-O2]) + AC_C_FLAG([-g],,[CFLAGS="$CFLAGS -g"]) + AC_C_FLAG([-O2],,[CFLAGS="$CFLAGS -O2"]) fi fi @@ -449,7 +453,7 @@ dnl ---------- AX_PTHREAD([ CC="$PTHREAD_CC" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + AC_CFLAGS="$AC_CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" ], [ AC_MSG_FAILURE([This FRR version needs pthreads]) @@ -969,7 +973,7 @@ dnl ------------------------- dnl Check other header files. dnl ------------------------- AC_CHECK_HEADERS([stropts.h sys/ksym.h \ - linux/version.h asm/types.h]) + linux/version.h asm/types.h endian.h sys/endian.h]) ac_stdatomic_ok=false AC_DEFINE([FRR_AUTOCONF_ATOMIC], [1], [did autoconf checks for atomic funcs]) @@ -1262,11 +1266,6 @@ if test "$enable_realms" = "yes"; then esac fi -dnl ------------------------------- -dnl Endian-ness check -dnl ------------------------------- -AC_WORDS_BIGENDIAN - dnl --------------- dnl other functions dnl --------------- @@ -1521,24 +1520,22 @@ FRR_INCLUDES #endif ])dnl -AC_MSG_CHECKING([for BSD struct ip_mreq hack]) -AC_TRY_COMPILE([#include <sys/param.h>], -[#if (defined(__FreeBSD__) && ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) || (defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ >= 106010000) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__DragonFly__) || defined(__sun) - return (0); -#else - #error No support for BSD struct ip_mreq hack detected -#endif],[AC_MSG_RESULT([yes]) -AC_DEFINE([HAVE_BSD_STRUCT_IP_MREQ_HACK], [1], [Can pass ifindex in struct ip_mreq])], -AC_MSG_RESULT([no])) - AC_MSG_CHECKING([for RFC3678 protocol-independed API]) -AC_TRY_COMPILE([ -#include <sys/types.h> -#include <netinet/in.h> -], [struct group_req gr; int sock; setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void*)&gr, sizeof(gr)); -], [AC_MSG_RESULT([yes]) -AC_DEFINE([HAVE_RFC3678], [1], [Have RFC3678 protocol-independed API])], -AC_MSG_RESULT([no])) +AC_COMPILE_IFELSE( +[ AC_LANG_PROGRAM([[ + #include <sys/types.h> + #include <netinet/in.h> + ]], [[ + struct group_req gr; + int sock; + setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void*)&gr, sizeof(gr)); + ]]) +],[ + AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_RFC3678], [1], [Have RFC3678 protocol-independed API]) +],[ + AC_MSG_RESULT(no) +]) dnl --------------------------------------------------------------- dnl figure out how to check link-state @@ -2135,12 +2132,16 @@ dnl ----------------------- dnl checking for IP_PKTINFO dnl ----------------------- AC_MSG_CHECKING([for IP_PKTINFO]) -AC_TRY_COMPILE([#include <netdb.h>], [ - int opt = IP_PKTINFO; -], [ +AC_COMPILE_IFELSE( +[ AC_LANG_PROGRAM([[ + #include <netdb.h> + ]], [[ + int opt = IP_PKTINFO; + ]]) +],[ AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_IP_PKTINFO], [1], [Have IP_PKTINFO]) -], [ +],[ AC_MSG_RESULT([no]) ]) @@ -2148,12 +2149,16 @@ dnl --------------------------- dnl checking for IP_RECVDSTADDR dnl --------------------------- AC_MSG_CHECKING([for IP_RECVDSTADDR]) -AC_TRY_COMPILE([#include <netinet/in.h>], [ - int opt = IP_RECVDSTADDR; -], [ +AC_COMPILE_IFELSE( +[ AC_LANG_PROGRAM([[ + #include <netinet/in.h> + ]], [[ + int opt = IP_RECVDSTADDR; + ]]) +],[ AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_IP_RECVDSTADDR], [1], [Have IP_RECVDSTADDR]) -], [ +],[ AC_MSG_RESULT([no]) ]) @@ -2161,12 +2166,16 @@ dnl ---------------------- dnl checking for IP_RECVIF dnl ---------------------- AC_MSG_CHECKING([for IP_RECVIF]) -AC_TRY_COMPILE([#include <netinet/in.h>], [ - int opt = IP_RECVIF; -], [ +AC_COMPILE_IFELSE( +[ AC_LANG_PROGRAM([[ + #include <netinet/in.h> + ]], [[ + int opt = IP_RECVIF; + ]]) +],[ AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_IP_RECVIF], [1], [Have IP_RECVIF]) -], [ +],[ AC_MSG_RESULT([no]) ]) @@ -2174,12 +2183,16 @@ dnl ---------------------- dnl checking for SO_BINDANY dnl ---------------------- AC_MSG_CHECKING([for SO_BINDANY]) -AC_TRY_COMPILE([#include <sys/socket.h>], [ - int opt = SO_BINDANY; -], [ +AC_COMPILE_IFELSE( +[ AC_LANG_PROGRAM([[ + #include <sys/socket.h> + ]], [[ + int opt = SO_BINDANY; + ]]) +],[ AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_SO_BINDANY], [1], [Have SO_BINDANY]) -], [ +],[ AC_MSG_RESULT([no]) ]) @@ -2187,20 +2200,30 @@ dnl ---------------------- dnl checking for IP_FREEBIND dnl ---------------------- AC_MSG_CHECKING([for IP_FREEBIND]) -AC_TRY_COMPILE([#include <netinet/in.h>], [ - int opt = IP_FREEBIND; -], [ +AC_COMPILE_IFELSE( +[ AC_LANG_PROGRAM([[ + #include <netinet/in.h> + ]], [[ + int opt = IP_FREEBIND; + ]]) +],[ AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_IP_FREEBIND], [1], [Have IP_FREEBIND]) -], [ +],[ AC_MSG_RESULT([no]) ]) dnl -------------------------------------- dnl checking for be32dec existence or not dnl -------------------------------------- -AC_CHECK_DECLS([be32enc, be32dec], [], [], - [#include <sys/endian.h>]) +AC_CHECK_DECLS([be32enc, be32dec], [], [], [ + #ifdef HAVE_SYS_ENDIAN_H + #include <sys/endian.h> + #endif + #ifdef HAVE_ENDIAN_H + #include <endian.h> + #endif +]) dnl -------------------------------------- dnl checking for clock_time monotonic struct and call @@ -2288,12 +2311,17 @@ dnl capabilities checks dnl ------------------- if test "$enable_capabilities" != "no"; then AC_MSG_CHECKING([whether prctl PR_SET_KEEPCAPS is available]) - AC_TRY_COMPILE([#include <sys/prctl.h>], [prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);], - [AC_MSG_RESULT([yes]) + AC_COMPILE_IFELSE( + [ AC_LANG_PROGRAM([[ + #include <sys/prctl.h> + ]], [[ + prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); + ]]) + ],[AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_PR_SET_KEEPCAPS], [1], [prctl]) - frr_ac_keepcaps="yes"], - AC_MSG_RESULT([no]) - ) + frr_ac_keepcaps="yes" + ],[AC_MSG_RESULT(no) + ]) if test "$frr_ac_keepcaps" = "yes"; then AC_CHECK_HEADERS([sys/capability.h]) fi @@ -2652,7 +2680,7 @@ FRR version : ${PACKAGE_VERSION} host operating system : ${host_os} source code location : ${srcdir} compiler : ${CC} -compiler flags : ${CFLAGS} ${SAN_FLAGS} +compiler flags : ${CFLAGS} ${AC_CFLAGS} ${SAN_FLAGS} make : ${MAKE-make} linker flags : ${LDFLAGS} ${SAN_FLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM} state file directory : ${frr_statedir} diff --git a/doc/user/Useful_Sysctl_Settings.md b/doc/user/Useful_Sysctl_Settings.md index 4244b5fdfb..eaf97b969c 100644 --- a/doc/user/Useful_Sysctl_Settings.md +++ b/doc/user/Useful_Sysctl_Settings.md @@ -37,6 +37,7 @@ net.ipv4.icmp_errors_use_inbound_ifaddr=1 # Keep ipv6 permanent addresses on an admin down net.ipv6.conf.all.keep_addr_on_down=1 +net.ipv6.route.skip_notify_on_dev_down=1 # igmp net.ipv4.igmp_max_memberships=1000 diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index 6f797f7cc1..99c024d118 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -326,12 +326,15 @@ OSPF6 BFD Configuration The following commands are available inside the interface configuration node. -.. clicmd:: ipv6 ospf6 bfd +.. clicmd:: ipv6 ospf6 bfd [profile BFDPROF] Listen for BFD events on peers created on the interface. Every time a new neighbor is found a BFD peer is created to monitor the link status for fast convergence. + Optionally uses the BFD profile ``BFDPROF`` in the created sessions under + that interface. + .. _bfd-pim-peer-config: @@ -340,12 +343,15 @@ PIM BFD Configuration The following commands are available inside the interface configuration node. -.. clicmd:: ip pim bfd +.. clicmd:: ip pim bfd [profile BFDPROF] Listen for BFD events on peers created on the interface. Every time a new neighbor is found a BFD peer is created to monitor the link status for fast convergence. + Optionally uses the BFD profile ``BFDPROF`` in the created sessions under + that interface. + .. _bfd-configuration: diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 205b25e53e..ac1686dd27 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -463,6 +463,78 @@ be updated with the new name. To illustrate, if you want to recompile with ./configure --with-defaultvrfname=global +.. _zebra-ecmp: + +ECMP +==== + +FRR supports ECMP as part of normal operations and is generally compiled +with a limit of 64 way ECMP. This of course can be modified via configure +options on compilation if the end operator desires to do so. Individual +protocols each have their own way of dictating ECMP policy and their +respective documentation should be read. + +ECMP can be inspected in zebra by doing a `show ip route X` command. + +.. code-block:: shell + + eva# show ip route 4.4.4.4/32 + Codes: K - kernel route, C - connected, S - static, R - RIP, + O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP, + F - PBR, f - OpenFabric, + > - selected route, * - FIB route, q - queued, r - rejected, b - backup + t - trapped, o - offload failure + + D>* 4.4.4.4/32 [150/0] via 192.168.161.1, enp39s0, weight 1, 00:00:02 + * via 192.168.161.2, enp39s0, weight 1, 00:00:02 + * via 192.168.161.3, enp39s0, weight 1, 00:00:02 + * via 192.168.161.4, enp39s0, weight 1, 00:00:02 + * via 192.168.161.5, enp39s0, weight 1, 00:00:02 + * via 192.168.161.6, enp39s0, weight 1, 00:00:02 + * via 192.168.161.7, enp39s0, weight 1, 00:00:02 + * via 192.168.161.8, enp39s0, weight 1, 00:00:02 + * via 192.168.161.9, enp39s0, weight 1, 00:00:02 + * via 192.168.161.10, enp39s0, weight 1, 00:00:02 + * via 192.168.161.11, enp39s0, weight 1, 00:00:02 + * via 192.168.161.12, enp39s0, weight 1, 00:00:02 + * via 192.168.161.13, enp39s0, weight 1, 00:00:02 + * via 192.168.161.14, enp39s0, weight 1, 00:00:02 + * via 192.168.161.15, enp39s0, weight 1, 00:00:02 + * via 192.168.161.16, enp39s0, weight 1, 00:00:02 + +In this example we have 16 way ecmp for the 4.4.4.4/32 route. The `*` character +tells us that the route is installed in the Data Plane, or FIB. + +If you are using the Linux kernel as a Data Plane, this can be inspected +via a `ip route show X` command: + +.. code-block:: shell + + sharpd@eva ~/f/doc(ecmp_doc_change)> ip route show 4.4.4.4/32 + 4.4.4.4 nhid 185483868 proto sharp metric 20 + nexthop via 192.168.161.1 dev enp39s0 weight 1 + nexthop via 192.168.161.10 dev enp39s0 weight 1 + nexthop via 192.168.161.11 dev enp39s0 weight 1 + nexthop via 192.168.161.12 dev enp39s0 weight 1 + nexthop via 192.168.161.13 dev enp39s0 weight 1 + nexthop via 192.168.161.14 dev enp39s0 weight 1 + nexthop via 192.168.161.15 dev enp39s0 weight 1 + nexthop via 192.168.161.16 dev enp39s0 weight 1 + nexthop via 192.168.161.2 dev enp39s0 weight 1 + nexthop via 192.168.161.3 dev enp39s0 weight 1 + nexthop via 192.168.161.4 dev enp39s0 weight 1 + nexthop via 192.168.161.5 dev enp39s0 weight 1 + nexthop via 192.168.161.6 dev enp39s0 weight 1 + nexthop via 192.168.161.7 dev enp39s0 weight 1 + nexthop via 192.168.161.8 dev enp39s0 weight 1 + nexthop via 192.168.161.9 dev enp39s0 weight 1 + +Once installed into the FIB, FRR currently has little control over what +nexthops are choosen to forward packets on. Currently the Linux kernel +has a `fib_multipath_hash_policy` sysctl which dictates how the hashing +algorithm is used to forward packets. + .. _zebra-mpls: MPLS Commands @@ -1021,6 +1093,35 @@ For protocols requiring an IPv6 router-id, the following commands are available: Display the user configured IPv6 router-id. +Expected sysctl settings +======================== + +The linux kernel has a variety of sysctl's that affect it's operation as a router. This +section is meant to act as a starting point for those sysctl's that must be used in +order to provide FRR with smooth operation as a router. This section is not meant +as the full documentation for sysctl's. The operator must use the sysctl documentation +with the linux kernel for that. + +.. option:: net.ipv4.ip_forward = 1 + + This option allows the linux kernel to forward ipv4 packets incoming from one interface + to an outgoing interface. Without this no forwarding will take place from off box packets. + +.. option:: net.ipv6.conf.all_forwarding=1 + + This option allows the linux kernel to forward ipv6 packets incoming from one interface + to an outgoing interface. Without this no forwarding will take place from off box packets. + +.. option:: net.ipv6.conf.all.keep_addr_on_down=1 + + When an interface is taken down, do not remove the v6 addresses associated with the interface. + This option is recommended because this is the default behavior for v4 as well. + +.. option:: net.ipv6.route.skip_notify_on_dev_down=1 + + When an interface is taken down, the linux kernel will not notify, via netlink, about routes + that used that interface being removed from the FIB. This option is recommended because this + is the default behavior for v4 as well. Debugging ========= diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index 56ac1c0d00..cb2b3eb69e 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -56,4 +56,4 @@ RUN apk add \ --allow-untrusted /pkgs/apk/*/*.apk \ && rm -rf /pkgs COPY docker/alpine/docker-start /usr/lib/frr/docker-start -ENTRYPOINT [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ] +CMD [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ] diff --git a/docker/centos-7/Dockerfile b/docker/centos-7/Dockerfile index a92326fcf3..d2ec9f974b 100644 --- a/docker/centos-7/Dockerfile +++ b/docker/centos-7/Dockerfile @@ -40,4 +40,4 @@ COPY --from=centos-7-builder /rpmbuild/RPMS/ /pkgs/rpm/ RUN yum install -y /pkgs/rpm/*/*.rpm \ && rm -rf /pkgs COPY docker/centos-7/docker-start /usr/lib/frr/docker-start -ENTRYPOINT [ "/usr/lib/frr/docker-start" ] +CMD [ "/usr/lib/frr/docker-start" ] diff --git a/docker/centos-8/Dockerfile b/docker/centos-8/Dockerfile index 7ed7948927..104501aabc 100644 --- a/docker/centos-8/Dockerfile +++ b/docker/centos-8/Dockerfile @@ -41,4 +41,4 @@ COPY --from=centos-8-builder /rpmbuild/RPMS/ /pkgs/rpm/ RUN yum install -y /pkgs/rpm/*/*.rpm \ && rm -rf /pkgs COPY docker/centos-8/docker-start /usr/lib/frr/docker-start -ENTRYPOINT [ "/usr/lib/frr/docker-start" ] +CMD [ "/usr/lib/frr/docker-start" ] diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile index 3f830348bc..cc9217f103 100644 --- a/docker/debian/Dockerfile +++ b/docker/debian/Dockerfile @@ -17,4 +17,4 @@ RUN apt-get update && \ rm -rf /var/lib/apt/lists/* ADD docker-start /usr/sbin/docker-start -ENTRYPOINT ["/usr/sbin/docker-start"] +CMD ["/usr/sbin/docker-start"] diff --git a/docker/debian/docker-start b/docker/debian/docker-start index 43854ab142..a0f31f5ac5 100755 --- a/docker/debian/docker-start +++ b/docker/debian/docker-start @@ -7,4 +7,6 @@ set -e ## chown -R frr:frr /etc/frr /etc/init.d/frr start -exec sleep 10000d + +# Sleep forever +exec tail -f /dev/null diff --git a/docker/ubuntu18-ci/Dockerfile b/docker/ubuntu18-ci/Dockerfile index ac745c60a8..f6fa910381 100644 --- a/docker/ubuntu18-ci/Dockerfile +++ b/docker/ubuntu18-ci/Dockerfile @@ -68,4 +68,4 @@ RUN cd ~/frr && \ RUN cd ~/frr && make check || true COPY docker/ubuntu18-ci/docker-start /usr/sbin/docker-start -ENTRYPOINT ["/usr/sbin/docker-start"] +CMD ["/usr/sbin/docker-start"] diff --git a/docker/ubuntu20-ci/Dockerfile b/docker/ubuntu20-ci/Dockerfile index 56657789ee..0b08c2f278 100644 --- a/docker/ubuntu20-ci/Dockerfile +++ b/docker/ubuntu20-ci/Dockerfile @@ -71,4 +71,4 @@ RUN cd ~/frr && \ RUN cd ~/frr && make check || true COPY docker/ubuntu20-ci/docker-start /usr/sbin/docker-start -ENTRYPOINT ["/usr/sbin/docker-start"] +CMD ["/usr/sbin/docker-start"] diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c index 13a2c4206f..e3680b31a3 100644 --- a/eigrpd/eigrp_hello.c +++ b/eigrpd/eigrp_hello.c @@ -125,6 +125,10 @@ eigrp_hello_parameter_decode(struct eigrp_neighbor *nbr, struct eigrp *eigrp = nbr->ei->eigrp; struct TLV_Parameter_Type *param = (struct TLV_Parameter_Type *)tlv; + /* First validate TLV length */ + if (tlv->length < sizeof(struct TLV_Parameter_Type)) + return NULL; + /* copy over the values passed in by the neighbor */ nbr->K1 = param->K1; nbr->K2 = param->K2; @@ -194,13 +198,22 @@ eigrp_hello_authentication_decode(struct stream *s, md5 = (struct TLV_MD5_Authentication_Type *)tlv_header; - if (md5->auth_type == EIGRP_AUTH_TYPE_MD5) + if (md5->auth_type == EIGRP_AUTH_TYPE_MD5) { + /* Validate tlv length */ + if (md5->length < sizeof(struct TLV_MD5_Authentication_Type)) + return 0; + return eigrp_check_md5_digest(s, md5, nbr, EIGRP_AUTH_BASIC_HELLO_FLAG); - else if (md5->auth_type == EIGRP_AUTH_TYPE_SHA256) + } else if (md5->auth_type == EIGRP_AUTH_TYPE_SHA256) { + /* Validate tlv length */ + if (md5->length < sizeof(struct TLV_SHA256_Authentication_Type)) + return 0; + return eigrp_check_sha256_digest( s, (struct TLV_SHA256_Authentication_Type *)tlv_header, nbr, EIGRP_AUTH_BASIC_HELLO_FLAG); + } return 0; } @@ -223,6 +236,10 @@ static void eigrp_sw_version_decode(struct eigrp_neighbor *nbr, { struct TLV_Software_Type *version = (struct TLV_Software_Type *)tlv; + /* Validate TLV length */ + if (tlv->length < sizeof(struct TLV_Software_Type)) + return; + nbr->os_rel_major = version->vender_major; nbr->os_rel_minor = version->vender_minor; nbr->tlv_rel_major = version->eigrp_major; @@ -250,6 +267,10 @@ static void eigrp_peer_termination_decode(struct eigrp_neighbor *nbr, struct TLV_Peer_Termination_type *param = (struct TLV_Peer_Termination_type *)tlv; + /* Validate TLV length */ + if (tlv->length < sizeof(struct TLV_Peer_Termination_type)) + return; + uint32_t my_ip = nbr->ei->address.u.prefix4.s_addr; uint32_t received_ip = param->neighbor_ip; @@ -346,6 +367,10 @@ void eigrp_hello_receive(struct eigrp *eigrp, struct ip *iph, type = ntohs(tlv_header->type); length = ntohs(tlv_header->length); + /* Validate length against packet size */ + if (length > size) + return; + if ((length > 0) && (length <= size)) { if (IS_DEBUG_EIGRP_PACKET(0, RECV)) zlog_debug( diff --git a/fpm/fpm_pb.h b/fpm/fpm_pb.h index 2e265511f2..659b5a64ac 100644 --- a/fpm/fpm_pb.h +++ b/fpm/fpm_pb.h @@ -29,7 +29,7 @@ #ifndef _FPM_PB_H #define _FPM_PB_H -#include "route_types.h" +#include "lib/route_types.h" #include "qpb/qpb.h" #include "fpm/fpm.pb-c.h" diff --git a/grpc/subdir.am b/grpc/subdir.am index 045848aee7..d9ec365ba8 100644 --- a/grpc/subdir.am +++ b/grpc/subdir.am @@ -23,12 +23,12 @@ EXTRA_DIST += grpc/frr-northbound.proto AM_V_PROTOC = $(am__v_PROTOC_$(V)) am__v_PROTOC_ = $(am__v_PROTOC_$(AM_DEFAULT_VERBOSITY)) -am__v_PROTOC_0 = @echo " PROTOC" $@; +am__v_PROTOC_0 = @echo " PROTOC " $@; am__v_PROTOC_1 = SUFFIXES += .pb.h .pb.cc .grpc.pb.cc .proto.pb.cc: - $(AM_V_PROTOC)$(PROTOC) -I$(top_srcdir) --cpp_out=$(top_srcdir) $(top_srcdir)/$^ + $(AM_V_PROTOC)$(PROTOC) -I$(top_srcdir) --cpp_out=$(top_builddir) $^ .proto.grpc.pb.cc: - $(AM_V_PROTOC)$(PROTOC) -I$(top_srcdir) --grpc_out=$(top_srcdir) --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` $(top_srcdir)/$^ + $(AM_V_PROTOC)$(PROTOC) -I$(top_srcdir) --grpc_out=$(top_builddir) --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` $^ diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index cbe4040b64..d4c7baea1a 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -31,6 +31,7 @@ #include "isis_constants.h" #include "isis_common.h" +#include "isis_csm.h" DECLARE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp)); @@ -77,7 +78,7 @@ struct isis_circuit_arg { }; struct isis_circuit { - int state; + enum isis_circuit_state state; uint8_t circuit_id; /* l1/l2 bcast CircuitID */ time_t last_uptime; struct isis *isis; diff --git a/isisd/isis_csm.c b/isisd/isis_csm.c index 736d8d63f9..ebb68ba3f0 100644 --- a/isisd/isis_csm.c +++ b/isisd/isis_csm.c @@ -60,12 +60,14 @@ static const char *const csm_eventstr[] = { #define EVENT2STR(E) csm_eventstr[E] -struct isis_circuit * -isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) +struct isis_circuit *isis_csm_state_change(enum isis_circuit_event event, + struct isis_circuit *circuit, + void *arg) { - int old_state; + enum isis_circuit_state old_state; struct isis *isis = NULL; struct isis_area *area = NULL; + struct interface *ifp; old_state = circuit ? circuit->state : C_STATE_NA; if (IS_DEBUG_EVENTS) @@ -85,23 +87,29 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) circuit->state = C_STATE_CONF; break; case IF_UP_FROM_Z: - isis = isis_lookup_by_vrfid(((struct interface *)arg)->vrf_id); + ifp = arg; + isis = isis_lookup_by_vrfid(ifp->vrf_id); if (isis == NULL) { - zlog_warn( - " %s : ISIS routing instance not found", - __func__); + if (IS_DEBUG_EVENTS) + zlog_debug( + " %s : ISIS routing instance not found when attempting to apply against interface %s", + __func__, ifp->name); break; } circuit = isis_circuit_new(isis); - isis_circuit_if_add(circuit, (struct interface *)arg); + isis_circuit_if_add(circuit, ifp); listnode_add(isis->init_circ_list, circuit); circuit->state = C_STATE_INIT; break; case ISIS_DISABLE: - zlog_warn("circuit already disabled"); + if (IS_DEBUG_EVENTS) + zlog_debug( + "circuit disable event passed for a non existent circuit"); break; case IF_DOWN_FROM_Z: - zlog_warn("circuit already disconnected"); + if (IS_DEBUG_EVENTS) + zlog_debug( + "circuit disconnect event passed for a non existent circuit"); break; } break; @@ -123,11 +131,14 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) circuit); break; case IF_UP_FROM_Z: - assert(circuit); - zlog_warn("circuit already connected"); + if (IS_DEBUG_EVENTS) + zlog_debug("circuit %s already connected", + circuit->interface->name); break; case ISIS_DISABLE: - zlog_warn("circuit already disabled"); + if (IS_DEBUG_EVENTS) + zlog_debug("circuit %s already disabled", + circuit->interface->name); break; case IF_DOWN_FROM_Z: isis_circuit_if_del(circuit, (struct interface *)arg); @@ -142,7 +153,9 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) assert(circuit); switch (event) { case ISIS_ENABLE: - zlog_warn("circuit already enabled"); + if (IS_DEBUG_EVENTS) + zlog_debug("circuit %p is already enabled", + circuit); break; case IF_UP_FROM_Z: isis_circuit_if_add(circuit, (struct interface *)arg); @@ -165,7 +178,9 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) circuit = NULL; break; case IF_DOWN_FROM_Z: - zlog_warn("circuit already disconnected"); + if (IS_DEBUG_EVENTS) + zlog_debug("circuit %p already disconnected", + circuit); break; } break; @@ -173,10 +188,14 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) assert(circuit); switch (event) { case ISIS_ENABLE: - zlog_warn("circuit already configured"); + if (IS_DEBUG_EVENTS) + zlog_debug("circuit %s already configured", + circuit->interface->name); break; case IF_UP_FROM_Z: - zlog_warn("circuit already connected"); + if (IS_DEBUG_EVENTS) + zlog_debug("circuit %s already connected", + circuit->interface->name); break; case ISIS_DISABLE: isis = circuit->isis; @@ -197,9 +216,6 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg) break; } break; - - default: - zlog_warn("Invalid circuit state %d", old_state); } if (IS_DEBUG_EVENTS) diff --git a/isisd/isis_csm.h b/isisd/isis_csm.h index 53a5f9d5d0..ad72ff5113 100644 --- a/isisd/isis_csm.h +++ b/isisd/isis_csm.h @@ -27,20 +27,25 @@ /* * Circuit states */ -#define C_STATE_NA 0 -#define C_STATE_INIT 1 /* Connected to interface */ -#define C_STATE_CONF 2 /* Configured for ISIS */ -#define C_STATE_UP 3 /* CONN | CONF */ +enum isis_circuit_state { + C_STATE_NA, + C_STATE_INIT, /* Connected to interface */ + C_STATE_CONF, /* Configured for ISIS */ + C_STATE_UP, /* CONN | CONF */ +}; /* * Circuit events */ -#define ISIS_ENABLE 1 -#define IF_UP_FROM_Z 2 -#define ISIS_DISABLE 3 -#define IF_DOWN_FROM_Z 4 +enum isis_circuit_event { + ISIS_ENABLE = 1, + IF_UP_FROM_Z, + ISIS_DISABLE, + IF_DOWN_FROM_Z, +}; -struct isis_circuit * -isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg); +struct isis_circuit *isis_csm_state_change(enum isis_circuit_event event, + struct isis_circuit *circuit, + void *arg); #endif /* _ZEBRA_ISIS_CSM_H */ diff --git a/isisd/isis_snmp.c b/isisd/isis_snmp.c index fe6a2f4052..1efe9f3bfb 100644 --- a/isisd/isis_snmp.c +++ b/isisd/isis_snmp.c @@ -36,7 +36,7 @@ #include "memory.h" #include "smux.h" #include "libfrr.h" -#include "version.h" +#include "lib/version.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" diff --git a/isisd/subdir.am b/isisd/subdir.am index 11bae41657..4243bd60cf 100644 --- a/isisd/subdir.am +++ b/isisd/subdir.am @@ -138,7 +138,7 @@ nodist_isisd_isisd_SOURCES = \ # end isisd_isisd_snmp_la_SOURCES = isisd/isis_snmp.c -isisd_isisd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 +isisd_isisd_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11 isisd_isisd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic isisd_isisd_snmp_la_LIBADD = lib/libfrrsnmp.la diff --git a/ldpd/lde.c b/ldpd/lde.c index 8fa74d1c3d..02dcec750b 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -134,6 +134,8 @@ lde(void) log_procname = log_procnames[PROC_LDE_ENGINE]; master = frr_init(); + /* no frr_config_fork() here, allow frr_pthread to create threads */ + frr_is_after_fork = true; /* setup signal handler */ signal_init(master, array_size(lde_signals), lde_signals); diff --git a/ldpd/ldp_snmp.c b/ldpd/ldp_snmp.c index 9fb4e46515..3932df48e0 100644 --- a/ldpd/ldp_snmp.c +++ b/ldpd/ldp_snmp.c @@ -36,7 +36,7 @@ #include "memory.h" #include "smux.h" #include "libfrr.h" -#include "version.h" +#include "lib/version.h" #include "ldpd.h" #include "ldpe.h" diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index d09eb2fa33..428d2ab7b4 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -111,6 +111,8 @@ ldpe(void) log_procname = log_procnames[ldpd_process]; master = frr_init(); + /* no frr_config_fork() here, allow frr_pthread to create threads */ + frr_is_after_fork = true; /* setup signal handler */ signal_init(master, array_size(ldpe_signals), ldpe_signals); diff --git a/ldpd/subdir.am b/ldpd/subdir.am index 5fc3847c6d..b7e2ab72d6 100644 --- a/ldpd/subdir.am +++ b/ldpd/subdir.am @@ -64,6 +64,6 @@ ldpd_ldpd_SOURCES = ldpd/ldpd.c ldpd_ldpd_LDADD = ldpd/libldp.a lib/libfrr.la $(LIBCAP) ldpd_ldpd_snmp_la_SOURCES = ldpd/ldp_snmp.c -ldpd_ldpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 +ldpd_ldpd_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11 ldpd_ldpd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic ldpd_ldpd_snmp_la_LIBADD = lib/libfrrsnmp.la diff --git a/lib/agentx.c b/lib/agentx.c index b5a035ee2b..6d4e68d651 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -30,7 +30,7 @@ #include "smux.h" #include "memory.h" #include "linklist.h" -#include "version.h" +#include "lib/version.h" #include "lib_errors.h" #include "xref.h" @@ -619,8 +619,6 @@ struct bfd_session_params { /** BFD session installation state. */ bool installed; - /** BFD session enabled. */ - bool enabled; /** Global BFD paramaters list. */ TAILQ_ENTRY(bfd_session_params) entry; @@ -748,6 +746,21 @@ static int _bfd_sess_send(struct thread *t) bsp->installed = false; else if (bsp->args.command == ZEBRA_BFD_DEST_REGISTER) bsp->installed = true; + } else { + struct ipaddr src, dst; + + src.ipa_type = bsp->args.family; + src.ipaddr_v6 = bsp->args.src; + dst.ipa_type = bsp->args.family; + dst.ipaddr_v6 = bsp->args.dst; + + zlog_err( + "%s: BFD session %pIA -> %pIA interface %s VRF %s(%u) was not %s", + __func__, &src, &dst, + bsp->args.ifnamelen ? bsp->args.ifname : "*", + vrf_id_to_name(bsp->args.vrf_id), bsp->args.vrf_id, + bsp->lastev == BSE_INSTALL ? "installed" + : "uninstalled"); } return 0; @@ -782,18 +795,33 @@ void bfd_sess_free(struct bfd_session_params **bsp) XFREE(MTYPE_BFD_INFO, (*bsp)); } -void bfd_sess_enable(struct bfd_session_params *bsp, bool enable) +static bool bfd_sess_address_changed(const struct bfd_session_params *bsp, + uint32_t family, + const struct in6_addr *src, + const struct in6_addr *dst) { - /* Remove the session when disabling. */ - if (!enable) - _bfd_sess_remove(bsp); + size_t addrlen; + + if (bsp->args.family != family) + return true; - bsp->enabled = enable; + addrlen = (family == AF_INET) ? sizeof(struct in_addr) + : sizeof(struct in6_addr); + if ((src == NULL && memcmp(&bsp->args.src, &i6a_zero, addrlen)) + || (src && memcmp(src, &bsp->args.src, addrlen)) + || memcmp(dst, &bsp->args.dst, addrlen)) + return true; + + return false; } void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp, struct in_addr *src, struct in_addr *dst) { + if (!bfd_sess_address_changed(bsp, AF_INET, (struct in6_addr *)src, + (struct in6_addr *)dst)) + return; + /* If already installed, remove the old setting. */ _bfd_sess_remove(bsp); @@ -814,6 +842,10 @@ void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp, void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp, struct in6_addr *src, struct in6_addr *dst) { + if (!bfd_sess_address_changed(bsp, AF_INET, (struct in6_addr *)src, + (struct in6_addr *)dst)) + return; + /* If already installed, remove the old setting. */ _bfd_sess_remove(bsp); @@ -831,6 +863,10 @@ void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp, void bfd_sess_set_interface(struct bfd_session_params *bsp, const char *ifname) { + if ((ifname == NULL && bsp->args.ifnamelen == 0) + || (ifname && strcmp(bsp->args.ifname, ifname) == 0)) + return; + /* If already installed, remove the old setting. */ _bfd_sess_remove(bsp); @@ -864,6 +900,9 @@ void bfd_sess_set_profile(struct bfd_session_params *bsp, const char *profile) void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id) { + if (bsp->args.vrf_id == vrf_id) + return; + /* If already installed, remove the old setting. */ _bfd_sess_remove(bsp); @@ -874,6 +913,9 @@ void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl) { assert(min_ttl != 0); + if (bsp->args.ttl == ((BFD_SINGLE_HOP_TTL + 1) - min_ttl)) + return; + /* If already installed, remove the old setting. */ _bfd_sess_remove(bsp); @@ -885,6 +927,9 @@ void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl) void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl) { + if (bsp->args.ttl == min_ttl) + return; + /* If already installed, remove the old setting. */ _bfd_sess_remove(bsp); @@ -909,10 +954,6 @@ void bfd_sess_set_timers(struct bfd_session_params *bsp, void bfd_sess_install(struct bfd_session_params *bsp) { - /* Don't attempt to install/update when disabled. */ - if (!bsp->enabled) - return; - bsp->lastev = BSE_INSTALL; thread_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev); } @@ -1060,8 +1101,8 @@ static int zclient_bfd_session_reply(ZAPI_CALLBACK_ARGS) /* Replay all activated peers. */ TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) { - /* Skip disabled sessions. */ - if (!bsp->enabled) + /* Skip not installed sessions. */ + if (!bsp->installed) continue; /* We are reconnecting, so we must send installation. */ @@ -1080,7 +1121,7 @@ static int zclient_bfd_session_reply(ZAPI_CALLBACK_ARGS) static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS) { - struct bfd_session_params *bsp; + struct bfd_session_params *bsp, *bspn; size_t sessions_updated = 0; struct interface *ifp; int remote_cbit = false; @@ -1137,9 +1178,9 @@ static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS) now = monotime(NULL); /* Notify all matching sessions about update. */ - TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) { - /* Skip disabled or not installed entries. */ - if (!bsp->enabled || !bsp->installed) + TAILQ_FOREACH_SAFE (bsp, &bsglobal.bsplist, entry, bspn) { + /* Skip not installed entries. */ + if (!bsp->installed) continue; /* Skip different VRFs. */ if (bsp->args.vrf_id != vrf_id) @@ -169,7 +169,7 @@ typedef void (*bsp_status_update)(struct bfd_session_params *bsp, /** * Allocates and initializes the session parameters. * - * \param updatedb status update notification callback. + * \param updatecb status update notification callback. * \param args application independent data. * * \returns pointer to configuration storage. @@ -185,16 +185,12 @@ struct bfd_session_params *bfd_sess_new(bsp_status_update updatecb, void *args); void bfd_sess_free(struct bfd_session_params **bsp); /** - * Enable/disable session installation. - * - * \param bsp session parameters. - * \param enable knob variable. - */ -void bfd_sess_enable(struct bfd_session_params *bsp, bool enable); - -/** * Set the local and peer address of the BFD session. * + * NOTE: + * If the address changed the session is removed and must be installed again + * with `bfd_sess_install`. + * * \param bsp BFD session parameters. * \param src local address (optional, can be `NULL`). * \param dst remote address (mandatory). @@ -205,6 +201,10 @@ void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp, /** * Set the local and peer address of the BFD session. * + * NOTE: + * If the address changed the session is removed and must be installed again + * with `bfd_sess_install`. + * * \param bsp BFD session parameters. * \param src local address (optional, can be `NULL`). * \param dst remote address (mandatory). @@ -215,6 +215,10 @@ void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp, /** * Configure the BFD session interface. * + * NOTE: + * If the interface changed the session is removed and must be installed again + * with `bfd_sess_install`. + * * \param bsp BFD session parameters. * \param ifname interface name (or `NULL` to remove it). */ @@ -223,6 +227,9 @@ void bfd_sess_set_interface(struct bfd_session_params *bsp, const char *ifname); /** * Configure the BFD session profile name. * + * NOTE: + * Session profile will only change after a `bfd_sess_install`. + * * \param bsp BFD session parameters. * \param profile profile name (or `NULL` to remove it). */ @@ -231,6 +238,10 @@ void bfd_sess_set_profile(struct bfd_session_params *bsp, const char *profile); /** * Configure the BFD session VRF. * + * NOTE: + * If the VRF changed the session is removed and must be installed again + * with `bfd_sess_install`. + * * \param bsp BFD session parameters. * \param vrf_id the VRF identification number. */ @@ -239,6 +250,10 @@ void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id); /** * Configure the BFD session single/multi hop setting. * + * NOTE: + * If the TTL changed the session is removed and must be installed again + * with `bfd_sess_install`. + * * \param bsp BFD session parameters. * \param min_ttl minimum TTL value expected (255 for single hop, 254 for * multi hop with single hop, 253 for multi hop with two hops @@ -260,6 +275,10 @@ void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl); * Instead of receiving the minimum expected TTL, it receives the amount of * hops the protocol will jump. * + * NOTE: + * If the TTL changed the session is removed and must be installed again + * with `bfd_sess_install`. + * * \param bsp BFD session parameters. * \param min_ttl minimum amount of hops expected (1 for single hop, 2 or * more for multi hop). @@ -269,6 +288,9 @@ void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl); /** * Configure the BFD session to set the Control Plane Independent bit. * + * NOTE: + * Session CPI bit will only change after a `bfd_sess_install`. + * * \param bsp BFD session parameters. * \param enable BFD Control Plane Independent state. */ @@ -280,6 +302,11 @@ void bfd_sess_set_cbit(struct bfd_session_params *bsp, bool enable); * Configures the BFD session timers to use. This is specially useful with * `ptm-bfd` which does not support timers. * + * NOTE: + * Session timers will only apply if the session has not been created yet. + * If the session is already installed you must uninstall and install again + * to take effect. + * * \param bsp BFD session parameters. * \param detection_multiplier the detection multiplier value. * \param min_rx minimum required receive period. @@ -292,6 +319,10 @@ void bfd_sess_set_timers(struct bfd_session_params *bsp, /** * Installs or updates the BFD session based on the saved session arguments. * + * NOTE: + * This function has a delayed effect: it will only install/update after + * all northbound/CLI command batch finishes. + * * \param bsp session parameters. */ void bfd_sess_install(struct bfd_session_params *bsp); @@ -299,6 +330,10 @@ void bfd_sess_install(struct bfd_session_params *bsp); /** * Uninstall the BFD session based on the saved session arguments. * + * NOTE: + * This function uninstalls the session immediately (if installed) and cancels + * any previous `bfd_sess_install` calls. + * * \param bsp session parameters. */ void bfd_sess_uninstall(struct bfd_session_params *bsp); diff --git a/lib/command_lex.l b/lib/command_lex.l index 0556605d63..9c096995f5 100644 --- a/lib/command_lex.l +++ b/lib/command_lex.l @@ -35,7 +35,7 @@ #pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wmissing-prototypes" -#include "command_parse.h" +#include "lib/command_parse.h" #define YY_USER_ACTION yylloc->last_column += yyleng; #define LOC_STEP do { if (yylloc) { \ diff --git a/lib/command_parse.y b/lib/command_parse.y index 5ebc19b278..f5e42cc304 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -75,7 +75,7 @@ %code provides { #ifndef FLEX_SCANNER - #include "command_lex.h" + #include "lib/command_lex.h" #endif extern void set_lexer_string (yyscan_t *scn, const char *string); diff --git a/lib/defaults.c b/lib/defaults.c index 7466aad5b1..fe099b6469 100644 --- a/lib/defaults.c +++ b/lib/defaults.c @@ -18,7 +18,7 @@ #include <zebra.h> #include "defaults.h" -#include "version.h" +#include "lib/version.h" static char df_version[128] = FRR_VER_SHORT, df_profile[128] = DFLT_NAME; static struct frr_default *dflt_first = NULL, **dflt_next = &dflt_first; diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index 03359f4d18..898fe98aad 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -28,6 +28,7 @@ #include "memory.h" #include "linklist.h" #include "zlog.h" +#include "libfrr.h" #include "libfrr_trace.h" DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread"); @@ -162,6 +163,8 @@ int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr) int ret; sigset_t oldsigs, blocksigs; + assert(frr_is_after_fork || !"trying to start thread before fork()"); + /* Ensure we never handle signals on a background thread by blocking * everything here (new thread inherits signal mask) */ diff --git a/lib/libfrr.c b/lib/libfrr.c index 5b0a523fb5..970e82c064 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -29,7 +29,7 @@ #include "privs.h" #include "vty.h" #include "command.h" -#include "version.h" +#include "lib/version.h" #include "lib_vty.h" #include "log_vty.h" #include "zclient.h" @@ -46,7 +46,8 @@ #include "frrscript.h" DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm)); -DEFINE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm)); +DEFINE_HOOK(frr_config_pre, (struct thread_master * tm), (tm)); +DEFINE_HOOK(frr_config_post, (struct thread_master * tm), (tm)); DEFINE_KOOH(frr_early_fini, (), ()); DEFINE_KOOH(frr_fini, (), ()); @@ -69,6 +70,8 @@ static char dbfile_default[512]; #endif static char vtypath_default[512]; +/* cleared in frr_preinit(), then re-set after daemonizing */ +bool frr_is_after_fork = true; bool debug_memstats_at_exit = false; static bool nodetach_term, nodetach_daemon; static uint64_t startup_fds; @@ -307,6 +310,7 @@ void frr_init_vtydir(void) void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv) { di = daemon; + frr_is_after_fork = false; /* basename(), opencoded. */ char *p = strrchr(argv[0], '/'); @@ -931,6 +935,8 @@ static void frr_daemonize(void) */ static int frr_config_read_in(struct thread *t) { + hook_call(frr_config_pre, master); + if (!vty_read_config(vty_shared_candidate_config, di->config_file, config_default) && di->backup_config_file) { @@ -964,7 +970,7 @@ static int frr_config_read_in(struct thread *t) __func__, nb_err_name(ret), errmsg); } - hook_call(frr_very_late_init, master); + hook_call(frr_config_post, master); return 0; } @@ -987,6 +993,8 @@ void frr_config_fork(void) if (di->daemon_mode || di->terminal) frr_daemonize(); + frr_is_after_fork = true; + if (!di->pid_file) di->pid_file = pidfile_default; pid_output(di->pid_file); diff --git a/lib/libfrr.h b/lib/libfrr.h index db0f364986..3dc5d7af81 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -141,8 +141,12 @@ extern enum frr_cli_mode frr_get_cli_mode(void); extern uint32_t frr_get_fd_limit(void); extern bool frr_is_startup_fd(int fd); +/* call order of these hooks is as ordered here */ DECLARE_HOOK(frr_late_init, (struct thread_master * tm), (tm)); -DECLARE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm)); +/* fork() happens between late_init and config_pre */ +DECLARE_HOOK(frr_config_pre, (struct thread_master * tm), (tm)); +DECLARE_HOOK(frr_config_post, (struct thread_master * tm), (tm)); + extern void frr_config_fork(void); extern void frr_run(struct thread_master *master); @@ -168,6 +172,8 @@ extern const char frr_scriptdir[]; extern char frr_protoname[]; extern char frr_protonameinst[]; +/* always set in the spot where we *would* fork even if we don't do so */ +extern bool frr_is_after_fork; extern bool debug_memstats_at_exit; diff --git a/lib/module.c b/lib/module.c index d2491a3479..1d51a6396d 100644 --- a/lib/module.c +++ b/lib/module.c @@ -25,7 +25,7 @@ #include "module.h" #include "memory.h" -#include "version.h" +#include "lib/version.h" DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name"); DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments"); diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index f88c2161da..81e30bce49 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -20,7 +20,7 @@ #include <zebra.h> #include "libfrr.h" -#include "version.h" +#include "lib/version.h" #include "defaults.h" #include "log.h" #include "lib_errors.h" diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c index 3d8771ffbc..403537e043 100644 --- a/lib/northbound_confd.c +++ b/lib/northbound_confd.c @@ -24,7 +24,7 @@ #include "command.h" #include "debug.h" #include "libfrr.h" -#include "version.h" +#include "lib/version.h" #include "northbound.h" #include <confd_lib.h> diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp index d042e15dad..58f4e42516 100644 --- a/lib/northbound_grpc.cpp +++ b/lib/northbound_grpc.cpp @@ -23,7 +23,7 @@ #include "log.h" #include "libfrr.h" -#include "version.h" +#include "lib/version.h" #include "command.h" #include "lib_errors.h" #include "northbound.h" diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c index 9fc640ceea..63fd40f8d3 100644 --- a/lib/northbound_sysrepo.c +++ b/lib/northbound_sysrepo.c @@ -25,7 +25,7 @@ #include "debug.h" #include "memory.h" #include "libfrr.h" -#include "version.h" +#include "lib/version.h" #include "northbound.h" #include <sysrepo.h> @@ -736,7 +736,7 @@ static int frr_sr_finish(void) return 0; } -static int frr_sr_module_very_late_init(struct thread_master *tm) +static int frr_sr_module_config_loaded(struct thread_master *tm) { master = tm; @@ -761,7 +761,7 @@ static int frr_sr_module_late_init(struct thread_master *tm) static int frr_sr_module_init(void) { hook_register(frr_late_init, frr_sr_module_late_init); - hook_register(frr_very_late_init, frr_sr_module_very_late_init); + hook_register(frr_config_post, frr_sr_module_config_loaded); return 0; } diff --git a/lib/pid_output.c b/lib/pid_output.c index bd1d89a94c..b82dde8258 100644 --- a/lib/pid_output.c +++ b/lib/pid_output.c @@ -22,7 +22,7 @@ #include <zebra.h> #include <fcntl.h> #include <log.h> -#include "version.h" +#include "lib/version.h" #include "network.h" #include "lib_errors.h" diff --git a/lib/sha256.c b/lib/sha256.c index 37ced5b402..a9b7a4aefc 100644 --- a/lib/sha256.c +++ b/lib/sha256.c @@ -35,8 +35,6 @@ static inline uint32_t be32dec(const void *pp) return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); } -#else -#include <sys/endian.h> #endif #if !HAVE_DECL_BE32ENC @@ -49,8 +47,6 @@ static inline void be32enc(void *pp, uint32_t x) p[1] = (x >> 16) & 0xff; p[0] = (x >> 24) & 0xff; } -#else -#include <sys/endian.h> #endif /* diff --git a/lib/sockopt.c b/lib/sockopt.c index ed21b72df7..b624fe2230 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -25,6 +25,16 @@ #include "sockunion.h" #include "lib_errors.h" +#if (defined(__FreeBSD__) \ + && ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) \ + || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) \ + || (defined(__NetBSD__) && defined(__NetBSD_Version__) \ + && __NetBSD_Version__ >= 106010000) \ + || defined(__OpenBSD__) || defined(__APPLE__) \ + || defined(__DragonFly__) || defined(__sun) +#define HAVE_BSD_STRUCT_IP_MREQ_HACK +#endif + void setsockopt_so_recvbuf(int sock, int size) { int orig_req = size; diff --git a/lib/subdir.am b/lib/subdir.am index b7efec4882..98ba1cf24c 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -318,7 +318,7 @@ if SNMP lib_LTLIBRARIES += lib/libfrrsnmp.la endif -lib_libfrrsnmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 +lib_libfrrsnmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11 lib_libfrrsnmp_la_LDFLAGS = -version-info 0:0:0 lib_libfrrsnmp_la_LIBADD = $(SNMP_LIBS) lib_libfrrsnmp_la_SOURCES = \ @@ -334,7 +334,7 @@ lib_LTLIBRARIES += lib/libfrrcares.la pkginclude_HEADERS += lib/resolver.h endif -lib_libfrrcares_la_CFLAGS = $(WERROR) $(CARES_CFLAGS) +lib_libfrrcares_la_CFLAGS = $(AM_CFLAGS) $(CARES_CFLAGS) lib_libfrrcares_la_LDFLAGS = -version-info 0:0:0 lib_libfrrcares_la_LIBADD = $(CARES_LIBS) lib_libfrrcares_la_SOURCES = \ @@ -349,7 +349,7 @@ lib_LTLIBRARIES += lib/libfrrzmq.la pkginclude_HEADERS += lib/frr_zmq.h endif -lib_libfrrzmq_la_CFLAGS = $(WERROR) $(ZEROMQ_CFLAGS) +lib_libfrrzmq_la_CFLAGS = $(AM_CFLAGS) $(ZEROMQ_CFLAGS) lib_libfrrzmq_la_LDFLAGS = -version-info 0:0:0 lib_libfrrzmq_la_LIBADD = $(ZEROMQ_LIBS) lib_libfrrzmq_la_SOURCES = \ @@ -363,7 +363,7 @@ if CONFD module_LTLIBRARIES += lib/confd.la endif -lib_confd_la_CFLAGS = $(WERROR) $(CONFD_CFLAGS) +lib_confd_la_CFLAGS = $(AM_CFLAGS) $(CONFD_CFLAGS) lib_confd_la_LDFLAGS = -avoid-version -module -shared -export-dynamic lib_confd_la_LIBADD = lib/libfrr.la $(CONFD_LIBS) lib_confd_la_SOURCES = lib/northbound_confd.c @@ -375,7 +375,7 @@ if SYSREPO module_LTLIBRARIES += lib/sysrepo.la endif -lib_sysrepo_la_CFLAGS = $(WERROR) $(SYSREPO_CFLAGS) +lib_sysrepo_la_CFLAGS = $(AM_CFLAGS) $(SYSREPO_CFLAGS) lib_sysrepo_la_LDFLAGS = -avoid-version -module -shared -export-dynamic lib_sysrepo_la_LIBADD = lib/libfrr.la $(SYSREPO_LIBS) lib_sysrepo_la_SOURCES = lib/northbound_sysrepo.c @@ -414,7 +414,7 @@ lib_grammar_sandbox_LDADD = \ lib/libfrr.la lib_clippy_CPPFLAGS = $(AM_CPPFLAGS) -D_GNU_SOURCE -DBUILDING_CLIPPY -lib_clippy_CFLAGS = $(PYTHON_CFLAGS) +lib_clippy_CFLAGS = $(AC_CFLAGS) $(PYTHON_CFLAGS) lib_clippy_LDADD = $(PYTHON_LIBS) $(UST_LIBS) -lelf lib_clippy_LDFLAGS = -export-dynamic lib_clippy_SOURCES = \ diff --git a/lib/version.h.in b/lib/version.h.in index d535d131c8..5078f3ad6e 100644 --- a/lib/version.h.in +++ b/lib/version.h.in @@ -25,7 +25,7 @@ #define _ZEBRA_VERSION_H #ifdef GIT_VERSION -#include "gitversion.h" +#include "lib/gitversion.h" #endif #ifdef __cplusplus diff --git a/lib/zebra.h b/lib/zebra.h index 5c3d91ba74..26c0fe05b5 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -68,6 +68,12 @@ #include <limits.h> #include <inttypes.h> #include <stdbool.h> +#ifdef HAVE_SYS_ENDIAN_H +#include <sys/endian.h> +#endif +#ifdef HAVE_ENDIAN_H +#include <endian.h> +#endif /* machine dependent includes */ #ifdef HAVE_LINUX_VERSION_H @@ -280,22 +286,10 @@ struct in_pktinfo { #define HAVE_IP_HDRINCL_BSD_ORDER #endif -/* Define BYTE_ORDER, if not defined. Useful for compiler conditional - * code, rather than preprocessor conditional. - * Not all the world has this BSD define. - */ +/* autoconf macros for this are deprecated, just find endian.h */ #ifndef BYTE_ORDER -#define BIG_ENDIAN 4321 /* least-significant byte first (vax, pc) */ -#define LITTLE_ENDIAN 1234 /* most-significant byte first (IBM, net) */ -#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */ - -#if defined(WORDS_BIGENDIAN) -#define BYTE_ORDER BIG_ENDIAN -#else /* !WORDS_BIGENDIAN */ -#define BYTE_ORDER LITTLE_ENDIAN -#endif /* WORDS_BIGENDIAN */ - -#endif /* ndef BYTE_ORDER */ +#error please locate an endian.h file appropriate to your platform +#endif /* For old definition. */ #ifndef IN6_ARE_ADDR_EQUAL @@ -312,7 +306,7 @@ struct in_pktinfo { #include "compiler.h" /* Zebra route's types are defined in route_types.h */ -#include "route_types.h" +#include "lib/route_types.h" #define strmatch(a,b) (!strcmp((a), (b))) diff --git a/m4/.gitignore b/m4/.gitignore index cc778b9e99..d444101103 100644 --- a/m4/.gitignore +++ b/m4/.gitignore @@ -8,3 +8,5 @@ !ax_sys_weak_alias.m4 !ax_sys_weak_alias.m4 !pkg.m4 + +/ac diff --git a/m4/ax_lua.m4 b/m4/ax_lua.m4 index 9feb352255..dde24eaf89 100644 --- a/m4/ax_lua.m4 +++ b/m4/ax_lua.m4 @@ -514,47 +514,24 @@ AC_DEFUN([AX_LUA_HEADERS], ]) AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'], - [ dnl Make a program to print LUA_VERSION defined in the header. - dnl TODO It would be really nice if we could do this without compiling a - dnl program, then it would work when cross compiling. But I'm not sure how - dnl to do this reliably. For now, assume versions match when cross compiling. - - AS_IF([test "x$cross_compiling" != 'xyes'], - [ AC_CACHE_CHECK([for Lua header version], - [ax_cv_lua_header_version], - [ _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" - AC_RUN_IFELSE( - [ AC_LANG_SOURCE([[ -#include <lua.h> -#include <stdlib.h> -#include <stdio.h> -int main(int argc, char ** argv) -{ - if(argc > 1) printf("%s", LUA_VERSION); - exit(EXIT_SUCCESS); -} -]]) - ], - [ ax_cv_lua_header_version=`./conftest$EXEEXT p | \ + [ AC_CACHE_CHECK([for Lua header version], + [ax_cv_lua_header_version], + [ + ax_cv_lua_header_version=`echo LUA_VERSION | \ + $CC -P -E $LUA_INCLUDE -imacros lua.h - | \ + $SED -e 's%"\s*"%%g' -e 's%^\s*%%' | \ + tr -d '"\n' | \ $SED -n "s|^Lua \(@<:@0-9@:>@\{1,\}\.@<:@0-9@:>@\{1,\}\).\{0,\}|\1|p"` - ], - [ax_cv_lua_header_version='unknown']) - CPPFLAGS=$_ax_lua_saved_cppflags - ]) - - dnl Compare this to the previously found LUA_VERSION. - AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION]) - AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"], - [ AC_MSG_RESULT([yes]) - ax_header_version_match='yes' - ], - [ AC_MSG_RESULT([no]) - ax_header_version_match='no' - ]) - ], - [ AC_MSG_WARN([cross compiling so assuming header version number matches]) + ]) + + dnl Compare this to the previously found LUA_VERSION. + AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION]) + AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"], + [ AC_MSG_RESULT([yes]) ax_header_version_match='yes' + ], + [ AC_MSG_RESULT([no]) + ax_header_version_match='no' ]) ]) diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c index 5c819017f4..e9bce3e09a 100644 --- a/nhrpd/nhrp_main.c +++ b/nhrpd/nhrp_main.c @@ -18,7 +18,7 @@ #include "getopt.h" #include "thread.h" #include "sigevent.h" -#include "version.h" +#include "lib/version.h" #include "log.h" #include "memory.h" #include "command.h" diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c index a701583621..ba8c398dee 100644 --- a/ospf6d/ospf6_bfd.c +++ b/ospf6d/ospf6_bfd.c @@ -45,71 +45,39 @@ extern struct zclient *zclient; /* - * ospf6_bfd_info_free - Free BFD info structure - */ -void ospf6_bfd_info_free(void **bfd_info) -{ - bfd_info_free((struct bfd_info **)bfd_info); -} - -/* - * ospf6_bfd_show_info - Show BFD info structure - */ -void ospf6_bfd_show_info(struct vty *vty, void *bfd_info, int param_only, - json_object *json_obj, bool use_json) -{ - if (param_only) - bfd_show_param(vty, bfd_info, 1, 0, use_json, json_obj); - else - bfd_show_info(vty, bfd_info, 0, 1, use_json, json_obj); -} - -/* - * ospf6_bfd_reg_dereg_nbr - Register/Deregister a neighbor with BFD through - * zebra for starting/stopping the monitoring of - * the neighbor rechahability. - */ -void ospf6_bfd_reg_dereg_nbr(struct ospf6_neighbor *on, int command) -{ - struct ospf6_interface *oi = on->ospf6_if; - struct interface *ifp = oi->interface; - struct bfd_info *bfd_info; - char src[64]; - int cbit; - - if (!oi->bfd_info || !on->bfd_info) - return; - bfd_info = (struct bfd_info *)oi->bfd_info; - - if (IS_OSPF6_DEBUG_ZEBRA(SEND)) { - inet_ntop(AF_INET6, &on->linklocal_addr, src, sizeof(src)); - zlog_debug("%s nbr (%s) with BFD", - bfd_get_command_dbg_str(command), src); - } - - cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON); - - bfd_peer_sendmsg(zclient, bfd_info, AF_INET6, &on->linklocal_addr, - on->ospf6_if->linklocal_addr, ifp->name, 0, 0, cbit, - command, 0, ifp->vrf_id); - - if (command == ZEBRA_BFD_DEST_DEREGISTER) - bfd_info_free((struct bfd_info **)&on->bfd_info); -} - -/* * ospf6_bfd_trigger_event - Neighbor is registered/deregistered with BFD when * neighbor state is changed to/from 2way. */ void ospf6_bfd_trigger_event(struct ospf6_neighbor *on, int old_state, int state) { - if ((old_state < OSPF6_NEIGHBOR_TWOWAY) - && (state >= OSPF6_NEIGHBOR_TWOWAY)) - ospf6_bfd_reg_dereg_nbr(on, ZEBRA_BFD_DEST_REGISTER); - else if ((old_state >= OSPF6_NEIGHBOR_TWOWAY) - && (state < OSPF6_NEIGHBOR_TWOWAY)) - ospf6_bfd_reg_dereg_nbr(on, ZEBRA_BFD_DEST_DEREGISTER); + int family; + struct in6_addr src, dst; + + /* Skip sessions without BFD. */ + if (on->bfd_session == NULL) + return; + + if (old_state < OSPF6_NEIGHBOR_TWOWAY + && state >= OSPF6_NEIGHBOR_TWOWAY) { + /* + * Check if neighbor address changed. + * + * When the neighbor is configured BFD before having an existing + * connection, then the destination address will be set to `::` + * which will cause session installation failure. This piece of + * code updates the address in that case. + */ + bfd_sess_addresses(on->bfd_session, &family, &src, &dst); + if (memcmp(&on->linklocal_addr, &dst, sizeof(dst))) { + bfd_sess_set_ipv6_addrs(on->bfd_session, &src, + &on->linklocal_addr); + } + + bfd_sess_install(on->bfd_session); + } else if (old_state >= OSPF6_NEIGHBOR_TWOWAY + && state < OSPF6_NEIGHBOR_TWOWAY) + bfd_sess_uninstall(on->bfd_session); } /* @@ -118,134 +86,43 @@ void ospf6_bfd_trigger_event(struct ospf6_neighbor *on, int old_state, * zebra for starting/stopping the monitoring of * the neighbor rechahability. */ -static void ospf6_bfd_reg_dereg_all_nbr(struct ospf6_interface *oi, int command) +static void ospf6_bfd_reg_dereg_all_nbr(struct ospf6_interface *oi, + bool install) { struct ospf6_neighbor *on; struct listnode *node; for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, on)) { - if (command == ZEBRA_BFD_DEST_REGISTER) - ospf6_bfd_info_nbr_create(oi, on); - - if (on->state < OSPF6_NEIGHBOR_TWOWAY) { - if (command == ZEBRA_BFD_DEST_DEREGISTER) - bfd_info_free( - (struct bfd_info **)&on->bfd_info); + /* Remove all sessions. */ + if (!install) { + bfd_sess_free(&on->bfd_session); continue; } - ospf6_bfd_reg_dereg_nbr(on, command); - } -} + /* Always allocate session data even if not enabled. */ + ospf6_bfd_info_nbr_create(oi, on); -/* - * ospf6_bfd_nbr_replay - Replay all the neighbors that have BFD enabled - * to zebra - */ -static int ospf6_bfd_nbr_replay(ZAPI_CALLBACK_ARGS) -{ - struct vrf *vrf = vrf_lookup_by_id(vrf_id); - struct listnode *node; - struct interface *ifp; - struct ospf6_interface *oi; - struct ospf6_neighbor *on; - char dst[64]; - - if (IS_OSPF6_DEBUG_ZEBRA(RECV)) - zlog_debug("Zebra: BFD Dest replay request"); - - /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id); - - /* Replay the neighbor, if BFD is enabled on the interface*/ - FOR_ALL_INTERFACES (vrf, ifp) { - oi = (struct ospf6_interface *)ifp->info; - - if (!oi || !oi->bfd_info) + /* + * If not connected yet, don't create any session but defer it + * for later. See function `ospf6_bfd_trigger_event`. + */ + if (on->state < OSPF6_NEIGHBOR_TWOWAY) continue; - for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, on)) { - if (on->state < OSPF6_NEIGHBOR_TWOWAY) - continue; - - if (IS_OSPF6_DEBUG_ZEBRA(SEND)) { - inet_ntop(AF_INET6, &on->linklocal_addr, dst, - sizeof(dst)); - zlog_debug("Replaying nbr (%s) to BFD", dst); - } - - ospf6_bfd_reg_dereg_nbr(on, ZEBRA_BFD_DEST_UPDATE); - } + bfd_sess_install(on->bfd_session); } - return 0; } -/* - * ospf6_bfd_interface_dest_update - Find the neighbor for which the BFD status - * has changed and bring down the neighbor - * connectivity if BFD down is received. - */ -static int ospf6_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) +static void ospf6_bfd_callback(struct bfd_session_params *bsp, + const struct bfd_session_status *bss, void *arg) { - struct interface *ifp; - struct ospf6_interface *oi; - struct ospf6_neighbor *on; - struct prefix dp; - struct prefix sp; - struct listnode *node, *nnode; - char dst[64]; - int status; - int old_status; - struct bfd_info *bfd_info; - struct timeval tv; - - ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status, - NULL, vrf_id); - - if ((ifp == NULL) || (dp.family != AF_INET6)) - return 0; - - if (IS_OSPF6_DEBUG_ZEBRA(RECV)) - zlog_debug("Zebra: interface %s bfd destination %pFX %s", - ifp->name, &dp, bfd_get_status_str(status)); - - - oi = (struct ospf6_interface *)ifp->info; - if (!oi || !oi->bfd_info) - return 0; - - for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) { - if (memcmp(&(on->linklocal_addr), &dp.u.prefix6, - sizeof(struct in6_addr))) - continue; - - if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT)) { - inet_ntop(AF_INET6, &on->linklocal_addr, dst, - sizeof(dst)); - zlog_debug("[%s:%s]: BFD %s", ifp->name, dst, - bfd_get_status_str(status)); - } - - if (!on->bfd_info) - continue; - - bfd_info = (struct bfd_info *)on->bfd_info; - if (bfd_info->status == status) - continue; + struct ospf6_neighbor *on = arg; - old_status = bfd_info->status; - BFD_SET_CLIENT_STATUS(bfd_info->status, status); - monotime(&tv); - bfd_info->last_update = tv.tv_sec; - - if ((status == BFD_STATUS_DOWN) - && (old_status == BFD_STATUS_UP)) { - THREAD_OFF(on->inactivity_timer); - thread_add_event(master, inactivity_timer, on, 0, NULL); - } + if (bss->state == BFD_STATUS_DOWN + && bss->previous_state == BFD_STATUS_UP) { + THREAD_OFF(on->inactivity_timer); + thread_add_event(master, inactivity_timer, on, 0, NULL); } - - return 0; } /* @@ -254,21 +131,19 @@ static int ospf6_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) void ospf6_bfd_info_nbr_create(struct ospf6_interface *oi, struct ospf6_neighbor *on) { - struct bfd_info *oi_bfd_info; - struct bfd_info *on_bfd_info; - - if (!oi->bfd_info) + if (!oi->bfd_config.enabled) return; - oi_bfd_info = (struct bfd_info *)oi->bfd_info; - - if (!on->bfd_info) - on->bfd_info = bfd_info_create(); + if (on->bfd_session == NULL) + on->bfd_session = bfd_sess_new(ospf6_bfd_callback, on); - on_bfd_info = (struct bfd_info *)on->bfd_info; - on_bfd_info->detect_mult = oi_bfd_info->detect_mult; - on_bfd_info->desired_min_tx = oi_bfd_info->desired_min_tx; - on_bfd_info->required_min_rx = oi_bfd_info->required_min_rx; + bfd_sess_set_timers(on->bfd_session, + oi->bfd_config.detection_multiplier, + oi->bfd_config.min_rx, oi->bfd_config.min_tx); + bfd_sess_set_ipv6_addrs(on->bfd_session, on->ospf6_if->linklocal_addr, + &on->linklocal_addr); + bfd_sess_set_interface(on->bfd_session, oi->interface->name); + bfd_sess_set_profile(on->bfd_session, oi->bfd_config.profile); } /* @@ -276,48 +151,63 @@ void ospf6_bfd_info_nbr_create(struct ospf6_interface *oi, */ void ospf6_bfd_write_config(struct vty *vty, struct ospf6_interface *oi) { -#if HAVE_BFDD == 0 - struct bfd_info *bfd_info; -#endif /* ! HAVE_BFDD */ - - if (!oi->bfd_info) + if (!oi->bfd_config.enabled) return; #if HAVE_BFDD == 0 - bfd_info = (struct bfd_info *)oi->bfd_info; - - if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) + if (oi->bfd_config.detection_multiplier != BFD_DEF_DETECT_MULT + || oi->bfd_config.min_rx != BFD_DEF_MIN_RX + || oi->bfd_config.min_tx != BFD_DEF_MIN_TX) vty_out(vty, " ipv6 ospf6 bfd %d %d %d\n", - bfd_info->detect_mult, bfd_info->required_min_rx, - bfd_info->desired_min_tx); + oi->bfd_config.detection_multiplier, + oi->bfd_config.min_rx, oi->bfd_config.min_tx); else #endif /* ! HAVE_BFDD */ vty_out(vty, " ipv6 ospf6 bfd\n"); + + if (oi->bfd_config.profile) + vty_out(vty, " ipv6 ospf6 bfd profile %s\n", + oi->bfd_config.profile); } -/* - * ospf6_bfd_if_param_set - Set the configured BFD paramter values for - * interface. - */ -static void ospf6_bfd_if_param_set(struct ospf6_interface *oi, uint32_t min_rx, - uint32_t min_tx, uint8_t detect_mult, - int defaults) +DEFUN(ipv6_ospf6_bfd, ipv6_ospf6_bfd_cmd, + "ipv6 ospf6 bfd [profile BFDPROF]", + IP6_STR OSPF6_STR + "Enables BFD support\n" + "BFD Profile selection\n" + "BFD Profile name\n") { - int command = 0; + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf6_interface *oi; + int prof_idx = 4; + assert(ifp); - bfd_set_param((struct bfd_info **)&(oi->bfd_info), min_rx, min_tx, - detect_mult, NULL, defaults, &command); - if (command) - ospf6_bfd_reg_dereg_all_nbr(oi, command); + oi = (struct ospf6_interface *)ifp->info; + if (oi == NULL) + oi = ospf6_interface_create(ifp); + assert(oi); + + oi->bfd_config.detection_multiplier = BFD_DEF_DETECT_MULT; + oi->bfd_config.min_rx = BFD_DEF_MIN_RX; + oi->bfd_config.min_tx = BFD_DEF_MIN_TX; + oi->bfd_config.enabled = true; + if (argc > prof_idx) { + XFREE(MTYPE_TMP, oi->bfd_config.profile); + oi->bfd_config.profile = + XSTRDUP(MTYPE_TMP, argv[prof_idx]->arg); + } + + ospf6_bfd_reg_dereg_all_nbr(oi, true); + + return CMD_SUCCESS; } -DEFUN (ipv6_ospf6_bfd, - ipv6_ospf6_bfd_cmd, - "ipv6 ospf6 bfd", - IP6_STR - OSPF6_STR - "Enables BFD support\n" - ) +DEFUN(no_ipv6_ospf6_bfd_profile, no_ipv6_ospf6_bfd_profile_cmd, + "no ipv6 ospf6 bfd profile [BFDPROF]", + NO_STR IP6_STR OSPF6_STR + "BFD support\n" + "BFD Profile selection\n" + "BFD Profile name\n") { VTY_DECLVAR_CONTEXT(interface, ifp); struct ospf6_interface *oi; @@ -328,8 +218,14 @@ DEFUN (ipv6_ospf6_bfd, oi = ospf6_interface_create(ifp); assert(oi); - ospf6_bfd_if_param_set(oi, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX, - BFD_DEF_DETECT_MULT, 1); + /* BFD not enabled, nothing to do. */ + if (!oi->bfd_config.enabled) + return CMD_SUCCESS; + + /* Remove profile and apply new configuration. */ + XFREE(MTYPE_TMP, oi->bfd_config.profile); + ospf6_bfd_reg_dereg_all_nbr(oi, true); + return CMD_SUCCESS; } @@ -353,10 +249,6 @@ DEFUN( int idx_number_2 = 4; int idx_number_3 = 5; struct ospf6_interface *oi; - uint32_t rx_val; - uint32_t tx_val; - uint8_t dm_val; - int ret; assert(ifp); @@ -365,13 +257,13 @@ DEFUN( oi = ospf6_interface_create(ifp); assert(oi); - if ((ret = bfd_validate_param( - vty, argv[idx_number]->arg, argv[idx_number_2]->arg, - argv[idx_number_3]->arg, &dm_val, &rx_val, &tx_val)) - != CMD_SUCCESS) - return ret; + oi->bfd_config.detection_multiplier = + strtoul(argv[idx_number]->arg, NULL, 10); + oi->bfd_config.min_rx = strtoul(argv[idx_number_2]->arg, NULL, 10); + oi->bfd_config.min_tx = strtoul(argv[idx_number_3]->arg, NULL, 10); + oi->bfd_config.enabled = true; - ospf6_bfd_if_param_set(oi, rx_val, tx_val, dm_val, 0); + ospf6_bfd_reg_dereg_all_nbr(oi, true); return CMD_SUCCESS; } @@ -394,24 +286,19 @@ DEFUN (no_ipv6_ospf6_bfd, oi = ospf6_interface_create(ifp); assert(oi); - if (oi->bfd_info) { - ospf6_bfd_reg_dereg_all_nbr(oi, ZEBRA_BFD_DEST_DEREGISTER); - bfd_info_free((struct bfd_info **)&(oi->bfd_info)); - } + oi->bfd_config.enabled = false; + ospf6_bfd_reg_dereg_all_nbr(oi, false); return CMD_SUCCESS; } void ospf6_bfd_init(void) { - bfd_gbl_init(); - - /* Initialize BFD client functions */ - zclient->interface_bfd_dest_update = ospf6_bfd_interface_dest_update; - zclient->bfd_dest_replay = ospf6_bfd_nbr_replay; + bfd_protocol_integration_init(zclient, master); /* Install BFD command */ install_element(INTERFACE_NODE, &ipv6_ospf6_bfd_cmd); install_element(INTERFACE_NODE, &ipv6_ospf6_bfd_param_cmd); + install_element(INTERFACE_NODE, &no_ipv6_ospf6_bfd_profile_cmd); install_element(INTERFACE_NODE, &no_ipv6_ospf6_bfd_cmd); } diff --git a/ospf6d/ospf6_bfd.h b/ospf6d/ospf6_bfd.h index ddf624efce..651ce2a6e3 100644 --- a/ospf6d/ospf6_bfd.h +++ b/ospf6d/ospf6_bfd.h @@ -24,6 +24,9 @@ #define OSPF6_BFD_H #include "lib/json.h" +/** + * Initialize BFD integration. + */ extern void ospf6_bfd_init(void); extern void ospf6_bfd_trigger_event(struct ospf6_neighbor *nbr, int old_state, @@ -34,10 +37,4 @@ extern void ospf6_bfd_write_config(struct vty *vty, struct ospf6_interface *oi); extern void ospf6_bfd_info_nbr_create(struct ospf6_interface *oi, struct ospf6_neighbor *on); -extern void ospf6_bfd_info_free(void **bfd_info); - -extern void ospf6_bfd_show_info(struct vty *vty, void *bfd_info, int param_only, - json_object *json_obj, bool use_json); - -extern void ospf6_bfd_reg_dereg_nbr(struct ospf6_neighbor *on, int command); #endif /* OSPF6_BFD_H */ diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 158b8dc483..f3af8b308f 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -272,11 +272,12 @@ void ospf6_interface_delete(struct ospf6_interface *oi) if (oi->plist_name) XFREE(MTYPE_CFG_PLIST_NAME, oi->plist_name); - ospf6_bfd_info_free(&(oi->bfd_info)); - /* disable from area list if possible */ ospf6_area_interface_delete(oi); + /* Free BFD allocated data. */ + XFREE(MTYPE_TMP, oi->bfd_config.profile); + XFREE(MTYPE_OSPF6_IF, oi); } @@ -1148,7 +1149,29 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, for (ALL_LSDB(oi->lsack_list, lsa, lsanext)) vty_out(vty, " %s\n", lsa->name); } - ospf6_bfd_show_info(vty, oi->bfd_info, 1, json_obj, use_json); + + /* BFD specific. */ + if (oi->bfd_config.enabled) { + if (use_json) { + struct json_object *json_bfd = json_object_new_object(); + + json_object_int_add( + json_bfd, "detectMultiplier", + oi->bfd_config.detection_multiplier); + json_object_int_add(json_bfd, "rxMinInterval", + oi->bfd_config.min_rx); + json_object_int_add(json_bfd, "txMinInterval", + oi->bfd_config.min_tx); + json_object_object_add(json_obj, "peerBfdInfo", + json_bfd); + } else { + vty_out(vty, + " BFD: Detect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n", + oi->bfd_config.detection_multiplier, + oi->bfd_config.min_rx, oi->bfd_config.min_tx); + } + } + return 0; } diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 2a5a9ba4a2..a45a841406 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -119,7 +119,13 @@ struct ospf6_interface { char *plist_name; /* BFD information */ - void *bfd_info; + struct { + bool enabled; + uint8_t detection_multiplier; + uint32_t min_rx; + uint32_t min_tx; + char *profile; + } bfd_config; /* Statistics Fields */ uint32_t hello_in; diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 485bde4b7b..b35d8bf975 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -26,6 +26,7 @@ #include "linklist.h" #include "vty.h" #include "command.h" +#include "lib/bfd.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" @@ -149,7 +150,7 @@ void ospf6_neighbor_delete(struct ospf6_neighbor *on) THREAD_OFF(on->thread_send_lsupdate); THREAD_OFF(on->thread_send_lsack); - ospf6_bfd_reg_dereg_nbr(on, ZEBRA_BFD_DEST_DEREGISTER); + bfd_sess_free(&on->bfd_session); XFREE(MTYPE_OSPF6_NEIGHBOR, on); } @@ -876,8 +877,7 @@ static void ospf6_neighbor_show_detail(struct vty *vty, json_object_object_add(json_neighbor, "pendingLsaLsAck", json_array); - ospf6_bfd_show_info(vty, on->bfd_info, 0, json_neighbor, - use_json); + bfd_sess_show(vty, json_neighbor, on->bfd_session); json_object_object_add(json, on->name, json_neighbor); @@ -965,7 +965,7 @@ static void ospf6_neighbor_show_detail(struct vty *vty, for (ALL_LSDB(on->lsack_list, lsa, lsanext)) vty_out(vty, " %s\n", lsa->name); - ospf6_bfd_show_info(vty, on->bfd_info, 0, NULL, use_json); + bfd_sess_show(vty, NULL, on->bfd_session); } } diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index f45b340507..47f8c834e2 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -96,7 +96,7 @@ struct ospf6_neighbor { struct thread *thread_send_lsack; /* BFD information */ - void *bfd_info; + struct bfd_session_params *bfd_session; }; /* Neighbor state */ diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index b9d413c3df..dcf76c7038 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -30,7 +30,7 @@ #include "vrf.h" #include "smux.h" #include "libfrr.h" -#include "version.h" +#include "lib/version.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 52e40dc1ad..d05c164225 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -890,7 +890,6 @@ static void ospf6_restart_spf(struct ospf6 *ospf6) { ospf6_route_remove_all(ospf6->route_table); ospf6_route_remove_all(ospf6->brouter_table); - ospf6_route_remove_all(ospf6->external_table); /* Trigger SPF */ ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_CONFIG_CHANGE); diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index 5ccae5b279..00388afd38 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -80,7 +80,7 @@ ospf6d_ospf6d_SOURCES = \ # end ospf6d_ospf6d_snmp_la_SOURCES = ospf6d/ospf6_snmp.c -ospf6d_ospf6d_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 +ospf6d_ospf6d_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11 ospf6d_ospf6d_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic ospf6d_ospf6d_snmp_la_LIBADD = lib/libfrrsnmp.la diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index b5c97eda3c..a6027ee9d1 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -1818,7 +1818,6 @@ static int ospf_abr_task_timer(struct thread *thread) ospf_abr_task(ospf); ospf_abr_nssa_task(ospf); /* if nssa-abr, then scan Type-7 LSDB */ - ospf_asbr_nssa_redist_task(ospf); return 0; } diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index 0b4e5d7762..6d80725ae6 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -277,10 +277,16 @@ void ospf_asbr_status_update(struct ospf *ospf, uint8_t status) /* If there's redistribution configured, we need to refresh external * LSAs in order to install Type-7 and flood to all NSSA Areas */ -void ospf_asbr_nssa_redist_task(struct ospf *ospf) +static int ospf_asbr_nssa_redist_update_timer(struct thread *thread) { + struct ospf *ospf = THREAD_ARG(thread); int type; + ospf->t_asbr_nssa_redist_update = NULL; + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("Running ASBR NSSA redistribution update on timer"); + for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { struct list *red_list; struct listnode *node; @@ -293,10 +299,22 @@ void ospf_asbr_nssa_redist_task(struct ospf *ospf) for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) ospf_external_lsa_refresh_type(ospf, type, red->instance, - LSA_REFRESH_IF_CHANGED); + LSA_REFRESH_FORCE); } ospf_external_lsa_refresh_default(ospf); + + return 0; +} + +void ospf_schedule_asbr_nssa_redist_update(struct ospf *ospf) +{ + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("Scheduling ASBR NSSA redistribution update"); + + thread_add_timer(master, ospf_asbr_nssa_redist_update_timer, ospf, + OSPF_ASBR_NSSA_REDIST_UPDATE_DELAY, + &ospf->t_asbr_nssa_redist_update); } void ospf_redistribute_withdraw(struct ospf *ospf, uint8_t type, diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h index 7759d45455..d3e50903ef 100644 --- a/ospfd/ospf_asbr.h +++ b/ospfd/ospf_asbr.h @@ -104,6 +104,7 @@ struct ospf_external_aggr_rt { }; #define OSPF_ASBR_CHECK_DELAY 30 +#define OSPF_ASBR_NSSA_REDIST_UPDATE_DELAY 9 extern void ospf_external_route_remove(struct ospf *, struct prefix_ipv4 *); extern struct external_info *ospf_external_info_new(uint8_t, unsigned short); @@ -121,7 +122,7 @@ extern struct external_info *ospf_external_info_lookup(struct ospf *, uint8_t, unsigned short, struct prefix_ipv4 *); extern void ospf_asbr_status_update(struct ospf *, uint8_t); -extern void ospf_asbr_nssa_redist_task(struct ospf *ospf); +extern void ospf_schedule_asbr_nssa_redist_update(struct ospf *ospf); extern void ospf_redistribute_withdraw(struct ospf *, uint8_t, unsigned short); extern void ospf_asbr_check(void); diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c index 2ab7db68bd..56116cd28d 100644 --- a/ospfd/ospf_bfd.c +++ b/ospfd/ospf_bfd.c @@ -99,7 +99,6 @@ void ospf_neighbor_bfd_apply(struct ospf_neighbor *nbr) bfd_sess_set_ipv4_addrs(nbr->bfd_session, NULL, &nbr->src); bfd_sess_set_interface(nbr->bfd_session, oi->ifp->name); bfd_sess_set_vrf(nbr->bfd_session, oi->ospf->vrf_id); - bfd_sess_enable(nbr->bfd_session, true); } /* Set new configuration. */ diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 43b998ac5b..432f95f9dd 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -34,7 +34,7 @@ #include "memory.h" #include "smux.h" #include "libfrr.h" -#include "version.h" +#include "lib/version.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index be446705ea..69a3e45878 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -1546,6 +1546,7 @@ static int ospf_area_nssa_cmd_handler(struct vty *vty, int argc, /* Flush the external LSA for the specified area */ ospf_flush_lsa_from_area(ospf, area_id, OSPF_AS_EXTERNAL_LSA); ospf_schedule_abr_task(ospf); + ospf_schedule_asbr_nssa_redist_update(ospf); return CMD_SUCCESS; } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 9949a78336..faec868b2a 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -791,6 +791,7 @@ static void ospf_finish_final(struct ospf *ospf) OSPF_TIMER_OFF(ospf->t_maxage_walker); OSPF_TIMER_OFF(ospf->t_abr_task); OSPF_TIMER_OFF(ospf->t_asbr_check); + OSPF_TIMER_OFF(ospf->t_asbr_nssa_redist_update); OSPF_TIMER_OFF(ospf->t_distribute_update); OSPF_TIMER_OFF(ospf->t_lsa_refresher); OSPF_TIMER_OFF(ospf->t_opaque_lsa_self); diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 2093eb2e42..318400e968 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -242,6 +242,8 @@ struct ospf { /* Threads. */ struct thread *t_abr_task; /* ABR task timer. */ struct thread *t_asbr_check; /* ASBR check timer. */ + struct thread *t_asbr_nssa_redist_update; /* ASBR NSSA redistribution + update timer. */ struct thread *t_distribute_update; /* Distirbute list update timer. */ struct thread *t_spf_calc; /* SPF calculation timer. */ struct thread *t_ase_calc; /* ASE calculation timer. */ diff --git a/ospfd/subdir.am b/ospfd/subdir.am index f592a9eec8..574e0e3bdf 100644 --- a/ospfd/subdir.am +++ b/ospfd/subdir.am @@ -115,7 +115,7 @@ ospfd_ospfd_LDADD = ospfd/libfrrospf.a lib/libfrr.la $(LIBCAP) $(LIBM) ospfd_ospfd_SOURCES = ospfd/ospf_main.c ospfd_ospfd_snmp_la_SOURCES = ospfd/ospf_snmp.c -ospfd_ospfd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 +ospfd_ospfd_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11 ospfd_ospfd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic ospfd_ospfd_snmp_la_LIBADD = lib/libfrrsnmp.la diff --git a/pathd/path_pcep.c b/pathd/path_pcep.c index d6cd48ecdb..ad24c2eb02 100644 --- a/pathd/path_pcep.c +++ b/pathd/path_pcep.c @@ -24,7 +24,7 @@ #include "command.h" #include "libfrr.h" #include "printfrr.h" -#include "version.h" +#include "lib/version.h" #include "northbound.h" #include "frr_pthread.h" #include "jhash.h" @@ -264,7 +264,11 @@ int pathd_candidate_removed_handler(struct srte_candidate *candidate) /* ------------ Module Functions ------------ */ -int pcep_module_late_init(struct thread_master *tm) +/* this creates threads, therefore must run after fork(). but it must also + * run before config load, so the CLI commands don't try to touch things that + * aren't set up yet... + */ +static int pcep_module_config_pre(struct thread_master *tm) { assert(pcep_g->fpt == NULL); assert(pcep_g->master == NULL); @@ -280,10 +284,16 @@ int pcep_module_late_init(struct thread_master *tm) pcep_g->master = tm; pcep_g->fpt = fpt; + return 0; +} + +static int pcep_module_late_init(struct thread_master *tm) +{ hook_register(pathd_candidate_created, pathd_candidate_created_handler); hook_register(pathd_candidate_updated, pathd_candidate_updated_handler); hook_register(pathd_candidate_removed, pathd_candidate_removed_handler); + hook_register(frr_config_pre, pcep_module_config_pre); hook_register(frr_fini, pcep_module_finish); pcep_cli_init(); diff --git a/pathd/path_pcep_cli.c b/pathd/path_pcep_cli.c index 14404b1d08..2e4e331ad9 100644 --- a/pathd/path_pcep_cli.c +++ b/pathd/path_pcep_cli.c @@ -25,7 +25,7 @@ #include "command.h" #include "libfrr.h" #include "printfrr.h" -#include "version.h" +#include "lib/version.h" #include "northbound.h" #include "frr_pthread.h" #include "jhash.h" diff --git a/pathd/path_pcep_controller.c b/pathd/path_pcep_controller.c index db7d2b55a5..528dcc3539 100644 --- a/pathd/path_pcep_controller.c +++ b/pathd/path_pcep_controller.c @@ -22,7 +22,7 @@ #include "command.h" #include "libfrr.h" #include "printfrr.h" -#include "version.h" +#include "lib/version.h" #include "northbound.h" #include "frr_pthread.h" #include "jhash.h" diff --git a/pathd/path_pcep_pcc.c b/pathd/path_pcep_pcc.c index a2c1e7cd4c..9af2148819 100644 --- a/pathd/path_pcep_pcc.c +++ b/pathd/path_pcep_pcc.c @@ -33,7 +33,7 @@ #include "command.h" #include "libfrr.h" #include "printfrr.h" -#include "version.h" +#include "lib/version.h" #include "northbound.h" #include "frr_pthread.h" #include "jhash.h" diff --git a/pathd/subdir.am b/pathd/subdir.am index 4eabdd2ac5..0666e8d3c8 100644 --- a/pathd/subdir.am +++ b/pathd/subdir.am @@ -75,5 +75,5 @@ pathd_pathd_pcep_la_LIBADD = endif -pathd_pathd_pcep_la_CFLAGS = $(WERROR) +#pathd_pathd_pcep_la_CFLAGS = $(AM_CFLAGS) pathd_pathd_pcep_la_LDFLAGS = -avoid-version -module -shared -export-dynamic diff --git a/pceplib/subdir.am b/pceplib/subdir.am index eee2ec28c7..2633f678fd 100644 --- a/pceplib/subdir.am +++ b/pceplib/subdir.am @@ -1,7 +1,7 @@ if PATHD_PCEP noinst_LTLIBRARIES = pceplib/libpcep_pcc.la pceplib/libsocket_comm_mock.la -pceplib_libpcep_pcc_la_CFLAGS = -fPIC +pceplib_libpcep_pcc_la_CFLAGS = $(AM_CFLAGS) -fPIC pceplib_libpcep_pcc_la_SOURCES = pceplib/pcep_msg_messages.c \ pceplib/pcep_msg_objects.c \ pceplib/pcep_msg_tlvs.c \ diff --git a/pceplib/test/subdir.am b/pceplib/test/subdir.am index 0ae61d1bce..88af592679 100644 --- a/pceplib/test/subdir.am +++ b/pceplib/test/subdir.am @@ -36,7 +36,7 @@ noinst_HEADERS += pceplib/test/pcep_msg_messages_test.h \ pceplib/test/pcep_utils_ordered_list_test.h \ pceplib/test/pcep_utils_queue_test.h -pceplib_test_pcep_msg_tests_CFLAGS = -I$(top_srcdir)/pceplib +pceplib_test_pcep_msg_tests_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/pceplib pceplib_test_pcep_msg_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread pceplib_test_pcep_msg_tests_SOURCES = pceplib/test/pcep_msg_messages_test.c \ pceplib/test/pcep_msg_messages_tests.c \ @@ -47,7 +47,7 @@ pceplib_test_pcep_msg_tests_SOURCES = pceplib/test/pcep_msg_messages_test.c \ # The pcc_api_tests and pcep_session_logic_tests use the # socket_comm_mock, so the LDADD variable needs to be modified -pceplib_test_pcep_pcc_api_tests_CFLAGS = -I$(top_srcdir)/pceplib +pceplib_test_pcep_pcc_api_tests_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/pceplib pceplib_test_pcep_pcc_api_tests_LDADD = $(top_builddir)/pceplib/libsocket_comm_mock.la $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la -lcunit -lpthread pceplib_test_pcep_pcc_api_tests_SOURCES = pceplib/test/pcep_pcc_api_test.c pceplib/test/pcep_pcc_api_tests.c diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c index 5e1b9a69e1..bc518391a5 100644 --- a/pimd/pim_bfd.c +++ b/pimd/pim_bfd.c @@ -42,36 +42,40 @@ void pim_bfd_write_config(struct vty *vty, struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; - struct bfd_info *bfd_info = NULL; - if (!pim_ifp) - return; - - bfd_info = pim_ifp->bfd_info; - if (!bfd_info) + if (!pim_ifp || !pim_ifp->bfd_config.enabled) return; #if HAVE_BFDD == 0 - if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) - vty_out(vty, " ip pim bfd %d %d %d\n", bfd_info->detect_mult, - bfd_info->required_min_rx, bfd_info->desired_min_tx); + if (pim_ifp->bfd_config.detection_multiplier != BFD_DEF_DETECT_MULT + || pim_ifp->bfd_config.min_rx != BFD_DEF_MIN_RX + || pim_ifp->bfd_config.min_tx != BFD_DEF_MIN_TX) + vty_out(vty, " ip pim bfd %d %d %d\n", + pim_ifp->bfd_config.detection_multiplier, + pim_ifp->bfd_config.min_rx, pim_ifp->bfd_config.min_tx); else #endif /* ! HAVE_BFDD */ vty_out(vty, " ip pim bfd\n"); + + if (pim_ifp->bfd_config.profile) + vty_out(vty, " ip pim bfd profile %s\n", + pim_ifp->bfd_config.profile); } -/* - * pim_bfd_show_info - Show BFD info structure - */ -void pim_bfd_show_info(struct vty *vty, void *bfd_info, json_object *json_obj, - bool use_json, int param_only) +static void pim_neighbor_bfd_cb(struct bfd_session_params *bsp, + const struct bfd_session_status *bss, void *arg) { - if (param_only) - bfd_show_param(vty, (struct bfd_info *)bfd_info, 1, 0, use_json, - json_obj); - else - bfd_show_info(vty, (struct bfd_info *)bfd_info, 0, 1, use_json, - json_obj); + struct pim_neighbor *nbr = arg; + + if (PIM_DEBUG_PIM_TRACE) { + zlog_debug("%s: status %s old_status %s", __func__, + bfd_get_status_str(bss->state), + bfd_get_status_str(bss->previous_state)); + } + + if (bss->state == BFD_STATUS_DOWN + && bss->previous_state == BFD_STATUS_UP) + pim_neighbor_delete(nbr->interface, nbr, "BFD Session Expired"); } /* @@ -80,60 +84,20 @@ void pim_bfd_show_info(struct vty *vty, void *bfd_info, json_object *json_obj, void pim_bfd_info_nbr_create(struct pim_interface *pim_ifp, struct pim_neighbor *neigh) { - struct bfd_info *nbr_bfd_info = NULL; - /* Check if Pim Interface BFD is enabled */ - if (!pim_ifp || !pim_ifp->bfd_info) - return; - - if (!neigh->bfd_info) - neigh->bfd_info = bfd_info_create(); - - if (!neigh->bfd_info) - return; - - nbr_bfd_info = neigh->bfd_info; - nbr_bfd_info->detect_mult = pim_ifp->bfd_info->detect_mult; - nbr_bfd_info->desired_min_tx = pim_ifp->bfd_info->desired_min_tx; - nbr_bfd_info->required_min_rx = pim_ifp->bfd_info->required_min_rx; -} - -/* - * pim_bfd_info_free - Free BFD info structure - */ -void pim_bfd_info_free(struct bfd_info **bfd_info) -{ - bfd_info_free(bfd_info); -} - -static void pim_bfd_reg_dereg_nbr(struct pim_neighbor *nbr, int command) -{ - struct pim_interface *pim_ifp = NULL; - struct bfd_info *bfd_info = NULL; - struct zclient *zclient = NULL; - int cbit; - - zclient = pim_zebra_zclient_get(); - - if (!nbr) + if (!pim_ifp || !pim_ifp->bfd_config.enabled) return; - pim_ifp = nbr->interface->info; - bfd_info = pim_ifp->bfd_info; - if (!bfd_info) - return; - if (PIM_DEBUG_PIM_TRACE) { - char str[INET_ADDRSTRLEN]; - pim_inet4_dump("<bfd_nbr?>", nbr->source_addr, str, - sizeof(str)); - zlog_debug("%s Nbr %s %s with BFD", __func__, str, - bfd_get_command_dbg_str(command)); - } - cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON); + if (neigh->bfd_session == NULL) + neigh->bfd_session = bfd_sess_new(pim_neighbor_bfd_cb, neigh); - bfd_peer_sendmsg(zclient, bfd_info, AF_INET, &nbr->source_addr, NULL, - nbr->interface->name, 0, 0, cbit, - command, 0, VRF_DEFAULT); + bfd_sess_set_timers( + neigh->bfd_session, pim_ifp->bfd_config.detection_multiplier, + pim_ifp->bfd_config.min_rx, pim_ifp->bfd_config.min_tx); + bfd_sess_set_ipv4_addrs(neigh->bfd_session, NULL, &neigh->source_addr); + bfd_sess_set_interface(neigh->bfd_session, neigh->interface->name); + bfd_sess_set_profile(neigh->bfd_session, pim_ifp->bfd_config.profile); + bfd_sess_install(neigh->bfd_session); } /* @@ -142,7 +106,7 @@ static void pim_bfd_reg_dereg_nbr(struct pim_neighbor *nbr, int command) * zebra for starting/stopping the monitoring of * the neighbor rechahability. */ -int pim_bfd_reg_dereg_all_nbr(struct interface *ifp, int command) +void pim_bfd_reg_dereg_all_nbr(struct interface *ifp) { struct pim_interface *pim_ifp = NULL; struct listnode *node = NULL; @@ -150,197 +114,17 @@ int pim_bfd_reg_dereg_all_nbr(struct interface *ifp, int command) pim_ifp = ifp->info; if (!pim_ifp) - return -1; - if (!pim_ifp->bfd_info) - return -1; + return; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { - if (command != ZEBRA_BFD_DEST_DEREGISTER) + if (pim_ifp->bfd_config.enabled) pim_bfd_info_nbr_create(pim_ifp, neigh); else - pim_bfd_info_free((struct bfd_info **)&neigh->bfd_info); - - pim_bfd_reg_dereg_nbr(neigh, command); - } - - return 0; -} - -/* - * pim_bfd_trigger_event - Neighbor is registered/deregistered with BFD when - * neighbor state is changed to/from 2way. - */ -void pim_bfd_trigger_event(struct pim_interface *pim_ifp, - struct pim_neighbor *nbr, uint8_t nbr_up) -{ - if (nbr_up) { - pim_bfd_info_nbr_create(pim_ifp, nbr); - pim_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_REGISTER); - } else { - pim_bfd_info_free(&nbr->bfd_info); - pim_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_DEREGISTER); - } -} - -/* - * pim_bfd_if_param_set - Set the configured BFD paramter values for - * interface. - */ -void pim_bfd_if_param_set(struct interface *ifp, uint32_t min_rx, - uint32_t min_tx, uint8_t detect_mult, int defaults) -{ - struct pim_interface *pim_ifp = ifp->info; - int command = 0; - - if (!pim_ifp) - return; - bfd_set_param(&(pim_ifp->bfd_info), min_rx, min_tx, detect_mult, NULL, - defaults, &command); - - if (pim_ifp->bfd_info) { - if (PIM_DEBUG_PIM_TRACE) - zlog_debug("%s: interface %s has bfd_info", __func__, - ifp->name); - } - if (command) - pim_bfd_reg_dereg_all_nbr(ifp, command); -} - - -/* - * pim_bfd_interface_dest_update - Find the neighbor for which the BFD status - * has changed and bring down the neighbor - * connectivity if the BFD status changed to - * down. - */ -static int pim_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp = NULL; - struct pim_interface *pim_ifp = NULL; - struct prefix p, src_p; - int status; - char msg[100]; - int old_status; - struct bfd_info *bfd_info = NULL; - struct timeval tv; - struct listnode *neigh_node = NULL; - struct listnode *neigh_nextnode = NULL; - struct pim_neighbor *neigh = NULL; - - ifp = bfd_get_peer_info(zclient->ibuf, &p, &src_p, &status, NULL, - vrf_id); - - if ((ifp == NULL) || (p.family != AF_INET)) - return 0; - - pim_ifp = ifp->info; - if (!pim_ifp) - return 0; - - if (!pim_ifp->bfd_info) { - if (PIM_DEBUG_PIM_TRACE) - zlog_debug("%s: pim interface %s BFD is disabled ", - __func__, ifp->name); - return 0; + bfd_sess_free(&neigh->bfd_session); } - - if (PIM_DEBUG_PIM_TRACE) - zlog_debug("%s: interface %s bfd destination %pFX %s", __func__, - ifp->name, &p, bfd_get_status_str(status)); - - for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node, - neigh_nextnode, neigh)) { - /* Check neigh address matches with BFD address */ - if (neigh->source_addr.s_addr != p.u.prefix4.s_addr) - continue; - - bfd_info = (struct bfd_info *)neigh->bfd_info; - if (bfd_info->status == status) { - if (PIM_DEBUG_PIM_TRACE) { - char str[INET_ADDRSTRLEN]; - pim_inet4_dump("<nht_nbr?>", neigh->source_addr, - str, sizeof(str)); - zlog_debug("%s: bfd status is same for nbr %s", - __func__, str); - } - continue; - } - old_status = bfd_info->status; - BFD_SET_CLIENT_STATUS(bfd_info->status, status); - monotime(&tv); - bfd_info->last_update = tv.tv_sec; - - if (PIM_DEBUG_PIM_TRACE) { - zlog_debug("%s: status %s old_status %s", __func__, - bfd_get_status_str(status), - bfd_get_status_str(old_status)); - } - if ((status == BFD_STATUS_DOWN) - && (old_status == BFD_STATUS_UP)) { - snprintf(msg, sizeof(msg), "BFD Session Expired"); - pim_neighbor_delete(ifp, neigh, msg); - } - } - return 0; -} - -/* - * pim_bfd_nbr_replay - Replay all the neighbors that have BFD enabled - * to zebra - */ -static int pim_bfd_nbr_replay(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp = NULL; - struct pim_interface *pim_ifp = NULL; - struct pim_neighbor *neigh = NULL; - struct listnode *neigh_node; - struct listnode *neigh_nextnode; - struct vrf *vrf = NULL; - - /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id); - - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - FOR_ALL_INTERFACES (vrf, ifp) { - pim_ifp = ifp->info; - - if (!pim_ifp) - continue; - - if (pim_ifp->pim_sock_fd < 0) - continue; - - for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, - neigh_node, neigh_nextnode, - neigh)) { - if (!neigh->bfd_info) - continue; - if (PIM_DEBUG_PIM_TRACE) { - char str[INET_ADDRSTRLEN]; - - pim_inet4_dump("<bfd_nbr?>", - neigh->source_addr, str, - sizeof(str)); - zlog_debug( - "%s: Replaying Pim Neigh %s to BFD vrf_id %u", - __func__, str, vrf->vrf_id); - } - pim_bfd_reg_dereg_nbr(neigh, - ZEBRA_BFD_DEST_UPDATE); - } - } - } - return 0; } void pim_bfd_init(void) { - struct zclient *zclient = NULL; - - zclient = pim_zebra_zclient_get(); - - bfd_gbl_init(); - - zclient->interface_bfd_dest_update = pim_bfd_interface_dest_update; - zclient->bfd_dest_replay = pim_bfd_nbr_replay; + bfd_protocol_integration_init(pim_zebra_zclient_get(), router->master); } diff --git a/pimd/pim_bfd.h b/pimd/pim_bfd.h index 962b727f88..3bfbb7486e 100644 --- a/pimd/pim_bfd.h +++ b/pimd/pim_bfd.h @@ -25,16 +25,35 @@ #include "if.h" +/** + * Initializes PIM BFD integration code. + */ void pim_bfd_init(void); + +/** + * Write configuration to `show running-config`. + * + * \param vty the vty output pointer. + * \param ifp the interface pointer that has the configuration. + */ void pim_bfd_write_config(struct vty *vty, struct interface *ifp); -void pim_bfd_show_info(struct vty *vty, void *bfd_info, json_object *json_obj, - bool use_json, int param_only); -void pim_bfd_if_param_set(struct interface *ifp, uint32_t min_rx, - uint32_t min_tx, uint8_t detect_mult, int defaults); -int pim_bfd_reg_dereg_all_nbr(struct interface *ifp, int command); -void pim_bfd_trigger_event(struct pim_interface *pim_ifp, - struct pim_neighbor *nbr, uint8_t nbr_up); + +/** + * Enables or disables all peers BFD sessions. + * + * \param ifp interface pointer. + * \param enable session state to set. + */ +void pim_bfd_reg_dereg_all_nbr(struct interface *ifp); + +/** + * Create and configure peer BFD session if it does not exist. It will use + * the interface configured parameters as the peer configuration. + * + * \param pim_ifp the interface configuration pointer. + * \param neigh the neighbor configuration pointer. + */ void pim_bfd_info_nbr_create(struct pim_interface *pim_ifp, struct pim_neighbor *neigh); -void pim_bfd_info_free(struct bfd_info **bfd_info); + #endif /* _PIM_BFD_H */ diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 4bbe7d35f0..c01cfec88e 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1955,8 +1955,8 @@ static void pim_show_neighbors_single(struct pim_instance *pim, struct vty *vty, vty_out(vty, " Hello Option - T-bit : %s\n", option_t_bit ? "yes" : "no"); - pim_bfd_show_info(vty, neigh->bfd_info, - json_ifp, uj, 0); + bfd_sess_show(vty, json_ifp, + neigh->bfd_session); vty_out(vty, "\n"); } } @@ -9676,19 +9676,16 @@ DEFUN (interface_no_pim_use_source, "frr-routing:ipv4"); } -DEFUN (ip_pim_bfd, +DEFPY (ip_pim_bfd, ip_pim_bfd_cmd, - "ip pim bfd", + "ip pim bfd [profile BFDPROF$prof]", IP_STR PIM_STR - "Enables BFD support\n") + "Enables BFD support\n" + "Use BFD profile\n" + "Use BFD profile name\n") { - struct bfd_info *bfd_info = NULL; - char default_rx_interval[5]; - char default_tx_interval[5]; - char default_detect_mult[3]; const struct lyd_node *igmp_enable_dnode; - char bfd_xpath[XPATH_MAXLEN + 20]; igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, "%s/frr-igmp:igmp/igmp-enable", @@ -9702,31 +9699,25 @@ DEFUN (ip_pim_bfd, "true"); } - snprintf(default_rx_interval, sizeof(default_rx_interval), "%d", - BFD_DEF_MIN_RX); - snprintf(default_tx_interval, sizeof(default_tx_interval), "%d", - BFD_DEF_MIN_TX); - snprintf(default_detect_mult, sizeof(default_detect_mult), "%d", - BFD_DEF_DETECT_MULT); + nb_cli_enqueue_change(vty, "./bfd", NB_OP_CREATE, NULL); + if (prof) + nb_cli_enqueue_change(vty, "./bfd/profile", NB_OP_MODIFY, prof); - snprintf(bfd_xpath, sizeof(bfd_xpath), "%s/frr-pim:pim/bfd", - VTY_CURR_XPATH); - bfd_info = nb_running_get_entry(NULL, bfd_xpath, false); - - if (!bfd_info || - !CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) { - nb_cli_enqueue_change(vty, "./bfd/min-rx-interval", - NB_OP_MODIFY, default_rx_interval); - nb_cli_enqueue_change(vty, "./bfd/min-tx-interval", - NB_OP_MODIFY, default_tx_interval); - nb_cli_enqueue_change(vty, "./bfd/detect_mult", - NB_OP_MODIFY, - default_detect_mult); + return nb_cli_apply_changes(vty, "./frr-pim:pim"); +} - return nb_cli_apply_changes(vty, "./frr-pim:pim"); - } +DEFPY(no_ip_pim_bfd_profile, no_ip_pim_bfd_profile_cmd, + "no ip pim bfd profile [BFDPROF]", + NO_STR + IP_STR + PIM_STR + "Enables BFD support\n" + "Disable BFD profile\n" + "BFD Profile name\n") +{ + nb_cli_enqueue_change(vty, "./bfd/profile", NB_OP_DESTROY, NULL); - return NB_OK; + return nb_cli_apply_changes(vty, "./frr-pim:pim"); } DEFUN (no_ip_pim_bfd, @@ -9847,19 +9838,8 @@ DEFUN_HIDDEN( int idx_number = 3; int idx_number_2 = 4; int idx_number_3 = 5; - uint32_t rx_val; - uint32_t tx_val; - uint8_t dm_val; - int ret; const struct lyd_node *igmp_enable_dnode; - if ((ret = bfd_validate_param(vty, argv[idx_number]->arg, - argv[idx_number_2]->arg, - argv[idx_number_3]->arg, &dm_val, &rx_val, - &tx_val)) - != CMD_SUCCESS) - return ret; - igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode, "%s/frr-igmp:igmp/igmp-enable", VTY_CURR_XPATH); @@ -9872,6 +9852,7 @@ DEFUN_HIDDEN( "true"); } + nb_cli_enqueue_change(vty, "./bfd", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./bfd/min-rx-interval", NB_OP_MODIFY, argv[idx_number_2]->arg); nb_cli_enqueue_change(vty, "./bfd/min-tx-interval", NB_OP_MODIFY, @@ -11731,6 +11712,7 @@ void pim_cmd_init(void) /* Install BFD command */ install_element(INTERFACE_NODE, &ip_pim_bfd_cmd); install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_bfd_profile_cmd); install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd); #if HAVE_BFDD == 0 install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd); diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 664ab31949..92784103fe 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -158,9 +158,16 @@ struct pim_interface { uint32_t pim_ifstat_bsm_cfg_miss; uint32_t pim_ifstat_ucast_bsm_cfg_miss; uint32_t pim_ifstat_bsm_invalid_sz; - struct bfd_info *bfd_info; bool bsm_enable; /* bsm processing enable */ bool ucast_bsm_accept; /* ucast bsm processing */ + + struct { + bool enabled; + uint32_t min_rx; + uint32_t min_tx; + uint8_t detection_multiplier; + char *profile; + } bfd_config; }; /* diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 70c233848a..96132c4425 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -21,7 +21,7 @@ #include "log.h" #include "privs.h" -#include "version.h" +#include "lib/version.h" #include <getopt.h> #include "command.h" #include "thread.h" @@ -32,7 +32,7 @@ #include "filter.h" #include "vty.h" #include "sigevent.h" -#include "version.h" +#include "lib/version.h" #include "prefix.h" #include "plist.h" #include "vrf.h" diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index 8ca0e0780b..37c539883d 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -259,6 +259,13 @@ const struct frr_yang_module_info frr_pim_info = { } }, { + .xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd/profile", + .cbs = { + .modify = lib_interface_pim_bfd_profile_modify, + .destroy = lib_interface_pim_bfd_profile_destroy, + } + }, + { .xpath = "/frr-interface:lib/interface/frr-pim:pim/bsm", .cbs = { .modify = lib_interface_pim_bsm_modify, diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index 78eb680103..440384e45c 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -121,6 +121,8 @@ int lib_interface_pim_bfd_min_rx_interval_modify(struct nb_cb_modify_args *args) int lib_interface_pim_bfd_min_tx_interval_modify( struct nb_cb_modify_args *args); int lib_interface_pim_bfd_detect_mult_modify(struct nb_cb_modify_args *args); +int lib_interface_pim_bfd_profile_modify(struct nb_cb_modify_args *args); +int lib_interface_pim_bfd_profile_destroy(struct nb_cb_destroy_args *args); int lib_interface_pim_bsm_modify(struct nb_cb_modify_args *args); int lib_interface_pim_unicast_bsm_modify(struct nb_cb_modify_args *args); int lib_interface_pim_active_active_modify(struct nb_cb_modify_args *args); diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 475e393cf0..8e6f2ec42b 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -755,18 +755,14 @@ int pim_join_prune_interval_modify(struct nb_cb_modify_args *args) */ int pim_register_suppress_time_modify(struct nb_cb_modify_args *args) { - struct vrf *vrf; - struct pim_instance *pim; - switch (args->event) { case NB_EV_VALIDATE: case NB_EV_PREPARE: case NB_EV_ABORT: break; case NB_EV_APPLY: - vrf = nb_running_get_entry(args->dnode, NULL, true); - pim = vrf->info; - pim->keep_alive_time = yang_dnode_get_uint16(args->dnode, NULL); + router->register_suppress_time = + yang_dnode_get_uint16(args->dnode, NULL); break; } @@ -1886,11 +1882,19 @@ int lib_interface_pim_hello_holdtime_destroy(struct nb_cb_destroy_args *args) */ int lib_interface_pim_bfd_create(struct nb_cb_create_args *args) { + struct interface *ifp; + struct pim_interface *pim_ifp; + switch (args->event) { case NB_EV_VALIDATE: case NB_EV_PREPARE: case NB_EV_ABORT: + /* NOTHING */ + break; case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + pim_ifp->bfd_config.enabled = true; break; } @@ -1916,13 +1920,10 @@ int lib_interface_pim_bfd_destroy(struct nb_cb_destroy_args *args) case NB_EV_PREPARE: break; case NB_EV_APPLY: - ifp = nb_running_get_entry(args->dnode->parent, NULL, true); + ifp = nb_running_get_entry(args->dnode, NULL, true); pim_ifp = ifp->info; - if (pim_ifp->bfd_info) { - pim_bfd_reg_dereg_all_nbr(ifp, - ZEBRA_BFD_DEST_DEREGISTER); - bfd_info_free(&(pim_ifp->bfd_info)); - } + pim_ifp->bfd_config.enabled = false; + pim_bfd_reg_dereg_all_nbr(ifp); break; } @@ -1936,11 +1937,8 @@ void lib_interface_pim_bfd_apply_finish(struct nb_cb_apply_finish_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; - uint32_t min_rx; - uint32_t min_tx; - uint8_t detect_mult; - ifp = nb_running_get_entry(args->dnode->parent, NULL, true); + ifp = nb_running_get_entry(args->dnode, NULL, true); pim_ifp = ifp->info; if (!pim_ifp) { @@ -1948,17 +1946,14 @@ void lib_interface_pim_bfd_apply_finish(struct nb_cb_apply_finish_args *args) return; } - min_rx = yang_dnode_get_uint16(args->dnode, "./min-rx-interval"); - min_tx = yang_dnode_get_uint16(args->dnode, "./min-tx-interval"); - detect_mult = yang_dnode_get_uint8(args->dnode, "./detect_mult"); + pim_ifp->bfd_config.detection_multiplier = + yang_dnode_get_uint8(args->dnode, "./detect_mult"); + pim_ifp->bfd_config.min_rx = + yang_dnode_get_uint16(args->dnode, "./min-rx-interval"); + pim_ifp->bfd_config.min_tx = + yang_dnode_get_uint16(args->dnode, "./min-tx-interval"); - if ((min_rx == BFD_DEF_MIN_RX) && (min_tx == BFD_DEF_MIN_TX) - && (detect_mult == BFD_DEF_DETECT_MULT)) - pim_bfd_if_param_set(ifp, min_rx, min_tx, detect_mult, 1); - else - pim_bfd_if_param_set(ifp, min_rx, min_tx, detect_mult, 0); - - nb_running_set_entry(args->dnode, pim_ifp->bfd_info); + pim_bfd_reg_dereg_all_nbr(ifp); } /* @@ -2010,6 +2005,53 @@ int lib_interface_pim_bfd_detect_mult_modify(struct nb_cb_modify_args *args) } /* + * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/profile + */ +int lib_interface_pim_bfd_profile_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + XFREE(MTYPE_TMP, pim_ifp->bfd_config.profile); + pim_ifp->bfd_config.profile = XSTRDUP( + MTYPE_TMP, yang_dnode_get_string(args->dnode, NULL)); + break; + } + + return NB_OK; +} + +int lib_interface_pim_bfd_profile_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + XFREE(MTYPE_TMP, pim_ifp->bfd_config.profile); + break; + } + + return NB_OK; +} + +/* * XPath: /frr-interface:lib/interface/frr-pim:pim/bsm */ int lib_interface_pim_bsm_modify(struct nb_cb_modify_args *args) diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 167aa3c604..19dc469091 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -377,7 +377,7 @@ pim_neighbor_new(struct interface *ifp, struct in_addr source_addr, } // Register PIM Neighbor with BFD - pim_bfd_trigger_event(pim_ifp, neigh, 1); + pim_bfd_info_nbr_create(pim_ifp, neigh); return neigh; } @@ -419,8 +419,7 @@ void pim_neighbor_free(struct pim_neighbor *neigh) list_delete(&neigh->upstream_jp_agg); THREAD_OFF(neigh->jp_timer); - if (neigh->bfd_info) - pim_bfd_info_free(&neigh->bfd_info); + bfd_sess_free(&neigh->bfd_session); XFREE(MTYPE_PIM_NEIGHBOR, neigh); } @@ -669,9 +668,6 @@ void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh, __func__, src_str, ifp->name); } - // De-Register PIM Neighbor with BFD - pim_bfd_trigger_event(pim_ifp, neigh, 0); - listnode_delete(pim_ifp->pim_neighbor_list, neigh); pim_neighbor_free(neigh); diff --git a/pimd/pim_neighbor.h b/pimd/pim_neighbor.h index a4f2e10c88..b461098a60 100644 --- a/pimd/pim_neighbor.h +++ b/pimd/pim_neighbor.h @@ -43,7 +43,7 @@ struct pim_neighbor { struct thread *jp_timer; struct list *upstream_jp_agg; - struct bfd_info *bfd_info; + struct bfd_session_params *bfd_session; }; void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime); diff --git a/qpb/subdir.am b/qpb/subdir.am index 80f8f3aca9..4f826355d9 100644 --- a/qpb/subdir.am +++ b/qpb/subdir.am @@ -35,7 +35,7 @@ if HAVE_PROTOBUF # Rules .proto.pb.h: - $(PROTOC) -I$(top_srcdir) --cpp_out=$(top_srcdir) $(top_srcdir)/$^ + $(PROTOC) -I$(top_srcdir) --cpp_out=$(top_builddir) $^ AM_V_PROTOC_C = $(am__v_PROTOC_C_$(V)) am__v_PROTOC_C_ = $(am__v_PROTOC_C_$(AM_DEFAULT_VERBOSITY)) @@ -43,7 +43,7 @@ am__v_PROTOC_C_0 = @echo " PROTOC_C" $@; am__v_PROTOC_C_1 = .proto.pb-c.c: - $(AM_V_PROTOC_C)$(PROTOC_C) -I$(top_srcdir) --c_out=$(top_srcdir) $(top_srcdir)/$^ + $(AM_V_PROTOC_C)$(PROTOC_C) -I$(top_srcdir) --c_out=$(top_builddir) $^ .pb-c.c.pb-c.h: @/bin/true diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c index b922d66912..d49d360b7e 100644 --- a/ripd/rip_snmp.c +++ b/ripd/rip_snmp.c @@ -31,7 +31,7 @@ #include "table.h" #include "smux.h" #include "libfrr.h" -#include "version.h" +#include "lib/version.h" #include "ripd/ripd.h" diff --git a/ripd/subdir.am b/ripd/subdir.am index 99979bff0d..8de0fc4b5a 100644 --- a/ripd/subdir.am +++ b/ripd/subdir.am @@ -56,6 +56,6 @@ nodist_ripd_ripd_SOURCES = \ # end ripd_ripd_snmp_la_SOURCES = ripd/rip_snmp.c -ripd_ripd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 +ripd_ripd_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11 ripd_ripd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic ripd_ripd_snmp_la_LIBADD = lib/libfrrsnmp.la diff --git a/tests/subdir.am b/tests/subdir.am index 370e6a49a9..ec0a154a2d 100644 --- a/tests/subdir.am +++ b/tests/subdir.am @@ -148,6 +148,7 @@ TESTS_CPPFLAGS = $(AM_CPPFLAGS) \ -I$(top_builddir)/tests/helpers/c \ # end TESTS_CFLAGS = \ + $(AC_CFLAGS) \ $(LIBYANG_CFLAGS) \ $(SAN_FLAGS) \ # end diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r1/peers_down.json b/tests/topotests/bfd-bgp-cbit-topo3/r1/peers_down.json index c7c7b96ee7..4984b52cf2 100644 --- a/tests/topotests/bfd-bgp-cbit-topo3/r1/peers_down.json +++ b/tests/topotests/bfd-bgp-cbit-topo3/r1/peers_down.json @@ -3,13 +3,13 @@ "multihop":true, "peer":"2001:db8:4::1", "local":"2001:db8:1::1", - "status":"up", + "status":"init", "receive-interval":300, "transmit-interval":300, "echo-receive-interval":50, "echo-transmit-interval":0, - "remote-receive-interval":300, - "remote-transmit-interval":300, + "remote-receive-interval":1000, + "remote-transmit-interval":1000, "remote-echo-receive-interval":50 } ] diff --git a/tests/topotests/bfd-profiles-topo1/r4/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r4/bfd-peers-initial.json index c73296ac97..9ab7479979 100644 --- a/tests/topotests/bfd-profiles-topo1/r4/bfd-peers-initial.json +++ b/tests/topotests/bfd-profiles-topo1/r4/bfd-peers-initial.json @@ -26,7 +26,7 @@ "local": "*", "multihop": false, "peer": "*", - "receive-interval": 300, + "receive-interval": 250, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", "remote-echo-receive-interval": 50, @@ -34,7 +34,7 @@ "remote-receive-interval": 300, "remote-transmit-interval": 300, "status": "up", - "transmit-interval": 300, + "transmit-interval": 250, "uptime": "*", "vrf": "default" } diff --git a/tests/topotests/bfd-profiles-topo1/r4/bfdd.conf b/tests/topotests/bfd-profiles-topo1/r4/bfdd.conf index 36ef4f0403..4f5e022077 100644 --- a/tests/topotests/bfd-profiles-topo1/r4/bfdd.conf +++ b/tests/topotests/bfd-profiles-topo1/r4/bfdd.conf @@ -3,4 +3,8 @@ debug bfd network debug bfd zebra ! bfd + profile fast-tx + receive-interval 250 + transmit-interval 250 + ! ! diff --git a/tests/topotests/bfd-profiles-topo1/r4/ospf6d.conf b/tests/topotests/bfd-profiles-topo1/r4/ospf6d.conf index 84157de24d..4ef28c39ca 100644 --- a/tests/topotests/bfd-profiles-topo1/r4/ospf6d.conf +++ b/tests/topotests/bfd-profiles-topo1/r4/ospf6d.conf @@ -1,5 +1,7 @@ interface r4-eth1 - ipv6 ospf6 bfd + ipv6 ospf6 bfd profile fast-tx + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 ! router ospf6 ospf6 router-id 10.254.254.4 diff --git a/tests/topotests/bfd-profiles-topo1/r5/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r5/bfd-peers-initial.json index fcb090959e..0fe56d576b 100644 --- a/tests/topotests/bfd-profiles-topo1/r5/bfd-peers-initial.json +++ b/tests/topotests/bfd-profiles-topo1/r5/bfd-peers-initial.json @@ -11,8 +11,8 @@ "remote-detect-multiplier": 3, "remote-diagnostic": "ok", "remote-id": "*", - "remote-receive-interval": 300, - "remote-transmit-interval": 300, + "remote-receive-interval": 250, + "remote-transmit-interval": 250, "status": "up", "transmit-interval": 300, "uptime": "*", diff --git a/tests/topotests/bfd-profiles-topo1/r5/ospf6d.conf b/tests/topotests/bfd-profiles-topo1/r5/ospf6d.conf index 970c713558..20b53cfc55 100644 --- a/tests/topotests/bfd-profiles-topo1/r5/ospf6d.conf +++ b/tests/topotests/bfd-profiles-topo1/r5/ospf6d.conf @@ -1,5 +1,7 @@ interface r5-eth0 ipv6 ospf6 bfd + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 ! router ospf6 ospf6 router-id 10.254.254.5 diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py index 524da05875..ee57b9c479 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py @@ -134,7 +134,6 @@ from lib.common_config import ( check_router_status, shutdown_bringup_interface, step, - kill_mininet_routers_process, get_frr_ipv6_linklocal, create_route_maps, required_linux_kernel_version, @@ -204,9 +203,6 @@ def setup_module(mod): tgen = Topogen(GenerateTopo, mod.__name__) # ... and here it calls Mininet initialization functions. - # Kill stale mininet routers and process - kill_mininet_routers_process(tgen) - # Starting topology, create tmp files which are loaded to routers # to start deamons and then start routers start_topology(tgen) diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py index 9438b90ef8..b6f8bf4cd9 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py @@ -133,7 +133,6 @@ from lib.common_config import ( check_router_status, shutdown_bringup_interface, step, - kill_mininet_routers_process, get_frr_ipv6_linklocal, create_route_maps, required_linux_kernel_version, diff --git a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py index 1b62d986bd..7ea5a24fd7 100644 --- a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py +++ b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py @@ -128,7 +128,6 @@ from lib.common_config import ( create_static_routes, create_prefix_lists, create_interface_in_kernel, - kill_mininet_routers_process, create_bgp_community_lists, check_router_status, apply_raw_config, @@ -229,9 +228,6 @@ def setup_module(mod): tgen = Topogen(CreateTopo, mod.__name__) # ... and here it calls Mininet initialization functions. - # Kill stale mininet routers and process - kill_mininet_routers_process(tgen) - # Starting topology, create tmp files which are loaded to routers # to start deamons and then start routers start_topology(tgen) diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py index 90356ec173..37da53fc31 100644 --- a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py +++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py @@ -87,7 +87,6 @@ from lib.common_config import ( create_vrf_cfg, create_interfaces_cfg, create_interface_in_kernel, - kill_mininet_routers_process, get_frr_ipv6_linklocal, check_router_status, apply_raw_config, @@ -182,9 +181,6 @@ def setup_module(mod): tgen = Topogen(CreateTopo, mod.__name__) # ... and here it calls Mininet initialization functions. - # Kill stale mininet routers and process - kill_mininet_routers_process(tgen) - # Starting topology, create tmp files which are loaded to routers # to start deamons and then start routers start_topology(tgen) diff --git a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py index 2a98cb341d..c758c31dc1 100644 --- a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py +++ b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py @@ -71,7 +71,6 @@ from lib.common_config import ( shutdown_bringup_interface, addKernelRoute, delete_route_maps, - kill_mininet_routers_process, ) from lib.topolog import logger from lib.bgp import ( diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index ead593d2ca..ba6004861e 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -401,30 +401,6 @@ def start_router_daemons(tgen, router, daemons): return res -def kill_mininet_routers_process(tgen): - """ - Kill all mininet stale router' processes - * `tgen` : topogen object - """ - - router_list = tgen.routers() - for rname, router in router_list.items(): - daemon_list = [ - "zebra", - "ospfd", - "ospf6d", - "bgpd", - "ripd", - "ripngd", - "isisd", - "pimd", - "ldpd", - "staticd", - ] - for daemon in daemon_list: - router.run("killall -9 {}".format(daemon)) - - def check_router_status(tgen): """ Check if all daemons are running for all routers in topology diff --git a/tests/topotests/pim-basic-topo2/__init__.py b/tests/topotests/pim-basic-topo2/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/__init__.py diff --git a/tests/topotests/pim-basic-topo2/r1/bfdd.conf b/tests/topotests/pim-basic-topo2/r1/bfdd.conf new file mode 100644 index 0000000000..76c6f82190 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r1/bfdd.conf @@ -0,0 +1,6 @@ +bfd + profile fast-tx + receive-interval 250 + transmit-interval 250 + ! +! diff --git a/tests/topotests/pim-basic-topo2/r1/pimd.conf b/tests/topotests/pim-basic-topo2/r1/pimd.conf new file mode 100644 index 0000000000..b895d7d573 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r1/pimd.conf @@ -0,0 +1,4 @@ +interface r1-eth0 + ip pim + ip pim bfd profile fast-tx +! diff --git a/tests/topotests/pim-basic-topo2/r1/zebra.conf b/tests/topotests/pim-basic-topo2/r1/zebra.conf new file mode 100644 index 0000000000..6bf02a3ee8 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r1/zebra.conf @@ -0,0 +1,3 @@ +interface r1-eth0 + ip address 192.168.1.1/24 +! diff --git a/tests/topotests/pim-basic-topo2/r2/bfdd.conf b/tests/topotests/pim-basic-topo2/r2/bfdd.conf new file mode 100644 index 0000000000..ca61e467dc --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r2/bfdd.conf @@ -0,0 +1,2 @@ +bfd +! diff --git a/tests/topotests/pim-basic-topo2/r2/pimd.conf b/tests/topotests/pim-basic-topo2/r2/pimd.conf new file mode 100644 index 0000000000..0b32ded19a --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r2/pimd.conf @@ -0,0 +1,12 @@ +interface r2-eth0 + ip pim + ip pim bfd +! +interface r2-eth1 + ip pim + ip pim bfd +! +interface r2-eth2 + ip pim + ip pim bfd +! diff --git a/tests/topotests/pim-basic-topo2/r2/zebra.conf b/tests/topotests/pim-basic-topo2/r2/zebra.conf new file mode 100644 index 0000000000..3ceb5f0fc2 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r2/zebra.conf @@ -0,0 +1,9 @@ +interface r2-eth0 + ip address 192.168.1.2/24 +! +interface r2-eth1 + ip address 192.168.2.1/24 +! +interface r2-eth2 + ip address 192.168.3.1/24 +! diff --git a/tests/topotests/pim-basic-topo2/r3/bfdd.conf b/tests/topotests/pim-basic-topo2/r3/bfdd.conf new file mode 100644 index 0000000000..ca61e467dc --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r3/bfdd.conf @@ -0,0 +1,2 @@ +bfd +! diff --git a/tests/topotests/pim-basic-topo2/r3/pimd.conf b/tests/topotests/pim-basic-topo2/r3/pimd.conf new file mode 100644 index 0000000000..691a28ea27 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r3/pimd.conf @@ -0,0 +1,4 @@ +interface r3-eth0 + ip pim + ip pim bfd +! diff --git a/tests/topotests/pim-basic-topo2/r3/zebra.conf b/tests/topotests/pim-basic-topo2/r3/zebra.conf new file mode 100644 index 0000000000..3df218ee16 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r3/zebra.conf @@ -0,0 +1,3 @@ +interface r3-eth0 + ip address 192.168.2.3/24 +! diff --git a/tests/topotests/pim-basic-topo2/r4/bfdd.conf b/tests/topotests/pim-basic-topo2/r4/bfdd.conf new file mode 100644 index 0000000000..ca61e467dc --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r4/bfdd.conf @@ -0,0 +1,2 @@ +bfd +! diff --git a/tests/topotests/pim-basic-topo2/r4/pimd.conf b/tests/topotests/pim-basic-topo2/r4/pimd.conf new file mode 100644 index 0000000000..2277b3e1f1 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r4/pimd.conf @@ -0,0 +1,4 @@ +interface r4-eth0 + ip pim + ip pim bfd +! diff --git a/tests/topotests/pim-basic-topo2/r4/zebra.conf b/tests/topotests/pim-basic-topo2/r4/zebra.conf new file mode 100644 index 0000000000..6ac5c78fc3 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r4/zebra.conf @@ -0,0 +1,3 @@ +interface r4-eth0 + ip address 192.168.3.4/24 +! diff --git a/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.dot b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.dot new file mode 100644 index 0000000000..22fce27e22 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.dot @@ -0,0 +1,73 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph template { + label="bfd-topo3"; + + # Routers + r1 [ + shape=doubleoctagon, + label="r1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon + label="r2", + fillcolor="#f08080", + style=filled, + ]; + r3 [ + shape=doubleoctagon + label="r3", + fillcolor="#f08080", + style=filled, + ]; + r4 [ + shape=doubleoctagon + label="r4", + fillcolor="#f08080", + style=filled, + ]; + + # Switches + sw1 [ + shape=oval, + label="sw1\n192.168.1.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw2 [ + shape=oval, + label="sw2\n192.168.2.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw2 [ + shape=oval, + label="sw2\n192.168.3.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + r1 -- sw1 [label="eth0\n.1"]; + r2 -- sw1 [label="eth0\n.2"]; + + r2 -- sw2 [label="eth1\n.1"]; + r3 -- sw2 [label="eth0\n.3"]; + + r2 -- sw3 [label="eth1\n.1"]; + r4 -- sw3 [label="eth2\n.4"]; +} diff --git a/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.png b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.png Binary files differnew file mode 100644 index 0000000000..39139a35b1 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.png diff --git a/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.py b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.py new file mode 100644 index 0000000000..883125cfc7 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python + +# +# test_pim_basic_topo2.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2021 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# 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_pim_basic_topo2.py: Test the FRR PIM protocol convergence. +""" + +import os +import sys +import json +from functools import partial +import pytest + +# 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 + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +pytestmark = [pytest.mark.bfdd, pytest.mark.pimd] + + +class PimBasicTopo2(Topo): + "Test topology builder" + + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # Create 4 routers + for routern in range(1, 5): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s2") + 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): + "Sets up the pytest environment" + tgen = Topogen(PimBasicTopo2, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + daemon_file = "{}/{}/bfdd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_BFD, daemon_file) + + daemon_file = "{}/{}/pimd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_PIM, daemon_file) + + daemon_file = "{}/{}/zebra.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_ZEBRA, daemon_file) + + # Initialize all routers. + tgen.start_router() + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +def expect_neighbor(router, interface, peer): + "Wait until peer is present on interface." + logger.info("waiting peer {} in {}".format(peer, interface)) + tgen = get_topogen() + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip pim neighbor json", + {interface: {peer: {}}} + ) + _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + assertmsg = '"{}" PIM convergence failure'.format(router) + assert result is None, assertmsg + + +def test_wait_pim_convergence(): + "Wait for PIM to converge" + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for PIM to converge") + + expect_neighbor('r1', 'r1-eth0', '192.168.1.2') + expect_neighbor('r2', 'r2-eth0', '192.168.1.1') + + expect_neighbor('r2', 'r2-eth1', '192.168.2.3') + expect_neighbor('r2', 'r2-eth2', '192.168.3.4') + + expect_neighbor('r3', 'r3-eth0', '192.168.2.1') + expect_neighbor('r4', 'r4-eth0', '192.168.3.1') + + +def test_bfd_peers(): + "Wait for BFD peers to show up." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for BFD to converge") + + def expect_bfd_peer(router, peer): + "Wait until peer is present on interface." + logger.info("waiting BFD peer {} in {}".format(peer, router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show bfd peers json", + [{"peer": peer, "status": "up"}] + ) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertmsg = '"{}" BFD convergence failure'.format(router) + assert result is None, assertmsg + + expect_bfd_peer("r1", "192.168.1.2") + expect_bfd_peer("r2", "192.168.1.1") + expect_bfd_peer("r2", "192.168.2.3") + expect_bfd_peer("r2", "192.168.3.4") + expect_bfd_peer("r3", "192.168.2.1") + expect_bfd_peer("r4", "192.168.3.1") + + +def test_pim_reconvergence(): + "Disconnect a peer and expect it to disconnect." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for disconnect convergence") + tgen.gears["r4"].link_enable("r4-eth0", enabled=False) + + def expect_neighbor_down(router, interface, peer): + "Wait until peer is present on interface." + logger.info("waiting peer {} in {} to disappear".format(peer, interface)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip pim neighbor json", + {interface: {peer: None}} + ) + _, result = topotest.run_and_expect(test_func, None, count=4, wait=1) + assertmsg = '"{}" PIM convergence failure'.format(router) + assert result is None, assertmsg + + expect_neighbor_down("r2", "r2-eth2", "192.168.3.4") + + logger.info("waiting for reconvergence") + tgen.gears["r4"].link_enable("r4-eth0", enabled=True) + expect_neighbor("r2", "r2-eth2", "192.168.3.4") + + +def test_pim_bfd_profile(): + "Test that the BFD profile is properly applied in BFD." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def expect_bfd_peer_settings(router, settings): + "Expect the following BFD configuration" + logger.info("Verifying BFD peer {} in {}".format(settings["peer"], router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show bfd peers json", + [settings] + ) + _, result = topotest.run_and_expect(test_func, None, count=4, wait=1) + assertmsg = '"{}" BFD convergence failure'.format(router) + assert result is None, assertmsg + + expect_bfd_peer_settings("r1", { + "peer": "192.168.1.2", + "receive-interval": 250, + "transmit-interval": 250, + }) + + expect_bfd_peer_settings("r2", { + "peer": "192.168.1.1", + "remote-receive-interval": 250, + "remote-transmit-interval": 250, + }) + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tools/frr-reload.py b/tools/frr-reload.py index f4b832691e..a617c0a9c5 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -188,17 +188,17 @@ class Vtysh(object): class Context(object): """ - A Context object represents a section of frr configuration such as: -! -interface swp3 - description swp3 -> r8's swp1 - ipv6 nd suppress-ra - link-detect -! + A Context object represents a section of frr configuration such as: + ! + interface swp3 + description swp3 -> r8's swp1 + ipv6 nd suppress-ra + link-detect + ! -or a single line context object such as this: + or a single line context object such as this: -ip forwarding + ip forwarding """ @@ -1091,7 +1091,7 @@ def check_for_exit_vrf(lines_to_add, lines_to_del): add_exit_vrf = False if ctx_keys[0].startswith("vrf") and line: - if line is not "exit-vrf": + if line != "exit-vrf": add_exit_vrf = True prior_ctx_key = ctx_keys[0] else: @@ -1119,12 +1119,15 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # in-place, to avoid requesting spurious label chunks which might fail if line and "segment-routing global-block" in line: for (add_key, add_line) in lines_to_add: - if ctx_keys[0] == add_key[0] and add_line and "segment-routing global-block" in add_line: + if ( + ctx_keys[0] == add_key[0] + and add_line + and "segment-routing global-block" in add_line + ): lines_to_del_to_del.append((ctx_keys, line)) break continue - if ctx_keys[0].startswith("router bgp") and line: if line.startswith("neighbor "): diff --git a/version.h b/version.h new file mode 100644 index 0000000000..28e0238dfd --- /dev/null +++ b/version.h @@ -0,0 +1,3 @@ +#include "lib/compiler.h" +CPP_NOTICE("Trying to include version.h. Please fix to use lib/version.h.") +#include "lib/version.h" diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang index 2070649ec2..52d8641613 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -331,6 +331,12 @@ module frr-pim { description "Detect Multiplier"; } + + leaf profile { + type string; + description + "Use a preconfigure BFD profile."; + } } leaf bsm { diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c index 600fc3f2fc..66a6bd0545 100644 --- a/zebra/irdp_main.c +++ b/zebra/irdp_main.c @@ -51,7 +51,7 @@ #include "privs.h" #include "libfrr.h" #include "lib_errors.h" -#include "version.h" +#include "lib/version.h" #include "zebra/interface.h" #include "zebra/rtadv.h" #include "zebra/rib.h" diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 9e675011ee..104f952b3b 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -347,17 +347,12 @@ void zebra_redistribute_add(ZAPI_HANDLER_ARGS) zvrf_id(zvrf), afi); } } else { - if (!vrf_bitmap_check(client->redist[afi][type], - zvrf_id(zvrf))) { - if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug( - "%s: setting vrf %s(%u) redist bitmap", - __func__, VRF_LOGNAME(zvrf->vrf), - zvrf_id(zvrf)); - vrf_bitmap_set(client->redist[afi][type], - zvrf_id(zvrf)); - zebra_redistribute(client, type, 0, zvrf_id(zvrf), afi); - } + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug("%s: setting vrf %s(%u) redist bitmap", + __func__, VRF_LOGNAME(zvrf->vrf), + zvrf_id(zvrf)); + vrf_bitmap_set(client->redist[afi][type], zvrf_id(zvrf)); + zebra_redistribute(client, type, 0, zvrf_id(zvrf), afi); } stream_failure: diff --git a/zebra/subdir.am b/zebra/subdir.am index f0d1c5844f..6fc8ef0df5 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -193,7 +193,7 @@ zebra_zebra_irdp_la_SOURCES = \ zebra_zebra_irdp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic zebra_zebra_snmp_la_SOURCES = zebra/zebra_snmp.c -zebra_zebra_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 +zebra_zebra_snmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11 zebra_zebra_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic zebra_zebra_snmp_la_LIBADD = lib/libfrrsnmp.la diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 5fe8934a82..07a8288605 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -29,7 +29,7 @@ #include "thread.h" #include "network.h" #include "command.h" -#include "version.h" +#include "lib/version.h" #include "jhash.h" #include "zebra/rib.h" diff --git a/zebra/zebra_mlag_private.c b/zebra/zebra_mlag_private.c index aaf93b4dc1..b1bba831d2 100644 --- a/zebra/zebra_mlag_private.c +++ b/zebra/zebra_mlag_private.c @@ -28,7 +28,7 @@ #include "thread.h" #include "frr_pthread.h" #include "libfrr.h" -#include "version.h" +#include "lib/version.h" #include "network.h" #include "lib/stream.h" diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 7edf022892..1d3da4e673 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -845,6 +845,8 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */ SET_FLAG(backup_nhe->flags, NEXTHOP_GROUP_RECURSIVE); done: + /* Reset time since last update */ + (*nhe)->uptime = monotime(NULL); return created; } @@ -1191,6 +1193,13 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug("%s: nhe %p (%u) is new", __func__, nhe, nhe->id); + /* + * If daemon nhg from the kernel, add a refcnt here to indicate the + * daemon owns it. + */ + if (PROTO_OWNED(nhe)) + zebra_nhg_increment_ref(nhe); + SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); @@ -2559,7 +2568,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) struct nhg_hash_entry *curr_nhe; uint32_t curr_active = 0, backup_active = 0; - if (re->nhe->id >= ZEBRA_NHG_PROTO_LOWER) + if (PROTO_OWNED(re->nhe)) return proto_nhg_nexthop_active_update(&re->nhe->nhg); afi_t rt_afi = family2afi(rn->p.family); @@ -2861,13 +2870,13 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) zebra_nhg_handle_install(nhe); /* If daemon nhg, send it an update */ - if (nhe->id >= ZEBRA_NHG_PROTO_LOWER) + if (PROTO_OWNED(nhe)) zsend_nhg_notify(nhe->type, nhe->zapi_instance, nhe->zapi_session, nhe->id, ZAPI_NHG_INSTALLED); } else { /* If daemon nhg, send it an update */ - if (nhe->id >= ZEBRA_NHG_PROTO_LOWER) + if (PROTO_OWNED(nhe)) zsend_nhg_notify(nhe->type, nhe->zapi_instance, nhe->zapi_session, nhe->id, ZAPI_NHG_FAIL_INSTALL); @@ -2927,7 +2936,31 @@ static void zebra_nhg_sweep_entry(struct hash_bucket *bucket, void *arg) nhe = (struct nhg_hash_entry *)bucket->data; - /* If its being ref'd, just let it be uninstalled via a route removal */ + /* + * same logic as with routes. + * + * If older than startup time, we know we read them in from the + * kernel and have not gotten and update for them since startup + * from an upper level proto. + */ + if (zrouter.startup_time < nhe->uptime) + return; + + /* + * If it's proto-owned and not being used by a route, remove it since + * we haven't gotten an update about it from the proto since startup. + * This means that either the config for it was removed or the daemon + * didn't get started. This handles graceful restart & retain scenario. + */ + if (PROTO_OWNED(nhe) && nhe->refcnt == 1) { + zebra_nhg_decrement_ref(nhe); + return; + } + + /* + * If its being ref'd by routes, just let it be uninstalled via a route + * removal. + */ if (ZEBRA_NHG_CREATED(nhe) && nhe->refcnt <= 0) zebra_nhg_uninstall_kernel(nhe); } @@ -3201,7 +3234,7 @@ static void zebra_nhg_score_proto_entry(struct hash_bucket *bucket, void *arg) iter = arg; /* Needs to match type and outside zebra ID space */ - if (nhe->type == iter->type && nhe->id >= ZEBRA_NHG_PROTO_LOWER) { + if (nhe->type == iter->type && PROTO_OWNED(nhe)) { if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug( "%s: found nhe %p (%u), vrf %d, type %s after client disconnect", diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 38015bf557..afbf1f6793 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -51,6 +51,9 @@ struct nhg_hash_entry { afi_t afi; vrf_id_t vrf_id; + /* Time since last update */ + time_t uptime; + /* Source protocol - zebra or another daemon */ int type; @@ -147,6 +150,8 @@ enum nhg_type { /* Is this an NHE owned by zebra and not an upper level protocol? */ #define ZEBRA_OWNED(NHE) (NHE->type == ZEBRA_ROUTE_NHG) +#define PROTO_OWNED(NHE) (NHE->id >= ZEBRA_NHG_PROTO_LOWER) + /* * Backup nexthops: this is a group object itself, so * that the backup nexthops can use the same code as a normal object. diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index bea855d1af..37d9399054 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -31,7 +31,7 @@ #include "ptm_lib.h" #include "rib.h" #include "stream.h" -#include "version.h" +#include "lib/version.h" #include "vrf.h" #include "vty.h" #include "lib_errors.h" diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 6a42c682ad..d07a49fb6e 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -30,7 +30,7 @@ #include "plist.h" #include "nexthop.h" #include "northbound_cli.h" -#include "route_types.h" +#include "lib/route_types.h" #include "vrf.h" #include "frrstr.h" diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index 3e08d83724..6fe24dfa54 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -36,7 +36,7 @@ #include "vrf.h" #include "hook.h" #include "libfrr.h" -#include "version.h" +#include "lib/version.h" #include "zebra/rib.h" #include "zebra/zserv.h" diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 283a3e52d6..8061f34d2b 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -445,6 +445,16 @@ static void zebra_show_ip_route_opaque(struct vty *vty, struct route_entry *re, } } +static void uptime2str(time_t uptime, char *buf, size_t bufsize) +{ + time_t cur; + + cur = monotime(NULL); + cur -= uptime; + + frrtime_to_interval(cur, buf, bufsize); +} + /* New RIB. Detailed information for IPv4 route. */ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, int mcast, bool use_fib, bool show_ng) @@ -499,12 +509,7 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, vty_out(vty, ", best"); vty_out(vty, "\n"); - time_t uptime; - - uptime = monotime(NULL); - uptime -= re->uptime; - - frrtime_to_interval(uptime, buf, sizeof(buf)); + uptime2str(re->uptime, buf, sizeof(buf)); vty_out(vty, " Last update %s ago\n", buf); @@ -839,17 +844,13 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object *json_nexthops = NULL; json_object *json_nexthop = NULL; json_object *json_route = NULL; - time_t uptime; const rib_dest_t *dest = rib_dest_from_rnode(rn); const struct nexthop_group *nhg; char up_str[MONOTIME_STRLEN]; bool first_p = true; bool nhg_from_backup = false; - uptime = monotime(NULL); - uptime -= re->uptime; - - frrtime_to_interval(uptime, up_str, sizeof(up_str)); + uptime2str(re->uptime, up_str, sizeof(up_str)); /* If showing fib information, use the fib view of the * nexthops. @@ -1339,9 +1340,13 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) struct nexthop *nexthop = NULL; struct nhg_connected *rb_node_dep = NULL; struct nexthop_group *backup_nhg; + char up_str[MONOTIME_STRLEN]; + + uptime2str(nhe->uptime, up_str, sizeof(up_str)); vty_out(vty, "ID: %u (%s)\n", nhe->id, zebra_route_string(nhe->type)); - vty_out(vty, " RefCnt: %d\n", nhe->refcnt); + vty_out(vty, " RefCnt: %u\n", nhe->refcnt); + vty_out(vty, " Uptime: %s\n", up_str); vty_out(vty, " VRF: %s\n", vrf_id_to_name(nhe->vrf_id)); if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) { |
