]> git.proxmox.com Git - mirror_frr.git/blobdiff - pimd/pim_ssmpingd.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / pimd / pim_ssmpingd.c
index e43b46604c857c5df185edbfb097b35133f62cc5..2fc30b4915355adbe56c6057eb14613d053777f9 100644 (file)
@@ -1,20 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * PIM for Quagga
  * Copyright (C) 2008  Everton da Silva Marques
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <zebra.h>
 #include "lib_errors.h"
 
 #include "pimd.h"
+#include "pim_instance.h"
 #include "pim_ssmpingd.h"
 #include "pim_time.h"
 #include "pim_sock.h"
+#include "network.h"
 
+#if PIM_IPV == 4
 static const char *const PIM_SSMPINGD_REPLY_GROUP = "232.43.211.234";
+#else
+static const char *const PIM_SSMPINGD_REPLY_GROUP = "ff3e::4321:1234";
+#endif
 
 enum { PIM_SSMPINGD_REQUEST = 'Q', PIM_SSMPINGD_REPLY = 'A' };
 
@@ -43,7 +36,7 @@ void pim_ssmpingd_init(struct pim_instance *pim)
 
        assert(!pim->ssmpingd_list);
 
-       result = inet_pton(AF_INET, PIM_SSMPINGD_REPLY_GROUP,
+       result = inet_pton(PIM_AF, PIM_SSMPINGD_REPLY_GROUP,
                           &pim->ssmpingd_group_addr);
 
        assert(result > 0);
@@ -56,7 +49,7 @@ void pim_ssmpingd_destroy(struct pim_instance *pim)
 }
 
 static struct ssmpingd_sock *ssmpingd_find(struct pim_instance *pim,
-                                          struct in_addr source_addr)
+                                          pim_addr source_addr)
 {
        struct listnode *node;
        struct ssmpingd_sock *ss;
@@ -65,7 +58,7 @@ static struct ssmpingd_sock *ssmpingd_find(struct pim_instance *pim,
                return 0;
 
        for (ALL_LIST_ELEMENTS_RO(pim->ssmpingd_list, node, ss))
-               if (source_addr.s_addr == ss->source_addr.s_addr)
+               if (!pim_addr_cmp(source_addr, ss->source_addr))
                        return ss;
 
        return 0;
@@ -76,73 +69,50 @@ static void ssmpingd_free(struct ssmpingd_sock *ss)
        XFREE(MTYPE_PIM_SSMPINGD, ss);
 }
 
-static int ssmpingd_socket(struct in_addr addr, int port, int mttl)
+#if PIM_IPV == 4
+static inline int ssmpingd_setsockopt(int fd, pim_addr addr, int mttl)
 {
-       struct sockaddr_in sockaddr;
-       int fd;
-
-       fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-       if (fd < 0) {
-               flog_err_sys(EC_LIB_SOCKET,
-                            "%s: could not create socket: errno=%d: %s",
-                            __func__, errno, safe_strerror(errno));
-               return -1;
+       /* Needed to obtain destination address from recvmsg() */
+#if defined(HAVE_IP_PKTINFO)
+       /* Linux and Solaris IP_PKTINFO */
+       int opt = 1;
+       if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt))) {
+               zlog_warn(
+                       "%s: could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
+                       __func__, fd, errno, safe_strerror(errno));
        }
+#elif defined(HAVE_IP_RECVDSTADDR)
+       /* BSD IP_RECVDSTADDR */
+       int opt = 1;
+       if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt))) {
+               zlog_warn(
+                       "%s: could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s",
+                       __func__, fd, errno, safe_strerror(errno));
+       }
+#else
+       flog_err(
+               EC_LIB_DEVELOPMENT,
+               "%s %s: missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()",
+               __FILE__, __func__);
+       close(fd);
+       return -1;
+#endif
 
-       sockaddr.sin_family = AF_INET;
-       sockaddr.sin_addr = addr;
-       sockaddr.sin_port = htons(port);
-
-       if (bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
-               char addr_str[INET_ADDRSTRLEN];
-               pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
+       if (setsockopt_ipv4_multicast_loop(fd, 0)) {
                zlog_warn(
-                       "%s: bind(fd=%d,addr=%s,port=%d,len=%zu) failure: errno=%d: %s",
-                       __func__, fd, addr_str, port, sizeof(sockaddr), errno,
-                       safe_strerror(errno));
+                       "%s: could not disable Multicast Loopback Option on socket fd=%d: errno=%d: %s",
+                       __func__, fd, errno, safe_strerror(errno));
                close(fd);
-               return -1;
+               return PIM_SOCK_ERR_LOOP;
        }
 
-       /* Needed to obtain destination address from recvmsg() */
-       {
-#if defined(HAVE_IP_PKTINFO)
-               /* Linux and Solaris IP_PKTINFO */
-               int opt = 1;
-               if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt))) {
-                       zlog_warn(
-                               "%s: could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
-                               __func__, fd, errno, safe_strerror(errno));
-               }
-#elif defined(HAVE_IP_RECVDSTADDR)
-               /* BSD IP_RECVDSTADDR */
-               int opt = 1;
-               if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt,
-                              sizeof(opt))) {
-                       zlog_warn(
-                               "%s: could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s",
-                               __func__, fd, errno, safe_strerror(errno));
-               }
-#else
-               flog_err(
-                       EC_LIB_DEVELOPMENT,
-                       "%s %s: missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()",
-                       __FILE__, __func__);
+       if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (void *)&addr,
+                      sizeof(addr))) {
+               zlog_warn(
+                       "%s: could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s",
+                       __func__, fd, errno, safe_strerror(errno));
                close(fd);
                return -1;
-#endif
-       }
-
-       {
-               int reuse = 1;
-               if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse,
-                              sizeof(reuse))) {
-                       zlog_warn(
-                               "%s: could not set Reuse Address Option on socket fd=%d: errno=%d: %s",
-                               __func__, fd, errno, safe_strerror(errno));
-                       close(fd);
-                       return -1;
-               }
        }
 
        if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&mttl,
@@ -154,7 +124,15 @@ static int ssmpingd_socket(struct in_addr addr, int port, int mttl)
                return -1;
        }
 
-       if (setsockopt_ipv4_multicast_loop(fd, 0)) {
+       return 0;
+}
+#else
+static inline int ssmpingd_setsockopt(int fd, pim_addr addr, int mttl)
+{
+       setsockopt_ipv6_pktinfo(fd, 1);
+       setsockopt_ipv6_multicast_hops(fd, mttl);
+
+       if (setsockopt_ipv6_multicast_loop(fd, 0)) {
                zlog_warn(
                        "%s: could not disable Multicast Loopback Option on socket fd=%d: errno=%d: %s",
                        __func__, fd, errno, safe_strerror(errno));
@@ -162,7 +140,7 @@ static int ssmpingd_socket(struct in_addr addr, int port, int mttl)
                return PIM_SOCK_ERR_LOOP;
        }
 
-       if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (void *)&addr,
+       if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, (void *)&addr,
                       sizeof(addr))) {
                zlog_warn(
                        "%s: could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s",
@@ -170,26 +148,45 @@ static int ssmpingd_socket(struct in_addr addr, int port, int mttl)
                close(fd);
                return -1;
        }
+       return 0;
+}
+#endif
 
-       {
-               long flags;
 
-               flags = fcntl(fd, F_GETFL, 0);
-               if (flags < 0) {
-                       zlog_warn(
-                               "%s: could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
-                               __func__, fd, errno, safe_strerror(errno));
-                       close(fd);
-                       return -1;
-               }
+static int ssmpingd_socket(pim_addr addr, int port, int mttl)
+{
+       struct sockaddr_storage sockaddr;
+       int fd;
+       int ret;
+       socklen_t len = sizeof(sockaddr);
 
-               if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
-                       zlog_warn(
-                               "%s: could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
-                               __func__, fd, errno, safe_strerror(errno));
-                       close(fd);
-                       return -1;
-               }
+       fd = socket(PIM_AF, SOCK_DGRAM, IPPROTO_UDP);
+       if (fd < 0) {
+               flog_err_sys(EC_LIB_SOCKET,
+                            "%s: could not create socket: errno=%d: %s",
+                            __func__, errno, safe_strerror(errno));
+               return -1;
+       }
+
+       pim_socket_getsockname(fd, (struct sockaddr *)&sockaddr, &len);
+
+       if (bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
+               zlog_warn(
+                       "%s: bind(fd=%d,addr=%pSUp,port=%d,len=%zu) failure: errno=%d: %s",
+                       __func__, fd, &sockaddr, port, sizeof(sockaddr), errno,
+                       safe_strerror(errno));
+               close(fd);
+               return -1;
+       }
+
+       set_nonblocking(fd);
+       sockopt_reuseaddr(fd);
+
+       ret = ssmpingd_setsockopt(fd, addr, mttl);
+       if (ret) {
+               zlog_warn("ssmpingd_setsockopt failed");
+               close(fd);
+               return -1;
        }
 
        return fd;
@@ -202,12 +199,9 @@ static void ssmpingd_delete(struct ssmpingd_sock *ss)
        THREAD_OFF(ss->t_sock_read);
 
        if (close(ss->sock_fd)) {
-               char source_str[INET_ADDRSTRLEN];
-               pim_inet4_dump("<src?>", ss->source_addr, source_str,
-                              sizeof(source_str));
                zlog_warn(
-                       "%s: failure closing ssmpingd sock_fd=%d for source %s: errno=%d: %s",
-                       __func__, ss->sock_fd, source_str, errno,
+                       "%s: failure closing ssmpingd sock_fd=%d for source %pPA: errno=%d: %s",
+                       __func__, ss->sock_fd, &ss->source_addr, errno,
                        safe_strerror(errno));
                /* warning only */
        }
@@ -217,7 +211,7 @@ static void ssmpingd_delete(struct ssmpingd_sock *ss)
 }
 
 static void ssmpingd_sendto(struct ssmpingd_sock *ss, const uint8_t *buf,
-                           int len, struct sockaddr_in to)
+                           int len, struct sockaddr_storage to)
 {
        socklen_t tolen = sizeof(to);
        int sent;
@@ -225,18 +219,15 @@ static void ssmpingd_sendto(struct ssmpingd_sock *ss, const uint8_t *buf,
        sent = sendto(ss->sock_fd, buf, len, MSG_DONTWAIT,
                      (struct sockaddr *)&to, tolen);
        if (sent != len) {
-               char to_str[INET_ADDRSTRLEN];
-               pim_inet4_dump("<to?>", to.sin_addr, to_str, sizeof(to_str));
                if (sent < 0) {
                        zlog_warn(
-                               "%s: sendto() failure to %s,%d: fd=%d len=%d: errno=%d: %s",
-                               __func__, to_str, ntohs(to.sin_port),
-                               ss->sock_fd, len, errno, safe_strerror(errno));
+                               "%s: sendto() failure to %pSUp,fd=%d len=%d: errno=%d: %s",
+                               __func__, &to, ss->sock_fd, len, errno,
+                               safe_strerror(errno));
                } else {
                        zlog_warn(
-                               "%s: sendto() partial to %s,%d: fd=%d len=%d: sent=%d",
-                               __func__, to_str, ntohs(to.sin_port),
-                               ss->sock_fd, len, sent);
+                               "%s: sendto() partial to %pSUp, fd=%d len=%d: sent=%d",
+                               __func__, &to, ss->sock_fd, len, sent);
                }
        }
 }
@@ -259,7 +250,7 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
 
        if (len < 0) {
                zlog_warn(
-                       "%s: failure receiving ssmping for source %pI4 on fd=%d: errno=%d: %s",
+                       "%s: failure receiving ssmping for source %pPA on fd=%d: errno=%d: %s",
                        __func__, &ss->source_addr, ss->sock_fd, errno,
                        safe_strerror(errno));
                return -1;
@@ -269,7 +260,7 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
 
        if (buf[0] != PIM_SSMPINGD_REQUEST) {
                zlog_warn(
-                       "%s: bad ssmping type=%d from %pSUp to %pSUp on interface %s ifindex=%d fd=%d src=%pI4",
+                       "%s: bad ssmping type=%d from %pSUp to %pSUp on interface %s ifindex=%d fd=%d src=%pPA",
                        __func__, buf[0], &from, &to,
                        ifp ? ifp->name : "<iface?>", ifindex, ss->sock_fd,
                        &ss->source_addr);
@@ -278,21 +269,19 @@ static int ssmpingd_read_msg(struct ssmpingd_sock *ss)
 
        if (PIM_DEBUG_SSMPINGD) {
                zlog_debug(
-                       "%s: recv ssmping from %pSUp, to %pSUp, on interface %s ifindex=%d fd=%d src=%pI4",
+                       "%s: recv ssmping from %pSUp, to %pSUp, on interface %s ifindex=%d fd=%d src=%pPA",
                        __func__, &from, &to, ifp ? ifp->name : "<iface?>",
                        ifindex, ss->sock_fd, &ss->source_addr);
        }
 
        buf[0] = PIM_SSMPINGD_REPLY;
 
-       struct sockaddr_in *from_addr = (struct sockaddr_in *)&from;
-
        /* unicast reply */
-       ssmpingd_sendto(ss, buf, len, *from_addr);
+       ssmpingd_sendto(ss, buf, len, from);
 
        /* multicast reply */
-       from_addr->sin_addr = ss->pim->ssmpingd_group_addr;
-       ssmpingd_sendto(ss, buf, len, *from_addr);
+       memcpy(&from, &ss->pim->ssmpingd_group_addr, sizeof(pim_addr));
+       ssmpingd_sendto(ss, buf, len, from);
 
        return 0;
 }
@@ -316,7 +305,7 @@ static void ssmpingd_read_on(struct ssmpingd_sock *ss)
 }
 
 static struct ssmpingd_sock *ssmpingd_new(struct pim_instance *pim,
-                                         struct in_addr source_addr)
+                                         pim_addr source_addr)
 {
        struct ssmpingd_sock *ss;
        int sock_fd;
@@ -329,11 +318,8 @@ static struct ssmpingd_sock *ssmpingd_new(struct pim_instance *pim,
        sock_fd =
                ssmpingd_socket(source_addr, /* port: */ 4321, /* mTTL: */ 64);
        if (sock_fd < 0) {
-               char source_str[INET_ADDRSTRLEN];
-               pim_inet4_dump("<src?>", source_addr, source_str,
-                              sizeof(source_str));
-               zlog_warn("%s: ssmpingd_socket() failure for source %s",
-                         __func__, source_str);
+               zlog_warn("%s: ssmpingd_socket() failure for source %pPA",
+                         __func__, &source_addr);
                return 0;
        }
 
@@ -353,7 +339,7 @@ static struct ssmpingd_sock *ssmpingd_new(struct pim_instance *pim,
        return ss;
 }
 
-int pim_ssmpingd_start(struct pim_instance *pim, struct in_addr source_addr)
+int pim_ssmpingd_start(struct pim_instance *pim, pim_addr source_addr)
 {
        struct ssmpingd_sock *ss;
 
@@ -363,48 +349,32 @@ int pim_ssmpingd_start(struct pim_instance *pim, struct in_addr source_addr)
                return 0;
        }
 
-       {
-               char source_str[INET_ADDRSTRLEN];
-               pim_inet4_dump("<src?>", source_addr, source_str,
-                              sizeof(source_str));
-               zlog_info("%s: starting ssmpingd for source %s", __func__,
-                         source_str);
-       }
+       zlog_info("%s: starting ssmpingd for source %pPAs", __func__,
+                 &source_addr);
 
        ss = ssmpingd_new(pim, source_addr);
        if (!ss) {
-               char source_str[INET_ADDRSTRLEN];
-               pim_inet4_dump("<src?>", source_addr, source_str,
-                              sizeof(source_str));
-               zlog_warn("%s: ssmpingd_new() failure for source %s", __func__,
-                         source_str);
+               zlog_warn("%s: ssmpingd_new() failure for source %pPAs",
+                         __func__, &source_addr);
                return -1;
        }
 
        return 0;
 }
 
-int pim_ssmpingd_stop(struct pim_instance *pim, struct in_addr source_addr)
+int pim_ssmpingd_stop(struct pim_instance *pim, pim_addr source_addr)
 {
        struct ssmpingd_sock *ss;
 
        ss = ssmpingd_find(pim, source_addr);
        if (!ss) {
-               char source_str[INET_ADDRSTRLEN];
-               pim_inet4_dump("<src?>", source_addr, source_str,
-                              sizeof(source_str));
-               zlog_warn("%s: could not find ssmpingd for source %s", __func__,
-                         source_str);
+               zlog_warn("%s: could not find ssmpingd for source %pPAs",
+                         __func__, &source_addr);
                return -1;
        }
 
-       {
-               char source_str[INET_ADDRSTRLEN];
-               pim_inet4_dump("<src?>", source_addr, source_str,
-                              sizeof(source_str));
-               zlog_info("%s: stopping ssmpingd for source %s", __func__,
-                         source_str);
-       }
+       zlog_info("%s: stopping ssmpingd for source %pPAs", __func__,
+                 &source_addr);
 
        ssmpingd_delete(ss);