]> git.proxmox.com Git - mirror_frr.git/commitdiff
isisd: add support for IPv6 BFD peers
authorRenato Westphal <renato@opensourcerouting.org>
Thu, 22 Aug 2019 14:29:37 +0000 (11:29 -0300)
committerRenato Westphal <renato@opensourcerouting.org>
Thu, 22 Aug 2019 15:52:44 +0000 (12:52 -0300)
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>
isisd/isis_bfd.c

index fa89c80049bb55524efdc2d111e0f00f0ae9e254..8fc7997d79f085cc46754355ebb7436a8d9bf3d3 100644 (file)
@@ -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"
 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,