mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 13:20:12 +00:00
pim6d: Mroute changes
Mroute and supporting changes Signed-off-by: plsaranya <Saranya_Panjarathina@dell.com>
This commit is contained in:
parent
116f0dd905
commit
a5fa982256
193
include/linux/mroute.h
Normal file
193
include/linux/mroute.h
Normal file
@ -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 */
|
163
include/linux/mroute6.h
Normal file
163
include/linux/mroute6.h
Normal file
@ -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 */
|
@ -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
|
||||
|
196
pimd/pim6_mroute_msg.c
Normal file
196
pimd/pim6_mroute_msg.c
Normal file
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
@ -30,18 +30,7 @@
|
||||
#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,
|
||||
|
@ -43,121 +43,19 @@
|
||||
#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
|
||||
vc.vifc_flags = flags;
|
||||
vc.vifc_threshold = PIM_MROUTE_MIN_TTL;
|
||||
vc.vifc_rate_limit = 0;
|
||||
#else
|
||||
vc.vc_pifi = ifp->ifindex;
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
@ -30,153 +30,107 @@
|
||||
#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
|
||||
#endif
|
||||
|
||||
#ifndef SIOCGETVIFCNT
|
||||
#define SIOCGETVIFCNT SIOCPROTOPRIVATE /* IP protocol privates */
|
||||
#define SIOCGETSGCNT (SIOCPROTOPRIVATE+1)
|
||||
#define SIOCGETRPF (SIOCPROTOPRIVATE+2)
|
||||
typedef struct vifctl pim_vifctl;
|
||||
typedef struct igmpmsg kernmsg;
|
||||
typedef struct sioc_sg_req pim_sioc_sg_req;
|
||||
|
||||
#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
|
||||
|
||||
#define msg_im_vif im_vif
|
||||
#define msg_im_src im_src
|
||||
#define msg_im_dst im_dst
|
||||
|
||||
#ifndef IGMPMSG_WRVIFWHOLE
|
||||
#define IGMPMSG_WRVIFWHOLE 4 /* For PIM processing */
|
||||
#endif
|
||||
|
||||
#ifndef PIM_IPPROTO
|
||||
#define PIM_IPPROTO IPPROTO_IP
|
||||
#endif
|
||||
#ifndef PIM_SIOCGETSGCNT
|
||||
#define PIM_SIOCGETSGCNT SIOCGETSGCNT
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#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 */
|
||||
#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
|
||||
|
||||
#ifndef MRT_TABLE
|
||||
#define MRT_TABLE (209) /* Specify mroute table ID */
|
||||
#ifndef PIM_IPPROTO
|
||||
#define PIM_IPPROTO IPPROTO_IPV6
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_VIFI_T
|
||||
typedef unsigned short vifi_t;
|
||||
#ifndef PIM_SIOCGETSGCNT
|
||||
#define PIM_SIOCGETSGCNT SIOCGETSGCNT_IN6
|
||||
#endif
|
||||
|
||||
#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 MRT6MSG_WRMIFWHOLE
|
||||
#define MRT6MSG_WRMIFWHOLE 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;
|
||||
};
|
||||
#endif
|
||||
typedef struct mif6ctl pim_vifctl;
|
||||
typedef struct mrt6msg kernmsg;
|
||||
typedef mifi_t vifi_t;
|
||||
typedef struct sioc_sg_req6 pim_sioc_sg_req;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
#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
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
};
|
||||
#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 */
|
||||
#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;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_LINUX_MROUTE_H */
|
||||
|
||||
typedef struct mfcctl pim_mfcctl;
|
||||
|
||||
#else /* PIM_IPV != 4 */
|
||||
#if defined(HAVE_LINUX_MROUTE6_H)
|
||||
#include <linux/mroute6.h>
|
||||
#endif
|
||||
|
||||
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 */
|
||||
|
239
pimd/pim_mroute_msg.c
Normal file
239
pimd/pim_mroute_msg.c
Normal file
@ -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;
|
||||
}
|
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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 = \
|
||||
|
Loading…
Reference in New Issue
Block a user