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