mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-06-14 22:07:43 +00:00
isisd: add support for IPv6 BFD peers
Make isisd create BFD sessions over IPv6 when IS-IS is configured for IPv6 operation only. When IS-IS is enabled for both IPv4 and IPv6 on a given interface, prefer creating a BFD session over IPv6 to avoid having two BFD sessions protecting the same IS-IS adjacency. Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
This commit is contained in:
parent
f197ecb35f
commit
e782cca726
129
isisd/isis_bfd.c
129
isisd/isis_bfd.c
@ -19,7 +19,9 @@
|
||||
#include <zebra.h>
|
||||
|
||||
#include "zclient.h"
|
||||
#include "nexthop.h"
|
||||
#include "bfd.h"
|
||||
#include "lib_errors.h"
|
||||
|
||||
#include "isisd/isis_bfd.h"
|
||||
#include "isisd/isis_zebra.h"
|
||||
@ -33,17 +35,19 @@
|
||||
DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session")
|
||||
|
||||
struct bfd_session {
|
||||
struct in_addr dst_ip;
|
||||
struct in_addr src_ip;
|
||||
int family;
|
||||
union g_addr dst_ip;
|
||||
union g_addr src_ip;
|
||||
int status;
|
||||
};
|
||||
|
||||
static struct bfd_session *bfd_session_new(struct in_addr *dst_ip,
|
||||
struct in_addr *src_ip)
|
||||
static struct bfd_session *bfd_session_new(int family, union g_addr *dst_ip,
|
||||
union g_addr *src_ip)
|
||||
{
|
||||
struct bfd_session *rv;
|
||||
|
||||
rv = XCALLOC(MTYPE_BFD_SESSION, sizeof(*rv));
|
||||
rv->family = family;
|
||||
rv->dst_ip = *dst_ip;
|
||||
rv->src_ip = *src_ip;
|
||||
return rv;
|
||||
@ -58,15 +62,60 @@ static void bfd_session_free(struct bfd_session **session)
|
||||
*session = NULL;
|
||||
}
|
||||
|
||||
static bool bfd_session_same(const struct bfd_session *session, int family,
|
||||
const union g_addr *src, const union g_addr *dst)
|
||||
{
|
||||
if (session->family != family)
|
||||
return false;
|
||||
|
||||
switch (session->family) {
|
||||
case AF_INET:
|
||||
if (!IPV4_ADDR_SAME(&session->dst_ip.ipv4, &dst->ipv4))
|
||||
return false;
|
||||
if (!IPV4_ADDR_SAME(&session->src_ip.ipv4, &src->ipv4))
|
||||
return false;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!IPV6_ADDR_SAME(&session->dst_ip.ipv6, &dst->ipv6))
|
||||
return false;
|
||||
if (!IPV6_ADDR_SAME(&session->src_ip.ipv6, &src->ipv6))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address-family: %u",
|
||||
__func__, session->family);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst,
|
||||
int new_status)
|
||||
{
|
||||
if (!adj->bfd_session)
|
||||
return;
|
||||
|
||||
if (adj->bfd_session->dst_ip.s_addr != dst->u.prefix4.s_addr)
|
||||
if (adj->bfd_session->family != dst->family)
|
||||
return;
|
||||
|
||||
switch (adj->bfd_session->family) {
|
||||
case AF_INET:
|
||||
if (!IPV4_ADDR_SAME(&adj->bfd_session->dst_ip.ipv4,
|
||||
&dst->u.prefix4))
|
||||
return;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (!IPV6_ADDR_SAME(&adj->bfd_session->dst_ip.ipv6,
|
||||
&dst->u.prefix6))
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address-family: %u",
|
||||
__func__, adj->bfd_session->family);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int old_status = adj->bfd_session->status;
|
||||
|
||||
adj->bfd_session->status = new_status;
|
||||
@ -76,7 +125,7 @@ static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst,
|
||||
if (isis->debugs & DEBUG_BFD) {
|
||||
char dst_str[INET6_ADDRSTRLEN];
|
||||
|
||||
inet_ntop(AF_INET, &adj->bfd_session->dst_ip,
|
||||
inet_ntop(adj->bfd_session->family, &adj->bfd_session->dst_ip,
|
||||
dst_str, sizeof(dst_str));
|
||||
zlog_debug("ISIS-BFD: Peer %s on %s changed from %s to %s",
|
||||
dst_str, adj->circuit->interface->name,
|
||||
@ -100,14 +149,14 @@ static int isis_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
|
||||
|
||||
ifp = bfd_get_peer_info(zclient->ibuf, &dst_ip, NULL, &status,
|
||||
NULL, vrf_id);
|
||||
if (!ifp || dst_ip.family != AF_INET)
|
||||
if (!ifp || (dst_ip.family != AF_INET && dst_ip.family != AF_INET6))
|
||||
return 0;
|
||||
|
||||
if (isis->debugs & DEBUG_BFD) {
|
||||
char dst_buf[INET6_ADDRSTRLEN];
|
||||
|
||||
inet_ntop(AF_INET, &dst_ip.u.prefix4,
|
||||
dst_buf, sizeof(dst_buf));
|
||||
inet_ntop(dst_ip.family, &dst_ip.u.prefix, dst_buf,
|
||||
sizeof(dst_buf));
|
||||
|
||||
zlog_debug("ISIS-BFD: Received update for %s on %s: Changed state to %s",
|
||||
dst_buf, ifp->name, bfd_get_status_str(status));
|
||||
@ -171,7 +220,7 @@ static void isis_bfd_zebra_connected(struct zclient *zclient)
|
||||
bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
|
||||
}
|
||||
|
||||
static void bfd_debug(struct in_addr *dst, struct in_addr *src,
|
||||
static void bfd_debug(int family, union g_addr *dst, union g_addr *src,
|
||||
const char *interface, int command)
|
||||
{
|
||||
if (!(isis->debugs & DEBUG_BFD))
|
||||
@ -180,8 +229,8 @@ static void bfd_debug(struct in_addr *dst, struct in_addr *src,
|
||||
char dst_str[INET6_ADDRSTRLEN];
|
||||
char src_str[INET6_ADDRSTRLEN];
|
||||
|
||||
inet_ntop(AF_INET, dst, dst_str, sizeof(dst_str));
|
||||
inet_ntop(AF_INET, src, src_str, sizeof(src_str));
|
||||
inet_ntop(family, dst, dst_str, sizeof(dst_str));
|
||||
inet_ntop(family, src, src_str, sizeof(src_str));
|
||||
|
||||
const char *command_str;
|
||||
|
||||
@ -209,10 +258,11 @@ static void bfd_handle_adj_down(struct isis_adjacency *adj)
|
||||
if (!adj->bfd_session)
|
||||
return;
|
||||
|
||||
bfd_debug(&adj->bfd_session->dst_ip, &adj->bfd_session->src_ip,
|
||||
adj->circuit->interface->name, ZEBRA_BFD_DEST_DEREGISTER);
|
||||
bfd_debug(adj->bfd_session->family, &adj->bfd_session->dst_ip,
|
||||
&adj->bfd_session->src_ip, adj->circuit->interface->name,
|
||||
ZEBRA_BFD_DEST_DEREGISTER);
|
||||
|
||||
bfd_peer_sendmsg(zclient, NULL, AF_INET,
|
||||
bfd_peer_sendmsg(zclient, NULL, adj->bfd_session->family,
|
||||
&adj->bfd_session->dst_ip,
|
||||
&adj->bfd_session->src_ip,
|
||||
adj->circuit->interface->name,
|
||||
@ -228,33 +278,50 @@ static void bfd_handle_adj_down(struct isis_adjacency *adj)
|
||||
static void bfd_handle_adj_up(struct isis_adjacency *adj, int command)
|
||||
{
|
||||
struct isis_circuit *circuit = adj->circuit;
|
||||
int family;
|
||||
union g_addr dst_ip;
|
||||
union g_addr src_ip;
|
||||
struct list *local_ips;
|
||||
struct prefix *local_ip;
|
||||
|
||||
if (!circuit->bfd_info
|
||||
|| !circuit->ip_router
|
||||
|| !adj->ipv4_address_count)
|
||||
if (!circuit->bfd_info)
|
||||
goto out;
|
||||
|
||||
struct list *local_ips = fabricd_ip_addrs(adj->circuit);
|
||||
|
||||
if (!local_ips)
|
||||
/*
|
||||
* If IS-IS is enabled for both IPv4 and IPv6 on the circuit, prefer
|
||||
* creating a BFD session over IPv6.
|
||||
*/
|
||||
if (circuit->ipv6_router && adj->ipv6_address_count) {
|
||||
family = AF_INET6;
|
||||
dst_ip.ipv6 = adj->ipv6_addresses[0];
|
||||
local_ips = circuit->ipv6_link;
|
||||
if (!local_ips || list_isempty(local_ips))
|
||||
goto out;
|
||||
local_ip = listgetdata(listhead(local_ips));
|
||||
src_ip.ipv6 = local_ip->u.prefix6;
|
||||
} else if (circuit->ip_router && adj->ipv4_address_count) {
|
||||
family = AF_INET;
|
||||
dst_ip.ipv4 = adj->ipv4_addresses[0];
|
||||
local_ips = fabricd_ip_addrs(adj->circuit);
|
||||
if (!local_ips || list_isempty(local_ips))
|
||||
goto out;
|
||||
local_ip = listgetdata(listhead(local_ips));
|
||||
src_ip.ipv4 = local_ip->u.prefix4;
|
||||
} else
|
||||
goto out;
|
||||
|
||||
struct in_addr *dst_ip = &adj->ipv4_addresses[0];
|
||||
struct prefix_ipv4 *local_ip = listgetdata(listhead(local_ips));
|
||||
struct in_addr *src_ip = &local_ip->prefix;
|
||||
|
||||
if (adj->bfd_session) {
|
||||
if (adj->bfd_session->dst_ip.s_addr != dst_ip->s_addr
|
||||
|| adj->bfd_session->src_ip.s_addr != src_ip->s_addr)
|
||||
if (bfd_session_same(adj->bfd_session, family, &src_ip,
|
||||
&dst_ip))
|
||||
bfd_handle_adj_down(adj);
|
||||
}
|
||||
|
||||
if (!adj->bfd_session)
|
||||
adj->bfd_session = bfd_session_new(dst_ip, src_ip);
|
||||
adj->bfd_session = bfd_session_new(family, &dst_ip, &src_ip);
|
||||
|
||||
bfd_debug(&adj->bfd_session->dst_ip, &adj->bfd_session->src_ip,
|
||||
circuit->interface->name, command);
|
||||
bfd_peer_sendmsg(zclient, circuit->bfd_info, AF_INET,
|
||||
bfd_debug(adj->bfd_session->family, &adj->bfd_session->dst_ip,
|
||||
&adj->bfd_session->src_ip, circuit->interface->name, command);
|
||||
bfd_peer_sendmsg(zclient, circuit->bfd_info, adj->bfd_session->family,
|
||||
&adj->bfd_session->dst_ip,
|
||||
&adj->bfd_session->src_ip,
|
||||
circuit->interface->name,
|
||||
|
Loading…
Reference in New Issue
Block a user