diff options
author | Renato Westphal <renato@opensourcerouting.org> | 2021-10-14 17:12:37 +0200 |
---|---|---|
committer | Rafael Zalamena <rzalamena@opensourcerouting.org> | 2023-04-19 14:15:01 +0200 |
commit | c262df828b2475632f590c256db677b424d868c7 (patch) | |
tree | 85a8ab1e5ff016e9cdc28e18f91d263a207c8d32 /ripd | |
parent | Merge pull request #13323 from LabNConsulting/style-update (diff) | |
download | frr-c262df828b2475632f590c256db677b424d868c7.tar.xz frr-c262df828b2475632f590c256db677b424d868c7.zip |
ripd: support BFD integration
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>
Diffstat (limited to 'ripd')
-rw-r--r-- | ripd/rip_bfd.c | 119 | ||||
-rw-r--r-- | ripd/rip_bfd.h | 21 | ||||
-rw-r--r-- | ripd/rip_cli.c | 101 | ||||
-rw-r--r-- | ripd/rip_interface.c | 2 | ||||
-rw-r--r-- | ripd/rip_main.c | 4 | ||||
-rw-r--r-- | ripd/rip_nb.c | 30 | ||||
-rw-r--r-- | ripd/rip_nb.h | 15 | ||||
-rw-r--r-- | ripd/rip_nb_config.c | 135 | ||||
-rw-r--r-- | ripd/rip_peer.c | 68 | ||||
-rw-r--r-- | ripd/rip_zebra.c | 4 | ||||
-rw-r--r-- | ripd/ripd.c | 54 | ||||
-rw-r--r-- | ripd/ripd.h | 31 | ||||
-rw-r--r-- | ripd/subdir.am | 3 |
13 files changed, 549 insertions, 38 deletions
diff --git a/ripd/rip_bfd.c b/ripd/rip_bfd.c new file mode 100644 index 000000000..ac5035f54 --- /dev/null +++ b/ripd/rip_bfd.c @@ -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 index 000000000..d49ca1515 --- /dev/null +++ b/ripd/rip_bfd.h @@ -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_ */ diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c index cac29c00d..ac9fc4b1a 100644 --- a/ripd/rip_cli.c +++ b/ripd/rip_cli.c @@ -582,6 +582,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 */ DEFPY_YANG (ip_rip_split_horizon, @@ -980,6 +1016,66 @@ void cli_show_ip_rip_authentication_key_chain(struct vty *vty, } /* + * 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 */ DEFPY_YANG (clear_ip_rip, @@ -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); } diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 0b92f174b..b383be042 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -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; } diff --git a/ripd/rip_main.c b/ripd/rip_main.c index a6e4ad776..0e26662cd 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -21,8 +21,10 @@ #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); diff --git a/ripd/rip_nb.c b/ripd/rip_nb.c index fa6652faf..d11f1e1d3 100644 --- a/ripd/rip_nb.c +++ b/ripd/rip_nb.c @@ -240,6 +240,14 @@ const struct frr_yang_module_info frr_ripd_info = { }, }, { + .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 = { .cli_show = cli_show_ip_rip_split_horizon, @@ -303,6 +311,28 @@ const struct frr_yang_module_info frr_ripd_info = { }, }, { + .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 = { .get_keys = ripd_instance_state_neighbors_neighbor_get_keys, diff --git a/ripd/rip_nb.h b/ripd/rip_nb.h index ebc60fefb..9929e0952 100644 --- a/ripd/rip_nb.h +++ b/ripd/rip_nb.h @@ -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); diff --git a/ripd/rip_nb_config.c b/ripd/rip_nb_config.c index 343bb9bb5..cbc62f9f1 100644 --- a/ripd/rip_nb_config.c +++ b/ripd/rip_nb_config.c @@ -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 @@ -906,6 +909,40 @@ int ripd_instance_version_send_modify(struct nb_cb_modify_args *args) } /* + * 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 */ int lib_interface_rip_split_horizon_modify(struct nb_cb_modify_args *args) @@ -1071,6 +1108,104 @@ int lib_interface_rip_authentication_password_destroy( } /* + * 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 */ int lib_interface_rip_authentication_key_chain_modify( diff --git a/ripd/rip_peer.c b/ripd/rip_peer.c index 9410ef380..449abe47b 100644 --- a/ripd/rip_peer.c +++ b/ripd/rip_peer.c @@ -11,8 +11,10 @@ #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; + } + } +} diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 35c4b1f1b..698dcb982 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -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[] = { diff --git a/ripd/ripd.c b/ripd/ripd.c index fb3d574aa..48f266a94 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -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); } diff --git a/ripd/ripd.h b/ripd/ripd.h index 176a3bfc3..bba3c2806 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -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); diff --git a/ripd/subdir.am b/ripd/subdir.am index 98cc765c9..294a05e57 100644 --- a/ripd/subdir.am +++ b/ripd/subdir.am @@ -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 \ |