]> git.proxmox.com Git - mirror_frr.git/commitdiff
ripd: support BFD integration
authorRenato Westphal <renato@opensourcerouting.org>
Thu, 14 Oct 2021 15:12:37 +0000 (12:12 -0300)
committerRafael Zalamena <rzalamena@opensourcerouting.org>
Wed, 19 Apr 2023 12:15:01 +0000 (09:15 -0300)
Implement RIP peer monitoring with BFD.

RFC 5882 Generic Application of Bidirectional Forwarding Detection
(BFD), Section 10.3 Interactions with RIP.

Co-authored-by: Renato Westphal <renato@opensourcerouting.org>
Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
15 files changed:
ripd/rip_bfd.c [new file with mode: 0644]
ripd/rip_bfd.h [new file with mode: 0644]
ripd/rip_cli.c
ripd/rip_interface.c
ripd/rip_main.c
ripd/rip_nb.c
ripd/rip_nb.h
ripd/rip_nb_config.c
ripd/rip_peer.c
ripd/rip_zebra.c
ripd/ripd.c
ripd/ripd.h
ripd/subdir.am
yang/frr-ripd.yang
zebra/zebra_ptm.h

diff --git a/ripd/rip_bfd.c b/ripd/rip_bfd.c
new file mode 100644 (file)
index 0000000..ac5035f
--- /dev/null
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * RIP BFD integration.
+ * Copyright (C) 2021-2023 Network Device Education Foundation, Inc. ("NetDEF")
+ */
+
+#include <zebra.h>
+
+#include "lib/zclient.h"
+#include "lib/bfd.h"
+
+#include "ripd/ripd.h"
+#include "ripd/rip_bfd.h"
+#include "ripd/rip_debug.h"
+
+extern struct zclient *zclient;
+
+static const char *rip_bfd_interface_profile(struct rip_interface *ri)
+{
+       struct rip *rip = ri->rip;
+
+       if (ri->bfd.profile)
+               return ri->bfd.profile;
+
+       if (rip->default_bfd_profile)
+               return rip->default_bfd_profile;
+
+       return NULL;
+}
+
+static void rip_bfd_session_change(struct bfd_session_params *bsp,
+                                  const struct bfd_session_status *bss,
+                                  void *arg)
+{
+       struct rip_peer *rp = arg;
+
+       /* BFD peer went down. */
+       if (bss->state == BFD_STATUS_DOWN &&
+           bss->previous_state == BFD_STATUS_UP) {
+               if (IS_RIP_DEBUG_EVENT)
+                       zlog_debug("%s: peer %pI4: BFD Down", __func__,
+                                  &rp->addr);
+
+               rip_peer_delete_routes(rp);
+               listnode_delete(rp->rip->peer_list, rp);
+               rip_peer_free(rp);
+               return;
+       }
+
+       /* BFD peer went up. */
+       if (bss->state == BSS_UP && bss->previous_state == BSS_DOWN)
+               if (IS_RIP_DEBUG_EVENT)
+                       zlog_debug("%s: peer %pI4: BFD Up", __func__,
+                                  &rp->addr);
+}
+
+void rip_bfd_session_update(struct rip_peer *rp)
+{
+       struct rip_interface *ri = rp->ri;
+
+       /* BFD configuration was removed. */
+       if (ri == NULL || !ri->bfd.enabled) {
+               bfd_sess_free(&rp->bfd_session);
+               return;
+       }
+
+       /* New BFD session. */
+       if (rp->bfd_session == NULL) {
+               rp->bfd_session = bfd_sess_new(rip_bfd_session_change, rp);
+               bfd_sess_set_ipv4_addrs(rp->bfd_session, NULL, &rp->addr);
+               bfd_sess_set_interface(rp->bfd_session, ri->ifp->name);
+               bfd_sess_set_vrf(rp->bfd_session, rp->rip->vrf->vrf_id);
+       }
+
+       /* Set new configuration. */
+       bfd_sess_set_timers(rp->bfd_session, BFD_DEF_DETECT_MULT,
+                           BFD_DEF_MIN_RX, BFD_DEF_MIN_TX);
+       bfd_sess_set_profile(rp->bfd_session, rip_bfd_interface_profile(ri));
+
+       bfd_sess_install(rp->bfd_session);
+}
+
+void rip_bfd_interface_update(struct rip_interface *ri)
+{
+       struct rip *rip;
+       struct rip_peer *rp;
+       struct listnode *node;
+
+       rip = ri->rip;
+       if (!rip)
+               return;
+
+       for (ALL_LIST_ELEMENTS_RO(rip->peer_list, node, rp)) {
+               if (rp->ri != ri)
+                       continue;
+
+               rip_bfd_session_update(rp);
+       }
+}
+
+void rip_bfd_instance_update(struct rip *rip)
+{
+       struct interface *ifp;
+
+       FOR_ALL_INTERFACES (rip->vrf, ifp) {
+               struct rip_interface *ri;
+
+               ri = ifp->info;
+               if (!ri)
+                       continue;
+
+               rip_bfd_interface_update(ri);
+       }
+}
+
+void rip_bfd_init(struct event_loop *tm)
+{
+       bfd_protocol_integration_init(zclient, tm);
+}
diff --git a/ripd/rip_bfd.h b/ripd/rip_bfd.h
new file mode 100644 (file)
index 0000000..d49ca15
--- /dev/null
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * RIP BFD integration.
+ * Copyright (C) 2021-2023 Network Device Education Foundation, Inc. ("NetDEF")
+ */
+
+#ifndef _RIP_BFD_
+#define _RIP_BFD_
+
+#include "frrevent.h"
+
+struct rip;
+struct rip_interface;
+struct rip_peer;
+
+void rip_bfd_session_update(struct rip_peer *rp);
+void rip_bfd_interface_update(struct rip_interface *ri);
+void rip_bfd_instance_update(struct rip *rip);
+void rip_bfd_init(struct event_loop *tm);
+
+#endif /* _RIP_BFD_ */
index cac29c00d458e80cd9fb41b165156a8c37bda650..ac9fc4b1a818ba651e60f633bdbc5dee2bd0ddb5 100644 (file)
@@ -581,6 +581,42 @@ void cli_show_rip_version(struct vty *vty, const struct lyd_node *dnode,
        }
 }
 
+/*
+ * XPath: /frr-ripd:ripd/instance/default-bfd-profile
+ */
+DEFPY_YANG(rip_bfd_default_profile, rip_bfd_default_profile_cmd,
+          "bfd default-profile BFDPROF$profile",
+          "Bidirectional Forwarding Detection\n"
+          "BFD default profile\n"
+          "Profile name\n")
+{
+       nb_cli_enqueue_change(vty, "./default-bfd-profile", NB_OP_MODIFY,
+                             profile);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY_YANG(no_rip_bfd_default_profile, no_rip_bfd_default_profile_cmd,
+          "no bfd default-profile [BFDPROF]",
+          NO_STR
+          "Bidirectional Forwarding Detection\n"
+          "BFD default profile\n"
+          "Profile name\n")
+{
+       nb_cli_enqueue_change(vty, "./default-bfd-profile", NB_OP_DESTROY,
+                             NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_ripd_instance_default_bfd_profile(struct vty *vty,
+                                               const struct lyd_node *dnode,
+                                               bool show_defaults)
+{
+       vty_out(vty, " bfd default-profile %s\n",
+               yang_dnode_get_string(dnode, NULL));
+}
+
 /*
  * XPath: /frr-interface:lib/interface/frr-ripd:rip/split-horizon
  */
@@ -979,6 +1015,66 @@ void cli_show_ip_rip_authentication_key_chain(struct vty *vty,
                yang_dnode_get_string(dnode, NULL));
 }
 
+/*
+ * XPath: /frr-interface:lib/interface/frr-ripd:rip/bfd-monitoring/enable
+ */
+DEFPY_YANG(ip_rip_bfd, ip_rip_bfd_cmd, "[no] ip rip bfd",
+          NO_STR IP_STR
+          "Routing Information Protocol\n"
+          "Enable BFD support\n")
+{
+       nb_cli_enqueue_change(vty, "./bfd-monitoring/enable", NB_OP_MODIFY,
+                             no ? "false" : "true");
+
+       return nb_cli_apply_changes(vty, "./frr-ripd:rip");
+}
+
+void cli_show_ip_rip_bfd_enable(struct vty *vty, const struct lyd_node *dnode,
+                               bool show_defaults)
+{
+       vty_out(vty, " ip rip bfd\n");
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-ripd:rip/bfd/profile
+ */
+DEFPY_YANG(ip_rip_bfd_profile, ip_rip_bfd_profile_cmd,
+          "[no] ip rip bfd profile BFDPROF$profile",
+          NO_STR IP_STR
+          "Routing Information Protocol\n"
+          "Enable BFD support\n"
+          "Use a pre-configured profile\n"
+          "Profile name\n")
+{
+       if (no)
+               nb_cli_enqueue_change(vty, "./bfd-monitoring/profile",
+                                     NB_OP_DESTROY, NULL);
+       else
+               nb_cli_enqueue_change(vty, "./bfd-monitoring/profile",
+                                     NB_OP_MODIFY, profile);
+
+       return nb_cli_apply_changes(vty, "./frr-ripd:rip");
+}
+
+DEFPY_YANG(no_ip_rip_bfd_profile, no_ip_rip_bfd_profile_cmd,
+          "no ip rip bfd profile",
+          NO_STR IP_STR
+          "Routing Information Protocol\n"
+          "Enable BFD support\n"
+          "Use a pre-configured profile\n")
+{
+       nb_cli_enqueue_change(vty, "./bfd-monitoring/profile", NB_OP_DESTROY,
+                             NULL);
+       return nb_cli_apply_changes(vty, "./frr-ripd:rip");
+}
+
+void cli_show_ip_rip_bfd_profile(struct vty *vty, const struct lyd_node *dnode,
+                                bool show_defaults)
+{
+       vty_out(vty, " ip rip bfd profile %s\n",
+               yang_dnode_get_string(dnode, NULL));
+}
+
 /*
  * XPath: /frr-ripd:clear-rip-route
  */
@@ -1078,6 +1174,8 @@ void rip_cli_init(void)
        install_element(RIP_NODE, &no_rip_timers_cmd);
        install_element(RIP_NODE, &rip_version_cmd);
        install_element(RIP_NODE, &no_rip_version_cmd);
+       install_element(RIP_NODE, &rip_bfd_default_profile_cmd);
+       install_element(RIP_NODE, &no_rip_bfd_default_profile_cmd);
 
        install_element(INTERFACE_NODE, &ip_rip_split_horizon_cmd);
        install_element(INTERFACE_NODE, &ip_rip_v2_broadcast_cmd);
@@ -1092,6 +1190,9 @@ void rip_cli_init(void)
        install_element(INTERFACE_NODE, &ip_rip_authentication_key_chain_cmd);
        install_element(INTERFACE_NODE,
                        &no_ip_rip_authentication_key_chain_cmd);
+       install_element(INTERFACE_NODE, &ip_rip_bfd_cmd);
+       install_element(INTERFACE_NODE, &ip_rip_bfd_profile_cmd);
+       install_element(INTERFACE_NODE, &no_ip_rip_bfd_profile_cmd);
 
        install_element(ENABLE_NODE, &clear_ip_rip_cmd);
 }
index 0b92f174b1ff1301424972f6dbae25c0b5d09229..b383be042a4c8cf18ed05e3e6bc61d449b4b3813 100644 (file)
@@ -457,6 +457,7 @@ static void rip_interface_reset(struct rip_interface *ri)
        ri->sent_updates = 0;
 
        ri->passive = 0;
+       XFREE(MTYPE_TMP, ri->bfd.profile);
 
        rip_interface_clean(ri);
 }
@@ -1109,6 +1110,7 @@ void rip_interface_sync(struct interface *ifp)
        struct rip_interface *ri;
 
        ri = ifp->info;
+       ri->ifp = ifp;
        if (ri)
                ri->rip = ifp->vrf->info;
 }
index a6e4ad776bf132ea44e66937c8bd819b1f62ea88..0e26662cdb5ca9b815568666fd0f603e0255d2af 100644 (file)
 #include "if_rmap.h"
 #include "libfrr.h"
 #include "routemap.h"
+#include "bfd.h"
 
 #include "ripd/ripd.h"
+#include "ripd/rip_bfd.h"
 #include "ripd/rip_nb.h"
 #include "ripd/rip_errors.h"
 
@@ -65,6 +67,7 @@ static void sigint(void)
 {
        zlog_notice("Terminating on signal");
 
+       bfd_protocol_integration_set_shutdown(true);
        rip_vrf_terminate();
        if_rmap_terminate();
        rip_zclient_stop();
@@ -162,6 +165,7 @@ int main(int argc, char **argv)
        rip_if_init();
        rip_cli_init();
        rip_zclient_init(master);
+       rip_bfd_init(master);
 
        frr_config_fork();
        frr_run(master);
index fa6652faf4043131c612846480390224adb7a190..d11f1e1d34fee98241d3adf7b0613cec8e04c4de 100644 (file)
@@ -239,6 +239,14 @@ const struct frr_yang_module_info frr_ripd_info = {
                                .modify = ripd_instance_version_send_modify,
                        },
                },
+               {
+                       .xpath = "/frr-ripd:ripd/instance/default-bfd-profile",
+                       .cbs = {
+                               .modify = ripd_instance_default_bfd_profile_modify,
+                               .destroy = ripd_instance_default_bfd_profile_destroy,
+                               .cli_show = cli_show_ripd_instance_default_bfd_profile,
+                       },
+               },
                {
                        .xpath = "/frr-interface:lib/interface/frr-ripd:rip/split-horizon",
                        .cbs = {
@@ -302,6 +310,28 @@ const struct frr_yang_module_info frr_ripd_info = {
                                .modify = lib_interface_rip_authentication_key_chain_modify,
                        },
                },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-ripd:rip/bfd-monitoring",
+                       .cbs = {
+                               .create = lib_interface_rip_bfd_create,
+                               .destroy = lib_interface_rip_bfd_destroy,
+                       },
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-ripd:rip/bfd-monitoring/enable",
+                       .cbs = {
+                               .cli_show = cli_show_ip_rip_bfd_enable,
+                               .modify = lib_interface_rip_bfd_enable_modify,
+                       },
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-ripd:rip/bfd-monitoring/profile",
+                       .cbs = {
+                               .cli_show = cli_show_ip_rip_bfd_profile,
+                               .modify = lib_interface_rip_bfd_profile_modify,
+                               .destroy = lib_interface_rip_bfd_profile_destroy,
+                       },
+               },
                {
                        .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor",
                        .cbs = {
index ebc60fefb4a8855138717bce6a007b0e31be34c3..9929e0952b6febb70ab3e20a38fe40212ea35703 100644 (file)
@@ -72,6 +72,8 @@ int ripd_instance_timers_holddown_interval_modify(
 int ripd_instance_timers_update_interval_modify(struct nb_cb_modify_args *args);
 int ripd_instance_version_receive_modify(struct nb_cb_modify_args *args);
 int ripd_instance_version_send_modify(struct nb_cb_modify_args *args);
+int ripd_instance_default_bfd_profile_modify(struct nb_cb_modify_args *args);
+int ripd_instance_default_bfd_profile_destroy(struct nb_cb_destroy_args *args);
 const void *ripd_instance_state_neighbors_neighbor_get_next(
        struct nb_cb_get_next_args *args);
 int ripd_instance_state_neighbors_neighbor_get_keys(
@@ -151,6 +153,12 @@ int lib_interface_rip_authentication_key_chain_modify(
        struct nb_cb_modify_args *args);
 int lib_interface_rip_authentication_key_chain_destroy(
        struct nb_cb_destroy_args *args);
+int lib_interface_rip_bfd_create(struct nb_cb_create_args *args);
+int lib_interface_rip_bfd_destroy(struct nb_cb_destroy_args *args);
+int lib_interface_rip_bfd_enable_modify(struct nb_cb_modify_args *args);
+int lib_interface_rip_bfd_enable_destroy(struct nb_cb_destroy_args *args);
+int lib_interface_rip_bfd_profile_modify(struct nb_cb_modify_args *args);
+int lib_interface_rip_bfd_profile_destroy(struct nb_cb_destroy_args *args);
 
 /* Optional 'apply_finish' callbacks. */
 void ripd_instance_redistribute_apply_finish(
@@ -206,6 +214,9 @@ void cli_show_ip_rip_receive_version(struct vty *vty,
                                     bool show_defaults);
 void cli_show_ip_rip_send_version(struct vty *vty, const struct lyd_node *dnode,
                                  bool show_defaults);
+void cli_show_ripd_instance_default_bfd_profile(struct vty *vty,
+                                               const struct lyd_node *dnode,
+                                               bool show_defaults);
 void cli_show_ip_rip_authentication_scheme(struct vty *vty,
                                           const struct lyd_node *dnode,
                                           bool show_defaults);
@@ -215,6 +226,10 @@ void cli_show_ip_rip_authentication_string(struct vty *vty,
 void cli_show_ip_rip_authentication_key_chain(struct vty *vty,
                                              const struct lyd_node *dnode,
                                              bool show_defaults);
+void cli_show_ip_rip_bfd_enable(struct vty *vty, const struct lyd_node *dnode,
+                               bool show_defaults);
+void cli_show_ip_rip_bfd_profile(struct vty *vty, const struct lyd_node *dnode,
+                                bool show_defaults);
 
 /* Notifications. */
 extern void ripd_notif_send_auth_type_failure(const char *ifname);
index 343bb9bb57b2d71900cea3533e306f879482777b..cbc62f9f1ff64eb8154edea25b2853eb3e46ed52 100644 (file)
@@ -23,6 +23,9 @@
 #include "ripd/rip_nb.h"
 #include "ripd/rip_debug.h"
 #include "ripd/rip_interface.h"
+#include "ripd/rip_bfd.h"
+
+DEFINE_MTYPE_STATIC(RIPD, RIP_BFD_PROFILE, "RIP BFD profile name");
 
 /*
  * XPath: /frr-ripd:ripd/instance
@@ -905,6 +908,40 @@ int ripd_instance_version_send_modify(struct nb_cb_modify_args *args)
        return NB_OK;
 }
 
+/*
+ * XPath: /frr-ripd:ripd/instance/default-bfd-profile
+ */
+int ripd_instance_default_bfd_profile_modify(struct nb_cb_modify_args *args)
+{
+       struct rip *rip;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       rip = nb_running_get_entry(args->dnode, NULL, true);
+       XFREE(MTYPE_RIP_BFD_PROFILE, rip->default_bfd_profile);
+       rip->default_bfd_profile =
+               XSTRDUP(MTYPE_RIP_BFD_PROFILE,
+                       yang_dnode_get_string(args->dnode, NULL));
+       rip_bfd_instance_update(rip);
+
+       return NB_OK;
+}
+
+int ripd_instance_default_bfd_profile_destroy(struct nb_cb_destroy_args *args)
+{
+       struct rip *rip;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       rip = nb_running_get_entry(args->dnode, NULL, true);
+       XFREE(MTYPE_RIP_BFD_PROFILE, rip->default_bfd_profile);
+       rip_bfd_instance_update(rip);
+
+       return NB_OK;
+}
+
 /*
  * XPath: /frr-interface:lib/interface/frr-ripd:rip/split-horizon
  */
@@ -1070,6 +1107,104 @@ int lib_interface_rip_authentication_password_destroy(
        return NB_OK;
 }
 
+/*
+ * XPath: /frr-interface:lib/interface/frr-ripd:rip/bfd-monitoring
+ */
+int lib_interface_rip_bfd_create(struct nb_cb_create_args *args)
+{
+       struct interface *ifp;
+       struct rip_interface *ri;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       ifp = nb_running_get_entry(args->dnode, NULL, true);
+       ri = ifp->info;
+       ri->bfd.enabled = yang_dnode_get_bool(args->dnode, "./enable");
+       XFREE(MTYPE_RIP_BFD_PROFILE, ri->bfd.profile);
+       if (yang_dnode_exists(args->dnode, "./profile"))
+               ri->bfd.profile = XSTRDUP(
+                       MTYPE_RIP_BFD_PROFILE,
+                       yang_dnode_get_string(args->dnode, "./profile"));
+
+       rip_bfd_interface_update(ri);
+
+       return NB_OK;
+}
+
+int lib_interface_rip_bfd_destroy(struct nb_cb_destroy_args *args)
+{
+       struct interface *ifp;
+       struct rip_interface *ri;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       ifp = nb_running_get_entry(args->dnode, NULL, true);
+       ri = ifp->info;
+       ri->bfd.enabled = false;
+       XFREE(MTYPE_RIP_BFD_PROFILE, ri->bfd.profile);
+       rip_bfd_interface_update(ri);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-ripd:rip/bfd-monitoring/enable
+ */
+int lib_interface_rip_bfd_enable_modify(struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct rip_interface *ri;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       ifp = nb_running_get_entry(args->dnode, NULL, true);
+       ri = ifp->info;
+       ri->bfd.enabled = yang_dnode_get_bool(args->dnode, NULL);
+       rip_bfd_interface_update(ri);
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-ripd:rip/bfd-monitoring/profile
+ */
+int lib_interface_rip_bfd_profile_modify(struct nb_cb_modify_args *args)
+{
+       struct interface *ifp;
+       struct rip_interface *ri;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       ifp = nb_running_get_entry(args->dnode, NULL, true);
+       ri = ifp->info;
+       XFREE(MTYPE_RIP_BFD_PROFILE, ri->bfd.profile);
+       ri->bfd.profile = XSTRDUP(MTYPE_RIP_BFD_PROFILE,
+                                 yang_dnode_get_string(args->dnode, NULL));
+       rip_bfd_interface_update(ri);
+
+       return NB_OK;
+}
+
+int lib_interface_rip_bfd_profile_destroy(struct nb_cb_destroy_args *args)
+{
+       struct interface *ifp;
+       struct rip_interface *ri;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       ifp = nb_running_get_entry(args->dnode, NULL, true);
+       ri = ifp->info;
+       XFREE(MTYPE_RIP_BFD_PROFILE, ri->bfd.profile);
+       rip_bfd_interface_update(ri);
+
+       return NB_OK;
+}
+
 /*
  * XPath: /frr-interface:lib/interface/frr-ripd:rip/authentication-key-chain
  */
index 9410ef380ecc723de5beafb65a415fe2ee67d175..449abe47b88a5078e6b8c0452d76482948a552a3 100644 (file)
 #include "linklist.h"
 #include "frrevent.h"
 #include "memory.h"
+#include "table.h"
 
 #include "ripd/ripd.h"
+#include "ripd/rip_bfd.h"
 
 DEFINE_MTYPE_STATIC(RIPD, RIP_PEER, "RIP peer");
 
@@ -21,8 +23,9 @@ static struct rip_peer *rip_peer_new(void)
        return XCALLOC(MTYPE_RIP_PEER, sizeof(struct rip_peer));
 }
 
-static void rip_peer_free(struct rip_peer *peer)
+void rip_peer_free(struct rip_peer *peer)
 {
+       bfd_sess_free(&peer->bfd_session);
        EVENT_OFF(peer->t_timeout);
        XFREE(MTYPE_RIP_PEER, peer);
 }
@@ -62,7 +65,8 @@ static void rip_peer_timeout(struct event *t)
 }
 
 /* Get RIP peer.  At the same time update timeout thread. */
-static struct rip_peer *rip_peer_get(struct rip *rip, struct in_addr *addr)
+static struct rip_peer *rip_peer_get(struct rip *rip, struct rip_interface *ri,
+                                    struct in_addr *addr)
 {
        struct rip_peer *peer;
 
@@ -73,7 +77,9 @@ static struct rip_peer *rip_peer_get(struct rip *rip, struct in_addr *addr)
        } else {
                peer = rip_peer_new();
                peer->rip = rip;
+               peer->ri = ri;
                peer->addr = *addr;
+               rip_bfd_session_update(peer);
                listnode_add_sort(rip->peer_list, peer);
        }
 
@@ -87,24 +93,27 @@ static struct rip_peer *rip_peer_get(struct rip *rip, struct in_addr *addr)
        return peer;
 }
 
-void rip_peer_update(struct rip *rip, struct sockaddr_in *from, uint8_t version)
+void rip_peer_update(struct rip *rip, struct rip_interface *ri,
+                    struct sockaddr_in *from, uint8_t version)
 {
        struct rip_peer *peer;
-       peer = rip_peer_get(rip, &from->sin_addr);
+       peer = rip_peer_get(rip, ri, &from->sin_addr);
        peer->version = version;
 }
 
-void rip_peer_bad_route(struct rip *rip, struct sockaddr_in *from)
+void rip_peer_bad_route(struct rip *rip, struct rip_interface *ri,
+                       struct sockaddr_in *from)
 {
        struct rip_peer *peer;
-       peer = rip_peer_get(rip, &from->sin_addr);
+       peer = rip_peer_get(rip, ri, &from->sin_addr);
        peer->recv_badroutes++;
 }
 
-void rip_peer_bad_packet(struct rip *rip, struct sockaddr_in *from)
+void rip_peer_bad_packet(struct rip *rip, struct rip_interface *ri,
+                        struct sockaddr_in *from)
 {
        struct rip_peer *peer;
-       peer = rip_peer_get(rip, &from->sin_addr);
+       peer = rip_peer_get(rip, ri, &from->sin_addr);
        peer->recv_badpackets++;
 }
 
@@ -155,3 +164,46 @@ void rip_peer_list_del(void *arg)
 {
        rip_peer_free(arg);
 }
+
+void rip_peer_delete_routes(const struct rip_peer *peer)
+{
+       struct route_node *route_node;
+
+       for (route_node = route_top(peer->rip->table); route_node;
+            route_node = route_next(route_node)) {
+               struct rip_info *route_entry;
+               struct listnode *listnode;
+               struct listnode *listnode_next;
+               struct list *list;
+
+               list = route_node->info;
+               if (list == NULL)
+                       continue;
+
+               for (ALL_LIST_ELEMENTS(list, listnode, listnode_next,
+                                      route_entry)) {
+                       if (!rip_route_rte(route_entry))
+                               continue;
+                       if (route_entry->from.s_addr != peer->addr.s_addr)
+                               continue;
+
+                       if (listcount(list) == 1) {
+                               EVENT_OFF(route_entry->t_timeout);
+                               EVENT_OFF(route_entry->t_garbage_collect);
+                               listnode_delete(list, route_entry);
+                               if (list_isempty(list)) {
+                                       list_delete((struct list **)&route_node
+                                                           ->info);
+                                       route_unlock_node(route_node);
+                               }
+                               rip_info_free(route_entry);
+
+                               /* Signal the output process to trigger an
+                                * update (see section 2.5). */
+                               rip_event(peer->rip, RIP_TRIGGERED_UPDATE, 0);
+                       } else
+                               rip_ecmp_delete(peer->rip, route_entry);
+                       break;
+               }
+       }
+}
index 35c4b1f1beef169f5634f450cfda38d540172ba3..698dcb982d8f5b9affdaa59a542228d71fb5ea96 100644 (file)
@@ -13,6 +13,7 @@
 #include "zclient.h"
 #include "log.h"
 #include "vrf.h"
+#include "bfd.h"
 #include "ripd/ripd.h"
 #include "ripd/rip_debug.h"
 #include "ripd/rip_interface.h"
@@ -196,6 +197,7 @@ void rip_zebra_vrf_register(struct vrf *vrf)
                           vrf->name, vrf->vrf_id);
 
        zclient_send_reg_requests(zclient, vrf->vrf_id);
+       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf->vrf_id);
 }
 
 void rip_zebra_vrf_deregister(struct vrf *vrf)
@@ -208,11 +210,13 @@ void rip_zebra_vrf_deregister(struct vrf *vrf)
                           vrf->name, vrf->vrf_id);
 
        zclient_send_dereg_requests(zclient, vrf->vrf_id);
+       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_DEREGISTER, vrf->vrf_id);
 }
 
 static void rip_zebra_connected(struct zclient *zclient)
 {
        zclient_send_reg_requests(zclient, VRF_DEFAULT);
+       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
 }
 
 zclient_handler *const rip_handlers[] = {
index fb3d574aaa70b71459875455c989610ef1233e7b..48f266a94c2db41877ca3f9b80c8488c689d8733 100644 (file)
@@ -1123,7 +1123,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
        if (from->sin_port != htons(RIP_PORT_DEFAULT)) {
                zlog_info("response doesn't come from RIP port: %d",
                          from->sin_port);
-               rip_peer_bad_packet(rip, from);
+               rip_peer_bad_packet(rip, ri, from);
                return;
        }
 
@@ -1137,7 +1137,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
                zlog_info(
                        "This datagram doesn't come from a valid neighbor: %pI4",
                        &from->sin_addr);
-               rip_peer_bad_packet(rip, from);
+               rip_peer_bad_packet(rip, ri, from);
                return;
        }
 
@@ -1147,7 +1147,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
        ; /* Alredy done in rip_read () */
 
        /* Update RIP peer. */
-       rip_peer_update(rip, from, packet->version);
+       rip_peer_update(rip, ri, from, packet->version);
 
        /* Set RTE pointer. */
        rte = packet->rte;
@@ -1176,7 +1176,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
                if (!rip_destination_check(rte->prefix)) {
                        zlog_info(
                                "Network is net 0 or net 127 or it is not unicast network");
-                       rip_peer_bad_route(rip, from);
+                       rip_peer_bad_route(rip, ri, from);
                        continue;
                }
 
@@ -1186,7 +1186,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
                /* - is the metric valid (i.e., between 1 and 16, inclusive) */
                if (!(rte->metric >= 1 && rte->metric <= 16)) {
                        zlog_info("Route's metric is not in the 1-16 range.");
-                       rip_peer_bad_route(rip, from);
+                       rip_peer_bad_route(rip, ri, from);
                        continue;
                }
 
@@ -1195,7 +1195,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
                    && rte->nexthop.s_addr != INADDR_ANY) {
                        zlog_info("RIPv1 packet with nexthop value %pI4",
                                  &rte->nexthop);
-                       rip_peer_bad_route(rip, from);
+                       rip_peer_bad_route(rip, ri, from);
                        continue;
                }
 
@@ -1326,7 +1326,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
                        zlog_warn(
                                "RIPv2 address %pI4 is not mask /%d applied one",
                                &rte->prefix, ip_masklen(rte->mask));
-                       rip_peer_bad_route(rip, from);
+                       rip_peer_bad_route(rip, ri, from);
                        continue;
                }
 
@@ -1643,7 +1643,7 @@ static void rip_request_process(struct rip_packet *packet, int size,
                return;
 
        /* RIP peer update. */
-       rip_peer_update(rip, from, packet->version);
+       rip_peer_update(rip, ri, from, packet->version);
 
        lim = ((caddr_t)packet) + size;
        rte = packet->rte;
@@ -1711,7 +1711,7 @@ static void rip_read(struct event *t)
        socklen_t fromlen;
        struct interface *ifp = NULL;
        struct connected *ifc;
-       struct rip_interface *ri;
+       struct rip_interface *ri = NULL;
        struct prefix p;
 
        /* Fetch socket then register myself. */
@@ -1743,8 +1743,10 @@ static void rip_read(struct event *t)
        /* Which interface is this packet comes from. */
        ifc = if_lookup_address((void *)&from.sin_addr, AF_INET,
                                rip->vrf->vrf_id);
-       if (ifc)
+       if (ifc) {
                ifp = ifc->ifp;
+               ri = ifp->info;
+       }
 
        /* RIP packet received */
        if (IS_RIP_DEBUG_EVENT)
@@ -1753,7 +1755,7 @@ static void rip_read(struct event *t)
                           ifp ? ifp->name : "unknown", rip->vrf_name);
 
        /* If this packet come from unknown interface, ignore it. */
-       if (ifp == NULL) {
+       if (ifp == NULL || ri == NULL) {
                zlog_info(
                        "%s: cannot find interface for packet from %pI4 port %d (VRF %s)",
                        __func__, &from.sin_addr, ntohs(from.sin_port),
@@ -1779,13 +1781,13 @@ static void rip_read(struct event *t)
        if (len < RIP_PACKET_MINSIZ) {
                zlog_warn("packet size %d is smaller than minimum size %d", len,
                          RIP_PACKET_MINSIZ);
-               rip_peer_bad_packet(rip, &from);
+               rip_peer_bad_packet(rip, ri, &from);
                return;
        }
        if (len > RIP_PACKET_MAXSIZ) {
                zlog_warn("packet size %d is larger than max size %d", len,
                          RIP_PACKET_MAXSIZ);
-               rip_peer_bad_packet(rip, &from);
+               rip_peer_bad_packet(rip, ri, &from);
                return;
        }
 
@@ -1793,7 +1795,7 @@ static void rip_read(struct event *t)
        if ((len - RIP_PACKET_MINSIZ) % 20) {
                zlog_warn("packet size %d is wrong for RIP packet alignment",
                          len);
-               rip_peer_bad_packet(rip, &from);
+               rip_peer_bad_packet(rip, ri, &from);
                return;
        }
 
@@ -1807,7 +1809,7 @@ static void rip_read(struct event *t)
        if (packet->version == 0) {
                zlog_info("version 0 with command %d received.",
                          packet->command);
-               rip_peer_bad_packet(rip, &from);
+               rip_peer_bad_packet(rip, ri, &from);
                return;
        }
 
@@ -1823,12 +1825,11 @@ static void rip_read(struct event *t)
                packet->version = RIPv2;
 
        /* Is RIP running or is this RIP neighbor ?*/
-       ri = ifp->info;
        if (!ri->running && !rip_neighbor_lookup(rip, &from)) {
                if (IS_RIP_DEBUG_EVENT)
                        zlog_debug("RIP is not enabled on interface %s.",
                                   ifp->name);
-               rip_peer_bad_packet(rip, &from);
+               rip_peer_bad_packet(rip, ri, &from);
                return;
        }
 
@@ -1842,7 +1843,7 @@ static void rip_read(struct event *t)
                        zlog_debug(
                                "  packet's v%d doesn't fit to if version spec",
                                packet->version);
-               rip_peer_bad_packet(rip, &from);
+               rip_peer_bad_packet(rip, ri, &from);
                return;
        }
 
@@ -1857,7 +1858,7 @@ static void rip_read(struct event *t)
                                "packet RIPv%d is dropped because authentication disabled",
                                packet->version);
                ripd_notif_send_auth_type_failure(ifp->name);
-               rip_peer_bad_packet(rip, &from);
+               rip_peer_bad_packet(rip, ri, &from);
                return;
        }
 
@@ -1893,7 +1894,7 @@ static void rip_read(struct event *t)
                                zlog_debug(
                                        "RIPv1 dropped because authentication enabled");
                        ripd_notif_send_auth_type_failure(ifp->name);
-                       rip_peer_bad_packet(rip, &from);
+                       rip_peer_bad_packet(rip, ri, &from);
                        return;
                }
        } else if (ri->auth_type != RIP_NO_AUTH) {
@@ -1906,7 +1907,7 @@ static void rip_read(struct event *t)
                                zlog_debug(
                                        "RIPv2 authentication failed: no auth RTE in packet");
                        ripd_notif_send_auth_type_failure(ifp->name);
-                       rip_peer_bad_packet(rip, &from);
+                       rip_peer_bad_packet(rip, ri, &from);
                        return;
                }
 
@@ -1916,7 +1917,7 @@ static void rip_read(struct event *t)
                                zlog_debug(
                                        "RIPv2 dropped because authentication enabled");
                        ripd_notif_send_auth_type_failure(ifp->name);
-                       rip_peer_bad_packet(rip, &from);
+                       rip_peer_bad_packet(rip, ri, &from);
                        return;
                }
 
@@ -1952,7 +1953,7 @@ static void rip_read(struct event *t)
                                zlog_debug("RIPv2 %s authentication failure",
                                           auth_desc);
                        ripd_notif_send_auth_failure(ifp->name);
-                       rip_peer_bad_packet(rip, &from);
+                       rip_peer_bad_packet(rip, ri, &from);
                        return;
                }
        }
@@ -1971,16 +1972,16 @@ static void rip_read(struct event *t)
                zlog_info(
                        "Obsolete command %s received, please sent it to routed",
                        lookup_msg(rip_msg, packet->command, NULL));
-               rip_peer_bad_packet(rip, &from);
+               rip_peer_bad_packet(rip, ri, &from);
                break;
        case RIP_POLL_ENTRY:
                zlog_info("Obsolete command %s received",
                          lookup_msg(rip_msg, packet->command, NULL));
-               rip_peer_bad_packet(rip, &from);
+               rip_peer_bad_packet(rip, ri, &from);
                break;
        default:
                zlog_info("Unknown RIP command %d received", packet->command);
-               rip_peer_bad_packet(rip, &from);
+               rip_peer_bad_packet(rip, ri, &from);
                break;
        }
 }
@@ -3339,6 +3340,7 @@ void rip_clean(struct rip *rip)
        route_table_finish(rip->distance_table);
 
        RB_REMOVE(rip_instance_head, &rip_instances, rip);
+       XFREE(MTYPE_TMP, rip->default_bfd_profile);
        XFREE(MTYPE_RIP_VRF_NAME, rip->vrf_name);
        XFREE(MTYPE_RIP, rip);
 }
index 176a3bfc376766655b4e73b4f3d3c6ca77ffb730..bba3c280697b9a080625371a8ff5c9ab52b83c60 100644 (file)
@@ -10,6 +10,7 @@
 #include "nexthop.h"
 #include "distribute.h"
 #include "memory.h"
+#include "bfd.h"
 
 /* RIP version number. */
 #define RIPv1                            1
@@ -182,6 +183,9 @@ struct rip {
                /* RIP queries. */
                long queries;
        } counters;
+
+       /* Default BFD profile to use with BFD sessions. */
+       char *default_bfd_profile;
 };
 RB_HEAD(rip_instance_head, rip);
 RB_PROTOTYPE(rip_instance_head, rip, entry, rip_instance_compare)
@@ -265,6 +269,9 @@ struct rip_interface {
        /* Parent routing instance. */
        struct rip *rip;
 
+       /* Interface data from zebra. */
+       struct interface *ifp;
+
        /* RIP is enabled on this interface. */
        int enable_network;
        int enable_interface;
@@ -318,6 +325,12 @@ struct rip_interface {
 
        /* Passive interface. */
        int passive;
+
+       /* BFD information. */
+       struct {
+               bool enabled;
+               char *profile;
+       } bfd;
 };
 
 /* RIP peer information. */
@@ -325,6 +338,9 @@ struct rip_peer {
        /* Parent routing instance. */
        struct rip *rip;
 
+       /* Back-pointer to RIP interface. */
+       struct rip_interface *ri;
+
        /* Peer address. */
        struct in_addr addr;
 
@@ -343,6 +359,9 @@ struct rip_peer {
 
        /* Timeout thread. */
        struct event *t_timeout;
+
+       /* BFD information */
+       struct bfd_session_params *bfd_session;
 };
 
 struct rip_distance {
@@ -461,16 +480,20 @@ extern void rip_if_rmap_update_interface(struct interface *ifp);
 extern int rip_show_network_config(struct vty *vty, struct rip *rip);
 extern void rip_show_redistribute_config(struct vty *vty, struct rip *rip);
 
-extern void rip_peer_update(struct rip *rip, struct sockaddr_in *from,
-                           uint8_t version);
-extern void rip_peer_bad_route(struct rip *rip, struct sockaddr_in *from);
-extern void rip_peer_bad_packet(struct rip *rip, struct sockaddr_in *from);
+extern void rip_peer_free(struct rip_peer *peer);
+extern void rip_peer_update(struct rip *rip, struct rip_interface *ri,
+                           struct sockaddr_in *from, uint8_t version);
+extern void rip_peer_bad_route(struct rip *rip, struct rip_interface *ri,
+                              struct sockaddr_in *from);
+extern void rip_peer_bad_packet(struct rip *rip, struct rip_interface *ri,
+                               struct sockaddr_in *from);
 extern void rip_peer_display(struct vty *vty, struct rip *rip);
 extern struct rip_peer *rip_peer_lookup(struct rip *rip, struct in_addr *addr);
 extern struct rip_peer *rip_peer_lookup_next(struct rip *rip,
                                             struct in_addr *addr);
 extern int rip_peer_list_cmp(struct rip_peer *p1, struct rip_peer *p2);
 extern void rip_peer_list_del(void *arg);
+void rip_peer_delete_routes(const struct rip_peer *peer);
 
 extern void rip_info_free(struct rip_info *);
 extern struct rip *rip_info_get_instance(const struct rip_info *rinfo);
index 98cc765c91cfb559d5dd6a22a663a104c653e492..294a05e575ae09b007011b388860202d6b3a632a 100644 (file)
@@ -13,6 +13,7 @@ man8 += $(MANBUILD)/frr-ripd.8
 endif
 
 ripd_ripd_SOURCES = \
+       ripd/rip_bfd.c \
        ripd/rip_cli.c \
        ripd/rip_debug.c \
        ripd/rip_errors.c \
@@ -31,10 +32,12 @@ ripd_ripd_SOURCES = \
        # end
 
 clippy_scan += \
+       ripd/rip_bfd.c \
        ripd/rip_cli.c \
        # end
 
 noinst_HEADERS += \
+       ripd/rip_bfd.h \
        ripd/rip_debug.h \
        ripd/rip_errors.h \
        ripd/rip_interface.h \
index d2088e589e77952c14dfaab66cac8b7c3bcc487b..a4bf50d958be3807c341eb3428f573d75e1e5109 100644 (file)
@@ -13,6 +13,9 @@ module frr-ripd {
   import frr-if-rmap {
     prefix frr-if-rmap;
   }
+  import frr-bfdd {
+    prefix frr-bfdd;
+  }
   import frr-interface {
     prefix frr-interface;
   }
@@ -376,6 +379,12 @@ module frr-ripd {
         }
       }
 
+      leaf default-bfd-profile {
+        description
+          "Use this BFD profile for all peers by default.";
+        type frr-bfdd:profile-ref;
+      }
+
       /*
        * Operational data.
        */
@@ -678,6 +687,24 @@ module frr-ripd {
             "Key-chain name.";
         }
       }
+
+      container bfd-monitoring {
+        presence
+          "Present if BFD is configured for RIP peers in this interface.";
+
+        leaf enable {
+          type boolean;
+          description
+            "Enable/disable BFD monitoring.";
+          default false;
+        }
+
+        leaf profile {
+          type frr-bfdd:profile-ref;
+          description
+            "BFD profile to use.";
+        }
+      }
     }
   }
 
index 1b2f7a02d41589008b1683a09ff752b54b32dbc7..4d09474b7f2287b25e191d43c45776510944fd84 100644 (file)
@@ -53,7 +53,7 @@ struct zebra_ptm_cb {
         (protocol) == ZEBRA_ROUTE_OSPF6 || (protocol) == ZEBRA_ROUTE_ISIS ||  \
         (protocol) == ZEBRA_ROUTE_PIM ||                                      \
         (protocol) == ZEBRA_ROUTE_OPENFABRIC ||                               \
-        (protocol) == ZEBRA_ROUTE_STATIC)
+        (protocol) == ZEBRA_ROUTE_STATIC || (protocol) == ZEBRA_ROUTE_RIP)
 
 void zebra_ptm_init(void);
 void zebra_ptm_finish(void);