]> git.puffer.fish Git - mirror/frr.git/commitdiff
pim6d: Mroute changes
authorplsaranya <saranya_panjarathina@dell.com>
Thu, 3 Mar 2022 16:25:50 +0000 (21:55 +0530)
committerplsaranya <saranya_panjarathina@dell.com>
Wed, 23 Mar 2022 14:04:28 +0000 (19:34 +0530)
Mroute and supporting changes

Signed-off-by: plsaranya <Saranya_Panjarathina@dell.com>
14 files changed:
include/linux/mroute.h [new file with mode: 0644]
include/linux/mroute6.h [new file with mode: 0644]
include/subdir.am
pimd/pim6_mroute_msg.c [new file with mode: 0644]
pimd/pim6_stubs.c
pimd/pim_instance.h
pimd/pim_mroute.c
pimd/pim_mroute.h
pimd/pim_mroute_msg.c [new file with mode: 0644]
pimd/pim_msg.h
pimd/pim_oil.c
pimd/pim_oil.h
pimd/pim_register.h
pimd/subdir.am

diff --git a/include/linux/mroute.h b/include/linux/mroute.h
new file mode 100644 (file)
index 0000000..a0bfdcb
--- /dev/null
@@ -0,0 +1,193 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI__LINUX_MROUTE_H
+#define _UAPI__LINUX_MROUTE_H
+
+#ifdef __LINUX__
+#include <linux/sockios.h>
+#include <linux/types.h>
+#endif
+#include <netinet/in.h>                /* For struct in_addr. */
+
+/* Based on the MROUTING 3.5 defines primarily to keep
+ * source compatibility with BSD.
+ *
+ * See the mrouted code for the original history.
+ *
+ * Protocol Independent Multicast (PIM) data structures included
+ * Carlos Picoto (cap@di.fc.ul.pt)
+ */
+
+#define MRT_BASE       200
+#define MRT_INIT       (MRT_BASE)      /* Activate the kernel mroute code      */
+#define MRT_DONE       (MRT_BASE+1)    /* Shutdown the kernel mroute           */
+#define MRT_ADD_VIF    (MRT_BASE+2)    /* Add a virtual interface              */
+#define MRT_DEL_VIF    (MRT_BASE+3)    /* Delete a virtual interface           */
+#define MRT_ADD_MFC    (MRT_BASE+4)    /* Add a multicast forwarding entry     */
+#define MRT_DEL_MFC    (MRT_BASE+5)    /* Delete a multicast forwarding entry  */
+#define MRT_VERSION    (MRT_BASE+6)    /* Get the kernel multicast version     */
+#define MRT_ASSERT     (MRT_BASE+7)    /* Activate PIM assert mode             */
+#define MRT_PIM                (MRT_BASE+8)    /* enable PIM code                      */
+#define MRT_TABLE      (MRT_BASE+9)    /* Specify mroute table ID              */
+#define MRT_ADD_MFC_PROXY      (MRT_BASE+10)   /* Add a (*,*|G) mfc entry      */
+#define MRT_DEL_MFC_PROXY      (MRT_BASE+11)   /* Del a (*,*|G) mfc entry      */
+#define MRT_FLUSH      (MRT_BASE+12)   /* Flush all mfc entries and/or vifs    */
+#define MRT_MAX                (MRT_BASE+12)
+
+#ifndef SIOCGETVIFCNT
+#define SIOCGETVIFCNT  SIOCPROTOPRIVATE        /* IP protocol privates */
+#define SIOCGETSGCNT   (SIOCPROTOPRIVATE+1)
+#define SIOCGETRPF     (SIOCPROTOPRIVATE+2)
+#endif
+
+#ifndef MAXVIFS
+#define MAXVIFS 32
+#endif
+/* MRT_FLUSH optional flags */
+#define MRT_FLUSH_MFC  1       /* Flush multicast entries */
+#define MRT_FLUSH_MFC_STATIC   2       /* Flush static multicast entries */
+#define MRT_FLUSH_VIFS 4       /* Flush multicast vifs */
+#define MRT_FLUSH_VIFS_STATIC  8       /* Flush static multicast vifs */
+
+typedef unsigned long vifbitmap_t;     /* User mode code depends on this lot */
+typedef unsigned short vifi_t;
+#define ALL_VIFS       ((vifi_t)(-1))
+
+/* Same idea as select */
+
+#define VIFM_SET(n,m)  ((m)|=(1<<(n)))
+#define VIFM_CLR(n,m)  ((m)&=~(1<<(n)))
+#define VIFM_ISSET(n,m)        ((m)&(1<<(n)))
+#define VIFM_CLRALL(m) ((m)=0)
+#define VIFM_COPY(mfrom,mto)   ((mto)=(mfrom))
+#define VIFM_SAME(m1,m2)       ((m1)==(m2))
+
+/* Passed by mrouted for an MRT_ADD_VIF - again we use the
+ * mrouted 3.6 structures for compatibility
+ */
+struct vifctl {
+       vifi_t  vifc_vifi;              /* Index of VIF */
+       unsigned char vifc_flags;       /* VIFF_ flags */
+       unsigned char vifc_threshold;   /* ttl limit */
+       unsigned int vifc_rate_limit;   /* Rate limiter values (NI) */
+       union {
+               struct in_addr vifc_lcl_addr;     /* Local interface address */
+               int            vifc_lcl_ifindex;  /* Local interface index   */
+       };
+       struct in_addr vifc_rmt_addr;   /* IPIP tunnel addr */
+};
+
+#define VIFF_TUNNEL            0x1     /* IPIP tunnel */
+#define VIFF_SRCRT             0x2     /* NI */
+#define VIFF_REGISTER          0x4     /* register vif */
+#define VIFF_USE_IFINDEX       0x8     /* use vifc_lcl_ifindex instead of
+                                          vifc_lcl_addr to find an interface */
+
+/* Cache manipulation structures for mrouted and PIMd */
+struct mfcctl {
+       struct in_addr mfcc_origin;             /* Origin of mcast      */
+       struct in_addr mfcc_mcastgrp;           /* Group in question    */
+       vifi_t  mfcc_parent;                    /* Where it arrived     */
+       unsigned char mfcc_ttls[MAXVIFS];       /* Where it is going    */
+       unsigned int mfcc_pkt_cnt;              /* pkt count for src-grp */
+       unsigned int mfcc_byte_cnt;
+       unsigned int mfcc_wrong_if;
+       int          mfcc_expire;
+};
+
+/*  Group count retrieval for mrouted */
+struct sioc_sg_req {
+       struct in_addr src;
+       struct in_addr grp;
+       unsigned long pktcnt;
+       unsigned long bytecnt;
+       unsigned long wrong_if;
+};
+
+/* To get vif packet counts */
+struct sioc_vif_req {
+       vifi_t  vifi;           /* Which iface */
+       unsigned long icount;   /* In packets */
+       unsigned long ocount;   /* Out packets */
+       unsigned long ibytes;   /* In bytes */
+       unsigned long obytes;   /* Out bytes */
+};
+
+/* This is the format the mroute daemon expects to see IGMP control
+ * data. Magically happens to be like an IP packet as per the original
+ */
+struct igmpmsg {
+       uint32_t unused1,unused2;
+       unsigned char im_msgtype;               /* What is this */
+       unsigned char im_mbz;                   /* Must be zero */
+       unsigned char im_vif;                   /* Low 8 bits of Interface */
+       unsigned char im_vif_hi;                /* High 8 bits of Interface */
+       struct in_addr im_src,im_dst;
+};
+
+/* ipmr netlink table attributes */
+enum {
+       IPMRA_TABLE_UNSPEC,
+       IPMRA_TABLE_ID,
+       IPMRA_TABLE_CACHE_RES_QUEUE_LEN,
+       IPMRA_TABLE_MROUTE_REG_VIF_NUM,
+       IPMRA_TABLE_MROUTE_DO_ASSERT,
+       IPMRA_TABLE_MROUTE_DO_PIM,
+       IPMRA_TABLE_VIFS,
+       IPMRA_TABLE_MROUTE_DO_WRVIFWHOLE,
+       __IPMRA_TABLE_MAX
+};
+#define IPMRA_TABLE_MAX (__IPMRA_TABLE_MAX - 1)
+
+/* ipmr netlink vif attribute format
+ * [ IPMRA_TABLE_VIFS ] - nested attribute
+ *   [ IPMRA_VIF ] - nested attribute
+ *     [ IPMRA_VIFA_xxx ]
+ */
+enum {
+       IPMRA_VIF_UNSPEC,
+       IPMRA_VIF,
+       __IPMRA_VIF_MAX
+};
+#define IPMRA_VIF_MAX (__IPMRA_VIF_MAX - 1)
+
+/* vif-specific attributes */
+enum {
+       IPMRA_VIFA_UNSPEC,
+       IPMRA_VIFA_IFINDEX,
+       IPMRA_VIFA_VIF_ID,
+       IPMRA_VIFA_FLAGS,
+       IPMRA_VIFA_BYTES_IN,
+       IPMRA_VIFA_BYTES_OUT,
+       IPMRA_VIFA_PACKETS_IN,
+       IPMRA_VIFA_PACKETS_OUT,
+       IPMRA_VIFA_LOCAL_ADDR,
+       IPMRA_VIFA_REMOTE_ADDR,
+       IPMRA_VIFA_PAD,
+       __IPMRA_VIFA_MAX
+};
+#define IPMRA_VIFA_MAX (__IPMRA_VIFA_MAX - 1)
+
+/* ipmr netlink cache report attributes */
+enum {
+       IPMRA_CREPORT_UNSPEC,
+       IPMRA_CREPORT_MSGTYPE,
+       IPMRA_CREPORT_VIF_ID,
+       IPMRA_CREPORT_SRC_ADDR,
+       IPMRA_CREPORT_DST_ADDR,
+       IPMRA_CREPORT_PKT,
+       IPMRA_CREPORT_TABLE,
+       __IPMRA_CREPORT_MAX
+};
+#define IPMRA_CREPORT_MAX (__IPMRA_CREPORT_MAX - 1)
+
+/* That's all usermode folks */
+
+#define MFC_ASSERT_THRESH (3*HZ)               /* Maximal freq. of asserts */
+
+/* Pseudo messages used by mrouted */
+#define IGMPMSG_NOCACHE                1               /* Kern cache fill request to mrouted */
+#define IGMPMSG_WRONGVIF       2               /* For PIM assert processing (unused) */
+#define IGMPMSG_WHOLEPKT       3               /* For PIM Register processing */
+#define IGMPMSG_WRVIFWHOLE     4               /* For PIM Register and assert processing */
+
+#endif /* _UAPI__LINUX_MROUTE_H */
diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h
new file mode 100644 (file)
index 0000000..1fb90ec
--- /dev/null
@@ -0,0 +1,163 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI__LINUX_MROUTE6_H
+#define _UAPI__LINUX_MROUTE6_H
+
+#ifdef __LINUX__
+#include <linux/const.h>
+#include <linux/types.h>
+#include <linux/sockios.h>
+#endif
+#include <netinet/in.h>                /* For struct sockaddr_in6. */
+
+/*
+ *     Based on the MROUTING 3.5 defines primarily to keep
+ *     source compatibility with BSD.
+ *
+ *     See the pim6sd code for the original history.
+ *
+ *      Protocol Independent Multicast (PIM) data structures included
+ *      Carlos Picoto (cap@di.fc.ul.pt)
+ *
+ */
+
+#define MRT6_BASE      200
+#define MRT6_INIT      (MRT6_BASE)     /* Activate the kernel mroute code      */
+#define MRT6_DONE      (MRT6_BASE+1)   /* Shutdown the kernel mroute           */
+#define MRT6_ADD_MIF   (MRT6_BASE+2)   /* Add a virtual interface              */
+#define MRT6_DEL_MIF   (MRT6_BASE+3)   /* Delete a virtual interface           */
+#define MRT6_ADD_MFC   (MRT6_BASE+4)   /* Add a multicast forwarding entry     */
+#define MRT6_DEL_MFC   (MRT6_BASE+5)   /* Delete a multicast forwarding entry  */
+#define MRT6_VERSION   (MRT6_BASE+6)   /* Get the kernel multicast version     */
+#define MRT6_ASSERT    (MRT6_BASE+7)   /* Activate PIM assert mode             */
+#define MRT6_PIM       (MRT6_BASE+8)   /* enable PIM code                      */
+#define MRT6_TABLE     (MRT6_BASE+9)   /* Specify mroute table ID              */
+#define MRT6_ADD_MFC_PROXY     (MRT6_BASE+10)  /* Add a (*,*|G) mfc entry      */
+#define MRT6_DEL_MFC_PROXY     (MRT6_BASE+11)  /* Del a (*,*|G) mfc entry      */
+#define MRT6_FLUSH     (MRT6_BASE+12)  /* Flush all mfc entries and/or vifs    */
+#define MRT6_MAX       (MRT6_BASE+12)
+
+#ifndef SIOCGETMIFCNT_IN6
+#define SIOCGETMIFCNT_IN6      SIOCPROTOPRIVATE        /* IP protocol privates */
+#define SIOCGETSGCNT_IN6       (SIOCPROTOPRIVATE+1)
+#define SIOCGETRPF     (SIOCPROTOPRIVATE+2)
+#endif
+
+#ifndef MAXMIFS
+#define MAXMIFS 32
+#endif
+/* MRT6_FLUSH optional flags */
+#define MRT6_FLUSH_MFC 1       /* Flush multicast entries */
+#define MRT6_FLUSH_MFC_STATIC  2       /* Flush static multicast entries */
+#define MRT6_FLUSH_MIFS        4       /* Flushing multicast vifs */
+#define MRT6_FLUSH_MIFS_STATIC 8       /* Flush static multicast vifs */
+
+typedef unsigned long mifbitmap_t;     /* User mode code depends on this lot */
+typedef unsigned short mifi_t;
+#define ALL_MIFS       ((mifi_t)(-1))
+
+#ifndef IF_SETSIZE
+#define IF_SETSIZE     256
+#endif
+
+typedef        uint32_t        if_mask;
+#define NIFBITS (sizeof(if_mask) * 8)        /* bits per mask */
+
+typedef struct if_set {
+       if_mask ifs_bits[__KERNEL_DIV_ROUND_UP(IF_SETSIZE, NIFBITS)];
+} if_set;
+
+#define IF_SET(n, p)    ((p)->ifs_bits[(n)/NIFBITS] |= (1 << ((n) % NIFBITS)))
+#define IF_CLR(n, p)    ((p)->ifs_bits[(n)/NIFBITS] &= ~(1 << ((n) % NIFBITS)))
+#define IF_ISSET(n, p)  ((p)->ifs_bits[(n)/NIFBITS] & (1 << ((n) % NIFBITS)))
+#define IF_COPY(f, t)   bcopy(f, t, sizeof(*(f)))
+#define IF_ZERO(p)      bzero(p, sizeof(*(p)))
+
+/*
+ *     Passed by mrouted for an MRT_ADD_MIF - again we use the
+ *     mrouted 3.6 structures for compatibility
+ */
+
+struct mif6ctl {
+       mifi_t  mif6c_mifi;             /* Index of MIF */
+       unsigned char mif6c_flags;      /* MIFF_ flags */
+       unsigned char vifc_threshold;   /* ttl limit */
+       __u16    mif6c_pifi;            /* the index of the physical IF */
+       unsigned int vifc_rate_limit;   /* Rate limiter values (NI) */
+};
+
+#define MIFF_REGISTER  0x1     /* register vif */
+
+/*
+ *     Cache manipulation structures for mrouted and PIMd
+ */
+
+struct mf6cctl {
+       struct sockaddr_in6 mf6cc_origin;               /* Origin of mcast      */
+       struct sockaddr_in6 mf6cc_mcastgrp;             /* Group in question    */
+       mifi_t  mf6cc_parent;                   /* Where it arrived     */
+       struct if_set mf6cc_ifset;              /* Where it is going */
+};
+
+/*
+ *     Group count retrieval for pim6sd
+ */
+
+struct sioc_sg_req6 {
+       struct sockaddr_in6 src;
+       struct sockaddr_in6 grp;
+       unsigned long pktcnt;
+       unsigned long bytecnt;
+       unsigned long wrong_if;
+};
+
+/*
+ *     To get vif packet counts
+ */
+
+struct sioc_mif_req6 {
+       mifi_t  mifi;           /* Which iface */
+       unsigned long icount;   /* In packets */
+       unsigned long ocount;   /* Out packets */
+       unsigned long ibytes;   /* In bytes */
+       unsigned long obytes;   /* Out bytes */
+};
+
+/*
+ *     That's all usermode folks
+ */
+
+
+
+/*
+ * Structure used to communicate from kernel to multicast router.
+ * We'll overlay the structure onto an MLD header (not an IPv6 heder like igmpmsg{}
+ * used for IPv4 implementation). This is because this structure will be passed via an
+ * IPv6 raw socket, on which an application will only receiver the payload i.e the data after
+ * the IPv6 header and all the extension headers. (See section 3 of RFC 3542)
+ */
+
+struct mrt6msg {
+#define MRT6MSG_NOCACHE                1
+#define MRT6MSG_WRONGMIF       2
+#define MRT6MSG_WHOLEPKT       3               /* used for use level encap */
+#define MRT6MSG_WRMIFWHOLE     4               /* For PIM Register and assert processing */
+       __u8            im6_mbz;                /* must be zero            */
+       __u8            im6_msgtype;            /* what type of message    */
+       __u16           im6_mif;                /* mif rec'd on            */
+       __u32           im6_pad;                /* padding for 64 bit arch */
+       struct in6_addr im6_src, im6_dst;
+};
+
+/* ip6mr netlink cache report attributes */
+enum {
+       IP6MRA_CREPORT_UNSPEC,
+       IP6MRA_CREPORT_MSGTYPE,
+       IP6MRA_CREPORT_MIF_ID,
+       IP6MRA_CREPORT_SRC_ADDR,
+       IP6MRA_CREPORT_DST_ADDR,
+       IP6MRA_CREPORT_PKT,
+       __IP6MRA_CREPORT_MAX
+};
+#define IP6MRA_CREPORT_MAX (__IP6MRA_CREPORT_MAX - 1)
+
+#endif /* _UAPI__LINUX_MROUTE6_H */
index a06a8e5649e46fd4f0ad38df8f7365a98ecb7c74..f6328ef38e71841b42d82b4f4e479f887cb88269 100644 (file)
@@ -17,4 +17,6 @@ noinst_HEADERS += \
        include/linux/seg6_hmac.h \
        include/linux/seg6_iptunnel.h \
        include/linux/seg6_local.h \
+       include/linux/mroute.h \
+       include/linux/mroute6.h \
        # end
diff --git a/pimd/pim6_mroute_msg.c b/pimd/pim6_mroute_msg.c
new file mode 100644 (file)
index 0000000..d67490a
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * PIM for Quagga
+ * Copyright (C) 2022  Dell Technologies Ltd
+ *
+ * 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 "log.h"
+#include "privs.h"
+#include "if.h"
+#include "prefix.h"
+#include "vty.h"
+#include "plist.h"
+#include "sockopt.h"
+#include "lib_errors.h"
+#include "lib/network.h"
+
+#include "pimd.h"
+#include "pim_mroute.h"
+#include "pim_oil.h"
+#include "pim_str.h"
+#include "pim_time.h"
+#include "pim_iface.h"
+#include "pim_macro.h"
+#include "pim_rp.h"
+#include "pim_oil.h"
+#include "pim_ssm.h"
+#include "pim_sock.h"
+
+int pim_mroute_set(struct pim_instance *pim, int enable)
+{
+       int err;
+       int opt, data;
+       socklen_t data_len = sizeof(data);
+       static const struct sock_filter filter[] = {
+               BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
+               BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1),
+               BPF_STMT(BPF_RET | BPF_K, 0xffff),
+               BPF_STMT(BPF_RET | BPF_K, 0),
+       };
+
+       static const struct sock_fprog bpf = {
+               .len = array_size(filter),
+               .filter = (struct sock_filter *)filter,
+       };
+
+       /*
+        * We need to create the VRF table for the pim mroute_socket
+        */
+       if (pim->vrf->vrf_id != VRF_DEFAULT) {
+               frr_with_privs (&pimd_privs) {
+
+                       data = pim->vrf->data.l.table_id;
+                       err = setsockopt(pim->mroute_socket, PIM_IPPROTO,
+                                        MRT6_TABLE, &data, data_len);
+                       if (err) {
+                               zlog_warn(
+                                       "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO, MRT6_TABLE=%d): errno=%d: %s",
+                                       __FILE__, __func__, pim->mroute_socket,
+                                       data, errno, safe_strerror(errno));
+                               return -1;
+                       }
+               }
+       }
+
+       frr_with_privs (&pimd_privs) {
+               opt = enable ? MRT6_INIT : MRT6_DONE;
+               /*
+                * *BSD *cares* about what value we pass down
+                * here
+                */
+               data = 1;
+               err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &data,
+                                data_len);
+               if (err) {
+                       zlog_warn(
+                               "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,%s=%d): errno=%d: %s",
+                               __FILE__, __func__, pim->mroute_socket,
+                               enable ? "MRT6_INIT" : "MRT6_DONE", data, errno,
+                               safe_strerror(errno));
+                       return -1;
+               }
+       }
+
+       if (enable) {
+               /* Linux and Solaris IPV6_PKTINFO */
+               data = 1;
+               if (setsockopt(pim->mroute_socket, PIM_IPPROTO, IPV6_PKTINFO,
+                              &data, data_len)) {
+                       zlog_warn(
+                               "Could not set IPV6_PKTINFO on socket fd=%d: errno=%d: %s",
+                               pim->mroute_socket, errno,
+                               safe_strerror(errno));
+               }
+       }
+
+       setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8);
+
+       if (set_nonblocking (pim->mroute_socket) < 0) {
+               zlog_warn(
+                       "Could not set non blocking on socket fd=%d: errno=%d: %s",
+                       pim->mroute_socket, errno,
+                       safe_strerror(errno));
+       }
+
+       if (enable) {
+#if defined linux
+               int upcalls = MRT6MSG_WRMIFWHOLE;
+               opt = MRT6_PIM;
+
+               err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &upcalls,
+                                sizeof(upcalls));
+               if (err) {
+                       zlog_warn(
+                               "Failure to register for WHOLE and WRONGMIF upcalls %d %s",
+                               errno, safe_strerror(errno));
+                       return -1;
+               }
+#else
+               zlog_warn(
+                       "PIM-SM will not work properly on this platform, until the ability to receive the WHOLEPKT upcall");
+#endif
+               if (setsockopt(pim->mroute_socket, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))) {
+                       zlog_warn("Failure to attach SO_ATTACH_FILTER on fd %d: %d %s",
+                                       pim->mroute_socket, errno, safe_strerror(errno));
+               }
+       }
+
+       return 0;
+}
+static const char *const mrt6msgtype2str[MRT6MSG_WRMIFWHOLE + 1] = {
+       "<unknown_upcall?>", "NOCACHE", "WRONGMIF", "WHOLEPKT", "WRMIFWHOLE"};
+
+int pim_mroute_msg(struct pim_instance *pim, const char *buf,
+                         size_t buf_size, ifindex_t ifindex)
+{
+       struct interface *ifp;
+       const struct ip6_hdr *ip6_hdr;
+       const struct mrt6msg *msg;
+
+       if (buf_size < (int)sizeof(struct ip6_hdr))
+               return 0;
+
+       ip6_hdr = (const struct ip6_hdr *)buf;
+
+       if ((ip6_hdr->ip6_vfc & 0xf) == 0) {
+               msg = (const struct mrt6msg *)buf;
+
+               ifp = pim_if_find_by_vif_index(pim, msg->im6_mif);
+
+               if (!ifp)
+                       return 0;
+               if (PIM_DEBUG_MROUTE) {
+                       zlog_debug(
+                               "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pPAs,%pPAs) on %s mifi=%d  size=%ld",
+                               __func__, mrt6msgtype2str[msg->im6_msgtype],
+                               msg->im6_msgtype, ip6_hdr->ip6_nxt,
+                               pim->mroute_socket, &msg->im6_src,
+                               &msg->im6_dst, ifp->name, msg->im6_mif,
+                               (long int)buf_size);
+               }
+
+               switch (msg->im6_msgtype) {
+               case MRT6MSG_WRONGMIF:
+                       return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
+                                                       msg);
+               case MRT6MSG_NOCACHE:
+                       return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
+                                                      msg);
+               case MRT6MSG_WHOLEPKT:
+                       return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
+                                                       (const char *)msg);
+               case MRT6MSG_WRMIFWHOLE:
+                       return pim_mroute_msg_wrvifwhole(
+                               pim->mroute_socket, ifp, (const char *)msg);
+               default:
+                       break;
+               }
+       } 
+
+       return 0;
+}
+
index e689c7aca4d437d0056d93e8c68a509873fc238d..f2781a3ce9d5be4edca3222ad0490512eb650146 100644 (file)
@@ -121,3 +121,12 @@ struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope,
 void pim_bsm_write_config(struct vty *vty, struct interface *ifp)
 {
 }
+void pim_register_send(const uint8_t *buf, int buf_size, pim_addr src,
+                      struct pim_rpf *rpg, int null_register,
+                      struct pim_upstream *up)
+{
+}
+void pim_register_stop_send(struct interface *ifp, pim_sgaddr *sg, pim_addr src,
+                           pim_addr originator)
+{
+}
index 4ac9ef7f5195809d9bd7f6b353d8b364f7f7e4a6..f8323deda0e330a293b8459cc7dbcb6ab72bc0a5 100644 (file)
 #include "pim_vxlan_instance.h"
 #include "pim_oil.h"
 #include "pim_upstream.h"
-
-#if defined(HAVE_LINUX_MROUTE_H)
-#include <linux/mroute.h>
-#else
-/*
-  Below: from <linux/mroute.h>
-*/
-
-#ifndef MAXVIFS
-#define MAXVIFS (256)
-#endif
-#endif
+#include "pim_mroute.h"
 
 enum pim_spt_switchover {
        PIM_SPT_IMMEDIATE,
index bce319b3ad679abd57072310dc3bb51f5b7b9eb6..7fc4f12d27678804f89bd80d664d5b0cc5aa8159 100644 (file)
 #include "pim_ssm.h"
 #include "pim_sock.h"
 #include "pim_vxlan.h"
+#include "pim_msg.h"
 
 static void mroute_read_on(struct pim_instance *pim);
 
-static int pim_mroute_set(struct pim_instance *pim, int enable)
-{
-       int err;
-       int opt, data;
-       socklen_t data_len = sizeof(data);
-       long flags;
-
-       /*
-        * We need to create the VRF table for the pim mroute_socket
-        */
-       if (pim->vrf->vrf_id != VRF_DEFAULT) {
-               frr_with_privs(&pimd_privs) {
-
-                       data = pim->vrf->data.l.table_id;
-                       err = setsockopt(pim->mroute_socket, IPPROTO_IP,
-                                        MRT_TABLE,
-                                        &data, data_len);
-                       if (err) {
-                               zlog_warn(
-                                       "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP, MRT_TABLE=%d): errno=%d: %s",
-                                       __FILE__, __func__, pim->mroute_socket,
-                                       data, errno, safe_strerror(errno));
-                               return -1;
-                       }
-
-               }
-       }
-
-       frr_with_privs(&pimd_privs) {
-               opt = enable ? MRT_INIT : MRT_DONE;
-               /*
-                * *BSD *cares* about what value we pass down
-                * here
-                */
-               data = 1;
-               err = setsockopt(pim->mroute_socket, IPPROTO_IP,
-                                opt, &data, data_len);
-               if (err) {
-                       zlog_warn(
-                               "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
-                               __FILE__, __func__, pim->mroute_socket,
-                               enable ? "MRT_INIT" : "MRT_DONE", data, errno,
-                               safe_strerror(errno));
-                       return -1;
-               }
-       }
-
-#if defined(HAVE_IP_PKTINFO)
-       if (enable) {
-               /* Linux and Solaris IP_PKTINFO */
-               data = 1;
-               if (setsockopt(pim->mroute_socket, IPPROTO_IP, IP_PKTINFO,
-                              &data, data_len)) {
-                       zlog_warn(
-                               "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
-                               pim->mroute_socket, errno,
-                               safe_strerror(errno));
-               }
-       }
-#endif
-
-       setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8);
-
-       flags = fcntl(pim->mroute_socket, F_GETFL, 0);
-       if (flags < 0) {
-               zlog_warn("Could not get flags on socket fd:%d %d %s",
-                         pim->mroute_socket, errno, safe_strerror(errno));
-               close(pim->mroute_socket);
-               return -1;
-       }
-       if (fcntl(pim->mroute_socket, F_SETFL, flags | O_NONBLOCK)) {
-               zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s",
-                         pim->mroute_socket, errno, safe_strerror(errno));
-               close(pim->mroute_socket);
-               return -1;
-       }
-
-       if (enable) {
-#if defined linux
-               int upcalls = IGMPMSG_WRVIFWHOLE;
-               opt = MRT_PIM;
-
-               err = setsockopt(pim->mroute_socket, IPPROTO_IP, opt, &upcalls,
-                                sizeof(upcalls));
-               if (err) {
-                       zlog_warn(
-                               "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
-                               errno, safe_strerror(errno));
-                       return -1;
-               }
-#else
-               zlog_warn(
-                       "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
-#endif
-       }
-
-       return 0;
-}
-
-#if PIM_IPV == 4
-static const char *const igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = {
-       "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
 
-static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
-                                 const struct igmpmsg *msg)
+int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg)
 {
        struct pim_interface *pim_ifp = ifp->info;
        struct pim_upstream *up;
        struct pim_rpf *rpg;
        pim_sgaddr sg;
 
-       rpg = pim_ifp ? RP(pim_ifp->pim, msg->im_dst) : NULL;
+       rpg = pim_ifp ? RP(pim_ifp->pim, msg->msg_im_dst) : NULL;
        /*
         * If the incoming interface is unknown OR
         * the Interface type is SSM we don't need to
@@ -176,7 +74,7 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
         * If we've received a multicast packet that isn't connected to
         * us
         */
-       if (!pim_if_connected_to_source(ifp, msg->im_src)) {
+       if (!pim_if_connected_to_source(ifp, msg->msg_im_src)) {
                if (PIM_DEBUG_MROUTE_DETAIL)
                        zlog_debug(
                                "%s: Received incoming packet that doesn't originate on our seg",
@@ -185,13 +83,14 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
        }
 
        memset(&sg, 0, sizeof(sg));
-       sg.src = msg->im_src;
-       sg.grp = msg->im_dst;
+       sg.src = msg->msg_im_src;
+       sg.grp = msg->msg_im_dst;
 
        if (!(PIM_I_am_DR(pim_ifp))) {
                if (PIM_DEBUG_MROUTE_DETAIL)
-                       zlog_debug("%s: Interface is not the DR blackholing incoming traffic for %pSG",
-                                  __func__, &sg);
+                       zlog_debug(
+                               "%s: Interface is not the DR blackholing incoming traffic for %pSG",
+                               __func__, &sg);
 
                /*
                 * We are not the DR, but we are still receiving packets
@@ -238,22 +137,21 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp,
        return 0;
 }
 
-static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
-                                  const char *buf)
+int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, const char *buf)
 {
        struct pim_interface *pim_ifp;
        pim_sgaddr sg;
        struct pim_rpf *rpg;
-       const struct ip *ip_hdr;
+       const ipv_hdr *ip_hdr;
        struct pim_upstream *up;
 
        pim_ifp = ifp->info;
 
-       ip_hdr = (const struct ip *)buf;
+       ip_hdr = (const ipv_hdr *)buf;
 
        memset(&sg, 0, sizeof(sg));
-       sg.src = ip_hdr->ip_src;
-       sg.grp = ip_hdr->ip_dst;
+       sg.src = IPV_SRC(ip_hdr);
+       sg.grp = IPV_DST(ip_hdr);
 
        up = pim_upstream_find(pim_ifp->pim, &sg);
        if (!up) {
@@ -268,8 +166,9 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
                                              __func__, NULL);
                        if (!up) {
                                if (PIM_DEBUG_MROUTE)
-                                       zlog_debug("%s: Unable to create upstream information for %pSG",
-                                                  __func__, &sg);
+                                       zlog_debug(
+                                               "%s: Unable to create upstream information for %pSG",
+                                               __func__, &sg);
                                return 0;
                        }
                        pim_upstream_keep_alive_timer_start(
@@ -283,8 +182,9 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
                        return 0;
                }
                if (PIM_DEBUG_MROUTE_DETAIL) {
-                       zlog_debug("%s: Unable to find upstream channel WHOLEPKT%pSG",
-                                  __func__, &sg);
+                       zlog_debug(
+                               "%s: Unable to find upstream channel WHOLEPKT%pSG",
+                               __func__, &sg);
                }
                return 0;
        }
@@ -314,8 +214,9 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
        if (!up->t_rs_timer) {
                if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
                        if (PIM_DEBUG_PIM_REG)
-                               zlog_debug("%pSG register forward skipped as group is SSM",
-                                          &sg);
+                               zlog_debug(
+                                       "%pSG register forward skipped as group is SSM",
+                                       &sg);
                        return 0;
                }
 
@@ -327,23 +228,22 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp,
                        return 0;
                }
 
-               pim_register_send((uint8_t *)buf + sizeof(struct ip),
-                                 ntohs(ip_hdr->ip_len) - sizeof(struct ip),
+               pim_register_send((uint8_t *)buf + sizeof(ipv_hdr),
+                                 ntohs(IPV_LEN(ip_hdr)) - sizeof(ipv_hdr),
                                  pim_ifp->primary_address, rpg, 0, up);
        }
        return 0;
 }
 
-static int pim_mroute_msg_wrongvif(int fd, struct interface *ifp,
-                                  const struct igmpmsg *msg)
+int pim_mroute_msg_wrongvif(int fd, struct interface *ifp, const kernmsg *msg)
 {
        struct pim_ifchannel *ch;
        struct pim_interface *pim_ifp;
        pim_sgaddr sg;
 
        memset(&sg, 0, sizeof(sg));
-       sg.src = msg->im_src;
-       sg.grp = msg->im_dst;
+       sg.src = msg->msg_im_src;
+       sg.grp = msg->msg_im_dst;
 
        /*
          Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
@@ -358,16 +258,18 @@ static int pim_mroute_msg_wrongvif(int fd, struct interface *ifp,
 
        if (!ifp) {
                if (PIM_DEBUG_MROUTE)
-                       zlog_debug("%s: WRONGVIF (S,G)=%pSG could not find input interface for input_vif_index=%d",
-                                  __func__, &sg, msg->im_vif);
+                       zlog_debug(
+                               "%s: WRONGVIF (S,G)=%pSG could not find input interface for input_vif_index=%d",
+                               __func__, &sg, msg->msg_im_vif);
                return -1;
        }
 
        pim_ifp = ifp->info;
        if (!pim_ifp) {
                if (PIM_DEBUG_MROUTE)
-                       zlog_debug("%s: WRONGVIF (S,G)=%pSG multicast not enabled on interface %s",
-                                  __func__, &sg, ifp->name);
+                       zlog_debug(
+                               "%s: WRONGVIF (S,G)=%pSG multicast not enabled on interface %s",
+                               __func__, &sg, ifp->name);
                return -2;
        }
 
@@ -375,16 +277,17 @@ static int pim_mroute_msg_wrongvif(int fd, struct interface *ifp,
        if (!ch) {
                pim_sgaddr star_g = sg;
                if (PIM_DEBUG_MROUTE)
-                       zlog_debug("%s: WRONGVIF (S,G)=%pSG could not find channel on interface %s",
-                                  __func__, &sg, ifp->name);
+                       zlog_debug(
+                               "%s: WRONGVIF (S,G)=%pSG could not find channel on interface %s",
+                               __func__, &sg, ifp->name);
 
                star_g.src = PIMADDR_ANY;
                ch = pim_ifchannel_find(ifp, &star_g);
                if (!ch) {
                        if (PIM_DEBUG_MROUTE)
-                               zlog_debug("%s: WRONGVIF (*,G)=%pSG could not find channel on interface %s",
-                                          __func__, &star_g,
-                                          ifp->name);
+                               zlog_debug(
+                                       "%s: WRONGVIF (*,G)=%pSG could not find channel on interface %s",
+                                       __func__, &star_g, ifp->name);
                        return -3;
                }
        }
@@ -433,10 +336,9 @@ static int pim_mroute_msg_wrongvif(int fd, struct interface *ifp,
        return 0;
 }
 
-static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
-                                    const char *buf)
+int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, const char *buf)
 {
-       const struct ip *ip_hdr = (const struct ip *)buf;
+       const ipv_hdr *ip_hdr = (const ipv_hdr *)buf;
        struct pim_interface *pim_ifp;
        struct pim_instance *pim;
        struct pim_ifchannel *ch;
@@ -447,8 +349,8 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
        pim_ifp = ifp->info;
 
        memset(&sg, 0, sizeof(sg));
-       sg.src = ip_hdr->ip_src;
-       sg.grp = ip_hdr->ip_dst;
+       sg.src = IPV_SRC(ip_hdr);
+       sg.grp = IPV_DST(ip_hdr);
 
        ch = pim_ifchannel_find(ifp, &sg);
        if (ch) {
@@ -481,8 +383,8 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
                struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp);
 
                /* No RPF or No RPF interface or No mcast on RPF interface */
-               if (!rpf || !rpf->source_nexthop.interface
-                   || !rpf->source_nexthop.interface->info)
+               if (!rpf || !rpf->source_nexthop.interface ||
+                   !rpf->source_nexthop.interface->info)
                        return 0;
 
                /*
@@ -512,7 +414,7 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
                         * bow out of doing a nexthop lookup and
                         * setting the SPTBIT to true
                         */
-                       if (up->upstream_register.s_addr != INADDR_ANY &&
+                       if (!(pim_addr_is_any(up->upstream_register)) &&
                            pim_nexthop_lookup(pim_ifp->pim, &source,
                                               up->upstream_register, 0)) {
                                pim_register_stop_send(source.interface, &sg,
@@ -551,8 +453,9 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
                                      NULL);
                if (!up) {
                        if (PIM_DEBUG_MROUTE)
-                               zlog_debug("%pSG: WRONGVIF%s unable to create upstream on interface",
-                                          &sg, ifp->name);
+                               zlog_debug(
+                                       "%pSG: WRONGVIF%s unable to create upstream on interface",
+                                       &sg, ifp->name);
                        return -2;
                }
                PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
@@ -577,119 +480,6 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp,
        return 0;
 }
 
-static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
-                         int buf_size, ifindex_t ifindex)
-{
-       struct interface *ifp;
-       const struct ip *ip_hdr;
-       const struct igmpmsg *msg;
-
-       if (buf_size < (int)sizeof(struct ip))
-               return 0;
-
-       ip_hdr = (const struct ip *)buf;
-
-       if (ip_hdr->ip_p == IPPROTO_IGMP) {
-#if PIM_IPV == 4
-               struct pim_interface *pim_ifp;
-               struct in_addr ifaddr;
-               struct gm_sock *igmp;
-               const struct prefix *connected_src;
-
-               /* We have the IP packet but we do not know which interface this
-                * packet was
-                * received on. Find the interface that is on the same subnet as
-                * the source
-                * of the IP packet.
-                */
-               ifp = if_lookup_by_index(ifindex, pim->vrf->vrf_id);
-
-               if (!ifp || !ifp->info)
-                       return 0;
-
-               connected_src = pim_if_connected_to_source(ifp, ip_hdr->ip_src);
-
-               if (!connected_src && !pim_addr_is_any(ip_hdr->ip_src)) {
-                       if (PIM_DEBUG_IGMP_PACKETS) {
-                               zlog_debug("Recv IGMP packet on interface: %s from a non-connected source: %pI4",
-                                          ifp->name, &ip_hdr->ip_src);
-                       }
-                       return 0;
-               }
-
-               pim_ifp = ifp->info;
-               ifaddr = connected_src ? connected_src->u.prefix4
-                                      : pim_ifp->primary_address;
-               igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list,
-                                                  ifaddr);
-
-               if (PIM_DEBUG_IGMP_PACKETS) {
-                       zlog_debug(
-                               "%s(%s): igmp kernel upcall on %s(%p) for %pI4 -> %pI4",
-                               __func__, pim->vrf->name, ifp->name, igmp,
-                               &ip_hdr->ip_src, &ip_hdr->ip_dst);
-               }
-               if (igmp)
-                       pim_igmp_packet(igmp, (char *)buf, buf_size);
-               else if (PIM_DEBUG_IGMP_PACKETS) {
-                       zlog_debug(
-                               "No IGMP socket on interface: %s with connected source: %pI4",
-                               ifp->name, &ifaddr);
-               }
-#endif
-       } else if (ip_hdr->ip_p) {
-               if (PIM_DEBUG_MROUTE_DETAIL) {
-                       zlog_debug(
-                               "%s: no kernel upcall proto=%d src: %pI4 dst: %pI4 msg_size=%d",
-                               __func__, ip_hdr->ip_p, &ip_hdr->ip_src, &ip_hdr->ip_dst,
-                               buf_size);
-               }
-
-       } else {
-               msg = (const struct igmpmsg *)buf;
-
-               ifp = pim_if_find_by_vif_index(pim, msg->im_vif);
-
-               if (!ifp)
-                       return 0;
-               if (PIM_DEBUG_MROUTE) {
-                       zlog_debug(
-                               "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI4,%pI4) on %s vifi=%d  size=%d",
-                               __func__, igmpmsgtype2str[msg->im_msgtype],
-                               msg->im_msgtype, ip_hdr->ip_p,
-                               pim->mroute_socket, &msg->im_src, &msg->im_dst, ifp->name,
-                               msg->im_vif, buf_size);
-               }
-
-               switch (msg->im_msgtype) {
-               case IGMPMSG_WRONGVIF:
-                       return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
-                                                      msg);
-               case IGMPMSG_NOCACHE:
-                       return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
-                                                     msg);
-               case IGMPMSG_WHOLEPKT:
-                       return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
-                                                      (const char *)msg);
-               case IGMPMSG_WRVIFWHOLE:
-                       return pim_mroute_msg_wrvifwhole(
-                               pim->mroute_socket, ifp, (const char *)msg);
-               default:
-                       break;
-               }
-       }
-
-       return 0;
-}
-#else /* PIM_IPV != 4 */
-
-static int pim_mroute_msg(struct pim_instance *pim, const char *buf,
-                         int buf_size, ifindex_t ifindex)
-{
-       return 0;
-}
-#endif /* PIM_IPV != 4 */
-
 static void mroute_read(struct thread *t)
 {
        struct pim_instance *pim;
@@ -726,6 +516,8 @@ static void mroute_read(struct thread *t)
 /* Keep reading */
 done:
        mroute_read_on(pim);
+
+       return;
 }
 
 static void mroute_read_on(struct pim_instance *pim)
@@ -745,8 +537,11 @@ int pim_mroute_socket_enable(struct pim_instance *pim)
 
        frr_with_privs(&pimd_privs) {
 
+#if PIM_IPV == 4
                fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
-
+#else
+               fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+#endif
                if (fd < 0) {
                        zlog_warn("Could not create mroute socket: errno=%d: %s",
                                  errno,
@@ -814,7 +609,7 @@ int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr,
                       unsigned char flags)
 {
        struct pim_interface *pim_ifp = ifp->info;
-       struct vifctl vc;
+       pim_vifctl vc;
        int err;
 
        if (PIM_DEBUG_MROUTE)
@@ -823,9 +618,10 @@ int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr,
                           pim_ifp->pim->vrf->name);
 
        memset(&vc, 0, sizeof(vc));
-       vc.vifc_vifi = pim_ifp->mroute_vif_index;
+       vc.vc_vifi = pim_ifp->mroute_vif_index;
+#if PIM_IPV == 4
 #ifdef VIFF_USE_IFINDEX
-       vc.vifc_lcl_ifindex = ifp->ifindex;
+       vc.vc_lcl_ifindex = ifp->ifindex;
 #else
        if (ifaddr.s_addr == INADDR_ANY) {
                zlog_warn(
@@ -833,24 +629,29 @@ int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr,
                        __func__);
                return -1;
        }
-       memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr));
+       memcpy(&vc.vc_lcl_addr, &ifaddr, sizeof(vc.vc_lcl_addr));
+#endif
+#else
+       vc.vc_pifi = ifp->ifindex;
 #endif
-       vc.vifc_flags = flags;
-       vc.vifc_threshold = PIM_MROUTE_MIN_TTL;
-       vc.vifc_rate_limit = 0;
+       vc.vc_flags = flags;
+       vc.vc_threshold = PIM_MROUTE_MIN_TTL;
+       vc.vc_rate_limit = 0;
 
+#if PIM_IPV == 4
 #ifdef PIM_DVMRP_TUNNEL
-       if (vc.vifc_flags & VIFF_TUNNEL) {
-               memcpy(&vc.vifc_rmt_addr, &vif_remote_addr,
-                      sizeof(vc.vifc_rmt_addr));
+       if (vc.vc_flags & VIFF_TUNNEL) {
+               memcpy(&vc.vc_rmt_addr, &vif_remote_addr,
+                      sizeof(vc.vc_rmt_addr));
        }
+#endif
 #endif
 
-       err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_ADD_VIF,
+       err = setsockopt(pim_ifp->pim->mroute_socket, PIM_IPPROTO, MRT_ADD_VIF,
                         (void *)&vc, sizeof(vc));
        if (err) {
                zlog_warn(
-                       "%s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
+                       "%s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
                        __func__, pim_ifp->pim->mroute_socket, ifp->ifindex,
                        &ifaddr, flags, errno, safe_strerror(errno));
                return -2;
@@ -862,7 +663,7 @@ int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr,
 int pim_mroute_del_vif(struct interface *ifp)
 {
        struct pim_interface *pim_ifp = ifp->info;
-       struct vifctl vc;
+       pim_vifctl vc;
        int err;
 
        if (PIM_DEBUG_MROUTE)
@@ -871,13 +672,13 @@ int pim_mroute_del_vif(struct interface *ifp)
                           pim_ifp->pim->vrf->name);
 
        memset(&vc, 0, sizeof(vc));
-       vc.vifc_vifi = pim_ifp->mroute_vif_index;
+       vc.vc_vifi = pim_ifp->mroute_vif_index;
 
-       err = setsockopt(pim_ifp->pim->mroute_socket, IPPROTO_IP, MRT_DEL_VIF,
+       err = setsockopt(pim_ifp->pim->mroute_socket, PIM_IPPROTO, MRT_DEL_VIF,
                         (void *)&vc, sizeof(vc));
        if (err) {
                zlog_warn(
-                       "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
+                       "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
                        __FILE__, __func__, pim_ifp->pim->mroute_socket,
                        pim_ifp->mroute_vif_index, errno, safe_strerror(errno));
                return -2;
@@ -985,20 +786,21 @@ static int pim_mroute_add(struct channel_oil *c_oil, const char *name)
            && *oil_parent(c_oil) != 0) {
                *oil_parent(tmp_oil) = 0;
        }
-       err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
+       /* For IPv6 MRT_ADD_MFC is defined to MRT6_ADD_MFC */
+       err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC,
                         &tmp_oil->oil, sizeof(tmp_oil->oil));
 
        if (!err && !c_oil->installed
            && !pim_addr_is_any(*oil_origin(c_oil))
            && *oil_parent(c_oil) != 0) {
                *oil_parent(tmp_oil) = *oil_parent(c_oil);
-               err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_ADD_MFC,
+               err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC,
                                 &tmp_oil->oil, sizeof(tmp_oil->oil));
        }
 
        if (err) {
                zlog_warn(
-                       "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
+                       "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_MFC): errno=%d: %s",
                        __FILE__, __func__, pim->mroute_socket, errno,
                        safe_strerror(errno));
                return -2;
@@ -1174,12 +976,12 @@ int pim_mroute_del(struct channel_oil *c_oil, const char *name)
                return -2;
        }
 
-       err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_DEL_MFC,
+       err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_DEL_MFC,
                         &c_oil->oil, sizeof(c_oil->oil));
        if (err) {
                if (PIM_DEBUG_MROUTE)
                        zlog_warn(
-                               "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
+                               "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_MFC): errno=%d: %s",
                                __FILE__, __func__, pim->mroute_socket, errno,
                                safe_strerror(errno));
                return -2;
@@ -1201,6 +1003,7 @@ int pim_mroute_del(struct channel_oil *c_oil, const char *name)
 void pim_mroute_update_counters(struct channel_oil *c_oil)
 {
        struct pim_instance *pim = c_oil->pim;
+       pim_sioc_sg_req sgreq;
 
        c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
        c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
@@ -1219,29 +1022,33 @@ void pim_mroute_update_counters(struct channel_oil *c_oil)
                return;
        }
 
-#if PIM_IPV == 4
-       struct sioc_sg_req sgreq;
 
        memset(&sgreq, 0, sizeof(sgreq));
+
+#if PIM_IPV == 4
        sgreq.src = *oil_origin(c_oil);
        sgreq.grp = *oil_mcastgrp(c_oil);
-
        pim_zlookup_sg_statistics(c_oil);
-       if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) {
+#else
+       sgreq.src = c_oil->oil.mf6cc_origin;
+       sgreq.grp = c_oil->oil.mf6cc_mcastgrp;
+       /* TODO Zlookup_sg_statistics for V6 to be added */
+#endif
+       if (ioctl(pim->mroute_socket, PIM_SIOCGETSGCNT, &sgreq)) {
                pim_sgaddr sg;
 
                sg.src = *oil_origin(c_oil);
                sg.grp = *oil_mcastgrp(c_oil);
 
-               zlog_warn("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
-                         (unsigned long)SIOCGETSGCNT, &sg,
-                         errno, safe_strerror(errno));
+               zlog_warn(
+                       "ioctl(PIM_SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
+                       (unsigned long)PIM_SIOCGETSGCNT, &sg, errno,
+                       safe_strerror(errno));
                return;
        }
 
        c_oil->cc.pktcnt = sgreq.pktcnt;
        c_oil->cc.bytecnt = sgreq.bytecnt;
        c_oil->cc.wrong_if = sgreq.wrong_if;
-#endif
        return;
 }
index 14b0a8ccafceae6bbc53ca0993e5b9f25ea7cbce..35ba60bf35039eb5ade0b0744cdc2af6e0561083 100644 (file)
 #define __EXTENSIONS__
 #endif
 
-#include <netinet/in.h>
-#ifdef HAVE_NETINET_IP_MROUTE_H
-#include <netinet/ip_mroute.h>
-#endif
 
 #define PIM_MROUTE_MIN_TTL (1)
 
 #if PIM_IPV == 4
+
+#include <netinet/in.h>
 #if defined(HAVE_LINUX_MROUTE_H)
 #include <linux/mroute.h>
 #else
-/*
-  Below: from <linux/mroute.h>
-*/
-
-#ifndef MAXVIFS
-#define MAXVIFS (256)
+#ifndef VTYSH_EXTRACT_PL
+#include "linux/mroute.h"
 #endif
-
-#ifndef SIOCGETVIFCNT
-#define SIOCGETVIFCNT   SIOCPROTOPRIVATE        /* IP protocol privates */
-#define SIOCGETSGCNT    (SIOCPROTOPRIVATE+1)
-#define SIOCGETRPF      (SIOCPROTOPRIVATE+2)
 #endif
 
-#ifndef MRT_INIT
-#define MRT_BASE     200
-#define MRT_INIT     (MRT_BASE)      /* Activate the kernel mroute code      */
-#define MRT_DONE     (MRT_BASE+1)    /* Shutdown the kernel mroute           */
-#define MRT_ADD_VIF  (MRT_BASE+2)    /* Add a virtual interface              */
-#define MRT_DEL_VIF  (MRT_BASE+3)    /* Delete a virtual interface           */
-#define MRT_ADD_MFC  (MRT_BASE+4)    /* Add a multicast forwarding entry     */
-#define MRT_DEL_MFC  (MRT_BASE+5)    /* Delete a multicast forwarding entry  */
-#define MRT_VERSION  (MRT_BASE+6)    /* Get the kernel multicast version     */
-#define MRT_ASSERT   (MRT_BASE+7)    /* Activate PIM assert mode             */
-#define MRT_PIM      (MRT_BASE+8)    /* enable PIM code      */
-#endif
+typedef struct vifctl pim_vifctl;
+typedef struct igmpmsg kernmsg;
+typedef struct sioc_sg_req pim_sioc_sg_req;
 
-#ifndef MRT_TABLE
-#define MRT_TABLE    (209)           /* Specify mroute table ID */
-#endif
+#define vc_vifi vifc_vifi
+#define vc_flags vifc_flags
+#define vc_threshold vifc_threshold
+#define vc_rate_limit vifc_rate_limit
+#define vc_lcl_addr vifc_lcl_addr
+#define vc_lcl_ifindex vifc_lcl_ifindex
+#define vc_rmt_addr vifc_rmt_addr
 
-#ifndef HAVE_VIFI_T
-typedef unsigned short vifi_t;
-#endif
+#define msg_im_vif im_vif
+#define msg_im_src im_src
+#define msg_im_dst im_dst
 
-#ifndef HAVE_STRUCT_VIFCTL
-struct vifctl {
-       vifi_t vifc_vifi;            /* Index of VIF */
-       unsigned char vifc_flags;     /* VIFF_ flags */
-       unsigned char vifc_threshold; /* ttl limit */
-       unsigned int vifc_rate_limit; /* Rate limiter values (NI) */
-       struct in_addr vifc_lcl_addr; /* Our address */
-       struct in_addr vifc_rmt_addr; /* IPIP tunnel addr */
-};
+#ifndef IGMPMSG_WRVIFWHOLE
+#define IGMPMSG_WRVIFWHOLE 4 /* For PIM processing */
 #endif
 
-#ifndef HAVE_STRUCT_MFCCTL
-struct mfcctl {
-       struct in_addr mfcc_origin;       /* Origin of mcast      */
-       struct in_addr mfcc_mcastgrp;     /* Group in question    */
-       vifi_t mfcc_parent;               /* Where it arrived     */
-       unsigned char mfcc_ttls[MAXVIFS]; /* Where it is going    */
-       unsigned int mfcc_pkt_cnt;      /* pkt count for src-grp */
-       unsigned int mfcc_byte_cnt;
-       unsigned int mfcc_wrong_if;
-       int mfcc_expire;
-};
+#ifndef PIM_IPPROTO
+#define PIM_IPPROTO IPPROTO_IP
+#endif
+#ifndef PIM_SIOCGETSGCNT
+#define PIM_SIOCGETSGCNT SIOCGETSGCNT
 #endif
 
-/*
- *      Group count retrieval for mrouted
- */
-/*
-  struct sioc_sg_req sgreq;
-  memset(&sgreq, 0, sizeof(sgreq));
-  memcpy(&sgreq.src, &source_addr, sizeof(sgreq.src));
-  memcpy(&sgreq.grp, &group_addr, sizeof(sgreq.grp));
-  ioctl(mrouter_s4, SIOCGETSGCNT, &sgreq);
- */
-#ifndef HAVE_STRUCT_SIOC_SG_REQ
-struct sioc_sg_req {
-       struct in_addr src;
-       struct in_addr grp;
-       unsigned long pktcnt;
-       unsigned long bytecnt;
-       unsigned long wrong_if;
-};
+#else /* PIM_IPV != 4 */
+
+#include <netinet/ip6.h>
+
+#if defined(HAVE_LINUX_MROUTE6_H)
+#include <linux/mroute6.h>
+#else
+#ifndef VTYSH_EXTRACT_PL
+#include "linux/mroute6.h"
+#endif
 #endif
 
-/*
- *      To get vif packet counts
- */
-/*
-  struct sioc_vif_req vreq;
-  memset(&vreq, 0, sizeof(vreq));
-  vreq.vifi = vif_index;
-  ioctl(mrouter_s4, SIOCGETVIFCNT, &vreq);
- */
-#ifndef HAVE_STRUCT_SIOC_VIF_REQ
-struct sioc_vif_req {
-       vifi_t vifi;      /* Which iface */
-       unsigned long icount; /* In packets */
-       unsigned long ocount; /* Out packets */
-       unsigned long ibytes; /* In bytes */
-       unsigned long obytes; /* Out bytes */
-};
+#ifndef MRT_INIT
+#define MRT_BASE MRT6_BASE
+#define MRT_INIT MRT6_INIT
+#define MRT_DONE MRT6_DONE
+#define MRT_ADD_VIF MRT6_ADD_MIF
+#define MRT_DEL_VIF MRT6_DEL_MIF
+#define MRT_ADD_MFC MRT6_ADD_MFC
+#define MRT_DEL_MFC MRT6_DEL_MFC
+#define MRT_VERSION MRT6_VERSION
+#define MRT_ASSERT MRT6_ASSERT
+#define MRT_PIM MRT6_PIM
 #endif
 
-/*
- *      Pseudo messages used by mrouted
- */
-#ifndef IGMPMSG_NOCACHE
-#define IGMPMSG_NOCACHE         1               /* Kern cache fill request to mrouted */
-#define IGMPMSG_WRONGVIF        2               /* For PIM assert processing (unused) */
-#define IGMPMSG_WHOLEPKT        3               /* For PIM Register processing */
+#ifndef PIM_IPPROTO
+#define PIM_IPPROTO IPPROTO_IPV6
 #endif
 
-#ifndef HAVE_STRUCT_IGMPMSG
-struct igmpmsg {
-       uint32_t unused1, unused2;
-       unsigned char im_msgtype; /* What is this */
-       unsigned char im_mbz;     /* Must be zero */
-       unsigned char im_vif;     /* Interface (this ought to be a vifi_t!) */
-       unsigned char unused3;
-       struct in_addr im_src, im_dst;
-};
+#ifndef PIM_SIOCGETSGCNT
+#define PIM_SIOCGETSGCNT SIOCGETSGCNT_IN6
 #endif
 
-#endif /* HAVE_LINUX_MROUTE_H */
+#ifndef MRT6MSG_WRMIFWHOLE
+#define MRT6MSG_WRMIFWHOLE 4 /* For PIM processing */
+#endif
 
-typedef struct mfcctl pim_mfcctl;
+typedef struct mif6ctl pim_vifctl;
+typedef struct mrt6msg kernmsg;
+typedef mifi_t vifi_t;
+typedef struct sioc_sg_req6 pim_sioc_sg_req;
 
-#else /* PIM_IPV != 4 */
-#if defined(HAVE_LINUX_MROUTE6_H)
-#include <linux/mroute6.h>
-#endif
+#define vc_vifi mif6c_mifi
+#define vc_flags mif6c_flags
+#define vc_threshold vifc_threshold
+#define vc_pifi mif6c_pifi
+#define vc_rate_limit vifc_rate_limit
 
-typedef struct mf6cctl pim_mfcctl;
+#define msg_im_vif im6_mif
+#define msg_im_src im6_src
+#define msg_im_dst im6_dst
 
+#ifndef MAXVIFS
 #define MAXVIFS IF_SETSIZE
 #endif
 
-#ifndef IGMPMSG_WRVIFWHOLE
-#define IGMPMSG_WRVIFWHOLE      4               /* For PIM processing */
+#define VIFF_REGISTER MIFF_REGISTER
 #endif
 
+
 /*
   Above: from <linux/mroute.h>
 */
@@ -201,4 +155,11 @@ int pim_mroute_del(struct channel_oil *c_oil, const char *name);
 void pim_mroute_update_counters(struct channel_oil *c_oil);
 bool pim_mroute_allow_iif_in_oil(struct channel_oil *c_oil,
                int oif_index);
+int pim_mroute_msg(struct pim_instance *pim, const char *buf, size_t buf_size,
+                  ifindex_t ifindex);
+int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg);
+int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, const char *buf);
+int pim_mroute_msg_wrongvif(int fd, struct interface *ifp, const kernmsg *msg);
+int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, const char *buf);
+int pim_mroute_set(struct pim_instance *pim, int enable);
 #endif /* PIM_MROUTE_H */
diff --git a/pimd/pim_mroute_msg.c b/pimd/pim_mroute_msg.c
new file mode 100644 (file)
index 0000000..7d80488
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * PIM for Quagga
+ * Copyright (C) 2022  Dell Technologies Ltd
+ *
+ * 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 "log.h"
+#include "privs.h"
+#include "if.h"
+#include "prefix.h"
+#include "vty.h"
+#include "plist.h"
+#include "sockopt.h"
+#include "lib_errors.h"
+#include "lib/network.h"
+
+#include "pimd.h"
+#include "pim_mroute.h"
+#include "pim_oil.h"
+#include "pim_str.h"
+#include "pim_iface.h"
+#include "pim_macro.h"
+#include "pim_rp.h"
+#include "pim_oil.h"
+#include "pim_msg.h"
+#include "pim_sock.h"
+
+
+int pim_mroute_set(struct pim_instance *pim, int enable)
+{
+       int err;
+       int opt, data;
+       socklen_t data_len = sizeof(data);
+
+       /*
+        * We need to create the VRF table for the pim mroute_socket
+        */
+       if (pim->vrf->vrf_id != VRF_DEFAULT) {
+               frr_with_privs(&pimd_privs) {
+
+                       data = pim->vrf->data.l.table_id;
+                       err = setsockopt(pim->mroute_socket, PIM_IPPROTO,
+                                       MRT_TABLE, &data, data_len);
+                       if (err) {
+                               zlog_warn(
+                                       "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO, MRT_TABLE=%d): errno=%d: %s",
+                                       __FILE__, __func__, pim->mroute_socket,
+                                       data, errno, safe_strerror(errno));
+                               return -1;
+                       }
+
+               }
+       }
+
+       frr_with_privs(&pimd_privs) {
+               opt = enable ? MRT_INIT : MRT_DONE;
+               /*
+                * *BSD *cares* about what value we pass down
+                * here
+                */
+               data = 1;
+               err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &data,
+                               data_len);
+               if (err) {
+                       zlog_warn(
+                               "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,%s=%d): errno=%d: %s",
+                               __FILE__, __func__, pim->mroute_socket,
+                               enable ? "MRT_INIT" : "MRT_DONE", data, errno,
+                               safe_strerror(errno));
+                       return -1;
+               }
+       }
+
+#if defined(HAVE_IP_PKTINFO)
+       if (enable) {
+               /* Linux and Solaris IP_PKTINFO */
+               data = 1;
+               if (setsockopt(pim->mroute_socket, PIM_IPPROTO, IP_PKTINFO,
+                               &data, data_len)) {
+                       zlog_warn(
+                               "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
+                               pim->mroute_socket, errno,
+                               safe_strerror(errno));
+               }
+       }
+#endif
+
+       setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8);
+
+       if (set_nonblocking (pim->mroute_socket) < 0) {
+               zlog_warn(
+                       "Could not set non blocking on socket fd=%d: errno=%d: %s",
+                       pim->mroute_socket, errno,
+                       safe_strerror(errno));
+       }
+
+       if (enable) {
+#if defined linux
+               int upcalls = IGMPMSG_WRVIFWHOLE;
+               opt = MRT_PIM;
+
+               err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &upcalls,
+                               sizeof(upcalls));
+               if (err) {
+                       zlog_warn(
+                               "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
+                               errno, safe_strerror(errno));
+                       return -1;
+               }
+#else
+               zlog_warn(
+                       "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
+#endif
+
+       }
+
+       return 0;
+}
+
+static const char *const igmpmsgtype2str[IGMPMSG_WRVIFWHOLE + 1] = {
+       "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
+
+
+int pim_mroute_msg(struct pim_instance *pim, const char *buf,
+                         size_t buf_size, ifindex_t ifindex)
+{
+       struct interface *ifp;
+       const struct ip *ip_hdr;
+       const struct igmpmsg *msg;
+
+       if (buf_size < (int)sizeof(struct ip))
+               return 0;
+
+       ip_hdr = (const struct ip *)buf;
+
+       if (ip_hdr->ip_p == IPPROTO_IGMP) {
+               struct pim_interface *pim_ifp;
+               struct in_addr ifaddr;
+               struct gm_sock *igmp;
+               const struct prefix *connected_src;
+
+               /* We have the IP packet but we do not know which interface this
+                * packet was
+                * received on. Find the interface that is on the same subnet as
+                * the source
+                * of the IP packet.
+                */
+               ifp = if_lookup_by_index(ifindex, pim->vrf->vrf_id);
+
+               if (!ifp || !ifp->info)
+                       return 0;
+
+               connected_src = pim_if_connected_to_source(ifp, ip_hdr->ip_src);
+
+               if (!connected_src) {
+                       if (PIM_DEBUG_IGMP_PACKETS) {
+                               zlog_debug(
+                                       "Recv IGMP packet on interface: %s from a non-connected source: %pI4",
+                                       ifp->name, &ip_hdr->ip_src);
+                       }
+                       return 0;
+               }
+
+               pim_ifp = ifp->info;
+               ifaddr = connected_src->u.prefix4;
+               igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list,
+                                                  ifaddr);
+
+               if (PIM_DEBUG_IGMP_PACKETS) {
+                       zlog_debug(
+                               "%s(%s): igmp kernel upcall on %s(%p) for %pI4 -> %pI4",
+                               __func__, pim->vrf->name, ifp->name, igmp,
+                               &ip_hdr->ip_src, &ip_hdr->ip_dst);
+               }
+               if (igmp)
+                       pim_igmp_packet(igmp, (char *)buf, buf_size);
+               else if (PIM_DEBUG_IGMP_PACKETS) {
+                       zlog_debug(
+                               "No IGMP socket on interface: %s with connected source: %pFX",
+                               ifp->name, connected_src);
+               }
+       } else if (ip_hdr->ip_p) {
+               if (PIM_DEBUG_MROUTE_DETAIL) {
+                       zlog_debug(
+                               "%s: no kernel upcall proto=%d src: %pI4 dst: %pI4 msg_size=%ld",
+                               __func__, ip_hdr->ip_p, &ip_hdr->ip_src,
+                               &ip_hdr->ip_dst, (long int)buf_size);
+               }
+
+       } else {
+               msg = (const struct igmpmsg *)buf;
+
+               ifp = pim_if_find_by_vif_index(pim, msg->im_vif);
+
+               if (!ifp)
+                       return 0;
+               if (PIM_DEBUG_MROUTE) {
+                       zlog_debug(
+                               "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI4,%pI4) on %s vifi=%d  size=%ld",
+                               __func__, igmpmsgtype2str[msg->im_msgtype],
+                               msg->im_msgtype, ip_hdr->ip_p,
+                               pim->mroute_socket, &msg->im_src, &msg->im_dst,
+                               ifp->name, msg->im_vif, (long int)buf_size);
+               }
+
+               switch (msg->im_msgtype) {
+               case IGMPMSG_WRONGVIF:
+                       return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
+                                                      msg);
+               case IGMPMSG_NOCACHE:
+                       return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
+                                                     msg);
+               case IGMPMSG_WHOLEPKT:
+                       return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
+                                                      (const char *)msg);
+               case IGMPMSG_WRVIFWHOLE:
+                       return pim_mroute_msg_wrvifwhole(
+                               pim->mroute_socket, ifp, (const char *)msg);
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+}
index 456c356d9faf377e58b1982fe05f7817f3cb70f3..3ad958f097eb18e70d7442cf543481190daa878b 100644 (file)
@@ -161,10 +161,18 @@ struct pim_encoded_source_ipv6 {
 typedef struct pim_encoded_ipv4_unicast pim_encoded_unicast;
 typedef struct pim_encoded_group_ipv4   pim_encoded_group;
 typedef struct pim_encoded_source_ipv4  pim_encoded_source;
+typedef struct ip                      ipv_hdr;
+#define IPV_SRC(ip_hdr)                        ((ip_hdr))->ip_src
+#define IPV_DST(ip_hdr)                        ((ip_hdr))->ip_dst
+#define IPV_LEN(ip_hdr)                        ((ip_hdr))->ip_len
 #else
 typedef struct pim_encoded_ipv6_unicast pim_encoded_unicast;
 typedef struct pim_encoded_group_ipv6   pim_encoded_group;
 typedef struct pim_encoded_source_ipv6  pim_encoded_source;
+typedef struct ip6_hdr                         ipv_hdr;
+#define IPV_SRC(ip_hdr)                        ((ip_hdr))->ip6_src
+#define IPV_DST(ip_hdr)                        ((ip_hdr))->ip6_dst
+#define IPV_LEN(ip_hdr)                        ((ip_hdr))->ip6_plen
 #endif
 /* clang-format on */
 
index d5e459b44e98cb855ecfd1b7e45fd310ec9cf65b..5b5cc2c10319cabebd13129426423e93a1bbb780 100644 (file)
@@ -544,20 +544,27 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
 
 int pim_channel_oil_empty(struct channel_oil *c_oil)
 {
+#if PIM_IPV == 4
+       static struct mfcctl null_oil;
+#else
+       static struct mf6cctl null_oil;
+#endif
+
        if (!c_oil)
                return 1;
 
+
        /* exclude pimreg from the OIL when checking if the inherited_oil is
         * non-NULL.
         * pimreg device (in all vrfs) uses a vifi of
         * 0 (PIM_OIF_PIM_REGISTER_VIF) so we simply mfcc_ttls[0] */
+       if (oil_if_has(c_oil, 0)) {
 #if PIM_IPV == 4
-       static pim_mfcctl null_oil;
-
-       return !memcmp(&c_oil->oil.mfcc_ttls[1], &null_oil.mfcc_ttls[1],
-               sizeof(null_oil.mfcc_ttls) - sizeof(null_oil.mfcc_ttls[0]));
+               null_oil.mfcc_ttls[0] = 1;
 #else
-       CPP_NOTICE("FIXME STUB");
-       return false;
+               IF_SET(0, &null_oil.mf6cc_ifset);
 #endif
+       }
+
+       return !oil_if_cmp(&c_oil->oil, &null_oil);
 }
index a52e23351e470f78fe88cd378551bb0972bdb26e..68b5ef474efdb72781b11cf093d104b62f318c13 100644 (file)
@@ -98,7 +98,11 @@ struct channel_oil {
 
        struct rb_pim_oil_item oil_rb;
 
-       pim_mfcctl oil;
+#if PIM_IPV == 4
+       struct mfcctl oil;
+#else
+       struct mf6cctl oil;
+#endif
        int installed;
        int oil_inherited_rescan;
        int oil_size;
@@ -135,6 +139,12 @@ static inline void oil_if_set(struct channel_oil *c_oil, vifi_t ifi, uint8_t set
 {
        c_oil->oil.mfcc_ttls[ifi] = set;
 }
+
+static inline int oil_if_cmp(struct mfcctl *oil1, struct mfcctl *oil2)
+{
+       return memcmp(&oil1->mfcc_ttls[0], &oil2->mfcc_ttls[0],
+                     sizeof(oil1->mfcc_ttls));
+}
 #else
 static inline pim_addr *oil_origin(struct channel_oil *c_oil)
 {
@@ -163,6 +173,12 @@ static inline void oil_if_set(struct channel_oil *c_oil, mifi_t ifi, bool set)
        else
                IF_CLR(ifi, &c_oil->oil.mf6cc_ifset);
 }
+
+static inline int oil_if_cmp(struct mf6cctl *oil1, struct mf6cctl *oil2)
+{
+       return memcmp(&oil1->mf6cc_ifset, &oil2->mf6cc_ifset,
+                     sizeof(oil1->mf6cc_ifset));
+}
 #endif
 
 extern int pim_channel_oil_compare(const struct channel_oil *c1,
index 0ebef40c58a196447df83261c72ffaaa7521fa2d..79c64d995fef1483c4703a79df155dc5f82c2f1d 100644 (file)
@@ -35,11 +35,11 @@ int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size);
 int pim_register_recv(struct interface *ifp, pim_addr dest_addr,
                      pim_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size);
 
-void pim_register_send(const uint8_t *buf, int buf_size, struct in_addr src,
+void pim_register_send(const uint8_t *buf, int buf_size, pim_addr src,
                       struct pim_rpf *rpg, int null_register,
                       struct pim_upstream *up);
-void pim_register_stop_send(struct interface *ifp, pim_sgaddr *sg,
-                           struct in_addr src, struct in_addr originator);
+void pim_register_stop_send(struct interface *ifp, pim_sgaddr *sg, pim_addr src,
+                           pim_addr originator);
 void pim_register_join(struct pim_upstream *up);
 void pim_null_register_send(struct pim_upstream *up);
 void pim_reg_del_on_couldreg_fail(struct interface *ifp);
index cda5acb00428c53f922cf195af26b40dd7261410..9e61b03c94d85aef0c07944d0b1ce8ef5a7dde98 100644 (file)
@@ -77,6 +77,7 @@ pimd_pimd_SOURCES = \
        pimd/pim_signals.c \
        pimd/pim_zlookup.c \
        pimd/pim_zpthread.c \
+       pimd/pim_mroute_msg.c \
        # end
 
 nodist_pimd_pimd_SOURCES = \
@@ -90,6 +91,7 @@ pimd_pim6d_SOURCES = \
        pimd/pim6_main.c \
        pimd/pim6_stubs.c \
        pimd/pim6_cmd.c \
+       pimd/pim6_mroute_msg.c \
        # end
 
 nodist_pimd_pim6d_SOURCES = \