From d06cc4164464539f278e10243a24fa7809fa3847 Mon Sep 17 00:00:00 2001 From: Rafael Zalamena Date: Wed, 14 Apr 2021 12:37:01 -0300 Subject: [PATCH] ospf6d: rework BFD integration Use the new BFD library to integrate with BFD. Signed-off-by: Rafael Zalamena --- ospf6d/ospf6_bfd.c | 308 ++++++++++----------------------------- ospf6d/ospf6_bfd.h | 9 +- ospf6d/ospf6_interface.c | 26 +++- ospf6d/ospf6_interface.h | 7 +- ospf6d/ospf6_neighbor.c | 8 +- ospf6d/ospf6_neighbor.h | 2 +- 6 files changed, 116 insertions(+), 244 deletions(-) diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c index a701583621..0ef5d597ed 100644 --- a/ospf6d/ospf6_bfd.c +++ b/ospf6d/ospf6_bfd.c @@ -44,59 +44,6 @@ 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. @@ -104,12 +51,33 @@ void ospf6_bfd_reg_dereg_nbr(struct ospf6_neighbor *on, int command) 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); - } -} - -/* - * 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; + /* Always allocate session data even if not enabled. */ + ospf6_bfd_info_nbr_create(oi, on); - 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; - - old_status = bfd_info->status; - BFD_SET_CLIENT_STATUS(bfd_info->status, status); - monotime(&tv); - bfd_info->last_update = tv.tv_sec; + struct ospf6_neighbor *on = arg; - 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_session == NULL) + on->bfd_session = bfd_sess_new(ospf6_bfd_callback, on); - if (!on->bfd_info) - on->bfd_info = bfd_info_create(); - - 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,41 +151,21 @@ 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"); } -/* - * 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) -{ - int command = 0; - - 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); -} - DEFUN (ipv6_ospf6_bfd, ipv6_ospf6_bfd_cmd, "ipv6 ospf6 bfd", @@ -328,8 +183,13 @@ 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); + 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; + + ospf6_bfd_reg_dereg_all_nbr(oi, true); + return CMD_SUCCESS; } @@ -353,10 +213,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 +221,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,21 +250,15 @@ 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); 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..60ead06f3e 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -272,8 +272,6 @@ 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); @@ -1148,7 +1146,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..49a9c2bba6 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -119,7 +119,12 @@ 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; + } 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 */ -- 2.39.5