diff options
47 files changed, 907 insertions, 627 deletions
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 7ccfae4ba4..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) @@ -477,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/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..2b23d5e464 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -1021,6 +1021,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/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 */ @@ -795,9 +795,33 @@ void bfd_sess_free(struct bfd_session_params **bsp) XFREE(MTYPE_BFD_INFO, (*bsp)); } +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) +{ + size_t addrlen; + + if (bsp->args.family != family) + return true; + + addrlen = (family == AF_INET) ? sizeof(struct in_addr) + : sizeof(struct in6_addr); + if ((src == NULL && memcmp(&bsp->args.src, &i6a_zero, addrlen)) + || (src && memcmp(src, &bsp->args.src, addrlen)) + || memcmp(dst, &bsp->args.dst, addrlen)) + return true; + + return false; +} + void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp, struct in_addr *src, struct in_addr *dst) { + if (!bfd_sess_address_changed(bsp, AF_INET, (struct in6_addr *)src, + (struct in6_addr *)dst)) + return; + /* If already installed, remove the old setting. */ _bfd_sess_remove(bsp); @@ -818,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); @@ -835,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); @@ -868,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); @@ -878,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); @@ -889,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); @@ -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,7 +1178,7 @@ static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS) now = monotime(NULL); /* Notify all matching sessions about update. */ - TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) { + TAILQ_FOREACH_SAFE (bsp, &bsglobal.bsplist, entry, bspn) { /* Skip not installed entries. */ if (!bsp->installed) continue; @@ -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. @@ -187,6 +187,10 @@ void bfd_sess_free(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). @@ -197,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). @@ -207,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). */ @@ -215,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). */ @@ -223,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. */ @@ -231,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 @@ -252,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). @@ -261,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. */ @@ -272,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. @@ -284,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); @@ -291,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/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/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_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 f64adc6254..8e6f2ec42b 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -1882,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; } @@ -1912,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; } @@ -1932,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) { @@ -1944,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"); - - 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); + 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"); - nb_running_set_entry(args->dnode, pim_ifp->bfd_info); + pim_bfd_reg_dereg_all_nbr(ifp); } /* @@ -2006,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/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/pim-basic-topo2/__init__.py b/tests/topotests/pim-basic-topo2/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/__init__.py diff --git a/tests/topotests/pim-basic-topo2/r1/bfdd.conf b/tests/topotests/pim-basic-topo2/r1/bfdd.conf new file mode 100644 index 0000000000..76c6f82190 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r1/bfdd.conf @@ -0,0 +1,6 @@ +bfd + profile fast-tx + receive-interval 250 + transmit-interval 250 + ! +! diff --git a/tests/topotests/pim-basic-topo2/r1/pimd.conf b/tests/topotests/pim-basic-topo2/r1/pimd.conf new file mode 100644 index 0000000000..b895d7d573 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r1/pimd.conf @@ -0,0 +1,4 @@ +interface r1-eth0 + ip pim + ip pim bfd profile fast-tx +! diff --git a/tests/topotests/pim-basic-topo2/r1/zebra.conf b/tests/topotests/pim-basic-topo2/r1/zebra.conf new file mode 100644 index 0000000000..6bf02a3ee8 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r1/zebra.conf @@ -0,0 +1,3 @@ +interface r1-eth0 + ip address 192.168.1.1/24 +! diff --git a/tests/topotests/pim-basic-topo2/r2/bfdd.conf b/tests/topotests/pim-basic-topo2/r2/bfdd.conf new file mode 100644 index 0000000000..ca61e467dc --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r2/bfdd.conf @@ -0,0 +1,2 @@ +bfd +! diff --git a/tests/topotests/pim-basic-topo2/r2/pimd.conf b/tests/topotests/pim-basic-topo2/r2/pimd.conf new file mode 100644 index 0000000000..0b32ded19a --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r2/pimd.conf @@ -0,0 +1,12 @@ +interface r2-eth0 + ip pim + ip pim bfd +! +interface r2-eth1 + ip pim + ip pim bfd +! +interface r2-eth2 + ip pim + ip pim bfd +! diff --git a/tests/topotests/pim-basic-topo2/r2/zebra.conf b/tests/topotests/pim-basic-topo2/r2/zebra.conf new file mode 100644 index 0000000000..3ceb5f0fc2 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r2/zebra.conf @@ -0,0 +1,9 @@ +interface r2-eth0 + ip address 192.168.1.2/24 +! +interface r2-eth1 + ip address 192.168.2.1/24 +! +interface r2-eth2 + ip address 192.168.3.1/24 +! diff --git a/tests/topotests/pim-basic-topo2/r3/bfdd.conf b/tests/topotests/pim-basic-topo2/r3/bfdd.conf new file mode 100644 index 0000000000..ca61e467dc --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r3/bfdd.conf @@ -0,0 +1,2 @@ +bfd +! diff --git a/tests/topotests/pim-basic-topo2/r3/pimd.conf b/tests/topotests/pim-basic-topo2/r3/pimd.conf new file mode 100644 index 0000000000..691a28ea27 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r3/pimd.conf @@ -0,0 +1,4 @@ +interface r3-eth0 + ip pim + ip pim bfd +! diff --git a/tests/topotests/pim-basic-topo2/r3/zebra.conf b/tests/topotests/pim-basic-topo2/r3/zebra.conf new file mode 100644 index 0000000000..3df218ee16 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r3/zebra.conf @@ -0,0 +1,3 @@ +interface r3-eth0 + ip address 192.168.2.3/24 +! diff --git a/tests/topotests/pim-basic-topo2/r4/bfdd.conf b/tests/topotests/pim-basic-topo2/r4/bfdd.conf new file mode 100644 index 0000000000..ca61e467dc --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r4/bfdd.conf @@ -0,0 +1,2 @@ +bfd +! diff --git a/tests/topotests/pim-basic-topo2/r4/pimd.conf b/tests/topotests/pim-basic-topo2/r4/pimd.conf new file mode 100644 index 0000000000..2277b3e1f1 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r4/pimd.conf @@ -0,0 +1,4 @@ +interface r4-eth0 + ip pim + ip pim bfd +! diff --git a/tests/topotests/pim-basic-topo2/r4/zebra.conf b/tests/topotests/pim-basic-topo2/r4/zebra.conf new file mode 100644 index 0000000000..6ac5c78fc3 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/r4/zebra.conf @@ -0,0 +1,3 @@ +interface r4-eth0 + ip address 192.168.3.4/24 +! diff --git a/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.dot b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.dot new file mode 100644 index 0000000000..22fce27e22 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.dot @@ -0,0 +1,73 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph template { + label="bfd-topo3"; + + # Routers + r1 [ + shape=doubleoctagon, + label="r1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon + label="r2", + fillcolor="#f08080", + style=filled, + ]; + r3 [ + shape=doubleoctagon + label="r3", + fillcolor="#f08080", + style=filled, + ]; + r4 [ + shape=doubleoctagon + label="r4", + fillcolor="#f08080", + style=filled, + ]; + + # Switches + sw1 [ + shape=oval, + label="sw1\n192.168.1.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw2 [ + shape=oval, + label="sw2\n192.168.2.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw2 [ + shape=oval, + label="sw2\n192.168.3.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + r1 -- sw1 [label="eth0\n.1"]; + r2 -- sw1 [label="eth0\n.2"]; + + r2 -- sw2 [label="eth1\n.1"]; + r3 -- sw2 [label="eth0\n.3"]; + + r2 -- sw3 [label="eth1\n.1"]; + r4 -- sw3 [label="eth2\n.4"]; +} diff --git a/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.png b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.png Binary files differnew file mode 100644 index 0000000000..39139a35b1 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.png diff --git a/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.py b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.py new file mode 100644 index 0000000000..883125cfc7 --- /dev/null +++ b/tests/topotests/pim-basic-topo2/test_pim_basic_topo2.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python + +# +# test_pim_basic_topo2.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2021 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_pim_basic_topo2.py: Test the FRR PIM protocol convergence. +""" + +import os +import sys +import json +from functools import partial +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +pytestmark = [pytest.mark.bfdd, pytest.mark.pimd] + + +class PimBasicTopo2(Topo): + "Test topology builder" + + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # Create 4 routers + for routern in range(1, 5): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r4"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(PimBasicTopo2, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + daemon_file = "{}/{}/bfdd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_BFD, daemon_file) + + daemon_file = "{}/{}/pimd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_PIM, daemon_file) + + daemon_file = "{}/{}/zebra.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_ZEBRA, daemon_file) + + # Initialize all routers. + tgen.start_router() + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +def expect_neighbor(router, interface, peer): + "Wait until peer is present on interface." + logger.info("waiting peer {} in {}".format(peer, interface)) + tgen = get_topogen() + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip pim neighbor json", + {interface: {peer: {}}} + ) + _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + assertmsg = '"{}" PIM convergence failure'.format(router) + assert result is None, assertmsg + + +def test_wait_pim_convergence(): + "Wait for PIM to converge" + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for PIM to converge") + + expect_neighbor('r1', 'r1-eth0', '192.168.1.2') + expect_neighbor('r2', 'r2-eth0', '192.168.1.1') + + expect_neighbor('r2', 'r2-eth1', '192.168.2.3') + expect_neighbor('r2', 'r2-eth2', '192.168.3.4') + + expect_neighbor('r3', 'r3-eth0', '192.168.2.1') + expect_neighbor('r4', 'r4-eth0', '192.168.3.1') + + +def test_bfd_peers(): + "Wait for BFD peers to show up." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for BFD to converge") + + def expect_bfd_peer(router, peer): + "Wait until peer is present on interface." + logger.info("waiting BFD peer {} in {}".format(peer, router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show bfd peers json", + [{"peer": peer, "status": "up"}] + ) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertmsg = '"{}" BFD convergence failure'.format(router) + assert result is None, assertmsg + + expect_bfd_peer("r1", "192.168.1.2") + expect_bfd_peer("r2", "192.168.1.1") + expect_bfd_peer("r2", "192.168.2.3") + expect_bfd_peer("r2", "192.168.3.4") + expect_bfd_peer("r3", "192.168.2.1") + expect_bfd_peer("r4", "192.168.3.1") + + +def test_pim_reconvergence(): + "Disconnect a peer and expect it to disconnect." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for disconnect convergence") + tgen.gears["r4"].link_enable("r4-eth0", enabled=False) + + def expect_neighbor_down(router, interface, peer): + "Wait until peer is present on interface." + logger.info("waiting peer {} in {} to disappear".format(peer, interface)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip pim neighbor json", + {interface: {peer: None}} + ) + _, result = topotest.run_and_expect(test_func, None, count=4, wait=1) + assertmsg = '"{}" PIM convergence failure'.format(router) + assert result is None, assertmsg + + expect_neighbor_down("r2", "r2-eth2", "192.168.3.4") + + logger.info("waiting for reconvergence") + tgen.gears["r4"].link_enable("r4-eth0", enabled=True) + expect_neighbor("r2", "r2-eth2", "192.168.3.4") + + +def test_pim_bfd_profile(): + "Test that the BFD profile is properly applied in BFD." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def expect_bfd_peer_settings(router, settings): + "Expect the following BFD configuration" + logger.info("Verifying BFD peer {} in {}".format(settings["peer"], router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show bfd peers json", + [settings] + ) + _, result = topotest.run_and_expect(test_func, None, count=4, wait=1) + assertmsg = '"{}" BFD convergence failure'.format(router) + assert result is None, assertmsg + + expect_bfd_peer_settings("r1", { + "peer": "192.168.1.2", + "receive-interval": 250, + "transmit-interval": 250, + }) + + expect_bfd_peer_settings("r2", { + "peer": "192.168.1.1", + "remote-receive-interval": 250, + "remote-transmit-interval": 250, + }) + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/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 { |
