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>
This commit is contained in:
Renato Westphal 2021-10-14 12:12:37 -03:00 committed by Rafael Zalamena
parent fec51f2e2b
commit c262df828b
15 changed files with 577 additions and 39 deletions

119
ripd/rip_bfd.c Normal file
View File

@ -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);
}

21
ripd/rip_bfd.h Normal file
View File

@ -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_ */

View 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 * 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)); 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 * 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, &no_rip_timers_cmd);
install_element(RIP_NODE, &rip_version_cmd); install_element(RIP_NODE, &rip_version_cmd);
install_element(RIP_NODE, &no_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_split_horizon_cmd);
install_element(INTERFACE_NODE, &ip_rip_v2_broadcast_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, &ip_rip_authentication_key_chain_cmd);
install_element(INTERFACE_NODE, install_element(INTERFACE_NODE,
&no_ip_rip_authentication_key_chain_cmd); &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); install_element(ENABLE_NODE, &clear_ip_rip_cmd);
} }

View File

@ -457,6 +457,7 @@ static void rip_interface_reset(struct rip_interface *ri)
ri->sent_updates = 0; ri->sent_updates = 0;
ri->passive = 0; ri->passive = 0;
XFREE(MTYPE_TMP, ri->bfd.profile);
rip_interface_clean(ri); rip_interface_clean(ri);
} }
@ -1109,6 +1110,7 @@ void rip_interface_sync(struct interface *ifp)
struct rip_interface *ri; struct rip_interface *ri;
ri = ifp->info; ri = ifp->info;
ri->ifp = ifp;
if (ri) if (ri)
ri->rip = ifp->vrf->info; ri->rip = ifp->vrf->info;
} }

View File

@ -21,8 +21,10 @@
#include "if_rmap.h" #include "if_rmap.h"
#include "libfrr.h" #include "libfrr.h"
#include "routemap.h" #include "routemap.h"
#include "bfd.h"
#include "ripd/ripd.h" #include "ripd/ripd.h"
#include "ripd/rip_bfd.h"
#include "ripd/rip_nb.h" #include "ripd/rip_nb.h"
#include "ripd/rip_errors.h" #include "ripd/rip_errors.h"
@ -65,6 +67,7 @@ static void sigint(void)
{ {
zlog_notice("Terminating on signal"); zlog_notice("Terminating on signal");
bfd_protocol_integration_set_shutdown(true);
rip_vrf_terminate(); rip_vrf_terminate();
if_rmap_terminate(); if_rmap_terminate();
rip_zclient_stop(); rip_zclient_stop();
@ -162,6 +165,7 @@ int main(int argc, char **argv)
rip_if_init(); rip_if_init();
rip_cli_init(); rip_cli_init();
rip_zclient_init(master); rip_zclient_init(master);
rip_bfd_init(master);
frr_config_fork(); frr_config_fork();
frr_run(master); frr_run(master);

View File

@ -239,6 +239,14 @@ const struct frr_yang_module_info frr_ripd_info = {
.modify = ripd_instance_version_send_modify, .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", .xpath = "/frr-interface:lib/interface/frr-ripd:rip/split-horizon",
.cbs = { .cbs = {
@ -302,6 +310,28 @@ const struct frr_yang_module_info frr_ripd_info = {
.modify = lib_interface_rip_authentication_key_chain_modify, .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", .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor",
.cbs = { .cbs = {

View 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_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_receive_modify(struct nb_cb_modify_args *args);
int ripd_instance_version_send_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( const void *ripd_instance_state_neighbors_neighbor_get_next(
struct nb_cb_get_next_args *args); struct nb_cb_get_next_args *args);
int ripd_instance_state_neighbors_neighbor_get_keys( 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); struct nb_cb_modify_args *args);
int lib_interface_rip_authentication_key_chain_destroy( int lib_interface_rip_authentication_key_chain_destroy(
struct nb_cb_destroy_args *args); 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. */ /* Optional 'apply_finish' callbacks. */
void ripd_instance_redistribute_apply_finish( void ripd_instance_redistribute_apply_finish(
@ -206,6 +214,9 @@ void cli_show_ip_rip_receive_version(struct vty *vty,
bool show_defaults); bool show_defaults);
void cli_show_ip_rip_send_version(struct vty *vty, const struct lyd_node *dnode, void cli_show_ip_rip_send_version(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults); 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, void cli_show_ip_rip_authentication_scheme(struct vty *vty,
const struct lyd_node *dnode, const struct lyd_node *dnode,
bool show_defaults); 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, void cli_show_ip_rip_authentication_key_chain(struct vty *vty,
const struct lyd_node *dnode, const struct lyd_node *dnode,
bool show_defaults); 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. */ /* Notifications. */
extern void ripd_notif_send_auth_type_failure(const char *ifname); extern void ripd_notif_send_auth_type_failure(const char *ifname);

View File

@ -23,6 +23,9 @@
#include "ripd/rip_nb.h" #include "ripd/rip_nb.h"
#include "ripd/rip_debug.h" #include "ripd/rip_debug.h"
#include "ripd/rip_interface.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 * XPath: /frr-ripd:ripd/instance
@ -905,6 +908,40 @@ int ripd_instance_version_send_modify(struct nb_cb_modify_args *args)
return NB_OK; 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 * XPath: /frr-interface:lib/interface/frr-ripd:rip/split-horizon
*/ */
@ -1070,6 +1107,104 @@ int lib_interface_rip_authentication_password_destroy(
return NB_OK; 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 * XPath: /frr-interface:lib/interface/frr-ripd:rip/authentication-key-chain
*/ */

View File

@ -11,8 +11,10 @@
#include "linklist.h" #include "linklist.h"
#include "frrevent.h" #include "frrevent.h"
#include "memory.h" #include "memory.h"
#include "table.h"
#include "ripd/ripd.h" #include "ripd/ripd.h"
#include "ripd/rip_bfd.h"
DEFINE_MTYPE_STATIC(RIPD, RIP_PEER, "RIP peer"); 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)); 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); EVENT_OFF(peer->t_timeout);
XFREE(MTYPE_RIP_PEER, peer); 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. */ /* 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; struct rip_peer *peer;
@ -73,7 +77,9 @@ static struct rip_peer *rip_peer_get(struct rip *rip, struct in_addr *addr)
} else { } else {
peer = rip_peer_new(); peer = rip_peer_new();
peer->rip = rip; peer->rip = rip;
peer->ri = ri;
peer->addr = *addr; peer->addr = *addr;
rip_bfd_session_update(peer);
listnode_add_sort(rip->peer_list, 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; 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; struct rip_peer *peer;
peer = rip_peer_get(rip, &from->sin_addr); peer = rip_peer_get(rip, ri, &from->sin_addr);
peer->version = version; 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; struct rip_peer *peer;
peer = rip_peer_get(rip, &from->sin_addr); peer = rip_peer_get(rip, ri, &from->sin_addr);
peer->recv_badroutes++; 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; struct rip_peer *peer;
peer = rip_peer_get(rip, &from->sin_addr); peer = rip_peer_get(rip, ri, &from->sin_addr);
peer->recv_badpackets++; peer->recv_badpackets++;
} }
@ -155,3 +164,46 @@ void rip_peer_list_del(void *arg)
{ {
rip_peer_free(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;
}
}
}

View File

@ -13,6 +13,7 @@
#include "zclient.h" #include "zclient.h"
#include "log.h" #include "log.h"
#include "vrf.h" #include "vrf.h"
#include "bfd.h"
#include "ripd/ripd.h" #include "ripd/ripd.h"
#include "ripd/rip_debug.h" #include "ripd/rip_debug.h"
#include "ripd/rip_interface.h" #include "ripd/rip_interface.h"
@ -196,6 +197,7 @@ void rip_zebra_vrf_register(struct vrf *vrf)
vrf->name, vrf->vrf_id); vrf->name, vrf->vrf_id);
zclient_send_reg_requests(zclient, 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) 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); vrf->name, vrf->vrf_id);
zclient_send_dereg_requests(zclient, 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) static void rip_zebra_connected(struct zclient *zclient)
{ {
zclient_send_reg_requests(zclient, VRF_DEFAULT); zclient_send_reg_requests(zclient, VRF_DEFAULT);
bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
} }
zclient_handler *const rip_handlers[] = { zclient_handler *const rip_handlers[] = {

View File

@ -1123,7 +1123,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
if (from->sin_port != htons(RIP_PORT_DEFAULT)) { if (from->sin_port != htons(RIP_PORT_DEFAULT)) {
zlog_info("response doesn't come from RIP port: %d", zlog_info("response doesn't come from RIP port: %d",
from->sin_port); from->sin_port);
rip_peer_bad_packet(rip, from); rip_peer_bad_packet(rip, ri, from);
return; return;
} }
@ -1137,7 +1137,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
zlog_info( zlog_info(
"This datagram doesn't come from a valid neighbor: %pI4", "This datagram doesn't come from a valid neighbor: %pI4",
&from->sin_addr); &from->sin_addr);
rip_peer_bad_packet(rip, from); rip_peer_bad_packet(rip, ri, from);
return; return;
} }
@ -1147,7 +1147,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
; /* Alredy done in rip_read () */ ; /* Alredy done in rip_read () */
/* Update RIP peer. */ /* Update RIP peer. */
rip_peer_update(rip, from, packet->version); rip_peer_update(rip, ri, from, packet->version);
/* Set RTE pointer. */ /* Set RTE pointer. */
rte = packet->rte; rte = packet->rte;
@ -1176,7 +1176,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
if (!rip_destination_check(rte->prefix)) { if (!rip_destination_check(rte->prefix)) {
zlog_info( zlog_info(
"Network is net 0 or net 127 or it is not unicast network"); "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; 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) */ /* - is the metric valid (i.e., between 1 and 16, inclusive) */
if (!(rte->metric >= 1 && rte->metric <= 16)) { if (!(rte->metric >= 1 && rte->metric <= 16)) {
zlog_info("Route's metric is not in the 1-16 range."); 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; continue;
} }
@ -1195,7 +1195,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
&& rte->nexthop.s_addr != INADDR_ANY) { && rte->nexthop.s_addr != INADDR_ANY) {
zlog_info("RIPv1 packet with nexthop value %pI4", zlog_info("RIPv1 packet with nexthop value %pI4",
&rte->nexthop); &rte->nexthop);
rip_peer_bad_route(rip, from); rip_peer_bad_route(rip, ri, from);
continue; continue;
} }
@ -1326,7 +1326,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
zlog_warn( zlog_warn(
"RIPv2 address %pI4 is not mask /%d applied one", "RIPv2 address %pI4 is not mask /%d applied one",
&rte->prefix, ip_masklen(rte->mask)); &rte->prefix, ip_masklen(rte->mask));
rip_peer_bad_route(rip, from); rip_peer_bad_route(rip, ri, from);
continue; continue;
} }
@ -1643,7 +1643,7 @@ static void rip_request_process(struct rip_packet *packet, int size,
return; return;
/* RIP peer update. */ /* RIP peer update. */
rip_peer_update(rip, from, packet->version); rip_peer_update(rip, ri, from, packet->version);
lim = ((caddr_t)packet) + size; lim = ((caddr_t)packet) + size;
rte = packet->rte; rte = packet->rte;
@ -1711,7 +1711,7 @@ static void rip_read(struct event *t)
socklen_t fromlen; socklen_t fromlen;
struct interface *ifp = NULL; struct interface *ifp = NULL;
struct connected *ifc; struct connected *ifc;
struct rip_interface *ri; struct rip_interface *ri = NULL;
struct prefix p; struct prefix p;
/* Fetch socket then register myself. */ /* Fetch socket then register myself. */
@ -1743,8 +1743,10 @@ static void rip_read(struct event *t)
/* Which interface is this packet comes from. */ /* Which interface is this packet comes from. */
ifc = if_lookup_address((void *)&from.sin_addr, AF_INET, ifc = if_lookup_address((void *)&from.sin_addr, AF_INET,
rip->vrf->vrf_id); rip->vrf->vrf_id);
if (ifc) if (ifc) {
ifp = ifc->ifp; ifp = ifc->ifp;
ri = ifp->info;
}
/* RIP packet received */ /* RIP packet received */
if (IS_RIP_DEBUG_EVENT) if (IS_RIP_DEBUG_EVENT)
@ -1753,7 +1755,7 @@ static void rip_read(struct event *t)
ifp ? ifp->name : "unknown", rip->vrf_name); ifp ? ifp->name : "unknown", rip->vrf_name);
/* If this packet come from unknown interface, ignore it. */ /* If this packet come from unknown interface, ignore it. */
if (ifp == NULL) { if (ifp == NULL || ri == NULL) {
zlog_info( zlog_info(
"%s: cannot find interface for packet from %pI4 port %d (VRF %s)", "%s: cannot find interface for packet from %pI4 port %d (VRF %s)",
__func__, &from.sin_addr, ntohs(from.sin_port), __func__, &from.sin_addr, ntohs(from.sin_port),
@ -1779,13 +1781,13 @@ static void rip_read(struct event *t)
if (len < RIP_PACKET_MINSIZ) { if (len < RIP_PACKET_MINSIZ) {
zlog_warn("packet size %d is smaller than minimum size %d", len, zlog_warn("packet size %d is smaller than minimum size %d", len,
RIP_PACKET_MINSIZ); RIP_PACKET_MINSIZ);
rip_peer_bad_packet(rip, &from); rip_peer_bad_packet(rip, ri, &from);
return; return;
} }
if (len > RIP_PACKET_MAXSIZ) { if (len > RIP_PACKET_MAXSIZ) {
zlog_warn("packet size %d is larger than max size %d", len, zlog_warn("packet size %d is larger than max size %d", len,
RIP_PACKET_MAXSIZ); RIP_PACKET_MAXSIZ);
rip_peer_bad_packet(rip, &from); rip_peer_bad_packet(rip, ri, &from);
return; return;
} }
@ -1793,7 +1795,7 @@ static void rip_read(struct event *t)
if ((len - RIP_PACKET_MINSIZ) % 20) { if ((len - RIP_PACKET_MINSIZ) % 20) {
zlog_warn("packet size %d is wrong for RIP packet alignment", zlog_warn("packet size %d is wrong for RIP packet alignment",
len); len);
rip_peer_bad_packet(rip, &from); rip_peer_bad_packet(rip, ri, &from);
return; return;
} }
@ -1807,7 +1809,7 @@ static void rip_read(struct event *t)
if (packet->version == 0) { if (packet->version == 0) {
zlog_info("version 0 with command %d received.", zlog_info("version 0 with command %d received.",
packet->command); packet->command);
rip_peer_bad_packet(rip, &from); rip_peer_bad_packet(rip, ri, &from);
return; return;
} }
@ -1823,12 +1825,11 @@ static void rip_read(struct event *t)
packet->version = RIPv2; packet->version = RIPv2;
/* Is RIP running or is this RIP neighbor ?*/ /* Is RIP running or is this RIP neighbor ?*/
ri = ifp->info;
if (!ri->running && !rip_neighbor_lookup(rip, &from)) { if (!ri->running && !rip_neighbor_lookup(rip, &from)) {
if (IS_RIP_DEBUG_EVENT) if (IS_RIP_DEBUG_EVENT)
zlog_debug("RIP is not enabled on interface %s.", zlog_debug("RIP is not enabled on interface %s.",
ifp->name); ifp->name);
rip_peer_bad_packet(rip, &from); rip_peer_bad_packet(rip, ri, &from);
return; return;
} }
@ -1842,7 +1843,7 @@ static void rip_read(struct event *t)
zlog_debug( zlog_debug(
" packet's v%d doesn't fit to if version spec", " packet's v%d doesn't fit to if version spec",
packet->version); packet->version);
rip_peer_bad_packet(rip, &from); rip_peer_bad_packet(rip, ri, &from);
return; return;
} }
@ -1857,7 +1858,7 @@ static void rip_read(struct event *t)
"packet RIPv%d is dropped because authentication disabled", "packet RIPv%d is dropped because authentication disabled",
packet->version); packet->version);
ripd_notif_send_auth_type_failure(ifp->name); ripd_notif_send_auth_type_failure(ifp->name);
rip_peer_bad_packet(rip, &from); rip_peer_bad_packet(rip, ri, &from);
return; return;
} }
@ -1893,7 +1894,7 @@ static void rip_read(struct event *t)
zlog_debug( zlog_debug(
"RIPv1 dropped because authentication enabled"); "RIPv1 dropped because authentication enabled");
ripd_notif_send_auth_type_failure(ifp->name); ripd_notif_send_auth_type_failure(ifp->name);
rip_peer_bad_packet(rip, &from); rip_peer_bad_packet(rip, ri, &from);
return; return;
} }
} else if (ri->auth_type != RIP_NO_AUTH) { } else if (ri->auth_type != RIP_NO_AUTH) {
@ -1906,7 +1907,7 @@ static void rip_read(struct event *t)
zlog_debug( zlog_debug(
"RIPv2 authentication failed: no auth RTE in packet"); "RIPv2 authentication failed: no auth RTE in packet");
ripd_notif_send_auth_type_failure(ifp->name); ripd_notif_send_auth_type_failure(ifp->name);
rip_peer_bad_packet(rip, &from); rip_peer_bad_packet(rip, ri, &from);
return; return;
} }
@ -1916,7 +1917,7 @@ static void rip_read(struct event *t)
zlog_debug( zlog_debug(
"RIPv2 dropped because authentication enabled"); "RIPv2 dropped because authentication enabled");
ripd_notif_send_auth_type_failure(ifp->name); ripd_notif_send_auth_type_failure(ifp->name);
rip_peer_bad_packet(rip, &from); rip_peer_bad_packet(rip, ri, &from);
return; return;
} }
@ -1952,7 +1953,7 @@ static void rip_read(struct event *t)
zlog_debug("RIPv2 %s authentication failure", zlog_debug("RIPv2 %s authentication failure",
auth_desc); auth_desc);
ripd_notif_send_auth_failure(ifp->name); ripd_notif_send_auth_failure(ifp->name);
rip_peer_bad_packet(rip, &from); rip_peer_bad_packet(rip, ri, &from);
return; return;
} }
} }
@ -1971,16 +1972,16 @@ static void rip_read(struct event *t)
zlog_info( zlog_info(
"Obsolete command %s received, please sent it to routed", "Obsolete command %s received, please sent it to routed",
lookup_msg(rip_msg, packet->command, NULL)); lookup_msg(rip_msg, packet->command, NULL));
rip_peer_bad_packet(rip, &from); rip_peer_bad_packet(rip, ri, &from);
break; break;
case RIP_POLL_ENTRY: case RIP_POLL_ENTRY:
zlog_info("Obsolete command %s received", zlog_info("Obsolete command %s received",
lookup_msg(rip_msg, packet->command, NULL)); lookup_msg(rip_msg, packet->command, NULL));
rip_peer_bad_packet(rip, &from); rip_peer_bad_packet(rip, ri, &from);
break; break;
default: default:
zlog_info("Unknown RIP command %d received", packet->command); zlog_info("Unknown RIP command %d received", packet->command);
rip_peer_bad_packet(rip, &from); rip_peer_bad_packet(rip, ri, &from);
break; break;
} }
} }
@ -3339,6 +3340,7 @@ void rip_clean(struct rip *rip)
route_table_finish(rip->distance_table); route_table_finish(rip->distance_table);
RB_REMOVE(rip_instance_head, &rip_instances, rip); 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_VRF_NAME, rip->vrf_name);
XFREE(MTYPE_RIP, rip); XFREE(MTYPE_RIP, rip);
} }

View File

@ -10,6 +10,7 @@
#include "nexthop.h" #include "nexthop.h"
#include "distribute.h" #include "distribute.h"
#include "memory.h" #include "memory.h"
#include "bfd.h"
/* RIP version number. */ /* RIP version number. */
#define RIPv1 1 #define RIPv1 1
@ -182,6 +183,9 @@ struct rip {
/* RIP queries. */ /* RIP queries. */
long queries; long queries;
} counters; } counters;
/* Default BFD profile to use with BFD sessions. */
char *default_bfd_profile;
}; };
RB_HEAD(rip_instance_head, rip); RB_HEAD(rip_instance_head, rip);
RB_PROTOTYPE(rip_instance_head, rip, entry, rip_instance_compare) RB_PROTOTYPE(rip_instance_head, rip, entry, rip_instance_compare)
@ -265,6 +269,9 @@ struct rip_interface {
/* Parent routing instance. */ /* Parent routing instance. */
struct rip *rip; struct rip *rip;
/* Interface data from zebra. */
struct interface *ifp;
/* RIP is enabled on this interface. */ /* RIP is enabled on this interface. */
int enable_network; int enable_network;
int enable_interface; int enable_interface;
@ -318,6 +325,12 @@ struct rip_interface {
/* Passive interface. */ /* Passive interface. */
int passive; int passive;
/* BFD information. */
struct {
bool enabled;
char *profile;
} bfd;
}; };
/* RIP peer information. */ /* RIP peer information. */
@ -325,6 +338,9 @@ struct rip_peer {
/* Parent routing instance. */ /* Parent routing instance. */
struct rip *rip; struct rip *rip;
/* Back-pointer to RIP interface. */
struct rip_interface *ri;
/* Peer address. */ /* Peer address. */
struct in_addr addr; struct in_addr addr;
@ -343,6 +359,9 @@ struct rip_peer {
/* Timeout thread. */ /* Timeout thread. */
struct event *t_timeout; struct event *t_timeout;
/* BFD information */
struct bfd_session_params *bfd_session;
}; };
struct rip_distance { 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 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_show_redistribute_config(struct vty *vty, struct rip *rip);
extern void rip_peer_update(struct rip *rip, struct sockaddr_in *from, extern void rip_peer_free(struct rip_peer *peer);
uint8_t version); extern void rip_peer_update(struct rip *rip, struct rip_interface *ri,
extern void rip_peer_bad_route(struct rip *rip, struct sockaddr_in *from); struct sockaddr_in *from, uint8_t version);
extern void rip_peer_bad_packet(struct rip *rip, struct sockaddr_in *from); 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 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(struct rip *rip, struct in_addr *addr);
extern struct rip_peer *rip_peer_lookup_next(struct rip *rip, extern struct rip_peer *rip_peer_lookup_next(struct rip *rip,
struct in_addr *addr); struct in_addr *addr);
extern int rip_peer_list_cmp(struct rip_peer *p1, struct rip_peer *p2); extern int rip_peer_list_cmp(struct rip_peer *p1, struct rip_peer *p2);
extern void rip_peer_list_del(void *arg); 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 void rip_info_free(struct rip_info *);
extern struct rip *rip_info_get_instance(const struct rip_info *rinfo); extern struct rip *rip_info_get_instance(const struct rip_info *rinfo);

View File

@ -13,6 +13,7 @@ man8 += $(MANBUILD)/frr-ripd.8
endif endif
ripd_ripd_SOURCES = \ ripd_ripd_SOURCES = \
ripd/rip_bfd.c \
ripd/rip_cli.c \ ripd/rip_cli.c \
ripd/rip_debug.c \ ripd/rip_debug.c \
ripd/rip_errors.c \ ripd/rip_errors.c \
@ -31,10 +32,12 @@ ripd_ripd_SOURCES = \
# end # end
clippy_scan += \ clippy_scan += \
ripd/rip_bfd.c \
ripd/rip_cli.c \ ripd/rip_cli.c \
# end # end
noinst_HEADERS += \ noinst_HEADERS += \
ripd/rip_bfd.h \
ripd/rip_debug.h \ ripd/rip_debug.h \
ripd/rip_errors.h \ ripd/rip_errors.h \
ripd/rip_interface.h \ ripd/rip_interface.h \

View File

@ -13,6 +13,9 @@ module frr-ripd {
import frr-if-rmap { import frr-if-rmap {
prefix frr-if-rmap; prefix frr-if-rmap;
} }
import frr-bfdd {
prefix frr-bfdd;
}
import frr-interface { import frr-interface {
prefix 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. * Operational data.
*/ */
@ -678,6 +687,24 @@ module frr-ripd {
"Key-chain name."; "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.";
}
}
} }
} }

View File

@ -53,7 +53,7 @@ struct zebra_ptm_cb {
(protocol) == ZEBRA_ROUTE_OSPF6 || (protocol) == ZEBRA_ROUTE_ISIS || \ (protocol) == ZEBRA_ROUTE_OSPF6 || (protocol) == ZEBRA_ROUTE_ISIS || \
(protocol) == ZEBRA_ROUTE_PIM || \ (protocol) == ZEBRA_ROUTE_PIM || \
(protocol) == ZEBRA_ROUTE_OPENFABRIC || \ (protocol) == ZEBRA_ROUTE_OPENFABRIC || \
(protocol) == ZEBRA_ROUTE_STATIC) (protocol) == ZEBRA_ROUTE_STATIC || (protocol) == ZEBRA_ROUTE_RIP)
void zebra_ptm_init(void); void zebra_ptm_init(void);
void zebra_ptm_finish(void); void zebra_ptm_finish(void);