]> git.puffer.fish Git - mirror/frr.git/commitdiff
staticd: BFD integration northbound support
authorRafael Zalamena <rzalamena@opensourcerouting.org>
Wed, 24 Mar 2021 12:39:55 +0000 (09:39 -0300)
committerRafael Zalamena <rzalamena@opensourcerouting.org>
Fri, 13 Jan 2023 18:32:12 +0000 (15:32 -0300)
Implement all BFD integration northbound callbacks and integrate BFD
with `staticd` route installation procedure.

Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
staticd/static_bfd.c [new file with mode: 0644]
staticd/static_nb.c
staticd/static_nb.h
staticd/static_nb_config.c
staticd/static_routes.c
staticd/static_routes.h
staticd/static_zebra.c
staticd/subdir.am

diff --git a/staticd/static_bfd.c b/staticd/static_bfd.c
new file mode 100644 (file)
index 0000000..dda0487
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Static daemon BFD integration.
+ *
+ * Copyright (C) 2020-2022 Network Device Education Foundation, Inc. ("NetDEF")
+ *                         Rafael Zalamena
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <zebra.h>
+
+#include "lib/bfd.h"
+#include "lib/printfrr.h"
+#include "lib/srcdest_table.h"
+
+#include "staticd/static_routes.h"
+#include "staticd/static_zebra.h"
+
+#include "lib/openbsd-queue.h"
+
+/*
+ * Next hop BFD monitoring settings.
+ */
+static void static_next_hop_bfd_change(struct static_nexthop *sn,
+                                      const struct bfd_session_status *bss)
+{
+       switch (bss->state) {
+       case BSS_UNKNOWN:
+               /* FALLTHROUGH: no known state yet. */
+       case BSS_ADMIN_DOWN:
+               /* NOTHING: we or the remote end administratively shutdown. */
+               break;
+       case BSS_DOWN:
+               /* Peer went down, remove this next hop. */
+               zlog_info("%s: next hop is down, remove it from RIB", __func__);
+               sn->path_down = true;
+               static_zebra_route_add(sn->pn, true);
+               break;
+       case BSS_UP:
+               /* Peer is back up, add this next hop. */
+               zlog_info("%s: next hop is up, add it to RIB", __func__);
+               sn->path_down = false;
+               static_zebra_route_add(sn->pn, true);
+               break;
+       }
+}
+
+static void static_next_hop_bfd_updatecb(
+       __attribute__((unused)) struct bfd_session_params *bsp,
+       const struct bfd_session_status *bss, void *arg)
+{
+       static_next_hop_bfd_change(arg, bss);
+}
+
+static inline int
+static_next_hop_type_to_family(const struct static_nexthop *sn)
+{
+       switch (sn->type) {
+       case STATIC_IPV4_GATEWAY_IFNAME:
+       case STATIC_IPV6_GATEWAY_IFNAME:
+       case STATIC_IPV4_GATEWAY:
+       case STATIC_IPV6_GATEWAY:
+               if (sn->type == STATIC_IPV4_GATEWAY ||
+                   sn->type == STATIC_IPV4_GATEWAY_IFNAME)
+                       return AF_INET;
+               else
+                       return AF_INET6;
+               break;
+       case STATIC_IFNAME:
+       case STATIC_BLACKHOLE:
+       default:
+               zlog_err("%s: invalid next hop type", __func__);
+               break;
+       }
+
+       return AF_UNSPEC;
+}
+
+void static_next_hop_bfd_monitor_enable(struct static_nexthop *sn,
+                                       const struct lyd_node *dnode)
+{
+       bool use_interface;
+       bool use_profile;
+       bool use_source;
+       bool onlink;
+       bool mhop;
+       int family;
+       struct ipaddr source;
+
+       use_interface = false;
+       use_source = yang_dnode_exists(dnode, "./source");
+       use_profile = yang_dnode_exists(dnode, "./profile");
+       onlink = yang_dnode_exists(dnode, "../onlink") &&
+                yang_dnode_get_bool(dnode, "../onlink");
+       mhop = yang_dnode_get_bool(dnode, "./multi-hop");
+
+
+       family = static_next_hop_type_to_family(sn);
+       if (family == AF_UNSPEC)
+               return;
+
+       if (sn->type == STATIC_IPV4_GATEWAY_IFNAME ||
+           sn->type == STATIC_IPV6_GATEWAY_IFNAME)
+               use_interface = true;
+
+       /* Reconfigure or allocate new memory. */
+       if (sn->bsp == NULL)
+               sn->bsp = bfd_sess_new(static_next_hop_bfd_updatecb, sn);
+
+       /* Configure the session. */
+       if (use_source)
+               yang_dnode_get_ip(&source, dnode, "./source");
+
+       if (onlink || mhop == false)
+               bfd_sess_set_auto_source(sn->bsp, false);
+       else
+               bfd_sess_set_auto_source(sn->bsp, !use_source);
+
+       /* Configure the session.*/
+       if (family == AF_INET)
+               bfd_sess_set_ipv4_addrs(sn->bsp,
+                                       use_source ? &source.ip._v4_addr : NULL,
+                                       &sn->addr.ipv4);
+       else if (family == AF_INET6)
+               bfd_sess_set_ipv6_addrs(sn->bsp,
+                                       use_source ? &source.ip._v6_addr : NULL,
+                                       &sn->addr.ipv6);
+
+       bfd_sess_set_interface(sn->bsp, use_interface ? sn->ifname : NULL);
+
+       bfd_sess_set_profile(sn->bsp, use_profile ? yang_dnode_get_string(
+                                                           dnode, "./profile")
+                                                 : NULL);
+
+       bfd_sess_set_hop_count(sn->bsp, (onlink || mhop == false) ? 1 : 254);
+
+       /* Install or update the session. */
+       bfd_sess_install(sn->bsp);
+
+       /* Update current path status. */
+       sn->path_down = (bfd_sess_status(sn->bsp) != BSS_UP);
+}
+
+void static_next_hop_bfd_monitor_disable(struct static_nexthop *sn)
+{
+       bfd_sess_free(&sn->bsp);
+
+       /* Reset path status. */
+       sn->path_down = false;
+}
+
+void static_next_hop_bfd_source(struct static_nexthop *sn,
+                               const struct ipaddr *source)
+{
+       int family;
+
+       if (sn->bsp == NULL)
+               return;
+
+       family = static_next_hop_type_to_family(sn);
+       if (family == AF_UNSPEC)
+               return;
+
+       bfd_sess_set_auto_source(sn->bsp, false);
+       if (family == AF_INET)
+               bfd_sess_set_ipv4_addrs(sn->bsp, &source->ip._v4_addr,
+                                       &sn->addr.ipv4);
+       else if (family == AF_INET6)
+               bfd_sess_set_ipv6_addrs(sn->bsp, &source->ip._v6_addr,
+                                       &sn->addr.ipv6);
+
+       bfd_sess_install(sn->bsp);
+}
+
+void static_next_hop_bfd_auto_source(struct static_nexthop *sn)
+{
+       if (sn->bsp == NULL)
+               return;
+
+       bfd_sess_set_auto_source(sn->bsp, true);
+       bfd_sess_install(sn->bsp);
+}
+
+void static_next_hop_bfd_multi_hop(struct static_nexthop *sn, bool mhop)
+{
+       if (sn->bsp == NULL)
+               return;
+
+       bfd_sess_set_hop_count(sn->bsp, mhop ? 254 : 1);
+       bfd_sess_install(sn->bsp);
+}
+
+void static_next_hop_bfd_profile(struct static_nexthop *sn, const char *name)
+{
+       if (sn->bsp == NULL)
+               return;
+
+       bfd_sess_set_profile(sn->bsp, name);
+       bfd_sess_install(sn->bsp);
+}
+
+void static_bfd_initialize(struct zclient *zc, struct thread_master *tm)
+{
+       /* Initialize BFD integration library. */
+       bfd_protocol_integration_init(zc, tm);
+}
index 5935364d5a61b35c3adcf9a83a97c6930433bcfe..68d9ba97b46cd94384d2c8c37f5b085542828cb9 100644 (file)
@@ -116,6 +116,33 @@ const struct frr_yang_module_info frr_staticd_info = {
                                .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring",
+                       .cbs = {
+                               .create = route_next_hop_bfd_create,
+                               .destroy = route_next_hop_bfd_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring/source",
+                       .cbs = {
+                               .modify = route_next_hop_bfd_source_modify,
+                               .destroy = route_next_hop_bfd_source_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring/multi-hop",
+                       .cbs = {
+                               .modify = route_next_hop_bfd_multi_hop_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring/profile",
+                       .cbs = {
+                               .modify = route_next_hop_bfd_profile_modify,
+                               .destroy = route_next_hop_bfd_profile_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list",
                        .cbs = {
index 5c3030fcfa5d4bd848971991dff6293121cdc63c..96c9f8d9b7098ea6404f0ad1b1d1c477b4abc970 100644 (file)
@@ -63,6 +63,13 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa
        struct nb_cb_modify_args *args);
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_destroy(
        struct nb_cb_destroy_args *args);
+int route_next_hop_bfd_create(struct nb_cb_create_args *args);
+int route_next_hop_bfd_destroy(struct nb_cb_destroy_args *args);
+int route_next_hop_bfd_source_modify(struct nb_cb_modify_args *args);
+int route_next_hop_bfd_source_destroy(struct nb_cb_destroy_args *args);
+int route_next_hop_bfd_profile_modify(struct nb_cb_modify_args *args);
+int route_next_hop_bfd_profile_destroy(struct nb_cb_destroy_args *args);
+int route_next_hop_bfd_multi_hop_modify(struct nb_cb_modify_args *args);
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_create(
        struct nb_cb_create_args *args);
 int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_destroy(
index 4a3d9e17a4433fcbfb72152244353b4f724330f7..cbb5b8234fc27ed01972f6b8dc7c38d215301512 100644 (file)
@@ -748,6 +748,113 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa
        return NB_OK;
 }
 
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring
+ */
+int route_next_hop_bfd_create(struct nb_cb_create_args *args)
+{
+       struct static_nexthop *sn;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       sn = nb_running_get_entry(args->dnode, NULL, true);
+       static_next_hop_bfd_monitor_enable(sn, args->dnode);
+       return NB_OK;
+}
+
+int route_next_hop_bfd_destroy(struct nb_cb_destroy_args *args)
+{
+       struct static_nexthop *sn;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       sn = nb_running_get_entry(args->dnode, NULL, true);
+       static_next_hop_bfd_monitor_disable(sn);
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring/source
+ */
+int route_next_hop_bfd_source_modify(struct nb_cb_modify_args *args)
+{
+       struct static_nexthop *sn;
+       struct ipaddr source;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       sn = nb_running_get_entry(args->dnode, NULL, true);
+       yang_dnode_get_ip(&source, args->dnode, NULL);
+       static_next_hop_bfd_source(sn, &source);
+       return NB_OK;
+}
+
+int route_next_hop_bfd_source_destroy(struct nb_cb_destroy_args *args)
+{
+       struct static_nexthop *sn;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       sn = nb_running_get_entry(args->dnode, NULL, true);
+       static_next_hop_bfd_auto_source(sn);
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring/multi-hop
+ */
+int route_next_hop_bfd_multi_hop_modify(struct nb_cb_modify_args *args)
+{
+       struct static_nexthop *sn;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       sn = nb_running_get_entry(args->dnode, NULL, true);
+       static_next_hop_bfd_multi_hop(sn,
+                                     yang_dnode_get_bool(args->dnode, NULL));
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bfd-monitoring/profile
+ */
+int route_next_hop_bfd_profile_modify(struct nb_cb_modify_args *args)
+{
+       struct static_nexthop *sn;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       sn = nb_running_get_entry(args->dnode, NULL, true);
+       static_next_hop_bfd_profile(sn,
+                                   yang_dnode_get_string(args->dnode, NULL));
+
+       return NB_OK;
+}
+
+int route_next_hop_bfd_profile_destroy(struct nb_cb_destroy_args *args)
+{
+       struct static_nexthop *sn;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       sn = nb_running_get_entry(args->dnode, NULL, true);
+       static_next_hop_bfd_profile(sn, NULL);
+
+       return NB_OK;
+}
+
 /*
  * XPath:
  * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list
index ed4cdc51ce717e8bbf93e71a6858abbf3a36708a..3595cc5644c2937969419a40fabdfce97ea1bf68 100644 (file)
@@ -276,6 +276,8 @@ struct static_nexthop *static_add_nexthop(struct static_path *pn,
        /* Make new static route structure. */
        nh = XCALLOC(MTYPE_STATIC_NEXTHOP, sizeof(struct static_nexthop));
 
+       /* Copy back pointers. */
+       nh->rn = rn;
        nh->pn = pn;
 
        nh->type = type;
@@ -393,6 +395,8 @@ void static_delete_nexthop(struct static_nexthop *nh)
        struct route_node *rn = pn->rn;
 
        static_nexthop_list_del(&(pn->nexthop_list), nh);
+       /* Remove BFD session/configuration if any. */
+       bfd_sess_free(&nh->bsp);
 
        if (nh->nh_vrf_id == VRF_UNKNOWN)
                goto EXIT;
index 71c3689be54ad3eb60e6d41b64a7350cda18721e..7082e8959d255ae7c802fa2ad7f8a4d6f27297b2 100644 (file)
@@ -20,6 +20,7 @@
 #ifndef __STATIC_ROUTES_H__
 #define __STATIC_ROUTES_H__
 
+#include "lib/bfd.h"
 #include "lib/mpls.h"
 #include "table.h"
 #include "memory.h"
@@ -30,6 +31,8 @@ extern "C" {
 
 DECLARE_MGROUP(STATIC);
 
+#include "staticd/static_vrf.h"
+
 /* Static route label information */
 struct static_nh_label {
        uint8_t num_labels;
@@ -148,6 +151,13 @@ struct static_nexthop {
 
        /* SR-TE color */
        uint32_t color;
+
+       /** BFD integration data. */
+       struct bfd_session_params *bsp;
+       /** Back pointer for route node. */
+       struct route_node *rn;
+       /** Path connection status. */
+       bool path_down;
 };
 
 DECLARE_DLIST(static_nexthop_list, struct static_nexthop, list);
@@ -218,6 +228,22 @@ extern void zebra_stable_node_cleanup(struct route_table *table,
 extern void static_get_nh_str(struct static_nexthop *nh, char *nexthop,
                              size_t size);
 
+/*
+ * BFD integration.
+ */
+extern void static_next_hop_bfd_source(struct static_nexthop *sn,
+                                      const struct ipaddr *source);
+extern void static_next_hop_bfd_auto_source(struct static_nexthop *sn);
+extern void static_next_hop_bfd_monitor_enable(struct static_nexthop *sn,
+                                              const struct lyd_node *dnode);
+extern void static_next_hop_bfd_monitor_disable(struct static_nexthop *sn);
+extern void static_next_hop_bfd_profile(struct static_nexthop *sn,
+                                       const char *name);
+extern void static_next_hop_bfd_multi_hop(struct static_nexthop *sn, bool mhop);
+
+/** Call this function after zebra client initialization. */
+extern void static_bfd_initialize(struct zclient *zc, struct thread_master *tm);
+
 #ifdef __cplusplus
 }
 #endif
index cb36304473f65903d659309a15683ed671d789e2..316247adb3118d023d73b8ce9db049952c4b774b 100644 (file)
@@ -441,6 +441,9 @@ extern void static_zebra_route_add(struct static_path *pn, bool install)
                api_nh = &api.nexthops[nh_num];
                if (nh->nh_vrf_id == VRF_UNKNOWN)
                        continue;
+               /* Skip next hop which peer is down. */
+               if (nh->path_down)
+                       continue;
 
                api_nh->vrf_id = nh->nh_vrf_id;
                if (nh->onlink)
@@ -545,6 +548,7 @@ void static_zebra_init(void)
        zclient->zebra_connected = zebra_connected;
 
        static_nht_hash_init(static_nht_hash);
+       static_bfd_initialize(zclient, master);
 }
 
 /* static_zebra_stop used by tests/lib/test_grpc.cpp */
index bb0fc95bc202b798da7b6ae5eaddd84fe8afaf48..022428281f60dbe5fc884fcbbb4e4279cdf41427 100644 (file)
@@ -10,6 +10,7 @@ man8 += $(MANBUILD)/frr-staticd.8
 endif
 
 staticd_libstatic_a_SOURCES = \
+       staticd/static_bfd.c \
        staticd/static_debug.c \
        staticd/static_nht.c \
        staticd/static_routes.c \
@@ -38,5 +39,6 @@ staticd_staticd_SOURCES = staticd/static_main.c
 staticd_staticd_LDADD = staticd/libstatic.a lib/libfrr.la $(LIBCAP)
 
 nodist_staticd_staticd_SOURCES = \
+       yang/frr-bfdd.yang.c \
        yang/frr-staticd.yang.c \
        # end