diff options
191 files changed, 2648 insertions, 1880 deletions
diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..d8e450a646 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,40 @@ +dist: focal +os: linux +language: c +services: + - docker +jobs: + include: + - script: + - docker/centos-7/build.sh + - docker images + name: centos7 + - script: + - docker/centos-8/build.sh + - docker images + name: centos8 + - script: + - sudo apt install -y linux-modules-extra-$(uname -r) + - docker build -t frr-ubuntu18:latest -f docker/ubuntu18-ci/Dockerfile . + - docker images + - uname -a + - docker run -d --privileged --name frr-ubuntu18 --mount type=bind,source=/lib/modules,target=/lib/modules frr-ubuntu18:latest + - docker ps + - docker exec frr-ubuntu18 bash -c 'cd ~/frr ; make check' + - docker exec frr-ubuntu18 bash -c 'ps agxu ; lsmod | grep mpls || true' + - docker exec frr-ubuntu18 bash -c 'cd ~/frr/tests/topotests/ospf-topo1 ; sudo pytest test_ospf_topo1.py' + - docker exec frr-ubuntu18 bash -c 'cd ~/frr/tests/topotests/bgp_l3vpn_to_bgp_vrf ; sudo pytest test_bgp_l3vpn_to_bgp_vrf.py' + name: ubuntu18+minimalCI + - script: + - sudo apt install -y linux-modules-extra-$(uname -r) + - docker build -t frr-ubuntu20:latest -f docker/ubuntu20-ci/Dockerfile . + - docker images + - uname -a + - docker run -d --privileged --name frr-ubuntu20 --mount type=bind,source=/lib/modules,target=/lib/modules frr-ubuntu20:latest + - docker ps + - docker exec frr-ubuntu20 bash -c 'cd ~/frr ; make check' + - docker exec frr-ubuntu20 bash -c 'ps agxu ; lsmod | grep mpls || true' + - docker exec frr-ubuntu20 bash -c 'cd ~/frr/tests/topotests/ospf-topo1 ; sudo pytest test_ospf_topo1.py' + - docker exec frr-ubuntu20 bash -c 'cd ~/frr/tests/topotests/bgp_l3vpn_to_bgp_vrf ; sudo pytest test_bgp_l3vpn_to_bgp_vrf.py' + name: ubuntu20+minimalCI + 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/alpine/APKBUILD.in b/alpine/APKBUILD.in index d6c6c5f0af..dfedf0b52b 100644 --- a/alpine/APKBUILD.in +++ b/alpine/APKBUILD.in @@ -18,7 +18,7 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre perl pkgconf python3 python3-dev readline readline-dev sqlite-libs squashfs-tools sudo tar texinfo xorriso xz-libs py-pip rtrlib rtrlib-dev - py3-sphinx" + py3-sphinx elfutils elfutils-dev" checkdepends="pytest py-setuptools" install="$pkgname.pre-install $pkgname.pre-deinstall $pkgname.post-deinstall" subpackages="$pkgname-dev $pkgname-doc $pkgname-dbg" 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_evpn.c b/bgpd/bgp_evpn.c index 2d4fea413a..a9fceb6cde 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -5382,11 +5382,12 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, switch (ret) { case BGP_ERR_AS_MISMATCH: flog_err(EC_BGP_EVPN_AS_MISMATCH, - "BGP is already running; AS is %u", as); + "BGP instance is already running; AS is %u", + as); return -1; case BGP_ERR_INSTANCE_MISMATCH: flog_err(EC_BGP_EVPN_INSTANCE_MISMATCH, - "BGP instance name and AS number mismatch"); + "BGP instance type mismatch"); return -1; } diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index 868238ebdd..6467ff8a28 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -2493,6 +2493,10 @@ static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf *es_vrf, if (!CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE)) continue; + /* Don't overrun the zapi buffer. */ + if (api_nhg.nexthop_num == MULTIPATH_NUM) + break; + /* overwrite the gw */ if (v4_nhg) nh.gate.ipv4 = es_vtep->vtep_ip; @@ -2514,9 +2518,6 @@ static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf *es_vrf, if (!api_nhg.nexthop_num) return; - if (api_nhg.nexthop_num > MULTIPATH_NUM) - return; - zclient_nhg_send(zclient, ZEBRA_NHG_ADD, &api_nhg); } 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_io.c b/bgpd/bgp_io.c index a696d95697..c2d8cae580 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -180,8 +180,8 @@ static int bgp_process_reads(struct thread *thread) bool more = true; // whether we got more data bool fatal = false; // whether fatal error occurred bool added_pkt = false; // whether we pushed onto ->ibuf + int code = 0; // FSM code if error occurred /* clang-format on */ - int code; peer = THREAD_ARG(thread); @@ -455,6 +455,9 @@ done : { /* * Reads a chunk of data from peer->fd into peer->ibuf_work. * + * code_p + * Pointer to location to store FSM event code in case of fatal error. + * * @return status flag (see top-of-file) */ static uint16_t bgp_read(struct peer *peer, int *code_p) 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..307fa4e9bc 100644 --- a/bgpd/bgp_nb_config.c +++ b/bgpd/bgp_nb_config.c @@ -105,16 +105,22 @@ int bgp_router_create(struct nb_cb_create_args *args) if (inst_type == BGP_INSTANCE_TYPE_DEFAULT) is_new_bgp = (bgp_lookup(as, name) == NULL); + else + is_new_bgp = (bgp_lookup_by_name(name) == NULL); ret = bgp_get_vty(&bgp, &as, name, inst_type); - if (ret == BGP_ERR_INSTANCE_MISMATCH) { - snprintf( - args->errmsg, args->errmsg_len, - "BGP instance name and AS number mismatch\nBGP instance is already running; AS is %u, input-as %u", - bgp->as, as); - + switch (ret) { + case BGP_ERR_AS_MISMATCH: + snprintf(args->errmsg, args->errmsg_len, + "BGP instance is already running; AS is %u", + as); + return NB_ERR_INCONSISTENCY; + case BGP_ERR_INSTANCE_MISMATCH: + snprintf(args->errmsg, args->errmsg_len, + "BGP instance type mismatch"); return NB_ERR_INCONSISTENCY; } + /* * If we just instantiated the default instance, complete * any pending VRF-VPN leaking that was configured via @@ -123,7 +129,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 (is_new_bgp) bgp_vpn_leak_export(bgp); UNSET_FLAG(bgp->vrf_flags, BGP_VRF_AUTO); @@ -239,15 +250,17 @@ int bgp_global_local_as_modify(struct nb_cb_modify_args *args) inst_type = BGP_INSTANCE_TYPE_VIEW; ret = bgp_lookup_by_as_name_type(&bgp, &as, name, inst_type); - if (ret == BGP_ERR_INSTANCE_MISMATCH) { - snprintf( - args->errmsg, args->errmsg_len, - "BGP instance name and AS number mismatch\nBGP instance is already running; input-as %u", - as); - + switch (ret) { + case BGP_ERR_AS_MISMATCH: + snprintf(args->errmsg, args->errmsg_len, + "BGP instance is already running; AS is %u", + as); + return NB_ERR_VALIDATION; + case BGP_ERR_INSTANCE_MISMATCH: + snprintf(args->errmsg, args->errmsg_len, + "BGP instance type mismatch"); return NB_ERR_VALIDATION; } - break; case NB_EV_PREPARE: case NB_EV_ABORT: 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 f56c866de5..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); @@ -11620,13 +11620,13 @@ DEFUN (show_ip_bgp_large_community_list, struct bgp *bgp = NULL; bool uj = use_json(argc, argv); - if (uj) - argc--; + if (uj) + argc--; - bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi, - &bgp, uj); - if (!idx) - return CMD_WARNING; + bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi, + &bgp, uj); + if (!idx) + return CMD_WARNING; argv_find(argv, argc, "large-community-list", &idx); 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..20bb5e5320 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3376,7 +3376,7 @@ int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, const char *name, if (bgp) { if (bgp->as != *as) { *as = bgp->as; - return BGP_ERR_INSTANCE_MISMATCH; + return BGP_ERR_AS_MISMATCH; } if (bgp->inst_type != inst_type) return BGP_ERR_INSTANCE_MISMATCH; @@ -3397,13 +3397,8 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name, int ret = 0; ret = bgp_lookup_by_as_name_type(bgp_val, as, name, inst_type); - switch (ret) { - case BGP_ERR_INSTANCE_MISMATCH: + if (ret || *bgp_val) return ret; - case BGP_SUCCESS: - if (*bgp_val) - return ret; - } bgp = bgp_create(as, name, inst_type); if (bgp_option_check(BGP_OPT_NO_ZEBRA) && name) 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..f9fa8e0713 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,12 +453,15 @@ 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]) ]) +orig_cflags="$CFLAGS" +CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + AC_SEARCH_LIBS([pthread_condattr_setclock], [], [frr_cv_pthread_condattr_setclock=yes], [frr_cv_pthread_condattr_setclock=no]) @@ -462,6 +469,13 @@ if test "$frr_cv_pthread_condattr_setclock" = "yes"; then AC_DEFINE([HAVE_PTHREAD_CONDATTR_SETCLOCK], [1], [Have pthread.h pthread_condattr_setclock]) fi +AC_CHECK_HEADERS([pthread_np.h],,, [ +#include <pthread.h> +]) +AC_CHECK_FUNCS([pthread_setname_np pthread_set_name_np pthread_getthreadid_np]) + +CFLAGS="$orig_cflags" + dnl -------------- dnl Check programs dnl -------------- @@ -969,7 +983,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]) @@ -1037,11 +1051,6 @@ int main(int argc, char **argv) { ]) ]) -AC_CHECK_HEADERS([pthread_np.h],,, [ -#include <pthread.h> -]) -AC_CHECK_FUNCS([pthread_setname_np pthread_set_name_np pthread_getthreadid_np]) - needsync=true AS_IF([$needsync], [ @@ -1262,11 +1271,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 +1525,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 +2137,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 +2154,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 +2171,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 +2188,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 +2205,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 +2316,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 +2685,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/developer/building-docker.rst b/doc/developer/building-docker.rst index 852a295fd0..35b51cd9c0 100644 --- a/doc/developer/building-docker.rst +++ b/doc/developer/building-docker.rst @@ -12,6 +12,13 @@ source-built FRR on the following base platforms: * Centos 7 * Centos 8 +The following platform images are used to support Travis CI and can also +be used to reproduce topotest failures when the docker host is Ubuntu +(tested on 18.04 and 20.04): + +* Ubuntu 18.04 +* Ubuntu 20.04 + The following platform images may also be built, but these simply install a binary package from an existing repository and do not perform source builds: @@ -99,3 +106,60 @@ No script:: No script, multi-arch (ex. amd64, arm64):: docker buildx build --platform linux/amd64,linux/arm64 -f docker/centos-8/Dockerfile -t frr-centos8:latest . + + + +Building Ubuntu 18.04 Image +--------------------------- + +Build image (from project root directory):: + + docker build -t frr-ubuntu18:latest -f docker/ubuntu18-ci/Dockerfile . + +Start the container:: + + docker run -d --privileged --name frr-ubuntu18 --mount type=bind,source=/lib/modules,target=/lib/modules frr-ubuntu18:latest + +Running a topotest (when the docker host is Ubuntu):: + + docker exec frr-ubuntu18 bash -c 'cd ~/frr/tests/topotests/ospf-topo1 ; sudo pytest test_ospf_topo1.py' + +Starting an interactive bash session:: + + docker exec -it frr-ubuntu18 bash + +Stopping an removing a container:: + + docker stop frr-ubuntu18 ; docker rm frr-ubuntu18 + +Removing the built image:: + + docker rmi frr-ubuntu18:latest + + +Building Ubuntu 20.04 Image +--------------------------- + +Build image (from project root directory):: + + docker build -t frr-ubuntu20:latest -f docker/ubuntu20-ci/Dockerfile . + +Start the container:: + + docker run -d --privileged --name frr-ubuntu20 --mount type=bind,source=/lib/modules,target=/lib/modules frr-ubuntu20:latest + +Running a topotest (when the docker host is Ubuntu):: + + docker exec frr-ubuntu20 bash -c 'cd ~/frr/tests/topotests/ospf-topo1 ; sudo pytest test_ospf_topo1.py' + +Starting an interactive bash session:: + + docker exec -it frr-ubuntu20 bash + +Stopping an removing a container:: + + docker stop frr-ubuntu20 ; docker rm frr-ubuntu20 + +Removing the built image:: + + docker rmi frr-ubuntu20:latest diff --git a/doc/manpages/vtysh.rst b/doc/manpages/vtysh.rst index 3e496956c2..b930cb915d 100644 --- a/doc/manpages/vtysh.rst +++ b/doc/manpages/vtysh.rst @@ -53,6 +53,10 @@ OPTIONS available for the vtysh command: When executing cli that does not invoke a vtysh shell, if an error ocurrs ignore it for purposes of return codes from vtysh. +.. option:: -H, --histfile + + Override the history file for vtysh commands. You can set ``vtysh -H /dev/null`` to turn logging of at all. + .. option:: -u, --user Restrict access to configuration commands by preventing use of the "enable" command. This option provides the same limited "security" as password-protected telnet access. *This security should not be relied on in production environments.* @@ -68,6 +72,10 @@ ENVIRONMENT VARIABLES VTYSH_PAGER This should be the name of the pager to use. Default is more. +VTYSH_HISTFILE + Override the history file for vtysh commands. Logging can be turned off using ``VTYSH_HISTFILE=/dev/null vtysh``. + Environment is prefered way to override the history file path over command line argument (-H/--histfile). + FILES ===== |INSTALL_PREFIX_SBIN|/vtysh 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/ospfd.rst b/doc/user/ospfd.rst index 7d1e91dc41..ba9917f72f 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -299,15 +299,11 @@ To start OSPF process you have to specify the OSPF router. command can be used when the neighbor state get stuck at some state and this can be used to recover it from that state. -.. index:: maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM) -.. clicmd:: maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM) +.. clicmd:: maximum-paths (1-64) -.. index:: maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM) -.. clicmd:: no maximum-paths - - CLI to control maximum number of equal cost paths to reach a specific - destination.(ECMP) - Reset CLI, resets the maximum supported multi path to the default value. + Use this command to control the maximum number of equal cost paths to reach + a specific destination. The upper limit may differ if you change the value + of MULTIPATH_NUM during compilation. The default is MULTIPATH_NUM (64). .. _ospf-area: 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 126710f8c2..cb2b3eb69e 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -1,5 +1,5 @@ # This stage builds a dist tarball from the source -FROM alpine:latest as source-builder +FROM alpine:3.13 as source-builder RUN mkdir -p /src/alpine COPY alpine/APKBUILD.in /src/alpine @@ -21,7 +21,7 @@ RUN cd /src \ && make dist # This stage builds an apk from the dist tarball -FROM alpine:latest as alpine-builder +FROM alpine:3.13 as alpine-builder # Don't use nocache here so that abuild can use the cache RUN apk add \ --update-cache \ @@ -44,7 +44,7 @@ RUN cd /dist \ && abuild -r -P /pkgs/apk # This stage installs frr from the apk -FROM alpine:latest +FROM alpine:3.13 RUN mkdir -p /pkgs/apk COPY --from=alpine-builder /pkgs/apk/ /pkgs/apk/ RUN apk add \ @@ -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 new file mode 100644 index 0000000000..f6fa910381 --- /dev/null +++ b/docker/ubuntu18-ci/Dockerfile @@ -0,0 +1,71 @@ +FROM ubuntu:18.04 + +ARG DEBIAN_FRONTEND=noninteractive +ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn +# Update Ubuntu Software repository +RUN apt update && \ + apt-get install -y \ + git autoconf automake libtool make libreadline-dev texinfo \ + pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ + libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ + install-info build-essential libsystemd-dev libsnmp-dev perl libcap-dev \ + libelf-dev \ + sudo gdb iputils-ping time \ + mininet python-pip iproute2 iperf && \ + pip install ipaddr && \ + pip install "pytest<5" && \ + pip install "scapy>=2.4.2" && \ + pip install exabgp==3.4.17 + +RUN groupadd -r -g 92 frr && \ + groupadd -r -g 85 frrvty && \ + adduser --system --ingroup frr --home /home/frr \ + --gecos "FRR suite" --shell /bin/bash frr && \ + usermod -a -G frrvty frr && \ + useradd -d /var/run/exabgp/ -s /bin/false exabgp && \ + echo 'frr ALL = NOPASSWD: ALL' | tee /etc/sudoers.d/frr && \ + mkdir -p /home/frr && chown frr.frr /home/frr + +#for libyang 1 +RUN apt-get install -y cmake libpcre3-dev + +USER frr:frr + +# build and install libyang1 +RUN cd && pwd && ls -al && \ + git clone https://github.com/CESNET/libyang.git && \ + cd libyang && \ + git checkout v1.0.225 && \ + mkdir build; cd build && \ + cmake -DENABLE_LYD_PRIV=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr \ + -D CMAKE_BUILD_TYPE:String="Release" .. && \ + make -j $(nproc) && \ + sudo make install + +COPY --chown=frr:frr . /home/frr/frr/ + +RUN cd && ls -al && ls -al frr + +RUN cd ~/frr && \ + ./bootstrap.sh && \ + ./configure \ + --prefix=/usr \ + --localstatedir=/var/run/frr \ + --sbindir=/usr/lib/frr \ + --sysconfdir=/etc/frr \ + --enable-vtysh \ + --enable-pimd \ + --enable-sharpd \ + --enable-multipath=64 \ + --enable-user=frr \ + --enable-group=frr \ + --enable-vty-group=frrvty \ + --enable-snmp=agentx \ + --with-pkg-extra-version=-my-manual-build && \ + make -j $(nproc) && \ + sudo make install + +RUN cd ~/frr && make check || true + +COPY docker/ubuntu18-ci/docker-start /usr/sbin/docker-start +CMD ["/usr/sbin/docker-start"] diff --git a/docker/ubuntu18-ci/README.md b/docker/ubuntu18-ci/README.md new file mode 100644 index 0000000000..4e8ab891e6 --- /dev/null +++ b/docker/ubuntu18-ci/README.md @@ -0,0 +1,44 @@ +# Ubuntu 18.04 + +This builds an ubuntu 18.04 container for dev / test + +# Build + +``` +docker build -t frr-ubuntu18:latest -f docker/ubuntu18-ci/Dockerfile . +``` + +# Running + +``` +docker run -d --privileged --name frr-ubuntu18 --mount type=bind,source=/lib/modules,target=/lib/modules frr-ubuntu18:latest +``` + +# make check + +``` +docker exec frr-ubuntu18 bash -c 'cd ~/frr ; make check' +``` + +# interactive bash +``` +docker exec -it frr-ubuntu18 bash +``` + +# topotest -- when Host O/S is Ubuntu only + +``` +docker exec frr-ubuntu18 bash -c 'cd ~/frr/tests/topotests/ospf-topo1 ; sudo pytest test_ospf_topo1.py' +``` + +# stop & remove container + +``` +docker stop frr-ubuntu18 ; docker rm frr-ubuntu18 +``` + +# remove image + +``` +docker rmi frr-ubuntu18:latest +``` diff --git a/docker/ubuntu18-ci/docker-start b/docker/ubuntu18-ci/docker-start new file mode 100755 index 0000000000..9a45c722f1 --- /dev/null +++ b/docker/ubuntu18-ci/docker-start @@ -0,0 +1,8 @@ +#!/bin/bash + +if [ $(uname -a | grep -ci Ubuntu) -ge 1 ]; then + #for topotests under ubuntu host + sudo modprobe mpls-router mpls-iptunnel + sudo /etc/init.d/openvswitch-switch start +fi +while true ; do sleep 365d ; done diff --git a/docker/ubuntu20-ci/Dockerfile b/docker/ubuntu20-ci/Dockerfile new file mode 100644 index 0000000000..0b08c2f278 --- /dev/null +++ b/docker/ubuntu20-ci/Dockerfile @@ -0,0 +1,74 @@ +FROM ubuntu:20.04 + +ARG DEBIAN_FRONTEND=noninteractive +ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn +# Update Ubuntu Software repository +RUN apt update && \ + apt-get install -y \ + git autoconf automake libtool make libreadline-dev texinfo \ + pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ + libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ + install-info build-essential libsystemd-dev libsnmp-dev perl \ + libcap-dev python2 libelf-dev \ + sudo gdb curl iputils-ping time \ + mininet iproute2 iperf && \ + curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output /tmp/get-pip.py && \ + python2 /tmp/get-pip.py && \ + rm -f /tmp/get-pip.py && \ + pip2 install ipaddr && \ + pip2 install "pytest<5" && \ + pip2 install "scapy>=2.4.2" && \ + pip2 install exabgp==3.4.17 + +RUN groupadd -r -g 92 frr && \ + groupadd -r -g 85 frrvty && \ + adduser --system --ingroup frr --home /home/frr \ + --gecos "FRR suite" --shell /bin/bash frr && \ + usermod -a -G frrvty frr && \ + useradd -d /var/run/exabgp/ -s /bin/false exabgp && \ + echo 'frr ALL = NOPASSWD: ALL' | tee /etc/sudoers.d/frr && \ + mkdir -p /home/frr && chown frr.frr /home/frr + +#for libyang 1 +RUN apt-get install -y cmake libpcre3-dev + +USER frr:frr + +# build and install libyang1 +RUN cd && pwd && ls -al && \ + git clone https://github.com/CESNET/libyang.git && \ + cd libyang && \ + git checkout v1.0.225 && \ + mkdir build; cd build && \ + cmake -DENABLE_LYD_PRIV=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr \ + -D CMAKE_BUILD_TYPE:String="Release" .. && \ + make -j $(nproc) && \ + sudo make install + +COPY --chown=frr:frr . /home/frr/frr/ + +RUN cd && ls -al && ls -al frr + +RUN cd ~/frr && \ + ./bootstrap.sh && \ + ./configure \ + --prefix=/usr \ + --localstatedir=/var/run/frr \ + --sbindir=/usr/lib/frr \ + --sysconfdir=/etc/frr \ + --enable-vtysh \ + --enable-pimd \ + --enable-sharpd \ + --enable-multipath=64 \ + --enable-user=frr \ + --enable-group=frr \ + --enable-vty-group=frrvty \ + --enable-snmp=agentx \ + --with-pkg-extra-version=-my-manual-build && \ + make -j $(nproc) && \ + sudo make install + +RUN cd ~/frr && make check || true + +COPY docker/ubuntu20-ci/docker-start /usr/sbin/docker-start +CMD ["/usr/sbin/docker-start"] diff --git a/docker/ubuntu20-ci/README.md b/docker/ubuntu20-ci/README.md new file mode 100644 index 0000000000..11138c6507 --- /dev/null +++ b/docker/ubuntu20-ci/README.md @@ -0,0 +1,45 @@ +# Ubuntu 20.04 + +This builds an ubuntu 20.04 container for dev / test + +# Build + +``` +docker build -t frr-ubuntu20:latest -f docker/ubuntu20-ci/Dockerfile . +``` + +# Running + +``` +docker run -d --privileged --name frr-ubuntu20 --mount type=bind,source=/lib/modules,target=/lib/modules frr-ubuntu20:latest +``` + +# make check + +``` +docker exec frr-ubuntu20 bash -c 'cd ~/frr ; make check' +``` + +# interactive bash + +``` +docker exec -it frr-ubuntu20 bash +``` + +# topotest -- when Host O/S is Ubuntu only + +``` +docker exec frr-ubuntu20 bash -c 'cd ~/frr/tests/topotests/ospf-topo1 ; sudo pytest test_ospf_topo1.py' +``` + +# stop & remove container + +``` +docker stop frr-ubuntu20 ; docker rm frr-ubuntu18 +``` + +# remove image + +``` +docker rmi frr-ubuntu20:latest +``` diff --git a/docker/ubuntu20-ci/docker-start b/docker/ubuntu20-ci/docker-start new file mode 100755 index 0000000000..9a45c722f1 --- /dev/null +++ b/docker/ubuntu20-ci/docker-start @@ -0,0 +1,8 @@ +#!/bin/bash + +if [ $(uname -a | grep -ci Ubuntu) -ge 1 ]; then + #for topotests under ubuntu host + sudo modprobe mpls-router mpls-iptunnel + sudo /etc/init.d/openvswitch-switch start +fi +while true ; do sleep 365d ; done 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/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c index d21e3c0409..6e925d1410 100644 --- a/ldpd/ldp_vty_conf.c +++ b/ldpd/ldp_vty_conf.c @@ -429,6 +429,9 @@ ldp_vty_mpls_ldp(struct vty *vty, const char *negate) vty_conf->flags |= F_LDPD_ENABLED; } + /* register / de-register to recv info from zebra */ + ldp_zebra_regdereg_zebra_info(!negate); + ldp_config_apply(vty, vty_conf); return (CMD_SUCCESS); diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index 7a0e097dbd..fd51625bbd 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -54,6 +54,7 @@ static int ldp_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS); static void ldp_sync_zebra_init(void); static struct zclient *zclient; +static bool zebra_registered = false; static void ifp2kif(struct interface *ifp, struct kif *kif) @@ -629,14 +630,42 @@ ldp_zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS) return (0); } +void ldp_zebra_regdereg_zebra_info(bool want_register) +{ + if (zebra_registered == want_register) + return; + + log_debug("%s to receive default VRF information", + want_register ? "Register" : "De-register"); + + if (want_register) { + zclient_send_reg_requests(zclient, VRF_DEFAULT); + zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, + ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT); + zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, + AFI_IP6, ZEBRA_ROUTE_ALL, 0, + VRF_DEFAULT); + } else { + zclient_send_dereg_requests(zclient, VRF_DEFAULT); + zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, + AFI_IP, ZEBRA_ROUTE_ALL, 0, + VRF_DEFAULT); + zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, + AFI_IP6, ZEBRA_ROUTE_ALL, 0, + VRF_DEFAULT); + } + zebra_registered = want_register; +} + static void ldp_zebra_connected(struct zclient *zclient) { - zclient_send_reg_requests(zclient, VRF_DEFAULT); - zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, - ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT); - zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, - ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT); + zebra_registered = false; + + /* if MPLS was already enabled and we are re-connecting, register again + */ + if (vty_conf->flags & F_LDPD_ENABLED) + ldp_zebra_regdereg_zebra_info(true); ldp_zebra_opaque_register(); diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index df29d405ec..cb7ac85d96 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -905,6 +905,8 @@ int ldp_sync_zebra_send_state_update(struct ldp_igp_sync_if_state *); int ldp_zebra_send_rlfa_labels(struct zapi_rlfa_response * rlfa_labels); +void ldp_zebra_regdereg_zebra_info(bool want_register); + /* compatibility */ #ifndef __OpenBSD__ #define __IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f) 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" @@ -237,7 +237,7 @@ struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp, memset(sp, 0, sizeof(*sp)); /* Get interface index. */ - ifindex = stream_getl(s); + STREAM_GETL(s, ifindex); /* Lookup index. */ if (ifindex != 0) { @@ -252,25 +252,28 @@ struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp, } /* Fetch destination address. */ - dp->family = stream_getc(s); + STREAM_GETC(s, dp->family); plen = prefix_blen(dp); - stream_get(&dp->u.prefix, s, plen); - dp->prefixlen = stream_getc(s); + STREAM_GET(&dp->u.prefix, s, plen); + STREAM_GETC(s, dp->prefixlen); /* Get BFD status. */ - *status = stream_getl(s); + STREAM_GETL(s, (*status)); - sp->family = stream_getc(s); + STREAM_GETC(s, sp->family); plen = prefix_blen(sp); - stream_get(&sp->u.prefix, s, plen); - sp->prefixlen = stream_getc(s); + STREAM_GET(&sp->u.prefix, s, plen); + STREAM_GETC(s, sp->prefixlen); - local_remote_cbit = stream_getc(s); + STREAM_GETC(s, local_remote_cbit); if (remote_cbit) *remote_cbit = local_remote_cbit; return ifp; + +stream_failure: + return NULL; } /* @@ -616,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; @@ -745,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; @@ -779,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; - bsp->enabled = enable; + if (bsp->args.family != family) + return true; + + 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); @@ -811,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); @@ -828,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); @@ -861,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); @@ -871,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); @@ -882,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); @@ -906,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); } @@ -1057,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. */ @@ -1077,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; @@ -1094,6 +1138,13 @@ static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS) ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &state, &remote_cbit, vrf_id); + /* + * When interface lookup fails or an invalid stream is read, we must + * not proceed otherwise it will trigger an assertion while checking + * family type below. + */ + if (dp.family == 0 || sp.family == 0) + return 0; if (bsglobal.debugging) { ifstr[0] = 0; @@ -1127,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.c b/lib/command.c index d2798b5002..7fb405bdfb 100644 --- a/lib/command.c +++ b/lib/command.c @@ -900,13 +900,31 @@ enum node_type node_parent(enum node_type node) /* Execute command by argument vline vector. */ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter, struct vty *vty, - const struct cmd_element **cmd) + const struct cmd_element **cmd, + unsigned int up_level) { struct list *argv_list; enum matcher_rv status; const struct cmd_element *matched_element = NULL; + unsigned int i; + int xpath_index = vty->xpath_index; + int node = vty->node; - struct graph *cmdgraph = cmd_node_graph(cmdvec, vty->node); + /* only happens for legacy split config file load; need to check for + * a match before calling node_exit handlers below + */ + for (i = 0; i < up_level; i++) { + if (node <= CONFIG_NODE) + return CMD_NO_LEVEL_UP; + + node = node_parent(node); + + if (xpath_index > 0 + && vty_check_node_for_xpath_decrement(node, vty->node)) + xpath_index--; + } + + struct graph *cmdgraph = cmd_node_graph(cmdvec, node); status = command_match(cmdgraph, vline, &argv_list, &matched_element); if (cmd) @@ -926,12 +944,16 @@ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter, } } + for (i = 0; i < up_level; i++) + cmd_exit(vty); + // build argv array from argv list struct cmd_token **argv = XMALLOC( MTYPE_TMP, argv_list->count * sizeof(struct cmd_token *)); struct listnode *ln; struct cmd_token *token; - unsigned int i = 0; + + i = 0; for (ALL_LIST_ELEMENTS_RO(argv_list, ln, token)) argv[i++] = token; @@ -1012,7 +1034,7 @@ int cmd_execute_command(vector vline, struct vty *vty, vector_lookup(vline, index)); ret = cmd_execute_command_real(shifted_vline, FILTER_RELAXED, - vty, cmd); + vty, cmd, 0); vector_free(shifted_vline); vty->node = onode; @@ -1021,7 +1043,7 @@ int cmd_execute_command(vector vline, struct vty *vty, } saved_ret = ret = - cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd); + cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd, 0); if (vtysh) return saved_ret; @@ -1038,7 +1060,7 @@ int cmd_execute_command(vector vline, struct vty *vty, onode)) vty->xpath_index--; ret = cmd_execute_command_real(vline, FILTER_RELAXED, - vty, cmd); + vty, cmd, 0); if (ret == CMD_SUCCESS || ret == CMD_WARNING || ret == CMD_NOT_MY_INSTANCE || ret == CMD_WARNING_CONFIG_FAILED) @@ -1069,7 +1091,7 @@ int cmd_execute_command(vector vline, struct vty *vty, int cmd_execute_command_strict(vector vline, struct vty *vty, const struct cmd_element **cmd) { - return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd); + return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd, 0); } /* @@ -1220,6 +1242,7 @@ int command_config_read_one_line(struct vty *vty, { vector vline; int ret; + unsigned up_level = 0; vline = cmd_make_strvec(vty->buf); @@ -1230,36 +1253,20 @@ int command_config_read_one_line(struct vty *vty, /* Execute configuration command : this is strict match */ ret = cmd_execute_command_strict(vline, vty, cmd); - // Climb the tree and try the command again at each node - if (!(use_daemon && ret == CMD_SUCCESS_DAEMON) - && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO) - && ret != CMD_SUCCESS && ret != CMD_WARNING - && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED - && vty->node != CONFIG_NODE) { - int saved_node = vty->node; - int saved_xpath_index = vty->xpath_index; - - while (!(use_daemon && ret == CMD_SUCCESS_DAEMON) - && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO) - && ret != CMD_SUCCESS && ret != CMD_WARNING - && vty->node > CONFIG_NODE) { - vty->node = node_parent(vty->node); - if (vty->xpath_index > 0 - && vty_check_node_for_xpath_decrement(vty->node, - saved_node)) - vty->xpath_index--; - ret = cmd_execute_command_strict(vline, vty, cmd); - } - - // If climbing the tree did not work then ignore the command and - // stay at the same node - if (!(use_daemon && ret == CMD_SUCCESS_DAEMON) - && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO) - && ret != CMD_SUCCESS && ret != CMD_WARNING) { - vty->node = saved_node; - vty->xpath_index = saved_xpath_index; - } - } + /* The logic for trying parent nodes is in cmd_execute_command_real() + * since calling ->node_exit() correctly is a bit involved. This is + * also the only reason CMD_NO_LEVEL_UP exists. + */ + while (!(use_daemon && ret == CMD_SUCCESS_DAEMON) + && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO) + && ret != CMD_SUCCESS && ret != CMD_WARNING + && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED + && ret != CMD_NO_LEVEL_UP) + ret = cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd, + ++up_level); + + if (ret == CMD_NO_LEVEL_UP) + ret = CMD_ERR_NO_MATCH; if (ret != CMD_SUCCESS && ret != CMD_WARNING && diff --git a/lib/command.h b/lib/command.h index 14e51486ea..7e135dbcf6 100644 --- a/lib/command.h +++ b/lib/command.h @@ -223,6 +223,7 @@ struct cmd_node { #define CMD_SUSPEND 12 #define CMD_WARNING_CONFIG_FAILED 13 #define CMD_NOT_MY_INSTANCE 14 +#define CMD_NO_LEVEL_UP 15 /* Argc max counts. */ #define CMD_ARGC_MAX 256 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/filter.c b/lib/filter.c index 5dbf30daa6..b7a935d076 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -175,6 +175,11 @@ void access_list_delete(struct access_list *access) else list->head = access->next; + route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED); + + if (master->delete_hook) + master->delete_hook(access); + XFREE(MTYPE_ACCESS_LIST_STR, access->name); XFREE(MTYPE_TMP, access->remark); diff --git a/lib/filter_nb.c b/lib/filter_nb.c index 08c29789b9..85805ffa47 100644 --- a/lib/filter_nb.c +++ b/lib/filter_nb.c @@ -508,17 +508,12 @@ static int lib_access_list_create(struct nb_cb_create_args *args) static int lib_access_list_destroy(struct nb_cb_destroy_args *args) { - struct access_master *am; struct access_list *acl; if (args->event != NB_EV_APPLY) return NB_OK; acl = nb_running_unset_entry(args->dnode); - am = acl->master; - if (am->delete_hook) - am->delete_hook(acl); - access_list_delete(acl); return NB_OK; 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/lib_errors.c b/lib/lib_errors.c index 6e5088142a..17695e6607 100644 --- a/lib/lib_errors.c +++ b/lib/lib_errors.c @@ -45,9 +45,15 @@ static struct log_ref ferr_lib_warn[] = { .suggestion = "Gather log data and open an Issue. restart FRR", }, { - .code = EC_LIB_SLOW_THREAD, - .title = "The Event subsystem has detected a slow process", - .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug, or some combination therof.", + .code = EC_LIB_SLOW_THREAD_CPU, + .title = "The Event subsystem has detected a slow cpu time process", + .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug, or some combination therof. In this case total CPU time was over 5 seconds. Which indicates that FRR is very busy doing some work and should be addressed", + .suggestion = "Gather log data and open an Issue", + }, + { + .code = EC_LIB_SLOW_THREAD_WALL, + .title = "The Event subsystem has detected a slow wall time process", + .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug or some combination therof. In this case total WALL time was over 5 seconds. Which indicates that FRR might be having trouble being scheduled or some system call is delaying", .suggestion = "Gather log data and open an Issue", }, { diff --git a/lib/lib_errors.h b/lib/lib_errors.h index 4730b6aa33..9f0f58d20b 100644 --- a/lib/lib_errors.h +++ b/lib/lib_errors.h @@ -44,7 +44,8 @@ enum lib_log_refs { EC_LIB_SNMP, EC_LIB_STREAM, EC_LIB_LINUX_NS, - EC_LIB_SLOW_THREAD, + EC_LIB_SLOW_THREAD_CPU, + EC_LIB_SLOW_THREAD_WALL, EC_LIB_NO_THREAD, EC_LIB_RMAP_RECURSION_LIMIT, EC_LIB_BACKUP_CONFIG, 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/log_vty.c b/lib/log_vty.c index c26621ae99..c6788dd35a 100644 --- a/lib/log_vty.c +++ b/lib/log_vty.c @@ -146,11 +146,11 @@ void log_show_syslog(struct vty *vty) zlog_progname); } -DEFUN (show_logging, - show_logging_cmd, - "show logging", - SHOW_STR - "Show current logging configuration\n") +DEFUN_NOSH (show_logging, + show_logging_cmd, + "show logging", + SHOW_STR + "Show current logging configuration\n") { log_show_syslog(vty); 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/sigevent.c b/lib/sigevent.c index 64cec1385d..be7297f264 100644 --- a/lib/sigevent.c +++ b/lib/sigevent.c @@ -237,9 +237,12 @@ core_handler(int signo, siginfo_t *siginfo, void *context) /* make sure we don't hang in here. default for SIGALRM is terminate. * - if we're in backtrace for more than a second, abort. */ struct sigaction sa_default = {.sa_handler = SIG_DFL}; + sigaction(SIGALRM, &sa_default, NULL); + sigaction(signo, &sa_default, NULL); sigset_t sigset; + sigemptyset(&sigset); sigaddset(&sigset, SIGALRM); sigprocmask(SIG_UNBLOCK, &sigset, NULL); @@ -252,7 +255,16 @@ core_handler(int signo, siginfo_t *siginfo, void *context) log_memstats(stderr, "core_handler"); zlog_tls_buffer_fini(); - abort(); + + /* give the kernel a chance to generate a coredump */ + sigaddset(&sigset, signo); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + raise(signo); + + /* only chance to end up here is if the default action for signo is + * something other than kill or coredump the process + */ + _exit(128 + signo); } static void trap_default_signals(void) 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 0853d4bb2b..98ba1cf24c 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -141,10 +141,14 @@ vtysh_scan += \ lib/if_rmap.c \ lib/keychain.c \ lib/lib_vty.c \ + lib/log_vty.c \ lib/nexthop_group.c \ lib/plist.c \ + lib/resolver.c \ lib/routemap.c \ lib/routemap_cli.c \ + lib/spf_backoff.c \ + lib/thread.c \ lib/vrf.c \ lib/vty.c \ # end @@ -314,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 = \ @@ -330,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 = \ @@ -345,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 = \ @@ -359,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 @@ -371,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 @@ -410,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/thread.c b/lib/thread.c index 866090341e..3d8b544678 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -124,11 +124,12 @@ static void cpu_record_hash_free(void *a) static void vty_out_cpu_thread_history(struct vty *vty, struct cpu_thread_history *a) { - vty_out(vty, "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu", + vty_out(vty, "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu %9zu %9zu", a->total_active, a->cpu.total / 1000, a->cpu.total % 1000, - a->total_calls, (a->cpu.total / a->total_calls), a->cpu.max, - (a->real.total / a->total_calls), a->real.max); - vty_out(vty, " %c%c%c%c%c %s\n", + a->total_calls, (a->cpu.total / a->total_calls), a->cpu.max, + (a->real.total / a->total_calls), a->real.max, + a->total_cpu_warn, a->total_wall_warn); + vty_out(vty, " %c%c%c%c%c %s\n", a->types & (1 << THREAD_READ) ? 'R' : ' ', a->types & (1 << THREAD_WRITE) ? 'W' : ' ', a->types & (1 << THREAD_TIMER) ? 'T' : ' ', @@ -149,6 +150,10 @@ static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[]) atomic_load_explicit(&a->total_active, memory_order_seq_cst); copy.total_calls = atomic_load_explicit(&a->total_calls, memory_order_seq_cst); + copy.total_cpu_warn = + atomic_load_explicit(&a->total_cpu_warn, memory_order_seq_cst); + copy.total_wall_warn = + atomic_load_explicit(&a->total_wall_warn, memory_order_seq_cst); copy.cpu.total = atomic_load_explicit(&a->cpu.total, memory_order_seq_cst); copy.cpu.max = atomic_load_explicit(&a->cpu.max, memory_order_seq_cst); @@ -165,6 +170,8 @@ static void cpu_record_hash_print(struct hash_bucket *bucket, void *args[]) vty_out_cpu_thread_history(vty, ©); totals->total_active += copy.total_active; totals->total_calls += copy.total_calls; + totals->total_cpu_warn += copy.total_cpu_warn; + totals->total_wall_warn += copy.total_wall_warn; totals->real.total += copy.real.total; if (totals->real.max < copy.real.max) totals->real.max = copy.real.max; @@ -202,7 +209,7 @@ static void cpu_record_print(struct vty *vty, uint8_t filter) vty_out(vty, "Active Runtime(ms) Invoked Avg uSec Max uSecs"); vty_out(vty, " Avg uSec Max uSecs"); - vty_out(vty, " Type Thread\n"); + vty_out(vty, " CPU_Warn Wall_Warn Type Thread\n"); if (m->cpu_record->count) hash_iterate( @@ -223,7 +230,7 @@ static void cpu_record_print(struct vty *vty, uint8_t filter) vty_out(vty, "%30s %18s %18s\n", "", "CPU (user+system):", "Real (wall-clock):"); vty_out(vty, "Active Runtime(ms) Invoked Avg uSec Max uSecs"); - vty_out(vty, " Avg uSec Max uSecs"); + vty_out(vty, " Avg uSec Max uSecs CPU_Warn Wall_Warn"); vty_out(vty, " Type Thread\n"); if (tmp.total_calls > 0) @@ -300,13 +307,13 @@ static uint8_t parse_filter(const char *filterstr) } #ifndef EXCLUDE_CPU_TIME -DEFUN (show_thread_cpu, - show_thread_cpu_cmd, - "show thread cpu [FILTER]", - SHOW_STR - "Thread information\n" - "Thread CPU usage\n" - "Display filter (rwtex)\n") +DEFUN_NOSH (show_thread_cpu, + show_thread_cpu_cmd, + "show thread cpu [FILTER]", + SHOW_STR + "Thread information\n" + "Thread CPU usage\n" + "Display filter (rwtex)\n") { uint8_t filter = (uint8_t)-1U; int idx = 0; @@ -367,12 +374,12 @@ static void show_thread_poll_helper(struct vty *vty, struct thread_master *m) } } -DEFUN (show_thread_poll, - show_thread_poll_cmd, - "show thread poll", - SHOW_STR - "Thread information\n" - "Show poll FD's and information\n") +DEFUN_NOSH (show_thread_poll, + show_thread_poll_cmd, + "show thread poll", + SHOW_STR + "Thread information\n" + "Show poll FD's and information\n") { struct listnode *node; struct thread_master *m; @@ -1850,15 +1857,33 @@ void thread_call(struct thread *thread) memory_order_seq_cst); #ifdef CONSUMED_TIME_CHECK - if (realtime > CONSUMED_TIME_CHECK) { + if (cputime > CONSUMED_TIME_CHECK) { /* - * We have a CPU Hog on our hands. + * We have a CPU Hog on our hands. The time FRR + * has spent doing actual work ( not sleeping ) + * is greater than 5 seconds. * Whinge about it now, so we're aware this is yet another task * to fix. */ + atomic_fetch_add_explicit(&thread->hist->total_cpu_warn, + 1, memory_order_seq_cst); + flog_warn( + EC_LIB_SLOW_THREAD_CPU, + "CPU HOG: task %s (%lx) ran for %lums (cpu time %lums)", + thread->xref->funcname, (unsigned long)thread->func, + realtime / 1000, cputime / 1000); + } else if (realtime > CONSUMED_TIME_CHECK) { + /* + * The runtime for a task is greater than 5 seconds, but + * the cpu time is under 5 seconds. Let's whine + * about this because this could imply some sort of + * scheduling issue. + */ + atomic_fetch_add_explicit(&thread->hist->total_wall_warn, + 1, memory_order_seq_cst); flog_warn( - EC_LIB_SLOW_THREAD, - "SLOW THREAD: task %s (%lx) ran for %lums (cpu time %lums)", + EC_LIB_SLOW_THREAD_WALL, + "STARVATION: task %s (%lx) ran for %lums (cpu time %lums)", thread->xref->funcname, (unsigned long)thread->func, realtime / 1000, cputime / 1000); } diff --git a/lib/thread.h b/lib/thread.h index af68331131..fee728dbf9 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -119,6 +119,8 @@ struct thread { struct cpu_thread_history { int (*func)(struct thread *); + atomic_size_t total_cpu_warn; + atomic_size_t total_wall_warn; atomic_size_t total_calls; atomic_size_t total_active; struct time_stats { 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 @@ -515,13 +515,19 @@ static int vty_command(struct vty *vty, char *buf) #ifdef CONSUMED_TIME_CHECK GETRUSAGE(&after); - if ((realtime = thread_consumed_time(&after, &before, &cputime)) - > CONSUMED_TIME_CHECK) + realtime = thread_consumed_time(&after, &before, &cputime); + if (cputime > CONSUMED_TIME_CHECK) { /* Warn about CPU hog that must be fixed. */ flog_warn( - EC_LIB_SLOW_THREAD, - "SLOW COMMAND: command took %lums (cpu time %lums): %s", + EC_LIB_SLOW_THREAD_CPU, + "CPU HOG: command took %lums (cpu time %lums): %s", realtime / 1000, cputime / 1000, buf); + } else if (realtime > CONSUMED_TIME_CHECK) { + flog_warn( + EC_LIB_SLOW_THREAD_WALL, + "STARVATION: command took %lums (cpu time %lums): %s", + realtime / 1000, cputime / 1000, buf); + } } #endif /* CONSUMED_TIME_CHECK */ diff --git a/lib/xref.h b/lib/xref.h index b1cb172b41..63166b069a 100644 --- a/lib/xref.h +++ b/lib/xref.h @@ -137,6 +137,19 @@ extern void xref_gcc_workaround(const struct xref *xref); extern const struct xref * const __start_xref_array[1] DSO_LOCAL; extern const struct xref * const __stop_xref_array[1] DSO_LOCAL; +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +/* no redzone around each of the xref_p please, we're building an array out + * of variables here. kinda breaks things if there's redzones between each + * array item. + */ +#define xref_array_attr used, section("xref_array"), no_sanitize("address") +#endif +#endif +#ifndef xref_array_attr +#define xref_array_attr used, section("xref_array") +#endif + /* this macro is invoked once for each standalone DSO through * FRR_MODULE_SETUP \ * }-> FRR_COREMOD_SETUP -> XREF_SETUP @@ -151,8 +164,7 @@ extern const struct xref * const __stop_xref_array[1] DSO_LOCAL; /* .func = */ "dummy", \ }; \ static const struct xref * const _dummy_xref_p \ - __attribute__((used, section("xref_array"))) \ - = &_dummy_xref; \ + __attribute__((xref_array_attr)) = &_dummy_xref; \ static void __attribute__((used, _CONSTRUCTOR(1100))) \ _xref_init(void) { \ static struct xref_block _xref_block = { \ @@ -225,7 +237,7 @@ extern const struct xref * const __stop_xref_array[1] DSO_LOCAL; #if defined(__clang__) || !defined(__cplusplus) #define XREF_LINK(dst) \ static const struct xref * const NAMECTR(xref_p_) \ - __attribute__((used, section("xref_array"))) \ + __attribute__((xref_array_attr)) \ = &(dst) \ /* end */ diff --git a/lib/zclient.h b/lib/zclient.h index 90240e40b2..26fa73fc0a 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -754,6 +754,29 @@ enum zclient_send_status { }; static inline const char * +zapi_nhg_notify_owner2str(enum zapi_nhg_notify_owner note) +{ + const char *ret = "UNKNOWN"; + + switch (note) { + case ZAPI_NHG_FAIL_INSTALL: + ret = "ZAPI_NHG_FAIL_INSTALL"; + break; + case ZAPI_NHG_INSTALLED: + ret = "ZAPI_NHG_INSTALLED"; + break; + case ZAPI_NHG_REMOVE_FAIL: + ret = "ZAPI_NHG_REMOVE_FAIL"; + break; + case ZAPI_NHG_REMOVED: + ret = "ZAPI_NHG_REMOVED"; + break; + } + + return ret; +} + +static inline const char * zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note) { const char *ret = "UNKNOWN"; 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/lib/zlog.c b/lib/zlog.c index f546709328..24800c6e64 100644 --- a/lib/zlog.c +++ b/lib/zlog.c @@ -142,6 +142,7 @@ struct zlog_msg { struct zlog_tls { char *mmbuf; size_t bufpos; + bool do_unlink; size_t nmsgs; struct zlog_msg msgs[TLS_LOG_MAXMSG]; @@ -266,13 +267,14 @@ void zlog_tls_buffer_init(void) mmpath, strerror(errno)); goto out_anon_unlink; } + zlog_tls->do_unlink = true; close(mmfd); zlog_tls_set(zlog_tls); return; out_anon_unlink: - unlink(mmpath); + unlinkat(zlog_tmpdirfd, mmpath, 0); close(mmfd); out_anon: @@ -296,14 +298,16 @@ out_anon: void zlog_tls_buffer_fini(void) { char mmpath[MAXPATHLEN]; + struct zlog_tls *zlog_tls = zlog_tls_get(); + bool do_unlink = zlog_tls ? zlog_tls->do_unlink : false; zlog_tls_buffer_flush(); - zlog_tls_free(zlog_tls_get()); + zlog_tls_free(zlog_tls); zlog_tls_set(NULL); snprintfrr(mmpath, sizeof(mmpath), "logbuf.%ld", zlog_gettid()); - if (unlinkat(zlog_tmpdirfd, mmpath, 0)) + if (do_unlink && unlinkat(zlog_tmpdirfd, mmpath, 0)) zlog_err("unlink logbuf: %s (%d)", strerror(errno), errno); } diff --git a/lib/zlog_targets.c b/lib/zlog_targets.c index f258a8fbbd..7799fbfda7 100644 --- a/lib/zlog_targets.c +++ b/lib/zlog_targets.c @@ -78,40 +78,48 @@ void zlog_fd(struct zlog_target *zt, struct zlog_msg *msgs[], size_t nmsgs) struct zlog_msg *msg = msgs[i]; int prio = zlog_msg_prio(msg); - if (prio > zt->prio_min) - continue; - - iov[iovpos].iov_base = ts_pos; - if (iovpos > 0) - *ts_pos++ = '\n'; - ts_pos += zlog_msg_ts(msg, ts_pos, sizeof(ts_buf) - 1 - - (ts_pos - ts_buf), - ZLOG_TS_LEGACY | zte->ts_subsec); - *ts_pos++ = ' '; - iov[iovpos].iov_len = ts_pos - (char *)iov[iovpos].iov_base; + if (prio <= zt->prio_min) { + iov[iovpos].iov_base = ts_pos; + if (iovpos > 0) + *ts_pos++ = '\n'; + ts_pos += zlog_msg_ts(msg, ts_pos, + sizeof(ts_buf) - 1 + - (ts_pos - ts_buf), + ZLOG_TS_LEGACY | zte->ts_subsec); + *ts_pos++ = ' '; + iov[iovpos].iov_len = + ts_pos - (char *)iov[iovpos].iov_base; - iovpos++; + iovpos++; - if (zte->record_priority) { - iov[iovpos].iov_base = (char *)prionames[prio]; - iov[iovpos].iov_len = strlen(iov[iovpos].iov_base); + if (zte->record_priority) { + iov[iovpos].iov_base = (char *)prionames[prio]; + iov[iovpos].iov_len = + strlen(iov[iovpos].iov_base); - iovpos++; - } + iovpos++; + } - iov[iovpos].iov_base = zlog_prefix; - iov[iovpos].iov_len = zlog_prefixsz; + iov[iovpos].iov_base = zlog_prefix; + iov[iovpos].iov_len = zlog_prefixsz; - iovpos++; + iovpos++; - iov[iovpos].iov_base = (char *)zlog_msg_text(msg, &textlen); - iov[iovpos].iov_len = textlen; + iov[iovpos].iov_base = + (char *)zlog_msg_text(msg, &textlen); + iov[iovpos].iov_len = textlen; - iovpos++; + iovpos++; + } - if (ts_buf + sizeof(ts_buf) - ts_pos < TS_LEN - || i + 1 == nmsgs - || array_size(iov) - iovpos < 5) { + /* conditions that trigger writing: + * - out of space for more timestamps/headers + * - this being the last message in the batch + * - not enough remaining iov entries + */ + if (iovpos > 0 && (ts_buf + sizeof(ts_buf) - ts_pos < TS_LEN + || i + 1 == nmsgs + || array_size(iov) - iovpos < 5)) { iov[iovpos].iov_base = (char *)"\n"; iov[iovpos].iov_len = 1; 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/linux.c b/nhrpd/linux.c index bcf97f030a..f697311d49 100644 --- a/nhrpd/linux.c +++ b/nhrpd/linux.c @@ -60,7 +60,7 @@ int os_sendmsg(const uint8_t *buf, size_t len, int ifindex, const uint8_t *addr, .msg_iov = &iov, .msg_iovlen = 1, }; - int status; + int status, fd; if (addrlen > sizeof(lladdr.sll_addr)) return -1; @@ -72,7 +72,11 @@ int os_sendmsg(const uint8_t *buf, size_t len, int ifindex, const uint8_t *addr, lladdr.sll_halen = addrlen; memcpy(lladdr.sll_addr, addr, addrlen); - status = sendmsg(os_socket(), &msg, 0); + fd = os_socket(); + if (fd < 0) + return -1; + + status = sendmsg(fd, &msg, 0); if (status < 0) return -errno; 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 e2cd5c259d..8c6d4b126d 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -814,7 +814,7 @@ DEFUN (no_ospf6_interface_area, /* Verify Area */ if (oi->area == NULL) { vty_out(vty, "%s not attached to area %s\n", - oi->interface->name, oi->area->name); + oi->interface->name, argv[idx_ipv4]->arg); return CMD_SUCCESS; } @@ -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); @@ -1120,6 +1119,80 @@ static void ospf6_show(struct vty *vty, struct ospf6 *o, json_object *json, } } +DEFUN(show_ipv6_ospf6_vrfs, show_ipv6_ospf6_vrfs_cmd, + "show ipv6 ospf6 vrfs [json]", + SHOW_STR IP6_STR OSPF6_STR "Show OSPF6 VRFs \n" JSON_STR) +{ + bool uj = use_json(argc, argv); + json_object *json = NULL; + json_object *json_vrfs = NULL; + struct ospf6 *ospf6 = NULL; + struct listnode *node = NULL; + int count = 0; + char buf[PREFIX_STRLEN]; + static const char header[] = + "Name Id RouterId "; + + if (uj) { + json = json_object_new_object(); + json_vrfs = json_object_new_object(); + } + + for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { + json_object *json_vrf = NULL; + const char *name = NULL; + int64_t vrf_id_ui = 0; + struct in_addr router_id; + + router_id.s_addr = ospf6->router_id; + count++; + + if (!uj && count == 1) + vty_out(vty, "%s\n", header); + if (uj) + json_vrf = json_object_new_object(); + + if (ospf6->vrf_id == VRF_DEFAULT) + name = VRF_DEFAULT_NAME; + else + name = ospf6->name; + + vrf_id_ui = (ospf6->vrf_id == VRF_UNKNOWN) + ? -1 + : (int64_t)ospf6->vrf_id; + + if (uj) { + json_object_int_add(json_vrf, "vrfId", vrf_id_ui); + json_object_string_add(json_vrf, "routerId", + inet_ntop(AF_INET, &router_id, + buf, sizeof(buf))); + json_object_object_add(json_vrfs, name, json_vrf); + + } else { + vty_out(vty, "%-25s %-5d %-16s \n", name, + ospf6->vrf_id, + inet_ntop(AF_INET, &router_id, buf, + sizeof(buf))); + } + } + + if (uj) { + json_object_object_add(json, "vrfs", json_vrfs); + json_object_int_add(json, "totalVrfs", count); + + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else { + if (count) + vty_out(vty, "\nTotal number of OSPF VRFs: %d\n", + count); + } + + return CMD_SUCCESS; +} + /* show top level structures */ DEFUN(show_ipv6_ospf6, show_ipv6_ospf6_cmd, @@ -1360,6 +1433,7 @@ void ospf6_top_init(void) install_node(&ospf6_node); install_element(VIEW_NODE, &show_ipv6_ospf6_cmd); + install_element(VIEW_NODE, &show_ipv6_ospf6_vrfs_cmd); install_element(CONFIG_NODE, &router_ospf6_cmd); install_element(CONFIG_NODE, &no_router_ospf6_cmd); 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_dump.c b/ospfd/ospf_dump.c index 2442f2e781..8f31f90346 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -169,8 +169,7 @@ const char *ospf_timeval_dump(struct timeval *t, char *buf, size_t size) /* Making formatted timer strings. */ #define MINUTE_IN_SECONDS 60 #define HOUR_IN_SECONDS (60*MINUTE_IN_SECONDS) -#define DAY_IN_SECONDS (24*HOUR_IN_SECONDS) -#define WEEK_IN_SECONDS (7*DAY_IN_SECONDS) + unsigned long w, d, h, m, ms, us; if (!t) @@ -191,14 +190,14 @@ const char *ospf_timeval_dump(struct timeval *t, char *buf, size_t size) ms %= 1000; } - if (t->tv_sec > WEEK_IN_SECONDS) { - w = t->tv_sec / WEEK_IN_SECONDS; - t->tv_sec -= w * WEEK_IN_SECONDS; + if (t->tv_sec > ONE_WEEK_SECOND) { + w = t->tv_sec / ONE_WEEK_SECOND; + t->tv_sec -= w * ONE_WEEK_SECOND; } - if (t->tv_sec > DAY_IN_SECONDS) { - d = t->tv_sec / DAY_IN_SECONDS; - t->tv_sec -= d * DAY_IN_SECONDS; + if (t->tv_sec > ONE_DAY_SECOND) { + d = t->tv_sec / ONE_DAY_SECOND; + t->tv_sec -= d * ONE_DAY_SECOND; } if (t->tv_sec >= HOUR_IN_SECONDS) { @@ -221,7 +220,7 @@ const char *ospf_timeval_dump(struct timeval *t, char *buf, size_t size) snprintf(buf, size, "%luh%02lum%02lds", h, m, (long)t->tv_sec); else if (m) snprintf(buf, size, "%lum%02lds", m, (long)t->tv_sec); - else if (ms) + else if (t->tv_sec > 0 || ms > 0) snprintf(buf, size, "%ld.%03lus", (long)t->tv_sec, ms); else snprintf(buf, size, "%ld usecs", (long)t->tv_usec); 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 38df326489..0666e8d3c8 100644 --- a/pathd/subdir.am +++ b/pathd/subdir.am @@ -5,13 +5,13 @@ if PATHD noinst_LIBRARIES += pathd/libpath.a sbin_PROGRAMS += pathd/pathd -vtysh_scan += $(top_srcdir)/pathd/path_cli.c +vtysh_scan += pathd/path_cli.c vtysh_daemons += pathd # TODO add man page #man8 += $(MANBUILD)/pathd.8 if PATHD_PCEP -vtysh_scan += $(top_srcdir)/pathd/path_pcep_cli.c +vtysh_scan += pathd/path_pcep_cli.c module_LTLIBRARIES += pathd/pathd_pcep.la endif @@ -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/python/vtysh-cmd-check.py b/python/vtysh-cmd-check.py new file mode 100644 index 0000000000..ef9eea41ad --- /dev/null +++ b/python/vtysh-cmd-check.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +# +# Quick demo program that checks whether files define commands that aren't +# in vtysh. Execute after building. +# +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# For more information, please refer to <http://unlicense.org/> + +import os +import json +import subprocess + +os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +with open("frr.xref", "r") as fd: + data = json.load(fd) + +vtysh_scan, _ = subprocess.Popen( + ["make", "var-vtysh_scan"], stdout=subprocess.PIPE +).communicate() +vtysh_scan = set(vtysh_scan.decode("US-ASCII").split()) + +check = set() +vtysh = {} + +for cmd, defs in data["cli"].items(): + for binary, clidef in defs.items(): + if clidef["defun"]["file"].startswith("vtysh/"): + vtysh[clidef["string"]] = clidef + +for cmd, defs in data["cli"].items(): + for binary, clidef in defs.items(): + if clidef["defun"]["file"].startswith("vtysh/"): + continue + + if clidef["defun"]["file"] not in vtysh_scan: + vtysh_def = vtysh.get(clidef["string"]) + if vtysh_def is not None: + print( + "\033[33m%s defines %s, has a custom define in vtysh %s\033[m" + % (clidef["defun"]["file"], cmd, vtysh_def["defun"]["file"]) + ) + else: + print( + "\033[31m%s defines %s, not in vtysh_scan\033[m" + % (clidef["defun"]["file"], cmd) + ) + check.add(clidef["defun"]["file"]) + +print("\nfiles to check:\n\t" + " ".join(sorted(check))) 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 b70626fcce..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) @@ -287,272 +283,6 @@ def next_hop_per_address_family( return next_hop -def test_BGP_GR_TC_46_p1(request): - """ - Test Objective : transition from Peer-level helper to Global Restarting - Global Mode : GR Restarting - PerPeer Mode : GR Helper - GR Mode effective : GR Helper - - """ - - tgen = get_topogen() - tc_name = request.node.name - write_test_header(tc_name) - - # Check router status - check_router_status(tgen) - - # Don't run this test if we have any failure. - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - # Creating configuration from JSON - reset_config_on_routers(tgen) - - step( - "Configure R1 and R2 as GR restarting node in global" - " and helper in per-Peer-level" - ) - - input_dict = { - "r1": { - "bgp": { - "graceful-restart": { - "graceful-restart": True, - }, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-helper": True} - } - } - } - } - }, - }, - } - }, - "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - step("Verify on R2 that R1 advertises GR capabilities as a restarting node") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r2" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - for addr_type in ADDR_TYPES: - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - for addr_type in ADDR_TYPES: - next_hop = next_hop_per_address_family( - tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - step("Kill BGP on R2") - - kill_router_daemons(tgen, "r2", ["bgpd"]) - - step( - "Verify that R1 keeps the stale entries in RIB & FIB and R2 keeps stale entries in FIB using" - ) - - for addr_type in ADDR_TYPES: - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - for addr_type in ADDR_TYPES: - next_hop = next_hop_per_address_family( - tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - step( - "Bring up BGP on R1 and remove Peer-level GR config" - " from R1 following by a session reset" - ) - - start_router_daemons(tgen, "r2", ["bgpd"]) - - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-helper": False} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-helper": False} - } - } - } - } - }, - } - } - } - } - - result = create_router_bgp(tgen, topo, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - step("Verify on R2 that R1 advertises GR capabilities as a restarting node") - - input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, - "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, - } - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r2" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - for addr_type in ADDR_TYPES: - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) - assert ( - result is True - ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( - tc_name, result - ) - - for addr_type in ADDR_TYPES: - next_hop = next_hop_per_address_family( - tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - result = verify_bgp_rib(tgen, addr_type, "r2", input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) - assert ( - result is True - ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( - tc_name, result - ) - - step("Kill BGP on R1") - - kill_router_daemons(tgen, "r1", ["bgpd"]) - - step( - "Verify that R1 keeps the stale entries in FIB command and R2 keeps stale entries in RIB & FIB" - ) - - for addr_type in ADDR_TYPES: - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) - assert ( - result is True - ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( - tc_name, result - ) - - for addr_type in ADDR_TYPES: - next_hop = next_hop_per_address_family( - tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - result = verify_bgp_rib(tgen, addr_type, "r2", input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) - assert ( - result is True - ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( - tc_name, result - ) - - step("Start BGP on R1") - - start_router_daemons(tgen, "r1", ["bgpd"]) - - write_test_footer(tc_name) - - def BGP_GR_TC_50_p1(request): """ Test Objective : Transition from Peer-level helper to Global inherit helper @@ -1979,198 +1709,6 @@ def test_BGP_GR_TC_8_p1(request): write_test_footer(tc_name) -def test_BGP_GR_TC_17_p1(request): - """ - Test Objective : Verify that only GR helper routers keep the stale - route entries, not any GR disabled router. - """ - - tgen = get_topogen() - tc_name = request.node.name - write_test_header(tc_name) - - # Check router status - check_router_status(tgen) - - # Don't run this test if we have any failure. - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - # Creating configuration from JSON - reset_config_on_routers(tgen) - - logger.info("[Phase 1] : Test Setup [Disable]R1-----R2[Restart] initialized ") - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "graceful-restart": { - "graceful-restart": True, - "preserve-fw-state": True, - }, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-disable": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-disable": True} - } - } - } - } - }, - }, - } - }, - "r2": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2-link1": {"graceful-restart": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2-link1": {"graceful-restart": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r2" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes - dut = "r1" - peer = "r2" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - protocol = "bgp" - result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("[Phase 2] : R2 goes for reload ") - - kill_router_daemons(tgen, "r2", ["bgpd"]) - - logger.info( - "[Phase 3] : R2 is still down, restart time 120 sec." - " So time verify the routes are present in BGP RIB and ZEBRA " - ) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib( - tgen, addr_type, dut, input_topo, next_hop, expected=False - ) - assert result is not True, ( - "Testcase {} : Failed \n " - "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - ) - ) - logger.info(" Expected behavior: {}".format(result)) - - # Verifying RIB routes - result = verify_rib( - tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False - ) - assert result is not True, ( - "Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) - ) - logger.info(" Expected behavior: {}".format(result)) - - logger.info("[Phase 5] : R2 is about to come up now ") - start_router_daemons(tgen, "r2", ["bgpd"]) - - logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r2" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - result = verify_r_bit( - tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False - ) - assert ( - result is not True - ), "Testcase {} : Failed \n " "r1: R-bit is set to True\n Error: {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - def test_BGP_GR_TC_19_p1(request): """ Test Objective : Verify that GR helper routers keeps all the routes received 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_ipv6_rtadv/test_bgp_ipv6_rtadv.py b/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py index cd845be296..0df2c9cb5a 100644 --- a/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py +++ b/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py @@ -112,7 +112,7 @@ def test_protocols_convergence(): test_func = partial( topotest.router_json_cmp, router, - "show ip route json".format(router.name), + "show ip route json", expected, ) _, result = topotest.run_and_expect(test_func, None, count=160, wait=0.5) @@ -131,7 +131,7 @@ def test_protocols_convergence(): test_func = partial( topotest.router_json_cmp, router, - "show ipv6 route json".format(router.name), + "show ipv6 route json", expected, ) _, result = topotest.run_and_expect(test_func, None, count=160, wait=0.5) 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 5ecaee2ece..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) @@ -2677,14 +2673,12 @@ def test_route_map_within_vrf_to_alter_bgp_attribute_nexthop_p0(request): result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) assert ( result is not True - ), "Testcase {} : Failed \n Expected Behaviour: Routes are rejected because" - " nexthop-self config is deleted \n Error {}".format(tc_name, result) + ), "Testcase {} : Failed \n Expected Behaviour: Routes are rejected because nexthop-self config is deleted \n Error {}".format(tc_name, result) result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False) assert ( result is not True - ), "Testcase {} : Failed \n Expected Behaviour: Routes are rejected because" - " nexthop-self config is deleted \n Error {}".format(tc_name, result) + ), "Testcase {} : Failed \n Expected Behaviour: Routes are rejected because nexthop-self config is deleted \n Error {}".format(tc_name, result) write_test_footer(tc_name) @@ -4958,8 +4952,7 @@ def test_prefix_list_to_permit_deny_prefixes_p0(request): result = verify_rib(tgen, addr_type, dut, denied_routes, expected=False) assert result is not True, "Testcase {} : Failed \n" - "Expected behaviour: Routes are denied by prefix-list \n" - "Error {}".format(tc_name, result) + "{}:Expected behaviour: Routes are denied by prefix-list \nError {}".format(tc_name, result) step( "On router R1, configure prefix-lists to permit 2 " @@ -5169,9 +5162,7 @@ def test_prefix_list_to_permit_deny_prefixes_p0(request): ) result = verify_rib(tgen, addr_type, dut, denied_routes, expected=False) - assert result is not True, "Testcase {} : Failed \n" - "Expected behaviour: Routes are denied by prefix-list \n" - "Error {}".format(tc_name, result) + assert result is not True, "Testcase {} : Failed \nExpected behaviour: Routes are denied by prefix-list \nError {}".format(tc_name, result) write_test_footer(tc_name) @@ -5449,8 +5440,7 @@ def test_route_map_set_and_match_tag_p0(request): result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False) assert ( result is not True - ), "Testcase {} : Failed \n Expected Behavior: Routes are denied \n" - "Error {}".format(tc_name, result) + ), "Testcase {} : Failed \n Expected Behavior: Routes are denied \nError {}".format(tc_name, result) write_test_footer(tc_name) @@ -5853,8 +5843,7 @@ def test_route_map_set_and_match_metric_p0(request): result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False) assert ( result is not True - ), "Testcase {} : Failed \n Expected Behavior: Routes are denied \n" - "Error {}".format(tc_name, result) + ), "Testcase {} : Failed \n Expected Behavior: Routes are denied \nError {}".format(tc_name, result) write_test_footer(tc_name) 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 c8d1330122..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) @@ -1571,9 +1567,7 @@ def test_shut_noshut_p1(request): sleep(HOLDDOWNTIMER + 1) result = verify_bgp_convergence(tgen, topo, expected=False) - assert result is not True, "Testcase {} : Failed \n " - "Expected Behaviour: BGP will not be converged \n " - "Error {}".format(tc_name, result) + assert result is not True, "Testcase {} : Failed \nExpected Behaviour: BGP will not be converged \nError {}".format(tc_name, result) for addr_type in ADDR_TYPES: dut = "r2" @@ -1616,14 +1610,10 @@ def test_shut_noshut_p1(request): } result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, "Testcase {} : Failed \n " - " Expected Behaviour: Routes are flushed out \n " - "Error {}".format(tc_name, result) + assert result is not True, "Testcase {} : Failed \nExpected Behaviour: Routes are flushed out \nError {}".format(tc_name, result) result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False) - assert result is not True, "Testcase {} : Failed \n " - " Expected Behaviour: Routes are flushed out \n " - "Error {}".format(tc_name, result) + assert result is not True, "Testcase {} : Failed \nExpected Behaviour: Routes are flushed out \nError {}".format(tc_name, result) step("Bring up connecting interface between R1<<>>R2 on R1.") for intf in interfaces: @@ -1862,8 +1852,7 @@ def test_vrf_vlan_routing_table_p1(request): result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) assert ( result is not True - ), "Testcase {} : Failed \n Expected Behaviour: Routes are" - " cleaned \n Error {}".format(tc_name, result) + ), "Testcase {} : Failed \n Expected Behaviour: Routes are cleaned \n Error {}".format(tc_name, result) step("Add/reconfigure the same VRF instance again") @@ -2180,7 +2169,7 @@ def test_restart_bgpd_daemon_p1(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) result = verify_bgp_convergence(tgen, topo) - assert result is True, "Testcase () :Failed\n Error {}".format(tc_name, result) + assert result is True, "Testcase {} :Failed\n Error {}".format(tc_name, result) step("Kill BGPd daemon on R1.") kill_router_daemons(tgen, "r1", ["bgpd"]) @@ -3392,14 +3381,12 @@ def test_vrf_name_significance_p1(request): result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) assert ( result is not True - ), "Testcase {} :Failed \n Expected Behaviour: Routes are not" - " present \n Error {}".format(tc_name, result) + ), "Testcase {} :Failed \n Expected Behaviour: Routes are not present \n Error {}".format(tc_name, result) result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) assert ( result is not True - ), "Testcase {} :Failed \n Expected Behaviour: Routes are not" - " present \n Error {}".format(tc_name, result) + ), "Testcase {} :Failed \n Expected Behaviour: Routes are not present \n Error {}".format(tc_name, result) for addr_type in ADDR_TYPES: dut = "blue2" @@ -3417,14 +3404,12 @@ def test_vrf_name_significance_p1(request): result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False) assert result is not True, ( - "Testcase {} :Failed \n Expected Behaviour: Routes are not" - " present \n Error {}".format(tc_name, result) + "Testcase {} :Failed \n Expected Behaviour: Routes are not present \n Error {}".format(tc_name, result) ) result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2, expected=False) assert result is not True, ( - "Testcase {} :Failed \n Expected Behaviour: Routes are not" - " present \n Error {}".format(tc_name, result) + "Testcase {} :Failed \n Expected Behaviour: Routes are not present \n Error {}".format(tc_name, result) ) step("Create 2 new VRFs PINK_A and GREY_A IN R3") 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/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py index 291a6e7c3a..83682fb36d 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py @@ -224,6 +224,7 @@ def disable_route_map_to_prefer_global_next_hop(tgen, topo): """ + tc_name = request.node.name logger.info("Remove prefer-global rmap applied on neighbors") input_dict = { "r1": { diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index d2212d1807..50cb586acd 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -1309,7 +1309,6 @@ def verify_bgp_community( command = "show bgp" - sleep(5) for net in network: if vrf: cmd = "{} vrf {} {} {} json".format(command, vrf, addr_type, net) 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/vtysh/extract.pl.in b/vtysh/extract.pl.in index 4855c23f4b..af974771cc 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -103,7 +103,7 @@ sub scan_file { elsif ($file =~ /lib\/(filter|filter_cli)\.c$/) { $protocol = "VTYSH_ACL"; } - elsif ($file =~ /lib\/lib_vty\.c$/) { + elsif ($file =~ /lib\/(lib|log)_vty\.c$/) { $protocol = "VTYSH_ALL"; } elsif ($file =~ /lib\/agentx\.c$/) { @@ -133,7 +133,13 @@ sub scan_file { $protocol = "VTYSH_RIPD"; } } - elsif ($file =~ /lib\/vty\.c$/) { + elsif ($file =~ /lib\/resolver\.c$/) { + $protocol = "VTYSH_NHRPD|VTYSH_BGPD"; + } + elsif ($file =~ /lib\/spf_backoff\.c$/) { + $protocol = "VTYSH_ISISD"; + } + elsif ($file =~ /lib\/(vty|thread)\.c$/) { $protocol = "VTYSH_ALL"; } elsif ($file =~ /librfp\/.*\.c$/ || $file =~ /rfapi\/.*\.c$/) { @@ -269,7 +275,7 @@ EOF foreach (sort keys %odefun) { my ($node, $str) = (split (/,/)); $cmd = $ocmd{$_}; - $cmd =~ s/_cmd/_cmd_vtysh/; + $cmd =~ s/_cmd$/_cmd_vtysh/; printf " install_element ($node, &$cmd);\n"; } diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 75fee1d297..a1417430ec 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2964,136 +2964,6 @@ DEFUN (vtysh_show_logging, "Logging configuration for %s:\n"); } -DEFUNSH(VTYSH_ALL, vtysh_log_stdout, vtysh_log_stdout_cmd, "log stdout", - "Logging control\n" - "Set stdout logging level\n") -{ - return CMD_SUCCESS; -} - -DEFUNSH(VTYSH_ALL, vtysh_log_stdout_level, vtysh_log_stdout_level_cmd, - "log stdout <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>", - "Logging control\n" - "Set stdout logging level\n" LOG_LEVEL_DESC) -{ - return CMD_SUCCESS; -} - -DEFUNSH(VTYSH_ALL, no_vtysh_log_stdout, no_vtysh_log_stdout_cmd, - "no log stdout [LEVEL]", NO_STR - "Logging control\n" - "Cancel logging to stdout\n" - "Logging level\n") -{ - return CMD_SUCCESS; -} - -DEFUNSH(VTYSH_ALL, vtysh_log_file, vtysh_log_file_cmd, "log file FILENAME", - "Logging control\n" - "Logging to file\n" - "Logging filename\n") -{ - return CMD_SUCCESS; -} - -DEFUNSH(VTYSH_ALL, vtysh_log_file_level, vtysh_log_file_level_cmd, - "log file FILENAME <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>", - "Logging control\n" - "Logging to file\n" - "Logging filename\n" LOG_LEVEL_DESC) -{ - return CMD_SUCCESS; -} - -DEFUNSH(VTYSH_ALL, no_vtysh_log_file, no_vtysh_log_file_cmd, - "no log file [FILENAME [LEVEL]]", NO_STR - "Logging control\n" - "Cancel logging to file\n" - "Logging file name\n" - "Logging level\n") -{ - return CMD_SUCCESS; -} - -DEFUNSH(VTYSH_ALL, vtysh_log_monitor, vtysh_log_monitor_cmd, - "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]", - "Logging control\n" - "Set terminal line (monitor) logging level\n" LOG_LEVEL_DESC) -{ - return CMD_SUCCESS; -} - -DEFUNSH(VTYSH_ALL, no_vtysh_log_monitor, no_vtysh_log_monitor_cmd, - "no log monitor [LEVEL]", NO_STR - "Logging control\n" - "Disable terminal line (monitor) logging\n" - "Logging level\n") -{ - return CMD_SUCCESS; -} - -DEFUNSH(VTYSH_ALL, vtysh_log_syslog, vtysh_log_syslog_cmd, - "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]", - "Logging control\n" - "Set syslog logging level\n" LOG_LEVEL_DESC) -{ - return CMD_SUCCESS; -} - -DEFUNSH(VTYSH_ALL, no_vtysh_log_syslog, no_vtysh_log_syslog_cmd, - "no log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]", - NO_STR - "Logging control\n" - "Cancel logging to syslog\n" - LOG_LEVEL_DESC) -{ - return CMD_SUCCESS; -} - -DEFUNSH(VTYSH_ALL, vtysh_log_facility, vtysh_log_facility_cmd, - "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>", - "Logging control\n" - "Facility parameter for syslog messages\n" LOG_FACILITY_DESC) -{ - return CMD_SUCCESS; -} - -DEFUNSH(VTYSH_ALL, no_vtysh_log_facility, no_vtysh_log_facility_cmd, - "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]", - NO_STR - "Logging control\n" - "Reset syslog facility to default (daemon)\n" - LOG_FACILITY_DESC) -{ - return CMD_SUCCESS; -} - -DEFUNSH(VTYSH_ALL, vtysh_log_record_priority, vtysh_log_record_priority_cmd, - "log record-priority", - "Logging control\n" - "Log the priority of the message within the message\n") -{ - return CMD_SUCCESS; -} - -DEFUNSH(VTYSH_ALL, no_vtysh_log_record_priority, - no_vtysh_log_record_priority_cmd, "no log record-priority", NO_STR - "Logging control\n" - "Do not log the priority of the message within the message\n") -{ - return CMD_SUCCESS; -} - -DEFUNSH(VTYSH_ALL, vtysh_log_timestamp_precision, - vtysh_log_timestamp_precision_cmd, "log timestamp precision (0-6)", - "Logging control\n" - "Timestamp configuration\n" - "Set the timestamp precision\n" - "Number of subsecond digits\n") -{ - return CMD_SUCCESS; -} - DEFUNSH(VTYSH_ALL, vtysh_debug_memstats, vtysh_debug_memstats_cmd, "[no] debug memstats-at-exit", NO_STR @@ -3103,16 +2973,6 @@ DEFUNSH(VTYSH_ALL, vtysh_debug_memstats, return CMD_SUCCESS; } -DEFUNSH(VTYSH_ALL, no_vtysh_log_timestamp_precision, - no_vtysh_log_timestamp_precision_cmd, "no log timestamp precision", - NO_STR - "Logging control\n" - "Timestamp configuration\n" - "Reset the timestamp precision to the default value of 0\n") -{ - return CMD_SUCCESS; -} - DEFUNSH(VTYSH_ALL, vtysh_service_password_encrypt, vtysh_service_password_encrypt_cmd, "service password-encryption", "Set up miscellaneous service\n" @@ -4605,22 +4465,6 @@ void vtysh_init_vty(void) /* Logging */ install_element(VIEW_NODE, &vtysh_show_logging_cmd); - install_element(CONFIG_NODE, &vtysh_log_stdout_cmd); - install_element(CONFIG_NODE, &vtysh_log_stdout_level_cmd); - install_element(CONFIG_NODE, &no_vtysh_log_stdout_cmd); - install_element(CONFIG_NODE, &vtysh_log_file_cmd); - install_element(CONFIG_NODE, &vtysh_log_file_level_cmd); - install_element(CONFIG_NODE, &no_vtysh_log_file_cmd); - install_element(CONFIG_NODE, &vtysh_log_monitor_cmd); - install_element(CONFIG_NODE, &no_vtysh_log_monitor_cmd); - install_element(CONFIG_NODE, &vtysh_log_syslog_cmd); - install_element(CONFIG_NODE, &no_vtysh_log_syslog_cmd); - install_element(CONFIG_NODE, &vtysh_log_facility_cmd); - install_element(CONFIG_NODE, &no_vtysh_log_facility_cmd); - install_element(CONFIG_NODE, &vtysh_log_record_priority_cmd); - install_element(CONFIG_NODE, &no_vtysh_log_record_priority_cmd); - install_element(CONFIG_NODE, &vtysh_log_timestamp_precision_cmd); - install_element(CONFIG_NODE, &no_vtysh_log_timestamp_precision_cmd); install_element(CONFIG_NODE, &vtysh_service_password_encrypt_cmd); install_element(CONFIG_NODE, &no_vtysh_service_password_encrypt_cmd); diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index db7cc312d6..fe33bed7f6 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -153,8 +153,10 @@ static void usage(int status) progname); else printf("Usage : %s [OPTION...]\n\n" - "Integrated shell for FRR (version " FRR_VERSION "). \n" - "Configured with:\n " FRR_CONFIG_ARGS "\n\n" + "Integrated shell for FRR (version " FRR_VERSION + "). \n" + "Configured with:\n " FRR_CONFIG_ARGS + "\n\n" "-b, --boot Execute boot startup configuration\n" "-c, --command Execute argument as command\n" "-d, --daemon Connect only to the specified daemon\n" @@ -167,6 +169,7 @@ static void usage(int status) "-N --pathspace Insert prefix into config & socket paths\n" "-u --user Run as an unprivileged user\n" "-w, --writeconfig Write integrated config (frr.conf) and exit\n" + "-H, --histfile Override history file\n" "-h, --help Display this help and exit\n\n" "Note that multiple commands may be executed from the command\n" "line by passing multiple -c args, or by embedding linefeed\n" @@ -189,6 +192,7 @@ struct option longopts[] = { {"vty_socket", required_argument, NULL, OPTION_VTYSOCK}, {"config_dir", required_argument, NULL, OPTION_CONFDIR}, {"inputfile", required_argument, NULL, 'f'}, + {"histfile", required_argument, NULL, 'H'}, {"echo", no_argument, NULL, 'E'}, {"dryrun", no_argument, NULL, 'C'}, {"help", no_argument, NULL, 'h'}, @@ -321,6 +325,7 @@ int main(int argc, char **argv, char **env) char sysconfdir[MAXPATHLEN]; const char *pathspace_arg = NULL; char pathspace[MAXPATHLEN] = ""; + const char *histfile = NULL; /* SUID: drop down to calling user & go back up when needed */ elevuid = geteuid(); @@ -341,8 +346,8 @@ int main(int argc, char **argv, char **env) /* Option handling. */ while (1) { - opt = getopt_long(argc, argv, "be:c:d:nf:mEhCwN:u", - longopts, 0); + opt = getopt_long(argc, argv, "be:c:d:nf:H:mEhCwN:u", longopts, + 0); if (opt == EOF) break; @@ -409,6 +414,9 @@ int main(int argc, char **argv, char **env) case 'h': usage(0); break; + case 'H': + histfile = optarg; + break; default: usage(1); break; @@ -569,12 +577,24 @@ int main(int argc, char **argv, char **env) /* * Setup history file for use by both -c and regular input * If we can't find the home directory, then don't store - * the history information + * the history information. + * VTYSH_HISTFILE is prefered over command line + * argument (-H/--histfile). */ - homedir = vtysh_get_home(); - if (homedir) { - snprintf(history_file, sizeof(history_file), "%s/.history_frr", - homedir); + if (getenv("VTYSH_HISTFILE")) { + const char *file = getenv("VTYSH_HISTFILE"); + + strlcpy(history_file, file, sizeof(history_file)); + } else if (histfile) { + strlcpy(history_file, histfile, sizeof(history_file)); + } else { + homedir = vtysh_get_home(); + if (homedir) + snprintf(history_file, sizeof(history_file), + "%s/.history_frr", homedir); + } + + if (strlen(history_file) > 0) { if (read_history(history_file) != 0) { int fp; 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..6f24ec4225 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: @@ -374,6 +369,14 @@ void zebra_redistribute_delete(ZAPI_HANDLER_ARGS) STREAM_GETC(msg, type); STREAM_GETW(msg, instance); + if (IS_ZEBRA_DEBUG_EVENT) + zlog_debug( + "%s: client proto %s afi=%d, no longer wants %s, vrf %s(%u), instance=%d", + __func__, zebra_route_string(client->proto), afi, + zebra_route_string(type), VRF_LOGNAME(zvrf->vrf), + zvrf_id(zvrf), instance); + + if (afi == 0 || afi >= AFI_MAX) { flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF, "%s: Specified afi %d does not exist", __func__, afi); diff --git a/zebra/rib.h b/zebra/rib.h index e7676a1324..75d7ae1b67 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -426,7 +426,11 @@ extern int rib_queue_add(struct route_node *rn); struct nhg_ctx; /* Forward declaration */ -extern int rib_queue_nhg_add(struct nhg_ctx *ctx); +/* Enqueue incoming nhg from OS for processing */ +extern int rib_queue_nhg_ctx_add(struct nhg_ctx *ctx); + +/* Enqueue incoming nhg from proto daemon for processing */ +extern int rib_queue_nhe_add(struct nhg_hash_entry *nhe); extern void meta_queue_free(struct meta_queue *mq); extern int zebra_rib_labeled_unicast(struct route_entry *re); diff --git a/zebra/subdir.am b/zebra/subdir.am index 80ea9ac7b8..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 @@ -232,7 +232,7 @@ zebra_dplane_fpm_nl_la_SOURCES = zebra/dplane_fpm_nl.c zebra_dplane_fpm_nl_la_LDFLAGS = -avoid-version -module -shared -export-dynamic zebra_dplane_fpm_nl_la_LIBADD = -vtysh_scan += $(top_srcdir)/zebra/dplane_fpm_nl.c +vtysh_scan += zebra/dplane_fpm_nl.c endif if NETLINK_DEBUG diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index e854d7ff3a..77a9188fe8 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -727,8 +727,8 @@ int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id, } if (IS_ZEBRA_DEBUG_SEND) - zlog_debug("%s: type %d, id %d, note %d", - __func__, type, id, note); + zlog_debug("%s: type %d, id %d, note %s", + __func__, type, id, zapi_nhg_notify_owner2str(note)); s = stream_new(ZEBRA_MAX_PACKET_SIZ); stream_reset(s); @@ -1921,27 +1921,35 @@ static void zread_nhg_add(ZAPI_HANDLER_ARGS) return; } - /* - * Create the nhg - */ - nhe = zebra_nhg_proto_add(api_nhg.id, api_nhg.proto, client->instance, - client->session_id, nhg, 0); + /* Create a temporary nhe */ + nhe = zebra_nhg_alloc(); + nhe->id = api_nhg.id; + nhe->type = api_nhg.proto; + nhe->zapi_instance = client->instance; + nhe->zapi_session = client->session_id; - nexthop_group_delete(&nhg); - zebra_nhg_backup_free(&bnhg); + /* Take over the list(s) of nexthops */ + nhe->nhg.nexthop = nhg->nexthop; + nhg->nexthop = NULL; + + if (bnhg) { + nhe->backup_info = bnhg; + bnhg = NULL; + } /* * TODO: * Assume fully resolved for now and install. - * * Resolution is going to need some more work. */ - /* If there's a failure, notify sender immediately */ - if (nhe == NULL) - zsend_nhg_notify(api_nhg.proto, client->instance, - client->session_id, api_nhg.id, - ZAPI_NHG_FAIL_INSTALL); + /* Enqueue to workqueue for processing */ + rib_queue_nhe_add(nhe); + + /* Free any local allocations */ + nexthop_group_delete(&nhg); + zebra_nhg_backup_free(&bnhg); + } static void zread_route_add(ZAPI_HANDLER_ARGS) 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_mpls.c b/zebra/zebra_mpls.c index 6d42957b24..a923782bfe 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -2018,6 +2018,7 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx) int start_count = 0, end_count = 0; /* Installed counts */ bool changed_p = false; bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS); + enum zebra_sr_policy_update_label_mode update_mode; if (is_debug) zlog_debug("LSP dplane notif, in-label %u", @@ -2091,10 +2092,21 @@ void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx) if (end_count > 0) { SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED); + /* SR-TE update too */ + if (start_count == 0) + update_mode = ZEBRA_SR_POLICY_LABEL_CREATED; + else + update_mode = ZEBRA_SR_POLICY_LABEL_UPDATED; + zebra_sr_policy_label_update(lsp->ile.in_label, update_mode); + if (changed_p) dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_UPDATE, ctx); } else { + /* SR-TE update too */ + zebra_sr_policy_label_update(lsp->ile.in_label, + ZEBRA_SR_POLICY_LABEL_REMOVED); + UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED); clear_nhlfe_installed(lsp); } diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 7edf022892..47651318a4 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; } @@ -990,7 +992,7 @@ static struct nhg_ctx *nhg_ctx_new(void) return new; } -static void nhg_ctx_free(struct nhg_ctx **ctx) +void nhg_ctx_free(struct nhg_ctx **ctx) { struct nexthop *nh; @@ -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); @@ -1233,7 +1242,7 @@ static int queue_add(struct nhg_ctx *ctx) if (nhg_ctx_get_status(ctx) == NHG_CTX_QUEUED) return 0; - if (rib_queue_nhg_add(ctx)) { + if (rib_queue_nhg_ctx_add(ctx)) { nhg_ctx_set_status(ctx, NHG_CTX_FAILURE); return -1; } @@ -1811,12 +1820,11 @@ static int resolve_backup_nexthops(const struct nexthop *nexthop, int i, j, idx; const struct nexthop *bnh; struct nexthop *nh, *newnh; + mpls_label_t labels[MPLS_MAX_LABELS]; + uint8_t num_labels; assert(nexthop->backup_num <= NEXTHOP_MAX_BACKUPS); - if (resolve_nhe->backup_info->nhe == NULL) - resolve_nhe->backup_info->nhe = zebra_nhg_alloc(); - /* Locate backups from the original nexthop's backup index and nhe */ for (i = 0; i < nexthop->backup_num; i++) { idx = nexthop->backup_idx[i]; @@ -1832,6 +1840,8 @@ static int resolve_backup_nexthops(const struct nexthop *nexthop, map->map[j].new_idx; resolved->backup_num++; + SET_FLAG(resolved->flags, NEXTHOP_FLAG_HAS_BACKUP); + if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug("%s: found map idx orig %d, new %d", __func__, map->map[j].orig_idx, @@ -1856,9 +1866,46 @@ static int resolve_backup_nexthops(const struct nexthop *nexthop, if (bnh == NULL) continue; + if (resolve_nhe->backup_info == NULL) + resolve_nhe->backup_info = zebra_nhg_backup_alloc(); + /* Update backup info in the resolving nexthop and its nhe */ newnh = nexthop_dup_no_recurse(bnh, NULL); + /* We may need some special handling for mpls labels: the new + * backup needs to carry the recursive nexthop's labels, + * if any: they may be vrf labels e.g. + * The original/inner labels are in the stack of 'resolve_nhe', + * if that is longer than the stack in 'nexthop'. + */ + if (newnh->nh_label && resolved->nh_label && + nexthop->nh_label) { + if (resolved->nh_label->num_labels > + nexthop->nh_label->num_labels) { + /* Prepare new label stack */ + num_labels = 0; + for (j = 0; j < newnh->nh_label->num_labels; + j++) { + labels[j] = newnh->nh_label->label[j]; + num_labels++; + } + + /* Include inner labels */ + for (j = nexthop->nh_label->num_labels; + j < resolved->nh_label->num_labels; + j++) { + labels[num_labels] = + resolved->nh_label->label[j]; + num_labels++; + } + + /* Replace existing label stack in the backup */ + nexthop_del_labels(newnh); + nexthop_add_labels(newnh, bnh->nh_label_type, + num_labels, labels); + } + } + /* Need to compute the new backup index in the new * backup list, and add to map struct. */ @@ -1871,6 +1918,7 @@ static int resolve_backup_nexthops(const struct nexthop *nexthop, } nh->next = newnh; + j++; } else /* First one */ resolve_nhe->backup_info->nhe->nhg.nexthop = newnh; @@ -1879,6 +1927,8 @@ static int resolve_backup_nexthops(const struct nexthop *nexthop, resolved->backup_idx[resolved->backup_num] = j; resolved->backup_num++; + SET_FLAG(resolved->flags, NEXTHOP_FLAG_HAS_BACKUP); + if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug("%s: added idx orig %d, new %d", __func__, idx, j); @@ -2559,7 +2609,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 +2911,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 +2977,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 +3275,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..3fbf778be2 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. @@ -269,6 +274,7 @@ extern bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2); * the rib meta queue. */ extern int nhg_ctx_process(struct nhg_ctx *ctx); +void nhg_ctx_free(struct nhg_ctx **ctx); /* Find via kernel nh creation */ extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, 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_rib.c b/zebra/zebra_rib.c index 82a0e6d015..bdacd411bd 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -62,6 +62,7 @@ DEFINE_MGROUP(ZEBRA, "zebra"); DEFINE_MTYPE(ZEBRA, RE, "Route Entry"); DEFINE_MTYPE_STATIC(ZEBRA, RIB_DEST, "RIB destination"); DEFINE_MTYPE_STATIC(ZEBRA, RIB_UPDATE_CTX, "Rib update context object"); +DEFINE_MTYPE_STATIC(ZEBRA, WQ_NHG_WRAPPER, "WQ nhg wrapper"); /* * Event, list, and mutex for delivery of dataplane results @@ -117,6 +118,20 @@ static const struct { /* no entry/default: 150 */ }; +/* Wrapper struct for nhg workqueue items; a 'ctx' is an incoming update + * from the OS, and an 'nhe' is a nhe update. + */ +struct wq_nhg_wrapper { + int type; + union { + struct nhg_ctx *ctx; + struct nhg_hash_entry *nhe; + } u; +}; + +#define WQ_NHG_WRAPPER_TYPE_CTX 0x01 +#define WQ_NHG_WRAPPER_TYPE_NHG 0x02 + static void PRINTFRR(5, 6) _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn, int priority, const char *msgfmt, ...) @@ -908,6 +923,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, if (nh_active) { if (IS_ZEBRA_DEBUG_RIB) { char buf[SRCDEST2STR_BUFFER]; + srcdest_rnode2str(rn, buf, sizeof(buf)); if (new != old) zlog_debug( @@ -1068,12 +1084,6 @@ static struct route_entry *rib_choose_best(struct route_entry *current, return current; } -/* Core function for processing nexthop group contexts's off metaq */ -static void rib_nhg_process(struct nhg_ctx *ctx) -{ - nhg_ctx_process(ctx); -} - /* Core function for processing routing information base. */ static void rib_process(struct route_node *rn) { @@ -2289,21 +2299,60 @@ done: dplane_ctx_fini(&ctx); } +/* + * Process the nexthop-group workqueue subqueue + */ static void process_subq_nhg(struct listnode *lnode) { - struct nhg_ctx *ctx = NULL; + struct nhg_ctx *ctx; + struct nhg_hash_entry *nhe, *newnhe; + struct wq_nhg_wrapper *w; uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map; - ctx = listgetdata(lnode); + w = listgetdata(lnode); - if (!ctx) + if (!w) return; - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug("NHG Context id=%u dequeued from sub-queue %u", - ctx->id, qindex); + /* Two types of object - an update from the local kernel, or + * an nhg update from a daemon. + */ + if (w->type == WQ_NHG_WRAPPER_TYPE_CTX) { + ctx = w->u.ctx; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug( + "NHG Context id=%u dequeued from sub-queue %u", + ctx->id, qindex); + + + /* Process nexthop group updates coming 'up' from the OS */ + nhg_ctx_process(ctx); - rib_nhg_process(ctx); + } else if (w->type == WQ_NHG_WRAPPER_TYPE_NHG) { + nhe = w->u.nhe; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("NHG %u dequeued from sub-queue %u", + nhe->id, qindex); + + /* Process incoming nhg update, probably from a proto daemon */ + newnhe = zebra_nhg_proto_add(nhe->id, nhe->type, + nhe->zapi_instance, + nhe->zapi_session, + &nhe->nhg, 0); + + /* Report error to daemon via ZAPI */ + if (newnhe == NULL) + zsend_nhg_notify(nhe->type, nhe->zapi_instance, + nhe->zapi_session, nhe->id, + ZAPI_NHG_FAIL_INSTALL); + + /* Free temp nhe - we own that memory. */ + zebra_nhg_free(nhe); + } + + XFREE(MTYPE_WQ_NHG_WRAPPER, w); } static void process_subq_route(struct listnode *lnode, uint8_t qindex) @@ -2335,8 +2384,8 @@ static void process_subq_route(struct listnode *lnode, uint8_t qindex) srcdest_rnode2str(rnode, buf, sizeof(buf)); zlog_debug("%s(%u:%u):%s: rn %p dequeued from sub-queue %u", - zvrf_name(zvrf), zvrf_id(zvrf), re ? re->table : 0, buf, - rnode, qindex); + zvrf_name(zvrf), zvrf_id(zvrf), re ? re->table : 0, + buf, rnode, qindex); } if (rnode->info) @@ -2369,8 +2418,7 @@ static unsigned int process_subq(struct list *subq, uint8_t qindex) /* Dispatch the meta queue by picking, processing and unlocking the next RN from * a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and - * data - * is pointed to the meta queue structure. + * data is pointed to the meta queue structure. */ static wq_item_status meta_queue_process(struct work_queue *dummy, void *data) { @@ -2463,17 +2511,23 @@ static int rib_meta_queue_add(struct meta_queue *mq, void *data) return 0; } -static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) +static int rib_meta_queue_nhg_ctx_add(struct meta_queue *mq, void *data) { struct nhg_ctx *ctx = NULL; uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map; + struct wq_nhg_wrapper *w; ctx = (struct nhg_ctx *)data; if (!ctx) return -1; - listnode_add(mq->subq[qindex], ctx); + w = XCALLOC(MTYPE_WQ_NHG_WRAPPER, sizeof(struct wq_nhg_wrapper)); + + w->type = WQ_NHG_WRAPPER_TYPE_CTX; + w->u.ctx = ctx; + + listnode_add(mq->subq[qindex], w); mq->size++; if (IS_ZEBRA_DEBUG_RIB_DETAILED) @@ -2483,6 +2537,32 @@ static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) return 0; } +static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) +{ + struct nhg_hash_entry *nhe = NULL; + uint8_t qindex = route_info[ZEBRA_ROUTE_NHG].meta_q_map; + struct wq_nhg_wrapper *w; + + nhe = (struct nhg_hash_entry *)data; + + if (!nhe) + return -1; + + w = XCALLOC(MTYPE_WQ_NHG_WRAPPER, sizeof(struct wq_nhg_wrapper)); + + w->type = WQ_NHG_WRAPPER_TYPE_NHG; + w->u.nhe = nhe; + + listnode_add(mq->subq[qindex], w); + mq->size++; + + if (IS_ZEBRA_DEBUG_RIB_DETAILED) + zlog_debug("NHG id=%u queued into sub-queue %u", + nhe->id, qindex); + + return 0; +} + static int mq_add_handler(void *data, int (*mq_add_func)(struct meta_queue *mq, void *data)) { @@ -2520,14 +2600,50 @@ int rib_queue_add(struct route_node *rn) return -1; } - return mq_add_handler(rn, &rib_meta_queue_add); + return mq_add_handler(rn, rib_meta_queue_add); } -int rib_queue_nhg_add(struct nhg_ctx *ctx) +/* + * Enqueue incoming nhg info from OS for processing + */ +int rib_queue_nhg_ctx_add(struct nhg_ctx *ctx) { assert(ctx); - return mq_add_handler(ctx, &rib_meta_queue_nhg_add); + return mq_add_handler(ctx, rib_meta_queue_nhg_ctx_add); +} + +/* + * Enqueue incoming nhg from proto daemon for processing + */ +int rib_queue_nhe_add(struct nhg_hash_entry *nhe) +{ + if (nhe == NULL) + return -1; + + return mq_add_handler(nhe, rib_meta_queue_nhg_add); +} + +/* Clean up the nhg meta-queue list */ +static void nhg_meta_queue_free(struct list *l) +{ + struct wq_nhg_wrapper *w; + struct listnode *node; + + /* Free the node wrapper object, and the struct it wraps */ + while ((node = listhead(l)) != NULL) { + w = node->data; + node->data = NULL; + + if (w->type == WQ_NHG_WRAPPER_TYPE_CTX) + nhg_ctx_free(&w->u.ctx); + else if (w->type == WQ_NHG_WRAPPER_TYPE_NHG) + zebra_nhg_free(w->u.nhe); + + XFREE(MTYPE_WQ_NHG_WRAPPER, w); + + list_delete_node(l, node); + } } /* Create new meta queue. @@ -2552,8 +2668,13 @@ void meta_queue_free(struct meta_queue *mq) { unsigned i; - for (i = 0; i < MQ_SIZE; i++) + for (i = 0; i < MQ_SIZE; i++) { + /* Some subqueues may need cleanup - nhgs for example */ + if (i == route_info[ZEBRA_ROUTE_NHG].meta_q_map) + nhg_meta_queue_free(mq->subq[i]); + list_delete(&mq->subq[i]); + } XFREE(MTYPE_WORK_QUEUE, mq); } @@ -2765,6 +2886,7 @@ static void _route_entry_dump_nh(const struct route_entry *re, char backup_str[50]; char wgt_str[50]; char temp_str[10]; + char label_str[MPLS_LABEL_STRLEN]; int i; struct interface *ifp; struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); @@ -2789,6 +2911,15 @@ static void _route_entry_dump_nh(const struct route_entry *re, break; } + /* Label stack */ + label_str[0] = '\0'; + if (nexthop->nh_label && nexthop->nh_label->num_labels > 0) { + mpls_label2str(nexthop->nh_label->num_labels, + nexthop->nh_label->label, label_str, + sizeof(label_str), 0 /*pretty*/); + strlcat(label_str, ", ", sizeof(label_str)); + } + backup_str[0] = '\0'; if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { snprintf(backup_str, sizeof(backup_str), "backup "); @@ -2803,9 +2934,9 @@ static void _route_entry_dump_nh(const struct route_entry *re, if (nexthop->weight) snprintf(wgt_str, sizeof(wgt_str), "wgt %d,", nexthop->weight); - zlog_debug("%s: %s %s[%u] vrf %s(%u) %s%s with flags %s%s%s%s%s%s%s%s", + zlog_debug("%s: %s %s[%u] %svrf %s(%u) %s%s with flags %s%s%s%s%s%s%s%s", straddr, (nexthop->rparent ? " NH" : "NH"), nhname, - nexthop->ifindex, vrf ? vrf->name : "Unknown", + nexthop->ifindex, label_str, vrf ? vrf->name : "Unknown", nexthop->vrf_id, wgt_str, backup_str, (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) 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)) { |
