forked from Mirror/frr
Merge pull request #13246 from opensourcerouting/rip-bfd
ripd: support BFD integration
This commit is contained in:
commit
257fddaeb6
|
@ -10,6 +10,7 @@ the following RFCs:
|
|||
|
||||
* :rfc:`5880`
|
||||
* :rfc:`5881`
|
||||
* :rfc:`5882`
|
||||
* :rfc:`5883`
|
||||
|
||||
Currently, there are two implementations of the BFD commands in FRR:
|
||||
|
@ -353,6 +354,33 @@ The following commands are available inside the interface configuration node.
|
|||
that interface.
|
||||
|
||||
|
||||
.. _bfd-rip-peer-config:
|
||||
|
||||
RIP BFD configuration
|
||||
---------------------
|
||||
|
||||
The following commands are available inside the interface configuration node:
|
||||
|
||||
.. clicmd:: ip rip bfd
|
||||
|
||||
Automatically create BFD session for each RIP peer discovered in this
|
||||
interface. When the BFD session monitor signalize that the link is down
|
||||
the RIP peer is removed and all the learned routes associated with that
|
||||
peer are removed.
|
||||
|
||||
|
||||
.. clicmd:: ip rip bfd profile BFD_PROFILE_NAME
|
||||
|
||||
Selects a BFD profile for the BFD sessions created in this interface.
|
||||
|
||||
|
||||
The following command is available in the RIP router configuration node:
|
||||
|
||||
.. clicmd:: bfd default-profile BFD_PROFILE_NAME
|
||||
|
||||
Selects a default BFD profile for all sessions without a profile specified.
|
||||
|
||||
|
||||
.. _bfd-static-peer-config:
|
||||
|
||||
BFD Static Route Monitoring Configuration
|
||||
|
|
|
@ -465,6 +465,8 @@ BFD
|
|||
:t:`Bidirectional Forwarding Detection (BFD), D. Katz, D. Ward. June 2010`
|
||||
- :rfc:`5881`
|
||||
:t:`Bidirectional Forwarding Detection (BFD) for IPv4 and IPv6 (Single Hop), D. Katz, D. Ward. June 2010`
|
||||
- :rfc:`5882`
|
||||
:t:`Generic Application of Bidirectional Forwarding Detection (BFD), D. Katz, D. Ward. June 2010`
|
||||
- :rfc:`5883`
|
||||
:t:`Bidirectional Forwarding Detection (BFD) for Multihop Paths, D. Katz, D. Ward. June 2010`
|
||||
|
||||
|
|
119
ripd/rip_bfd.c
Normal file
119
ripd/rip_bfd.c
Normal 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
21
ripd/rip_bfd.h
Normal 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_ */
|
101
ripd/rip_cli.c
101
ripd/rip_cli.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
54
ripd/ripd.c
54
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);
|
||||
}
|
||||
|
|
31
ripd/ripd.h
31
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);
|
||||
|
|
|
@ -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 \
|
||||
|
|
0
tests/topotests/rip_bfd_topo1/__init__.py
Executable file
0
tests/topotests/rip_bfd_topo1/__init__.py
Executable file
6
tests/topotests/rip_bfd_topo1/r1/bfdd.conf
Normal file
6
tests/topotests/rip_bfd_topo1/r1/bfdd.conf
Normal file
|
@ -0,0 +1,6 @@
|
|||
bfd
|
||||
profile slow
|
||||
receive-interval 1000
|
||||
transmit-interval 1000
|
||||
exit
|
||||
exit
|
17
tests/topotests/rip_bfd_topo1/r1/ripd.conf
Normal file
17
tests/topotests/rip_bfd_topo1/r1/ripd.conf
Normal file
|
@ -0,0 +1,17 @@
|
|||
interface r1-eth0
|
||||
ip rip bfd
|
||||
ip rip bfd profile slow
|
||||
exit
|
||||
!
|
||||
interface r1-eth1
|
||||
ip rip bfd
|
||||
ip rip bfd profile slow
|
||||
exit
|
||||
!
|
||||
router rip
|
||||
allow-ecmp
|
||||
network 192.168.0.1/24
|
||||
network 192.168.1.1/24
|
||||
redistribute connected
|
||||
timers basic 10 40 30
|
||||
exit
|
11
tests/topotests/rip_bfd_topo1/r1/zebra.conf
Normal file
11
tests/topotests/rip_bfd_topo1/r1/zebra.conf
Normal file
|
@ -0,0 +1,11 @@
|
|||
interface r1-eth0
|
||||
ip address 192.168.0.1/24
|
||||
exit
|
||||
!
|
||||
interface r1-eth1
|
||||
ip address 192.168.1.1/24
|
||||
exit
|
||||
!
|
||||
interface lo
|
||||
ip address 10.254.254.1/32
|
||||
exit
|
6
tests/topotests/rip_bfd_topo1/r2/bfdd.conf
Normal file
6
tests/topotests/rip_bfd_topo1/r2/bfdd.conf
Normal file
|
@ -0,0 +1,6 @@
|
|||
bfd
|
||||
profile slow
|
||||
receive-interval 1000
|
||||
transmit-interval 1000
|
||||
exit
|
||||
exit
|
11
tests/topotests/rip_bfd_topo1/r2/ripd.conf
Normal file
11
tests/topotests/rip_bfd_topo1/r2/ripd.conf
Normal file
|
@ -0,0 +1,11 @@
|
|||
interface r2-eth0
|
||||
ip rip bfd
|
||||
exit
|
||||
!
|
||||
router rip
|
||||
bfd default-profile slow
|
||||
network 192.168.0.2/24
|
||||
redistribute connected
|
||||
redistribute static
|
||||
timers basic 10 40 30
|
||||
exit
|
1
tests/topotests/rip_bfd_topo1/r2/staticd.conf
Normal file
1
tests/topotests/rip_bfd_topo1/r2/staticd.conf
Normal file
|
@ -0,0 +1 @@
|
|||
ip route 10.254.254.100/32 lo
|
8
tests/topotests/rip_bfd_topo1/r2/zebra.conf
Normal file
8
tests/topotests/rip_bfd_topo1/r2/zebra.conf
Normal file
|
@ -0,0 +1,8 @@
|
|||
interface r2-eth0
|
||||
ip address 192.168.0.2/24
|
||||
exit
|
||||
!
|
||||
interface lo
|
||||
ip address 10.254.254.2/32
|
||||
exit
|
||||
|
6
tests/topotests/rip_bfd_topo1/r3/bfdd.conf
Normal file
6
tests/topotests/rip_bfd_topo1/r3/bfdd.conf
Normal file
|
@ -0,0 +1,6 @@
|
|||
bfd
|
||||
profile slow
|
||||
receive-interval 1000
|
||||
transmit-interval 1000
|
||||
exit
|
||||
exit
|
11
tests/topotests/rip_bfd_topo1/r3/ripd.conf
Normal file
11
tests/topotests/rip_bfd_topo1/r3/ripd.conf
Normal file
|
@ -0,0 +1,11 @@
|
|||
interface r3-eth0
|
||||
ip rip bfd
|
||||
ip rip bfd profile slow
|
||||
exit
|
||||
!
|
||||
router rip
|
||||
network 192.168.1.2/24
|
||||
redistribute connected
|
||||
redistribute static
|
||||
timers basic 10 40 30
|
||||
exit
|
1
tests/topotests/rip_bfd_topo1/r3/staticd.conf
Normal file
1
tests/topotests/rip_bfd_topo1/r3/staticd.conf
Normal file
|
@ -0,0 +1 @@
|
|||
ip route 10.254.254.100/32 lo
|
7
tests/topotests/rip_bfd_topo1/r3/zebra.conf
Normal file
7
tests/topotests/rip_bfd_topo1/r3/zebra.conf
Normal file
|
@ -0,0 +1,7 @@
|
|||
interface r3-eth0
|
||||
ip address 192.168.1.2/24
|
||||
exit
|
||||
!
|
||||
interface lo
|
||||
ip address 10.254.254.3/32
|
||||
exit
|
58
tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.dot
Normal file
58
tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.dot
Normal file
|
@ -0,0 +1,58 @@
|
|||
## Color coding:
|
||||
#########################
|
||||
## Main FRR: #f08080 red
|
||||
## Switches: #d0e0d0 gray
|
||||
## RIP: #19e3d9 Cyan
|
||||
## RIPng: #fcb314 dark yellow
|
||||
## OSPFv2: #32b835 Green
|
||||
## OSPFv3: #19e3d9 Cyan
|
||||
## ISIS IPv4 #fcb314 dark yellow
|
||||
## ISIS IPv6 #9a81ec purple
|
||||
## BGP IPv4 #eee3d3 beige
|
||||
## BGP IPv6 #fdff00 yellow
|
||||
##### Colors (see http://www.color-hex.com/)
|
||||
|
||||
graph template {
|
||||
label="rip_bfd_topo1";
|
||||
|
||||
# Routers
|
||||
r1 [
|
||||
shape=doubleoctagon,
|
||||
label="r1",
|
||||
fillcolor="#f08080",
|
||||
style=filled,
|
||||
];
|
||||
r2 [
|
||||
shape=doubleoctagon
|
||||
label="r2",
|
||||
fillcolor="#f08080",
|
||||
style=filled,
|
||||
];
|
||||
r3 [
|
||||
shape=doubleoctagon
|
||||
label="r3",
|
||||
fillcolor="#f08080",
|
||||
style=filled,
|
||||
];
|
||||
|
||||
# Switches
|
||||
s1 [
|
||||
shape=oval,
|
||||
label="s1\n192.168.0.0/24",
|
||||
fillcolor="#d0e0d0",
|
||||
style=filled,
|
||||
];
|
||||
s2 [
|
||||
shape=oval,
|
||||
label="s1\n192.168.1.0/24",
|
||||
fillcolor="#d0e0d0",
|
||||
style=filled,
|
||||
];
|
||||
|
||||
# Connections
|
||||
r1 -- s1 [label="r1-eth0\n.1"];
|
||||
r2 -- s1 [label="r2-eth0\n.2"];
|
||||
|
||||
r1 -- s2 [label="r1-eth1\n.1"];
|
||||
r3 -- s2 [label="r1-eth0\n.2"];
|
||||
}
|
BIN
tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.png
Normal file
BIN
tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
252
tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py
Normal file
252
tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py
Normal file
|
@ -0,0 +1,252 @@
|
|||
#!/usr/bin/env python
|
||||
# SPDX-License-Identifier: ISC
|
||||
|
||||
#
|
||||
# test_rip_bfd_topo1.py
|
||||
# Part of NetDEF Topology Tests
|
||||
#
|
||||
# Copyright (c) 2023 by
|
||||
# Network Device Education Foundation, Inc. ("NetDEF")
|
||||
#
|
||||
|
||||
"""
|
||||
test_rip_bfd_topo1.py: Test RIP BFD integration.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import re
|
||||
import pytest
|
||||
|
||||
from functools import partial
|
||||
from lib import topotest
|
||||
from lib.topogen import Topogen, TopoRouter
|
||||
from lib.topolog import logger
|
||||
|
||||
pytestmark = [
|
||||
pytest.mark.bfdd,
|
||||
pytest.mark.ripd,
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def tgen(request):
|
||||
"Setup/Teardown the environment and provide tgen argument to tests"
|
||||
|
||||
topodef = {
|
||||
"s1": ("r1", "r2"),
|
||||
"s2": ("r1", "r3")
|
||||
}
|
||||
tgen = Topogen(topodef, request.module.__name__)
|
||||
tgen.start_topology()
|
||||
|
||||
router_list = tgen.routers()
|
||||
|
||||
for router_name, router in router_list.items():
|
||||
router.load_config(TopoRouter.RD_BFD, "bfdd.conf")
|
||||
router.load_config(TopoRouter.RD_RIP, "ripd.conf")
|
||||
router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf")
|
||||
if router_name in ["r2", "r3"]:
|
||||
router.load_config(TopoRouter.RD_STATIC, "staticd.conf")
|
||||
|
||||
tgen.start_router()
|
||||
yield tgen
|
||||
tgen.stop_topology()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def skip_on_failure(tgen):
|
||||
"Test if routers is still running otherwise skip tests"
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip("skipped because of previous test failure")
|
||||
|
||||
|
||||
def show_rip_json(router):
|
||||
"Get router 'show ip rip' JSON output"
|
||||
output = router.vtysh_cmd("show ip rip")
|
||||
routes = output.splitlines()[6:]
|
||||
json = {}
|
||||
|
||||
for route in routes:
|
||||
match = re.match(
|
||||
r"(.)\((.)\)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)", route)
|
||||
if match is None:
|
||||
continue
|
||||
|
||||
route_entry = {
|
||||
"code": match[1],
|
||||
"subCode": match[2],
|
||||
"nextHop": match[4],
|
||||
"metric": int(match[5]),
|
||||
"from": match[6],
|
||||
}
|
||||
|
||||
if json.get(match[3]) is None:
|
||||
json[match[3]] = []
|
||||
|
||||
json[match[3]].append(route_entry)
|
||||
|
||||
return json
|
||||
|
||||
|
||||
def expect_routes(router, routes, time_amount):
|
||||
"Expect 'routes' in 'router'."
|
||||
|
||||
def test_function():
|
||||
"Internal test function."
|
||||
return topotest.json_cmp(show_rip_json(router), routes)
|
||||
|
||||
_, result = topotest.run_and_expect(test_function,
|
||||
None,
|
||||
count=time_amount,
|
||||
wait=1)
|
||||
assert result is None, "Unexpected routing table in {}".format(
|
||||
router.name)
|
||||
|
||||
|
||||
def expect_bfd_peers(router, peers):
|
||||
"Expect 'peers' in 'router' BFD status."
|
||||
test_func = partial(
|
||||
topotest.router_json_cmp,
|
||||
router,
|
||||
"show bfd peers json",
|
||||
peers,
|
||||
)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
|
||||
assert result is None, "{} BFD peer status mismatch".format(router)
|
||||
|
||||
|
||||
def test_rip_convergence(tgen):
|
||||
"Test that RIP learns the neighbor routes."
|
||||
|
||||
expect_routes(
|
||||
tgen.gears["r1"], {
|
||||
"10.254.254.2/32": [{
|
||||
"code": "R",
|
||||
"subCode": "n",
|
||||
"from": "192.168.0.2"
|
||||
}],
|
||||
"10.254.254.3/32": [{
|
||||
"code": "R",
|
||||
"subCode": "n",
|
||||
"from": "192.168.1.2"
|
||||
}],
|
||||
"10.254.254.100/32": [{
|
||||
"code": "R",
|
||||
"subCode": "n",
|
||||
"from": "192.168.0.2",
|
||||
}, {
|
||||
"code": "R",
|
||||
"subCode": "n",
|
||||
"from": "192.168.1.2",
|
||||
}]
|
||||
}, 40)
|
||||
|
||||
expect_bfd_peers(tgen.gears["r1"], [{
|
||||
"peer": "192.168.0.2",
|
||||
"status": "up",
|
||||
"receive-interval": 1000,
|
||||
"transmit-interval": 1000,
|
||||
}, {
|
||||
"peer": "192.168.1.2",
|
||||
"status": "up",
|
||||
"receive-interval": 1000,
|
||||
"transmit-interval": 1000,
|
||||
}])
|
||||
|
||||
expect_routes(
|
||||
tgen.gears["r2"], {
|
||||
"10.254.254.1/32": [{
|
||||
"code": "R",
|
||||
"subCode": "n",
|
||||
"from": "192.168.0.1"
|
||||
}],
|
||||
"10.254.254.3/32": [{
|
||||
"code": "R",
|
||||
"subCode": "n",
|
||||
"from": "192.168.0.1"
|
||||
}],
|
||||
"10.254.254.100/32": [{
|
||||
"code": "S",
|
||||
"subCode": "r",
|
||||
"from": "self"
|
||||
}]
|
||||
}, 40)
|
||||
|
||||
expect_bfd_peers(tgen.gears["r2"], [{
|
||||
"peer": "192.168.0.1",
|
||||
"status": "up",
|
||||
"receive-interval": 1000,
|
||||
"transmit-interval": 1000,
|
||||
}])
|
||||
|
||||
expect_routes(
|
||||
tgen.gears["r3"], {
|
||||
"10.254.254.1/32": [{
|
||||
"code": "R",
|
||||
"subCode": "n",
|
||||
"from": "192.168.1.1"
|
||||
}],
|
||||
"10.254.254.2/32": [{
|
||||
"code": "R",
|
||||
"subCode": "n",
|
||||
"from": "192.168.1.1"
|
||||
}],
|
||||
"10.254.254.100/32": [{
|
||||
"code": "S",
|
||||
"subCode": "r",
|
||||
"from": "self"
|
||||
}]
|
||||
}, 40)
|
||||
|
||||
expect_bfd_peers(tgen.gears["r3"], [{
|
||||
"peer": "192.168.1.1",
|
||||
"status": "up",
|
||||
"receive-interval": 1000,
|
||||
"transmit-interval": 1000,
|
||||
}])
|
||||
|
||||
|
||||
def test_rip_bfd_convergence(tgen):
|
||||
"Test that RIP drop the gone neighbor routes."
|
||||
|
||||
tgen.gears["r3"].link_enable("r3-eth0", False)
|
||||
|
||||
expect_routes(
|
||||
tgen.gears["r1"], {
|
||||
"10.254.254.2/32": [{
|
||||
"code": "R",
|
||||
"subCode": "n",
|
||||
"from": "192.168.0.2"
|
||||
}],
|
||||
"10.254.254.3/32": None,
|
||||
"10.254.254.100/32": [{
|
||||
"code": "R",
|
||||
"subCode": "n",
|
||||
"from": "192.168.0.2",
|
||||
}]
|
||||
}, 6)
|
||||
|
||||
expect_routes(
|
||||
tgen.gears["r3"], {
|
||||
"10.254.254.1/32": None,
|
||||
"10.254.254.2/32": None,
|
||||
"10.254.254.100/32": [{
|
||||
"code": "S",
|
||||
"subCode": "r",
|
||||
"from": "self"
|
||||
}]
|
||||
}, 6)
|
||||
|
||||
|
||||
def test_memory_leak(tgen):
|
||||
"Run the memory leak test and report results."
|
||||
|
||||
if not tgen.is_memleak_enabled():
|
||||
pytest.skip("Memory leak test/report is disabled")
|
||||
|
||||
tgen.report_memory_leaks()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
|
@ -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.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue