2023-02-08 13:17:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2015-02-04 07:01:14 +01:00
|
|
|
/*
|
2017-05-13 10:25:29 +02:00
|
|
|
* PIM for Quagga
|
|
|
|
* Copyright (C) 2008 Everton da Silva Marques
|
|
|
|
*/
|
2015-02-04 07:01:14 +01:00
|
|
|
|
|
|
|
#include <zebra.h>
|
2024-01-04 20:26:33 +01:00
|
|
|
#include <netinet/icmp6.h>
|
2024-01-04 20:42:17 +01:00
|
|
|
#include <sys/ioctl.h>
|
2024-01-04 20:26:33 +01:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
#include "log.h"
|
|
|
|
#include "privs.h"
|
2016-06-18 02:43:21 +02:00
|
|
|
#include "if.h"
|
2016-06-29 18:12:13 +02:00
|
|
|
#include "prefix.h"
|
2016-09-13 21:41:33 +02:00
|
|
|
#include "vty.h"
|
|
|
|
#include "plist.h"
|
2017-05-10 14:36:20 +02:00
|
|
|
#include "sockopt.h"
|
2018-06-18 16:17:36 +02:00
|
|
|
#include "lib_errors.h"
|
2022-06-22 12:35:07 +02:00
|
|
|
#include "lib/network.h"
|
2015-02-04 07:01:14 +01:00
|
|
|
|
|
|
|
#include "pimd.h"
|
2016-08-10 22:16:22 +02:00
|
|
|
#include "pim_rpf.h"
|
2015-02-04 07:01:14 +01:00
|
|
|
#include "pim_mroute.h"
|
2015-10-28 20:22:22 +01:00
|
|
|
#include "pim_oil.h"
|
2015-02-04 07:01:14 +01:00
|
|
|
#include "pim_str.h"
|
|
|
|
#include "pim_time.h"
|
|
|
|
#include "pim_iface.h"
|
|
|
|
#include "pim_macro.h"
|
2015-10-27 21:13:23 +01:00
|
|
|
#include "pim_rp.h"
|
2015-10-29 14:41:24 +01:00
|
|
|
#include "pim_oil.h"
|
2015-10-29 19:27:39 +01:00
|
|
|
#include "pim_register.h"
|
2016-07-15 21:42:09 +02:00
|
|
|
#include "pim_ifchannel.h"
|
2016-08-11 02:04:20 +02:00
|
|
|
#include "pim_zlookup.h"
|
2017-03-17 19:51:13 +01:00
|
|
|
#include "pim_ssm.h"
|
2017-05-24 16:37:23 +02:00
|
|
|
#include "pim_sock.h"
|
2019-03-24 20:31:50 +01:00
|
|
|
#include "pim_vxlan.h"
|
2022-03-03 17:25:50 +01:00
|
|
|
#include "pim_msg.h"
|
2024-11-25 17:36:54 +01:00
|
|
|
#include "pim_util.h"
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2017-05-11 03:34:27 +02:00
|
|
|
static void mroute_read_on(struct pim_instance *pim);
|
2022-06-01 09:54:31 +02:00
|
|
|
static int pim_upstream_mroute_update(struct channel_oil *c_oil,
|
|
|
|
const char *name);
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2022-06-22 12:35:07 +02:00
|
|
|
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
|
|
|
|
*/
|
2023-04-26 11:59:58 +02:00
|
|
|
if (enable && pim->vrf->vrf_id != VRF_DEFAULT) {
|
2022-06-22 12:35:07 +02:00
|
|
|
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) {
|
2024-05-30 21:48:33 +02:00
|
|
|
if (err == ENOPROTOOPT)
|
|
|
|
zlog_err("%s Kernel is not compiled with CONFIG_IP_MROUTE_MULTIPLE_TABLES and vrf's will not work",
|
|
|
|
__func__);
|
|
|
|
else
|
|
|
|
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));
|
2022-06-22 12:35:07 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
#if PIM_IPV == 6
|
|
|
|
if (enable) {
|
|
|
|
/* Linux and Solaris IPV6_PKTINFO */
|
|
|
|
data = 1;
|
|
|
|
if (setsockopt(pim->mroute_socket, PIM_IPPROTO,
|
|
|
|
IPV6_RECVPKTINFO, &data, data_len)) {
|
|
|
|
zlog_warn(
|
|
|
|
"Could not set IPV6_RECVPKTINFO 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));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (enable) {
|
|
|
|
#if defined linux
|
|
|
|
int upcalls = GMMSG_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 gmmsgtype2str[GMMSG_WRVIFWHOLE + 1] = {
|
|
|
|
"<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-03-03 17:25:50 +01:00
|
|
|
int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2015-10-23 16:10:30 +02:00
|
|
|
struct pim_interface *pim_ifp = ifp->info;
|
2015-10-29 14:41:24 +01:00
|
|
|
struct pim_upstream *up;
|
2022-01-04 17:54:44 +01:00
|
|
|
pim_sgaddr sg;
|
2022-06-01 09:54:31 +02:00
|
|
|
bool desync = false;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-03-10 13:59:26 +01:00
|
|
|
memset(&sg, 0, sizeof(sg));
|
|
|
|
sg.src = msg->msg_im_src;
|
|
|
|
sg.grp = msg->msg_im_dst;
|
|
|
|
|
2023-02-28 07:50:29 +01:00
|
|
|
|
|
|
|
if (!pim_ifp || !pim_ifp->pim_enable) {
|
2022-03-10 13:59:26 +01:00
|
|
|
if (PIM_DEBUG_MROUTE)
|
|
|
|
zlog_debug(
|
2023-02-28 07:50:29 +01:00
|
|
|
"%s: %s on interface, dropping packet to %pSG",
|
|
|
|
ifp->name,
|
|
|
|
!pim_ifp ? "Multicast not enabled"
|
|
|
|
: "PIM not enabled",
|
|
|
|
&sg);
|
2022-03-10 13:59:26 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-05-06 15:39:26 +02:00
|
|
|
if (!pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
|
|
|
|
/* for ASM, check that we have enough information (i.e. path
|
|
|
|
* to RP) to make a decision on what to do with this packet.
|
|
|
|
*
|
|
|
|
* for SSM, this is meaningless, everything is join-driven,
|
|
|
|
* and for NOCACHE we need to install an empty OIL MFC entry
|
|
|
|
* so the kernel doesn't keep nagging us.
|
|
|
|
*/
|
|
|
|
struct pim_rpf *rpg;
|
2024-10-02 14:22:48 +02:00
|
|
|
#if PIM_IPV == 6
|
|
|
|
pim_addr embedded_rp;
|
|
|
|
|
|
|
|
if (pim_ifp->pim->embedded_rp.enable &&
|
|
|
|
pim_embedded_rp_extract(&sg.grp, &embedded_rp) &&
|
|
|
|
!pim_embedded_rp_filter_match(pim_ifp->pim, &sg.grp))
|
|
|
|
pim_embedded_rp_new(pim_ifp->pim, &sg.grp, &embedded_rp);
|
|
|
|
#endif /* PIM_IPV == 6 */
|
2022-05-06 15:39:26 +02:00
|
|
|
|
|
|
|
rpg = RP(pim_ifp->pim, msg->msg_im_dst);
|
|
|
|
if (!rpg) {
|
|
|
|
if (PIM_DEBUG_MROUTE)
|
|
|
|
zlog_debug("%s: no RPF for packet to %pSG",
|
|
|
|
ifp->name, &sg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (pim_rpf_addr_is_inaddr_any(rpg)) {
|
|
|
|
if (PIM_DEBUG_MROUTE)
|
|
|
|
zlog_debug("%s: null RPF for packet to %pSG",
|
|
|
|
ifp->name, &sg);
|
|
|
|
return 0;
|
|
|
|
}
|
2016-11-03 21:23:50 +01:00
|
|
|
}
|
2015-10-23 16:10:30 +02:00
|
|
|
|
2016-06-29 18:12:13 +02:00
|
|
|
/*
|
|
|
|
* If we've received a multicast packet that isn't connected to
|
|
|
|
* us
|
|
|
|
*/
|
2022-03-03 17:25:50 +01:00
|
|
|
if (!pim_if_connected_to_source(ifp, msg->msg_im_src)) {
|
2022-03-10 13:59:26 +01:00
|
|
|
if (PIM_DEBUG_MROUTE)
|
2016-08-17 01:22:32 +02:00
|
|
|
zlog_debug(
|
2022-03-10 13:59:26 +01:00
|
|
|
"%s: incoming packet to %pSG from non-connected source",
|
|
|
|
ifp->name, &sg);
|
2016-06-29 18:12:13 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-21 17:41:46 +02:00
|
|
|
if (!(PIM_I_am_DR(pim_ifp))) {
|
2022-03-10 13:59:26 +01:00
|
|
|
/* unlike the other debug messages, this one is further in the
|
|
|
|
* "normal operation" category and thus under _DETAIL
|
|
|
|
*/
|
2018-09-21 17:41:46 +02:00
|
|
|
if (PIM_DEBUG_MROUTE_DETAIL)
|
2022-03-03 17:25:50 +01:00
|
|
|
zlog_debug(
|
2022-03-10 13:59:26 +01:00
|
|
|
"%s: not DR on interface, not forwarding traffic for %pSG",
|
|
|
|
ifp->name, &sg);
|
2018-09-21 17:41:46 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We are not the DR, but we are still receiving packets
|
|
|
|
* Let's blackhole those packets for the moment
|
|
|
|
* As that they will be coming up to the cpu
|
|
|
|
* and causing us to consider them.
|
2019-06-14 02:03:08 +02:00
|
|
|
*
|
|
|
|
* This *will* create a dangling channel_oil
|
|
|
|
* that I see no way to get rid of. Just noting
|
|
|
|
* this for future reference.
|
2018-09-21 17:41:46 +02:00
|
|
|
*/
|
2019-07-09 02:00:43 +02:00
|
|
|
up = pim_upstream_find_or_add(
|
2020-03-05 19:17:54 +01:00
|
|
|
&sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE, __func__);
|
|
|
|
pim_upstream_mroute_add(up->channel_oil, __func__);
|
2018-09-21 17:41:46 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-10 16:26:00 +01:00
|
|
|
up = pim_upstream_find_or_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR,
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__);
|
2022-06-01 09:54:31 +02:00
|
|
|
if (up->channel_oil->installed) {
|
|
|
|
zlog_warn(
|
|
|
|
"%s: NOCACHE for %pSG, MFC entry disappeared - reinstalling",
|
|
|
|
ifp->name, &sg);
|
|
|
|
desync = true;
|
|
|
|
}
|
2016-08-09 14:05:48 +02:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/*
|
2017-03-10 16:26:00 +01:00
|
|
|
* I moved this debug till after the actual add because
|
|
|
|
* I want to take advantage of the up->sg_str being filled in.
|
2017-07-17 14:03:14 +02:00
|
|
|
*/
|
2017-03-10 16:26:00 +01:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
|
|
|
zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, up->sg_str);
|
2015-10-29 14:41:24 +01:00
|
|
|
}
|
2016-11-17 14:17:25 +01:00
|
|
|
|
2016-09-13 14:20:39 +02:00
|
|
|
PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
|
2017-07-13 03:16:00 +02:00
|
|
|
pim_upstream_keep_alive_timer_start(up, pim_ifp->pim->keep_alive_time);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-13 20:22:42 +02:00
|
|
|
up->channel_oil->cc.pktcnt++;
|
pimd: Pim Nexthop Tracking support with ECMP
In this patch, PIM nexthop tracking uses locally populated nexthop cached list
to determine ECMP based nexthop (w/ ECMP knob enabled), otherwise picks
the first nexthop as RPF.
Introduced '[no] ip pim ecmp' command to enable/disable PIM ECMP knob.
By default, PIM ECMP is disabled.
Intorudced '[no] ip pim ecmp rebalance' command to provide existing mcache
entry to switch new path based on hash chosen path.
Introduced, show command to display pim registered addresses and respective nexthops.
Introuduce, show command to find nexthop and out interface for (S,G) or (RP,G).
Re-Register an address with nexthop when Interface UP event received,
to ensure the PIM nexthop cache is updated (being PIM enabled).
During PIM neighbor UP, traverse all RPs and Upstreams nexthop and determine, if
any of nexthop's IPv4 address changes/resolves due to neigbor UP event.
Testing Done: Run various LHR, RP and FHR related cases to resolve RPF using
nexthop cache with ECMP knob disabled, performed interface/PIM neighbor flap events.
Executed pim-smoke with knob disabled.
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2017-04-05 22:14:12 +02:00
|
|
|
// resolve mfcc_parent prior to mroute_add in channel_add_oif
|
2019-02-22 10:59:07 +01:00
|
|
|
if (up->rpf.source_nexthop.interface &&
|
2023-09-14 13:18:37 +02:00
|
|
|
*oil_incoming_vif(up->channel_oil) >= MAXVIFS) {
|
2019-11-15 20:09:13 +01:00
|
|
|
pim_upstream_mroute_iif_update(up->channel_oil, __func__);
|
pimd: Pim Nexthop Tracking support with ECMP
In this patch, PIM nexthop tracking uses locally populated nexthop cached list
to determine ECMP based nexthop (w/ ECMP knob enabled), otherwise picks
the first nexthop as RPF.
Introduced '[no] ip pim ecmp' command to enable/disable PIM ECMP knob.
By default, PIM ECMP is disabled.
Intorudced '[no] ip pim ecmp rebalance' command to provide existing mcache
entry to switch new path based on hash chosen path.
Introduced, show command to display pim registered addresses and respective nexthops.
Introuduce, show command to find nexthop and out interface for (S,G) or (RP,G).
Re-Register an address with nexthop when Interface UP event received,
to ensure the PIM nexthop cache is updated (being PIM enabled).
During PIM neighbor UP, traverse all RPs and Upstreams nexthop and determine, if
any of nexthop's IPv4 address changes/resolves due to neigbor UP event.
Testing Done: Run various LHR, RP and FHR related cases to resolve RPF using
nexthop cache with ECMP knob disabled, performed interface/PIM neighbor flap events.
Executed pim-smoke with knob disabled.
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2017-04-05 22:14:12 +02:00
|
|
|
}
|
2024-11-25 17:36:54 +01:00
|
|
|
|
|
|
|
if (!pim_is_group_filtered(pim_ifp, &sg.grp, &sg.src))
|
|
|
|
pim_register_join(up);
|
2020-03-16 02:37:07 +01:00
|
|
|
/* if we have receiver, inherit from parent */
|
|
|
|
pim_upstream_inherited_olist_decide(pim_ifp->pim, up);
|
2015-10-29 14:41:24 +01:00
|
|
|
|
2022-06-01 09:54:31 +02:00
|
|
|
/* we just got NOCACHE from the kernel, so... MFC is not in the
|
|
|
|
* kernel for some reason or another. Try installing again.
|
|
|
|
*/
|
|
|
|
if (desync)
|
|
|
|
pim_upstream_mroute_update(up->channel_oil, __func__);
|
2015-10-20 15:00:02 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2022-05-03 15:49:26 +02:00
|
|
|
int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, const char *buf,
|
|
|
|
size_t len)
|
2015-10-20 15:00:02 +02:00
|
|
|
{
|
2015-10-29 14:41:24 +01:00
|
|
|
struct pim_interface *pim_ifp;
|
2022-01-04 17:54:44 +01:00
|
|
|
pim_sgaddr sg;
|
2015-10-28 15:00:31 +01:00
|
|
|
struct pim_rpf *rpg;
|
2022-03-03 17:25:50 +01:00
|
|
|
const ipv_hdr *ip_hdr;
|
2015-10-29 14:41:24 +01:00
|
|
|
struct pim_upstream *up;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-20 01:36:53 +02:00
|
|
|
pim_ifp = ifp->info;
|
|
|
|
|
2022-03-03 17:25:50 +01:00
|
|
|
ip_hdr = (const ipv_hdr *)buf;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-01-04 17:54:44 +01:00
|
|
|
memset(&sg, 0, sizeof(sg));
|
2022-03-03 17:25:50 +01:00
|
|
|
sg.src = IPV_SRC(ip_hdr);
|
|
|
|
sg.grp = IPV_DST(ip_hdr);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-20 01:36:53 +02:00
|
|
|
up = pim_upstream_find(pim_ifp->pim, &sg);
|
2015-10-29 14:41:24 +01:00
|
|
|
if (!up) {
|
2022-01-04 17:54:44 +01:00
|
|
|
pim_sgaddr star = sg;
|
2022-01-05 16:07:17 +01:00
|
|
|
star.src = PIMADDR_ANY;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-20 01:36:53 +02:00
|
|
|
up = pim_upstream_find(pim_ifp->pim, &star);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-02-06 18:30:51 +01:00
|
|
|
if (up && PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags)) {
|
2017-05-24 16:37:23 +02:00
|
|
|
up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
|
pimd: Allow SPT switchover
This allows SPT switchover for S,G upon receipt of packets
on the LHR.
1) When we create a *,G from a IGMP Group Report, install
the *,G route with the pimreg device on the OIL.
2) When a packet hits the LHR that matches the *,G, we will
get a WHOLEPKT callback from the kernel and if we cannot
find the S,G, that means we have matched it on the LHR via
the *,G mroute. Create the S,G start the KAT and run
inherited_olist.
3) When the S,G times out, safely remove the S,G via
the KAT expiry
4) When the *,G is removed, remove any S,G associated
with it via the LHR flag.
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
2017-03-23 02:07:57 +01:00
|
|
|
PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, NULL);
|
2017-03-30 16:50:04 +02:00
|
|
|
if (!up) {
|
|
|
|
if (PIM_DEBUG_MROUTE)
|
2022-03-03 17:25:50 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%s: Unable to create upstream information for %pSG",
|
|
|
|
__func__, &sg);
|
2017-03-30 16:50:04 +02:00
|
|
|
return 0;
|
|
|
|
}
|
pimd: Allow SPT switchover
This allows SPT switchover for S,G upon receipt of packets
on the LHR.
1) When we create a *,G from a IGMP Group Report, install
the *,G route with the pimreg device on the OIL.
2) When a packet hits the LHR that matches the *,G, we will
get a WHOLEPKT callback from the kernel and if we cannot
find the S,G, that means we have matched it on the LHR via
the *,G mroute. Create the S,G start the KAT and run
inherited_olist.
3) When the S,G times out, safely remove the S,G via
the KAT expiry
4) When the *,G is removed, remove any S,G associated
with it via the LHR flag.
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
2017-03-23 02:07:57 +01:00
|
|
|
pim_upstream_keep_alive_timer_start(
|
2017-07-13 03:16:00 +02:00
|
|
|
up, pim_ifp->pim->keep_alive_time);
|
2017-05-20 01:36:53 +02:00
|
|
|
pim_upstream_inherited_olist(pim_ifp->pim, up);
|
2019-11-15 20:21:11 +01:00
|
|
|
pim_upstream_update_join_desired(pim_ifp->pim, up);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
pimd: Allow SPT switchover
This allows SPT switchover for S,G upon receipt of packets
on the LHR.
1) When we create a *,G from a IGMP Group Report, install
the *,G route with the pimreg device on the OIL.
2) When a packet hits the LHR that matches the *,G, we will
get a WHOLEPKT callback from the kernel and if we cannot
find the S,G, that means we have matched it on the LHR via
the *,G mroute. Create the S,G start the KAT and run
inherited_olist.
3) When the S,G times out, safely remove the S,G via
the KAT expiry
4) When the *,G is removed, remove any S,G associated
with it via the LHR flag.
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
2017-03-23 02:07:57 +01:00
|
|
|
if (PIM_DEBUG_MROUTE)
|
|
|
|
zlog_debug("%s: Creating %s upstream on LHR",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, up->sg_str);
|
pimd: Allow SPT switchover
This allows SPT switchover for S,G upon receipt of packets
on the LHR.
1) When we create a *,G from a IGMP Group Report, install
the *,G route with the pimreg device on the OIL.
2) When a packet hits the LHR that matches the *,G, we will
get a WHOLEPKT callback from the kernel and if we cannot
find the S,G, that means we have matched it on the LHR via
the *,G mroute. Create the S,G start the KAT and run
inherited_olist.
3) When the S,G times out, safely remove the S,G via
the KAT expiry
4) When the *,G is removed, remove any S,G associated
with it via the LHR flag.
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
2017-03-23 02:07:57 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2016-08-17 03:13:22 +02:00
|
|
|
if (PIM_DEBUG_MROUTE_DETAIL) {
|
2022-03-03 17:25:50 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%s: Unable to find upstream channel WHOLEPKT%pSG",
|
|
|
|
__func__, &sg);
|
2015-10-29 14:41:24 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-02-22 10:59:07 +01:00
|
|
|
if (!up->rpf.source_nexthop.interface) {
|
2019-11-12 14:02:06 +01:00
|
|
|
if (PIM_DEBUG_PIM_TRACE)
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug("%s: up %s RPF is not present", __func__,
|
|
|
|
up->sg_str);
|
2019-02-22 10:59:07 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-29 19:27:39 +01:00
|
|
|
pim_ifp = up->rpf.source_nexthop.interface->info;
|
|
|
|
|
2018-07-03 15:39:50 +02:00
|
|
|
rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
|
2015-10-27 21:13:23 +01:00
|
|
|
|
2022-02-25 14:17:08 +01:00
|
|
|
if ((pim_rpf_addr_is_inaddr_any(rpg)) || (!pim_ifp) ||
|
|
|
|
(!(PIM_I_am_DR(pim_ifp)))) {
|
2016-07-24 01:54:51 +02:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug("%s: Failed Check send packet", __func__);
|
2015-10-29 19:27:39 +01:00
|
|
|
}
|
2015-10-27 21:13:23 +01:00
|
|
|
return 0;
|
2015-10-23 16:10:30 +02:00
|
|
|
}
|
2015-10-23 16:37:45 +02:00
|
|
|
|
2016-07-14 23:16:42 +02:00
|
|
|
/*
|
|
|
|
* If we've received a register suppress
|
|
|
|
*/
|
|
|
|
if (!up->t_rs_timer) {
|
2017-05-21 15:30:02 +02:00
|
|
|
if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
|
2017-03-17 19:51:13 +01:00
|
|
|
if (PIM_DEBUG_PIM_REG)
|
2022-03-03 17:25:50 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%pSG register forward skipped as group is SSM",
|
|
|
|
&sg);
|
2017-03-17 19:51:13 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2019-11-15 21:28:01 +01:00
|
|
|
|
|
|
|
if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
|
|
|
|
if (PIM_DEBUG_PIM_REG)
|
|
|
|
zlog_debug(
|
|
|
|
"%s register forward skipped, not FHR",
|
|
|
|
up->sg_str);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-03-03 17:25:50 +01:00
|
|
|
pim_register_send((uint8_t *)buf + sizeof(ipv_hdr),
|
2022-05-03 15:49:26 +02:00
|
|
|
len - sizeof(ipv_hdr),
|
2017-03-17 19:51:13 +01:00
|
|
|
pim_ifp->primary_address, rpg, 0, up);
|
|
|
|
}
|
2015-10-20 15:00:02 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2022-03-03 17:25:50 +01:00
|
|
|
int pim_mroute_msg_wrongvif(int fd, struct interface *ifp, const kernmsg *msg)
|
2015-10-20 15:00:02 +02:00
|
|
|
{
|
|
|
|
struct pim_ifchannel *ch;
|
|
|
|
struct pim_interface *pim_ifp;
|
2022-01-04 17:54:44 +01:00
|
|
|
pim_sgaddr sg;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-01-04 17:54:44 +01:00
|
|
|
memset(&sg, 0, sizeof(sg));
|
2022-03-03 17:25:50 +01:00
|
|
|
sg.src = msg->msg_im_src;
|
|
|
|
sg.grp = msg->msg_im_dst;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
|
|
|
/*
|
2015-10-20 15:00:02 +02:00
|
|
|
Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-10-20 15:00:02 +02:00
|
|
|
RFC 4601 4.8.2. PIM-SSM-Only Routers
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-10-20 15:00:02 +02:00
|
|
|
iif is the incoming interface of the packet.
|
|
|
|
if (iif is in inherited_olist(S,G)) {
|
|
|
|
send Assert(S,G) on iif
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2015-10-20 15:00:02 +02:00
|
|
|
if (!ifp) {
|
2016-11-12 01:13:55 +01:00
|
|
|
if (PIM_DEBUG_MROUTE)
|
2022-03-03 17:25:50 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%s: WRONGVIF (S,G)=%pSG could not find input interface for input_vif_index=%d",
|
|
|
|
__func__, &sg, msg->msg_im_vif);
|
2015-10-20 15:00:02 +02:00
|
|
|
return -1;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2016-08-09 14:05:48 +02:00
|
|
|
pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp) {
|
2016-11-12 01:13:55 +01:00
|
|
|
if (PIM_DEBUG_MROUTE)
|
2022-03-03 17:25:50 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%s: WRONGVIF (S,G)=%pSG multicast not enabled on interface %s",
|
|
|
|
__func__, &sg, ifp->name);
|
2015-10-20 15:00:02 +02:00
|
|
|
return -2;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2016-08-09 14:05:48 +02:00
|
|
|
|
2016-07-23 05:12:06 +02:00
|
|
|
ch = pim_ifchannel_find(ifp, &sg);
|
2015-10-20 15:00:02 +02:00
|
|
|
if (!ch) {
|
2022-01-04 17:54:44 +01:00
|
|
|
pim_sgaddr star_g = sg;
|
2016-11-12 01:13:55 +01:00
|
|
|
if (PIM_DEBUG_MROUTE)
|
2022-03-03 17:25:50 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%s: WRONGVIF (S,G)=%pSG could not find channel on interface %s",
|
|
|
|
__func__, &sg, ifp->name);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-01-05 16:07:17 +01:00
|
|
|
star_g.src = PIMADDR_ANY;
|
2016-11-12 01:13:55 +01:00
|
|
|
ch = pim_ifchannel_find(ifp, &star_g);
|
|
|
|
if (!ch) {
|
|
|
|
if (PIM_DEBUG_MROUTE)
|
2022-03-03 17:25:50 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%s: WRONGVIF (*,G)=%pSG could not find channel on interface %s",
|
|
|
|
__func__, &star_g, ifp->name);
|
2015-10-20 15:00:02 +02:00
|
|
|
return -3;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/*
|
2015-10-20 15:00:02 +02:00
|
|
|
RFC 4601: 4.6.1. (S,G) Assert Message State Machine
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-10-20 15:00:02 +02:00
|
|
|
Transitions from NoInfo State
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-10-20 15:00:02 +02:00
|
|
|
An (S,G) data packet arrives on interface I, AND
|
|
|
|
CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
|
|
|
|
downstream interface that is in our (S,G) outgoing interface
|
|
|
|
list. We optimistically assume that we will be the assert
|
|
|
|
winner for this (S,G), and so we transition to the "I am Assert
|
|
|
|
Winner" state and perform Actions A1 (below), which will
|
|
|
|
initiate the assert negotiation for (S,G).
|
2017-07-17 14:03:14 +02:00
|
|
|
*/
|
|
|
|
|
2015-10-20 15:00:02 +02:00
|
|
|
if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
|
|
|
|
if (PIM_DEBUG_MROUTE) {
|
2016-08-09 14:05:48 +02:00
|
|
|
zlog_debug(
|
|
|
|
"%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, ch->sg_str, ifp->name);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2015-10-20 15:00:02 +02:00
|
|
|
return -4;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2015-10-20 15:00:02 +02:00
|
|
|
|
|
|
|
if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
|
2016-11-12 01:13:55 +01:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
2016-08-09 14:05:48 +02:00
|
|
|
zlog_debug(
|
|
|
|
"%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, ch->sg_str, ifp->name);
|
2015-10-20 15:00:02 +02:00
|
|
|
}
|
2016-11-12 01:13:55 +01:00
|
|
|
return -5;
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-10-20 15:00:02 +02:00
|
|
|
if (assert_action_a1(ch)) {
|
2016-07-24 01:54:51 +02:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
2016-08-09 14:05:48 +02:00
|
|
|
zlog_debug(
|
|
|
|
"%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, ch->sg_str, ifp->name);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2015-10-20 15:00:02 +02:00
|
|
|
return -6;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-05-03 15:49:26 +02:00
|
|
|
int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, const char *buf,
|
|
|
|
size_t len)
|
2016-08-09 18:30:26 +02:00
|
|
|
{
|
2022-03-03 17:25:50 +01:00
|
|
|
const ipv_hdr *ip_hdr = (const ipv_hdr *)buf;
|
2016-08-09 18:30:26 +02:00
|
|
|
struct pim_interface *pim_ifp;
|
2019-12-20 13:57:28 +01:00
|
|
|
struct pim_instance *pim;
|
2016-08-09 18:30:26 +02:00
|
|
|
struct pim_ifchannel *ch;
|
|
|
|
struct pim_upstream *up;
|
2022-01-04 17:54:44 +01:00
|
|
|
pim_sgaddr star_g;
|
|
|
|
pim_sgaddr sg;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-19 22:41:25 +02:00
|
|
|
pim_ifp = ifp->info;
|
|
|
|
|
2022-01-04 17:54:44 +01:00
|
|
|
memset(&sg, 0, sizeof(sg));
|
2022-03-03 17:25:50 +01:00
|
|
|
sg.src = IPV_SRC(ip_hdr);
|
|
|
|
sg.grp = IPV_DST(ip_hdr);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-08-09 18:30:26 +02:00
|
|
|
ch = pim_ifchannel_find(ifp, &sg);
|
|
|
|
if (ch) {
|
|
|
|
if (PIM_DEBUG_MROUTE)
|
|
|
|
zlog_debug(
|
|
|
|
"WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
|
2016-11-17 14:17:25 +01:00
|
|
|
ch->sg_str, ifp->name);
|
2016-08-09 18:30:26 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-02-15 02:03:18 +01:00
|
|
|
|
2016-11-12 01:13:55 +01:00
|
|
|
star_g = sg;
|
2022-01-05 16:07:17 +01:00
|
|
|
star_g.src = PIMADDR_ANY;
|
2019-12-20 13:57:28 +01:00
|
|
|
|
|
|
|
pim = pim_ifp->pim;
|
|
|
|
/*
|
|
|
|
* If the incoming interface is the pimreg, then
|
|
|
|
* we know the callback is associated with a pim register
|
|
|
|
* packet and there is nothing to do here as that
|
|
|
|
* normal pim processing will see the packet and allow
|
|
|
|
* us to do the right thing.
|
|
|
|
*/
|
|
|
|
if (ifp == pim->regiface) {
|
|
|
|
return 0;
|
|
|
|
}
|
2016-08-09 18:30:26 +02:00
|
|
|
|
2017-05-20 01:36:53 +02:00
|
|
|
up = pim_upstream_find(pim_ifp->pim, &sg);
|
2016-08-10 22:16:22 +02:00
|
|
|
if (up) {
|
2017-02-15 02:03:18 +01:00
|
|
|
struct pim_upstream *parent;
|
2016-11-01 01:49:18 +01:00
|
|
|
struct pim_nexthop source;
|
2017-05-19 22:41:25 +02:00
|
|
|
struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp);
|
pimd: avoiding crash in wrvifwhole path
Observed crash in the wrvif whole path.
RCA: Wrongvif path trying to access pim attributes of pim disabled RPF interface.
This was resulting in Null access.
(gdb) p/x rpf->source_nexthop
$19 = {last_lookup = {s_addr = 0xa282828}, last_lookup_time = 0x59c0de0828c98,
interface = 0x1013e5011300, mrib_nexthop_addr = {family = 0x2,
prefixlen = 0x20, u = {prefix = 0x28, prefix4 = {s_addr = 0xa282828},
prefix6 = {__in6_u = {__u6_addr8 = {0x28, 0x28, 0x28, 0xa,
0x0 <repeats 12 times>}, __u6_addr16 = {0x2828, 0xa28, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0}, __u6_addr32 = {0xa282828, 0x0, 0x0, 0x0}}},
lp = {id = {s_addr = 0xa282828}, adv_router = {s_addr = 0x0}},
prefix_eth = {octet = {0x28, 0x28, 0x28, 0xa, 0x0, 0x0}}, val = {0x28,
0x28, 0x28, 0xa, 0x0 <repeats 12 times>}, ptr = 0xa282828,
prefix_evpn = {route_type = 0x28, u = {_ead_addr = {esi = {val = {0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, eth_tag = 0x0},
_macip_addr = {eth_tag = 0x0, ip_prefix_length = 0x0, mac = {
octet = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, ip = {ipa_type = 0x0,
ip = {addr = 0x0, _v4_addr = {s_addr = 0x0}, _v6_addr = {
__in6_u = {__u6_addr8 = {0x0 <repeats 16 times>},
__u6_addr16 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
__u6_addr32 = {0x0, 0x0, 0x0, 0x0}}}}}}, _imet_addr = {
eth_tag = 0x0, ip_prefix_length = 0x0, ip = {ipa_type = 0x0, ip = {
addr = 0x0, _v4_addr = {s_addr = 0x0}, _v6_addr = {__in6_u = {
__u6_addr8 = {0x0 <repeats 16 times>}, __u6_addr16 = {0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, __u6_addr32 = {0x0,
0x0, 0x0, 0x0}}}}}}, _es_addr = {esi = {val = {0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}},
---Type <return> to continue, or q <return> to quit---q
ip_prefix_length = 0x0Quit
(gdb) p/x rpf->source_nexthop.interface
$20 = 0x1013e5011300
(gdb) p/x rpf->source_nexthop.interface->info
$21 = 0x0 <======================== Pim & Igmp is disabled on this interface
Fix: Return when the rpf interface is not pim enabled
Signed-off-by: Saravanan K <saravanank@vmware.com>
2020-03-24 09:26:25 +01:00
|
|
|
|
|
|
|
/* No RPF or No RPF interface or No mcast on RPF interface */
|
2022-03-03 17:25:50 +01:00
|
|
|
if (!rpf || !rpf->source_nexthop.interface ||
|
|
|
|
!rpf->source_nexthop.interface->info)
|
2016-11-01 01:49:18 +01:00
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-02-15 02:03:18 +01:00
|
|
|
/*
|
|
|
|
* If we have received a WRVIFWHOLE and are at this
|
|
|
|
* point, we could be receiving the packet on the *,G
|
|
|
|
* tree, let's check and if so we can safely drop
|
|
|
|
* it.
|
|
|
|
*/
|
2017-05-20 01:36:53 +02:00
|
|
|
parent = pim_upstream_find(pim_ifp->pim, &star_g);
|
2017-02-15 02:03:18 +01:00
|
|
|
if (parent && parent->rpf.source_nexthop.interface == ifp)
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-01 01:49:18 +01:00
|
|
|
pim_ifp = rpf->source_nexthop.interface->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-01 01:49:18 +01:00
|
|
|
memset(&source, 0, sizeof(source));
|
2016-08-19 16:05:01 +02:00
|
|
|
/*
|
|
|
|
* If we are the fhr that means we are getting a callback during
|
|
|
|
* the pimreg period, so I believe we can ignore this packet
|
|
|
|
*/
|
2016-09-12 19:02:53 +02:00
|
|
|
if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
|
2019-11-22 22:16:26 +01:00
|
|
|
/*
|
|
|
|
* No if channel, but upstream we are at the RP.
|
|
|
|
*
|
|
|
|
* This could be a anycast RP too and we may
|
|
|
|
* not have received a register packet from
|
|
|
|
* the source here at all. So gracefully
|
|
|
|
* bow out of doing a nexthop lookup and
|
|
|
|
* setting the SPTBIT to true
|
|
|
|
*/
|
2022-03-03 17:25:50 +01:00
|
|
|
if (!(pim_addr_is_any(up->upstream_register)) &&
|
2019-11-22 22:16:26 +01:00
|
|
|
pim_nexthop_lookup(pim_ifp->pim, &source,
|
2019-04-01 21:41:32 +02:00
|
|
|
up->upstream_register, 0)) {
|
2016-09-22 21:55:02 +02:00
|
|
|
pim_register_stop_send(source.interface, &sg,
|
|
|
|
pim_ifp->primary_address,
|
|
|
|
up->upstream_register);
|
2017-06-22 18:58:02 +02:00
|
|
|
up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
|
|
|
|
}
|
2019-07-09 01:57:01 +02:00
|
|
|
|
2017-05-20 01:36:53 +02:00
|
|
|
pim_upstream_inherited_olist(pim_ifp->pim, up);
|
2016-08-22 20:59:24 +02:00
|
|
|
if (!up->channel_oil->installed)
|
2019-11-15 19:40:00 +01:00
|
|
|
pim_upstream_mroute_add(up->channel_oil,
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__);
|
2016-10-04 13:56:09 +02:00
|
|
|
} else {
|
2017-05-20 19:43:58 +02:00
|
|
|
if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
|
|
|
|
if (pim_nexthop_lookup(pim_ifp->pim, &source,
|
2019-04-01 21:41:32 +02:00
|
|
|
up->upstream_register,
|
|
|
|
0))
|
2016-11-01 01:49:18 +01:00
|
|
|
pim_register_stop_send(
|
|
|
|
source.interface, &sg,
|
|
|
|
pim_ifp->primary_address,
|
|
|
|
up->upstream_register);
|
|
|
|
up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
|
pimd: Send immediate join( with possible SG RPT prune bit set
When pimd has this setup:
src ----- rtr ------ receiver
|
rp
And the receiver sends a *,G join to rtr. When the
src starts sending a S,G, rtr can wait up to one join/prune
interval before sending a S,G rpt prune. This interval
causes the pimreg device to be in the S,G OIL as that the
RP does not know to prune this leg off.
before:
Timestamp: Thu Mar 31 10:15:18 2022 288767 usec
[MROUTE](10.103.0.5,239.0.0.4) Iif: rtr-lan_src Oifs: rtr-lan State: resolved Table: default
Timestamp: Thu Mar 31 10:15:18 2022 288777 usec
[MROUTE](10.103.0.5,239.0.0.4) Iif: rtr-lan_src Oifs: rtr-lan rtr-lan-1 State: resolved Table: default
Timestamp: Thu Mar 31 10:15:18 2022 288789 usec
[MROUTE](10.103.0.5,239.0.0.4) Iif: rtr-lan_src Oifs: pimreg rtr-lan rtr-lan-1 State: resolved Table: default
Timestamp: Thu Mar 31 10:15:49 2022 324995 usec
[MROUTE](10.103.0.5,239.0.0.4) Iif: rtr-lan_src Oifs: rtr-lan rtr-lan-1 State: resolved Table: default
<31 seconds>
After:
Timestamp: Thu Mar 31 12:56:15 2022 501921 usec
(10.103.0.5,239.0.0.27) Iif: rtr-lan_src Oifs: pimreg rtr-lan State: resolved Table: default
Timestamp: Thu Mar 31 12:56:15 2022 501930 usec
(10.103.0.5,239.0.0.27) Iif: rtr-lan_src Oifs: pimreg rtr-lan rtr-lan-1 State: resolved Table: default
Timestamp: Thu Mar 31 12:56:15 2022 502181 usec
(10.103.0.5,239.0.0.27) Iif: rtr-lan_src Oifs: rtr-lan rtr-lan-1 State: resolved Table: default
<sub second>
What is actually happening:
rtr receives a *,G igmp join, sends a *,G join towards the rp
rtr receives a S,G packet <WRVIFWHOLE>
creates the S,G upstream, sends the register packet to the rp
the rp sees that it still has downstream interest so it forwards the packet on
After (up to 60 seconds ) the rtr, sends the normally scheduled join for
the G and sends the S,GRPT prune as part of it.
What is being done to fix it:
In wrvifwhole handling, when pimd detects that this is the FHR
and is not the RP *and* the incoming interface for the *,G
is different than the incomding interface for the S,G immediately
send a single join packet for the G( which will have the S,G RPT
prune in it ). Only do this on the first time receiving the
WRVIFWHOLE.
Ticket: #2755650
Signed-off-by: Donald Sharp <sharpd@nvidia.com>
2022-03-31 19:07:06 +02:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* At this point pimd is connected to
|
|
|
|
* the source, it has a parent, we are not
|
|
|
|
* the RP and the SPTBIT should be set
|
|
|
|
* since we know *the* S,G is on the SPT.
|
|
|
|
* The first time this happens, let's cause
|
|
|
|
* an immediate join to go out so that
|
|
|
|
* the RP can trim this guy immediately
|
|
|
|
* if necessary, instead of waiting
|
|
|
|
* one join/prune send cycle
|
|
|
|
*/
|
|
|
|
if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE &&
|
|
|
|
up->parent &&
|
|
|
|
up->rpf.source_nexthop.interface !=
|
|
|
|
up->parent->rpf.source_nexthop
|
|
|
|
.interface) {
|
|
|
|
up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
|
|
|
|
pim_jp_agg_single_upstream_send(
|
|
|
|
&up->parent->rpf, up->parent,
|
|
|
|
true);
|
|
|
|
}
|
2016-11-01 01:49:18 +01:00
|
|
|
}
|
2016-10-04 13:56:09 +02:00
|
|
|
pim_upstream_keep_alive_timer_start(
|
2017-07-13 03:16:00 +02:00
|
|
|
up, pim_ifp->pim->keep_alive_time);
|
2017-05-20 01:36:53 +02:00
|
|
|
pim_upstream_inherited_olist(pim_ifp->pim, up);
|
2022-05-03 15:49:26 +02:00
|
|
|
pim_mroute_msg_wholepkt(fd, ifp, buf, len);
|
2016-10-04 13:56:09 +02:00
|
|
|
}
|
|
|
|
return 0;
|
2016-08-10 22:16:22 +02:00
|
|
|
}
|
|
|
|
|
2016-08-31 16:50:20 +02:00
|
|
|
pim_ifp = ifp->info;
|
|
|
|
if (pim_if_connected_to_source(ifp, sg.src)) {
|
2017-05-24 16:37:23 +02:00
|
|
|
up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
|
2020-03-05 19:17:54 +01:00
|
|
|
PIM_UPSTREAM_FLAG_MASK_FHR, __func__,
|
|
|
|
NULL);
|
2016-08-31 16:50:20 +02:00
|
|
|
if (!up) {
|
|
|
|
if (PIM_DEBUG_MROUTE)
|
2022-03-03 17:25:50 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%pSG: WRONGVIF%s unable to create upstream on interface",
|
|
|
|
&sg, ifp->name);
|
2016-08-31 16:50:20 +02:00
|
|
|
return -2;
|
|
|
|
}
|
2016-09-13 14:20:39 +02:00
|
|
|
PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
|
2017-07-13 03:16:00 +02:00
|
|
|
pim_upstream_keep_alive_timer_start(
|
|
|
|
up, pim_ifp->pim->keep_alive_time);
|
2016-08-31 16:50:20 +02:00
|
|
|
up->channel_oil->cc.pktcnt++;
|
2024-11-25 17:36:54 +01:00
|
|
|
if (!pim_is_group_filtered(pim_ifp, &sg.grp, &sg.src))
|
|
|
|
pim_register_join(up);
|
2017-05-20 01:36:53 +02:00
|
|
|
pim_upstream_inherited_olist(pim_ifp->pim, up);
|
2019-11-15 19:40:00 +01:00
|
|
|
if (!up->channel_oil->installed)
|
|
|
|
pim_upstream_mroute_add(up->channel_oil, __func__);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-08-31 16:50:20 +02:00
|
|
|
// Send the packet to the RP
|
2022-05-03 15:49:26 +02:00
|
|
|
pim_mroute_msg_wholepkt(fd, ifp, buf, len);
|
2019-07-09 02:00:43 +02:00
|
|
|
} else {
|
|
|
|
up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
|
|
|
|
PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE,
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, NULL);
|
2019-07-09 02:00:43 +02:00
|
|
|
if (!up->channel_oil->installed)
|
2020-03-05 19:17:54 +01:00
|
|
|
pim_upstream_mroute_add(up->channel_oil, __func__);
|
2016-08-31 16:50:20 +02:00
|
|
|
}
|
2016-08-09 18:30:26 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-06-22 12:35:07 +02:00
|
|
|
#if PIM_IPV == 4
|
|
|
|
static int process_igmp_packet(struct pim_instance *pim, const char *buf,
|
|
|
|
size_t buf_size, ifindex_t ifindex)
|
|
|
|
{
|
|
|
|
struct interface *ifp;
|
|
|
|
struct pim_interface *pim_ifp;
|
|
|
|
struct in_addr ifaddr;
|
|
|
|
struct gm_sock *igmp;
|
|
|
|
const struct prefix *connected_src;
|
|
|
|
const struct ip *ip_hdr = (const struct ip *)buf;
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
2022-11-02 11:17:30 +01:00
|
|
|
if (!connected_src && !pim_addr_is_any(ip_hdr->ip_src)) {
|
2022-09-05 07:45:33 +02:00
|
|
|
if (PIM_DEBUG_GM_PACKETS) {
|
2022-06-22 12:35:07 +02:00
|
|
|
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;
|
2022-11-02 11:17:30 +01:00
|
|
|
ifaddr = connected_src ? connected_src->u.prefix4
|
|
|
|
: pim_ifp->primary_address;
|
2022-06-22 12:35:07 +02:00
|
|
|
igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr);
|
|
|
|
|
2022-09-05 07:45:33 +02:00
|
|
|
if (PIM_DEBUG_GM_PACKETS) {
|
2022-06-22 12:35:07 +02:00
|
|
|
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);
|
2022-11-02 11:17:30 +01:00
|
|
|
else if (PIM_DEBUG_GM_PACKETS)
|
2022-06-22 12:35:07 +02:00
|
|
|
zlog_debug(
|
2022-11-02 11:17:30 +01:00
|
|
|
"No IGMP socket on interface: %s with connected source: %pI4",
|
|
|
|
ifp->name, &ifaddr);
|
|
|
|
|
2022-06-22 12:35:07 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int pim_mroute_msg(struct pim_instance *pim, const char *buf, size_t buf_size,
|
|
|
|
ifindex_t ifindex)
|
|
|
|
{
|
|
|
|
struct interface *ifp;
|
|
|
|
const ipv_hdr *ip_hdr;
|
|
|
|
const kernmsg *msg;
|
|
|
|
|
|
|
|
if (buf_size < (int)sizeof(ipv_hdr))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ip_hdr = (const ipv_hdr *)buf;
|
|
|
|
|
|
|
|
#if PIM_IPV == 4
|
|
|
|
if (ip_hdr->ip_p == IPPROTO_IGMP) {
|
|
|
|
process_igmp_packet(pim, buf, buf_size, ifindex);
|
|
|
|
} 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 {
|
|
|
|
#else
|
|
|
|
|
|
|
|
if ((ip_hdr->ip6_vfc & 0xf) == 0) {
|
|
|
|
#endif
|
|
|
|
msg = (const kernmsg *)buf;
|
|
|
|
|
|
|
|
ifp = pim_if_find_by_vif_index(pim, msg->msg_im_vif);
|
|
|
|
|
|
|
|
if (!ifp)
|
|
|
|
return 0;
|
|
|
|
if (PIM_DEBUG_MROUTE) {
|
|
|
|
#if PIM_IPV == 4
|
|
|
|
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__, gmmsgtype2str[msg->msg_im_msgtype],
|
|
|
|
msg->msg_im_msgtype, ip_hdr->ip_p,
|
|
|
|
pim->mroute_socket, &msg->msg_im_src,
|
|
|
|
&msg->msg_im_dst, ifp->name, msg->msg_im_vif,
|
|
|
|
(long int)buf_size);
|
|
|
|
#else
|
|
|
|
zlog_debug(
|
|
|
|
"%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI6,%pI6) on %s vifi=%d size=%ld",
|
|
|
|
__func__, gmmsgtype2str[msg->msg_im_msgtype],
|
|
|
|
msg->msg_im_msgtype, ip_hdr->ip6_nxt,
|
|
|
|
pim->mroute_socket, &msg->msg_im_src,
|
|
|
|
&msg->msg_im_dst, ifp->name, msg->msg_im_vif,
|
|
|
|
(long int)buf_size);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (msg->msg_im_msgtype) {
|
|
|
|
case GMMSG_WRONGVIF:
|
|
|
|
return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
|
|
|
|
msg);
|
|
|
|
case GMMSG_NOCACHE:
|
|
|
|
return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
|
|
|
|
msg);
|
|
|
|
case GMMSG_WHOLEPKT:
|
|
|
|
return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
|
|
|
|
(const char *)msg,
|
|
|
|
buf_size);
|
|
|
|
case GMMSG_WRVIFWHOLE:
|
|
|
|
return pim_mroute_msg_wrvifwhole(pim->mroute_socket,
|
|
|
|
ifp, (const char *)msg,
|
|
|
|
buf_size);
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-03-01 22:18:12 +01:00
|
|
|
static void mroute_read(struct event *t)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2017-05-11 03:34:27 +02:00
|
|
|
struct pim_instance *pim;
|
2016-11-17 17:18:06 +01:00
|
|
|
static long long count;
|
|
|
|
char buf[10000];
|
|
|
|
int cont = 1;
|
|
|
|
int rd;
|
2017-06-02 00:59:43 +02:00
|
|
|
ifindex_t ifindex;
|
2022-12-25 16:26:52 +01:00
|
|
|
pim = EVENT_ARG(t);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-17 17:18:06 +01:00
|
|
|
while (cont) {
|
2017-06-02 00:59:43 +02:00
|
|
|
rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf,
|
|
|
|
sizeof(buf), NULL, NULL, NULL, NULL,
|
|
|
|
&ifindex);
|
2017-05-11 02:04:02 +02:00
|
|
|
if (rd <= 0) {
|
2016-11-17 17:18:06 +01:00
|
|
|
if (errno == EINTR)
|
|
|
|
continue;
|
|
|
|
if (errno == EWOULDBLOCK || errno == EAGAIN)
|
2017-03-31 22:28:22 +02:00
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_warn(
|
|
|
|
"%s: failure reading rd=%d: fd=%d: errno=%d: %s",
|
|
|
|
__func__, rd, pim->mroute_socket, errno,
|
|
|
|
safe_strerror(errno));
|
2016-11-17 17:18:06 +01:00
|
|
|
goto done;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-23 01:04:25 +01:00
|
|
|
pim_mroute_msg(pim, buf, rd, ifindex);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-17 17:18:06 +01:00
|
|
|
count++;
|
2018-12-21 14:57:22 +01:00
|
|
|
if (count % router->packet_process == 0)
|
2016-11-17 17:18:06 +01:00
|
|
|
cont = 0;
|
|
|
|
}
|
2015-02-04 07:01:14 +01:00
|
|
|
/* Keep reading */
|
2016-11-17 17:18:06 +01:00
|
|
|
done:
|
2017-05-11 03:34:27 +02:00
|
|
|
mroute_read_on(pim);
|
2022-03-03 17:25:50 +01:00
|
|
|
|
|
|
|
return;
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2017-05-11 03:34:27 +02:00
|
|
|
static void mroute_read_on(struct pim_instance *pim)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_read(router->master, mroute_read, pim, pim->mroute_socket,
|
|
|
|
&pim->thread);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2017-05-11 03:34:27 +02:00
|
|
|
static void mroute_read_off(struct pim_instance *pim)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(pim->thread);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2017-05-10 14:45:25 +02:00
|
|
|
int pim_mroute_socket_enable(struct pim_instance *pim)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
2019-08-13 15:47:23 +02:00
|
|
|
frr_with_privs(&pimd_privs) {
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2022-03-03 17:25:50 +01:00
|
|
|
#if PIM_IPV == 4
|
2018-08-10 18:36:43 +02:00
|
|
|
fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
|
2022-03-03 17:25:50 +01:00
|
|
|
#else
|
|
|
|
fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
|
|
|
|
#endif
|
2018-08-10 18:36:43 +02:00
|
|
|
if (fd < 0) {
|
|
|
|
zlog_warn("Could not create mroute socket: errno=%d: %s",
|
|
|
|
errno,
|
|
|
|
safe_strerror(errno));
|
|
|
|
return -2;
|
|
|
|
}
|
2017-08-25 01:54:21 +02:00
|
|
|
|
2022-04-27 09:23:27 +02:00
|
|
|
#if PIM_IPV == 6
|
|
|
|
struct icmp6_filter filter[1];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* Unlike IPv4, this socket is not used for MLD, so just drop
|
|
|
|
* everything with an empty ICMP6 filter. Otherwise we get
|
|
|
|
* all kinds of garbage here, possibly even non-multicast
|
|
|
|
* related ICMPv6 traffic (e.g. ping)
|
|
|
|
*
|
|
|
|
* (mroute kernel upcall "packets" are injected directly on the
|
|
|
|
* socket, this sockopt -or any other- has no effect on them)
|
|
|
|
*/
|
|
|
|
ICMP6_FILTER_SETBLOCKALL(filter);
|
|
|
|
ret = setsockopt(fd, SOL_ICMPV6, ICMP6_FILTER, filter,
|
|
|
|
sizeof(filter));
|
|
|
|
if (ret)
|
|
|
|
zlog_err(
|
|
|
|
"(VRF %s) failed to set mroute control filter: %m",
|
|
|
|
pim->vrf->name);
|
|
|
|
#endif
|
|
|
|
|
2017-06-02 19:30:48 +02:00
|
|
|
#ifdef SO_BINDTODEVICE
|
2018-08-10 18:36:43 +02:00
|
|
|
if (pim->vrf->vrf_id != VRF_DEFAULT
|
2018-08-13 19:52:57 +02:00
|
|
|
&& setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
|
|
|
|
pim->vrf->name, strlen(pim->vrf->name))) {
|
2018-08-10 18:36:43 +02:00
|
|
|
zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
|
|
|
|
safe_strerror(errno));
|
|
|
|
close(fd);
|
|
|
|
return -3;
|
|
|
|
}
|
2017-06-02 19:30:48 +02:00
|
|
|
#endif
|
2017-06-02 00:59:43 +02:00
|
|
|
|
2018-08-10 18:36:43 +02:00
|
|
|
}
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2017-05-11 02:52:20 +02:00
|
|
|
pim->mroute_socket = fd;
|
|
|
|
if (pim_mroute_set(pim, 1)) {
|
2015-02-04 07:01:14 +01:00
|
|
|
zlog_warn(
|
|
|
|
"Could not enable mroute on socket fd=%d: errno=%d: %s",
|
|
|
|
fd, errno, safe_strerror(errno));
|
|
|
|
close(fd);
|
2017-05-11 02:52:20 +02:00
|
|
|
pim->mroute_socket = -1;
|
2015-02-04 07:01:14 +01:00
|
|
|
return -3;
|
|
|
|
}
|
|
|
|
|
2017-05-10 14:45:25 +02:00
|
|
|
pim->mroute_socket_creation = pim_time_monotonic_sec();
|
2015-10-20 03:23:16 +02:00
|
|
|
|
2017-05-11 03:34:27 +02:00
|
|
|
mroute_read_on(pim);
|
2015-02-04 07:01:14 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-10 14:45:25 +02:00
|
|
|
int pim_mroute_socket_disable(struct pim_instance *pim)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2017-05-11 02:52:20 +02:00
|
|
|
if (pim_mroute_set(pim, 0)) {
|
2015-02-04 07:01:14 +01:00
|
|
|
zlog_warn(
|
|
|
|
"Could not disable mroute on socket fd=%d: errno=%d: %s",
|
2017-05-11 03:44:25 +02:00
|
|
|
pim->mroute_socket, errno, safe_strerror(errno));
|
2015-02-04 07:01:14 +01:00
|
|
|
return -2;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-10 14:45:25 +02:00
|
|
|
if (close(pim->mroute_socket)) {
|
2015-02-04 07:01:14 +01:00
|
|
|
zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
|
2017-05-11 03:44:25 +02:00
|
|
|
pim->mroute_socket, errno, safe_strerror(errno));
|
2015-02-04 07:01:14 +01:00
|
|
|
return -3;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-11 03:34:27 +02:00
|
|
|
mroute_read_off(pim);
|
2017-05-10 14:45:25 +02:00
|
|
|
pim->mroute_socket = -1;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
For each network interface (e.g., physical or a virtual tunnel) that
|
|
|
|
would be used for multicast forwarding, a corresponding multicast
|
|
|
|
interface must be added to the kernel.
|
|
|
|
*/
|
2022-01-18 14:33:04 +01:00
|
|
|
int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr,
|
2016-06-18 02:43:21 +02:00
|
|
|
unsigned char flags)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2016-06-18 02:43:21 +02:00
|
|
|
struct pim_interface *pim_ifp = ifp->info;
|
2022-03-03 17:25:50 +01:00
|
|
|
pim_vifctl vc;
|
2015-02-04 07:01:14 +01:00
|
|
|
int err;
|
|
|
|
|
2017-07-31 23:16:54 +02:00
|
|
|
if (PIM_DEBUG_MROUTE)
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug("%s: Add Vif %d (%s[%s])", __func__,
|
2017-08-01 00:02:23 +02:00
|
|
|
pim_ifp->mroute_vif_index, ifp->name,
|
|
|
|
pim_ifp->pim->vrf->name);
|
2017-07-31 23:16:54 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
memset(&vc, 0, sizeof(vc));
|
2022-03-03 17:25:50 +01:00
|
|
|
vc.vc_vifi = pim_ifp->mroute_vif_index;
|
|
|
|
#if PIM_IPV == 4
|
2016-08-04 15:07:30 +02:00
|
|
|
#ifdef VIFF_USE_IFINDEX
|
2022-03-03 17:25:50 +01:00
|
|
|
vc.vc_lcl_ifindex = ifp->ifindex;
|
2016-08-04 15:07:30 +02:00
|
|
|
#else
|
|
|
|
if (ifaddr.s_addr == INADDR_ANY) {
|
|
|
|
zlog_warn(
|
|
|
|
"%s: unnumbered interfaces are not supported on this platform",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__);
|
2016-08-04 15:07:30 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2022-03-03 17:25:50 +01:00
|
|
|
memcpy(&vc.vc_lcl_addr, &ifaddr, sizeof(vc.vc_lcl_addr));
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
vc.vc_pifi = ifp->ifindex;
|
2016-08-04 15:07:30 +02:00
|
|
|
#endif
|
2022-03-03 17:25:50 +01:00
|
|
|
vc.vc_flags = flags;
|
|
|
|
vc.vc_threshold = PIM_MROUTE_MIN_TTL;
|
|
|
|
vc.vc_rate_limit = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-03-03 17:25:50 +01:00
|
|
|
#if PIM_IPV == 4
|
2015-02-04 07:01:14 +01:00
|
|
|
#ifdef PIM_DVMRP_TUNNEL
|
2022-03-03 17:25:50 +01:00
|
|
|
if (vc.vc_flags & VIFF_TUNNEL) {
|
|
|
|
memcpy(&vc.vc_rmt_addr, &vif_remote_addr,
|
|
|
|
sizeof(vc.vc_rmt_addr));
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2022-03-03 17:25:50 +01:00
|
|
|
#endif
|
2015-02-04 07:01:14 +01:00
|
|
|
#endif
|
|
|
|
|
2022-03-03 17:25:50 +01:00
|
|
|
err = setsockopt(pim_ifp->pim->mroute_socket, PIM_IPPROTO, MRT_ADD_VIF,
|
2015-10-20 03:23:16 +02:00
|
|
|
(void *)&vc, sizeof(vc));
|
2015-02-04 07:01:14 +01:00
|
|
|
if (err) {
|
2015-10-29 14:41:24 +01:00
|
|
|
zlog_warn(
|
2022-03-03 17:25:50 +01:00
|
|
|
"%s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, pim_ifp->pim->mroute_socket, ifp->ifindex,
|
2022-01-18 14:33:04 +01:00
|
|
|
&ifaddr, flags, errno, safe_strerror(errno));
|
2015-02-04 07:01:14 +01:00
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-14 20:33:53 +02:00
|
|
|
int pim_mroute_del_vif(struct interface *ifp)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2017-05-14 20:33:53 +02:00
|
|
|
struct pim_interface *pim_ifp = ifp->info;
|
2022-03-03 17:25:50 +01:00
|
|
|
pim_vifctl vc;
|
2015-02-04 07:01:14 +01:00
|
|
|
int err;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-14 20:33:53 +02:00
|
|
|
if (PIM_DEBUG_MROUTE)
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug("%s: Del Vif %d (%s[%s])", __func__,
|
2017-07-31 23:16:54 +02:00
|
|
|
pim_ifp->mroute_vif_index, ifp->name,
|
2017-08-01 00:02:23 +02:00
|
|
|
pim_ifp->pim->vrf->name);
|
2015-02-04 07:01:14 +01:00
|
|
|
|
|
|
|
memset(&vc, 0, sizeof(vc));
|
2022-03-03 17:25:50 +01:00
|
|
|
vc.vc_vifi = pim_ifp->mroute_vif_index;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-03-03 17:25:50 +01:00
|
|
|
err = setsockopt(pim_ifp->pim->mroute_socket, PIM_IPPROTO, MRT_DEL_VIF,
|
2015-02-04 07:01:14 +01:00
|
|
|
(void *)&vc, sizeof(vc));
|
|
|
|
if (err) {
|
|
|
|
zlog_warn(
|
2022-03-03 17:25:50 +01:00
|
|
|
"%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
|
2020-03-05 19:17:54 +01:00
|
|
|
__FILE__, __func__, pim_ifp->pim->mroute_socket,
|
|
|
|
pim_ifp->mroute_vif_index, errno, safe_strerror(errno));
|
2015-02-04 07:01:14 +01:00
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-15 20:46:04 +01:00
|
|
|
/*
|
|
|
|
* Prevent creating MFC entry with OIF=IIF.
|
|
|
|
*
|
|
|
|
* This is a protection against implementation mistakes.
|
|
|
|
*
|
|
|
|
* PIM protocol implicitely ensures loopfree multicast topology.
|
|
|
|
*
|
|
|
|
* IGMP must be protected against adding looped MFC entries created
|
|
|
|
* by both source and receiver attached to the same interface. See
|
|
|
|
* TODO T22.
|
|
|
|
* We shall allow igmp to create upstream when it is DR for the intf.
|
|
|
|
* Assume RP reachable via non DR.
|
|
|
|
*/
|
|
|
|
bool pim_mroute_allow_iif_in_oil(struct channel_oil *c_oil,
|
|
|
|
int oif_index)
|
|
|
|
{
|
|
|
|
#ifdef PIM_ENFORCE_LOOPFREE_MFC
|
|
|
|
struct interface *ifp_out;
|
|
|
|
struct pim_interface *pim_ifp;
|
|
|
|
|
|
|
|
if (c_oil->up &&
|
|
|
|
PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil->up->flags))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
ifp_out = pim_if_find_by_vif_index(c_oil->pim, oif_index);
|
|
|
|
if (!ifp_out)
|
|
|
|
return false;
|
|
|
|
pim_ifp = ifp_out->info;
|
|
|
|
if (!pim_ifp)
|
|
|
|
return false;
|
2022-04-13 10:00:50 +02:00
|
|
|
if ((c_oil->oif_flags[oif_index] & PIM_OIF_FLAG_PROTO_GM) &&
|
|
|
|
PIM_I_am_DR(pim_ifp))
|
2019-11-15 20:46:04 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
#else
|
|
|
|
return true;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-01-18 14:33:04 +01:00
|
|
|
static inline void pim_mroute_copy(struct channel_oil *out,
|
|
|
|
struct channel_oil *in)
|
2019-11-15 18:29:04 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2022-01-18 14:33:04 +01:00
|
|
|
*oil_origin(out) = *oil_origin(in);
|
|
|
|
*oil_mcastgrp(out) = *oil_mcastgrp(in);
|
2023-09-14 13:18:37 +02:00
|
|
|
*oil_incoming_vif(out) = *oil_incoming_vif(in);
|
2019-11-15 18:29:04 +01:00
|
|
|
|
|
|
|
for (i = 0; i < MAXVIFS; ++i) {
|
2023-09-14 13:18:37 +02:00
|
|
|
if (*oil_incoming_vif(out) == i &&
|
2022-01-18 14:33:04 +01:00
|
|
|
!pim_mroute_allow_iif_in_oil(in, i)) {
|
|
|
|
oil_if_set(out, i, 0);
|
2019-11-15 20:46:04 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-01-18 14:33:04 +01:00
|
|
|
if (in->oif_flags[i] & PIM_OIF_FLAG_MUTE)
|
|
|
|
oil_if_set(out, i, 0);
|
2019-11-15 18:29:04 +01:00
|
|
|
else
|
2022-01-18 14:33:04 +01:00
|
|
|
oil_if_set(out, i, oil_if_has(in, i));
|
2019-11-15 18:29:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-15 19:40:00 +01:00
|
|
|
/* This function must not be called directly 0
|
|
|
|
* use pim_upstream_mroute_add or pim_static_mroute_add instead
|
|
|
|
*/
|
|
|
|
static int pim_mroute_add(struct channel_oil *c_oil, const char *name)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2017-05-21 15:16:49 +02:00
|
|
|
struct pim_instance *pim = c_oil->pim;
|
2022-01-18 14:33:04 +01:00
|
|
|
struct channel_oil tmp_oil[1] = { };
|
2015-02-04 07:01:14 +01:00
|
|
|
int err;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-18 23:58:40 +02:00
|
|
|
pim->mroute_add_last = pim_time_monotonic_sec();
|
|
|
|
++pim->mroute_add_events;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-11-15 18:29:04 +01:00
|
|
|
/* Copy the oil to a temporary structure to fixup (without need to
|
|
|
|
* later restore) before sending the mroute add to the dataplane
|
|
|
|
*/
|
2022-01-18 14:33:04 +01:00
|
|
|
pim_mroute_copy(tmp_oil, c_oil);
|
2016-06-27 18:54:30 +02:00
|
|
|
|
2016-08-02 15:21:51 +02:00
|
|
|
/* The linux kernel *expects* the incoming
|
|
|
|
* vif to be part of the outgoing list
|
|
|
|
* in the case of a (*,G).
|
|
|
|
*/
|
2022-01-18 14:33:04 +01:00
|
|
|
if (pim_addr_is_any(*oil_origin(c_oil))) {
|
2023-09-14 13:18:37 +02:00
|
|
|
oil_if_set(tmp_oil, *oil_incoming_vif(c_oil), 1);
|
2019-03-26 21:43:23 +01:00
|
|
|
}
|
|
|
|
|
2017-07-17 14:03:14 +02:00
|
|
|
/*
|
2016-08-02 15:21:51 +02:00
|
|
|
* If we have an unresolved cache entry for the S,G
|
|
|
|
* it is owned by the pimreg for the incoming IIF
|
|
|
|
* So set pimreg as the IIF temporarily to cause
|
|
|
|
* the packets to be forwarded. Then set it
|
|
|
|
* to the correct IIF afterwords.
|
2017-07-17 14:03:14 +02:00
|
|
|
*/
|
2023-09-14 13:18:37 +02:00
|
|
|
if (!c_oil->installed && !pim_addr_is_any(*oil_origin(c_oil)) &&
|
|
|
|
*oil_incoming_vif(c_oil) != 0) {
|
|
|
|
*oil_incoming_vif(tmp_oil) = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2022-03-03 17:25:50 +01:00
|
|
|
/* For IPv6 MRT_ADD_MFC is defined to MRT6_ADD_MFC */
|
|
|
|
err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC,
|
2022-01-18 14:33:04 +01:00
|
|
|
&tmp_oil->oil, sizeof(tmp_oil->oil));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2023-09-14 13:18:37 +02:00
|
|
|
if (!err && !c_oil->installed && !pim_addr_is_any(*oil_origin(c_oil)) &&
|
|
|
|
*oil_incoming_vif(c_oil) != 0) {
|
|
|
|
*oil_incoming_vif(tmp_oil) = *oil_incoming_vif(c_oil);
|
2022-03-03 17:25:50 +01:00
|
|
|
err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC,
|
2022-01-18 14:33:04 +01:00
|
|
|
&tmp_oil->oil, sizeof(tmp_oil->oil));
|
2019-06-07 15:28:39 +02:00
|
|
|
}
|
2019-03-24 20:31:50 +01:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (err) {
|
|
|
|
zlog_warn(
|
2022-03-03 17:25:50 +01:00
|
|
|
"%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_MFC): errno=%d: %s",
|
2020-03-05 19:17:54 +01:00
|
|
|
__FILE__, __func__, pim->mroute_socket, errno,
|
|
|
|
safe_strerror(errno));
|
2015-02-04 07:01:14 +01:00
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
2016-12-06 16:08:09 +01:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
2017-01-19 18:09:26 +01:00
|
|
|
char buf[1000];
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug("%s(%s), vrf %s Added Route: %s", __func__, name,
|
|
|
|
pim->vrf->name,
|
2017-01-19 18:09:26 +01:00
|
|
|
pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
|
2016-12-06 16:08:09 +01:00
|
|
|
}
|
|
|
|
|
2020-03-09 08:00:28 +01:00
|
|
|
if (!c_oil->installed) {
|
|
|
|
c_oil->installed = 1;
|
|
|
|
c_oil->mroute_creation = pim_time_monotonic_sec();
|
|
|
|
}
|
2019-04-01 08:38:28 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-15 20:09:13 +01:00
|
|
|
static int pim_upstream_get_mroute_iif(struct channel_oil *c_oil,
|
|
|
|
const char *name)
|
2019-11-15 19:40:00 +01:00
|
|
|
{
|
|
|
|
vifi_t iif = MAXVIFS;
|
|
|
|
struct interface *ifp = NULL;
|
|
|
|
struct pim_interface *pim_ifp;
|
|
|
|
struct pim_upstream *up = c_oil->up;
|
|
|
|
|
|
|
|
if (up) {
|
|
|
|
if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags)) {
|
|
|
|
if (up->parent)
|
|
|
|
ifp = up->parent->rpf.source_nexthop.interface;
|
|
|
|
} else {
|
|
|
|
ifp = up->rpf.source_nexthop.interface;
|
|
|
|
}
|
|
|
|
if (ifp) {
|
|
|
|
pim_ifp = (struct pim_interface *)ifp->info;
|
|
|
|
if (pim_ifp)
|
|
|
|
iif = pim_ifp->mroute_vif_index;
|
|
|
|
}
|
|
|
|
}
|
2019-11-15 20:09:13 +01:00
|
|
|
return iif;
|
|
|
|
}
|
2019-11-15 19:40:00 +01:00
|
|
|
|
2019-11-15 20:09:13 +01:00
|
|
|
static int pim_upstream_mroute_update(struct channel_oil *c_oil,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
char buf[1000];
|
2019-11-15 19:40:00 +01:00
|
|
|
|
2023-09-14 13:18:37 +02:00
|
|
|
if (*oil_incoming_vif(c_oil) >= MAXVIFS) {
|
2019-11-15 19:40:00 +01:00
|
|
|
/* the c_oil cannot be installed as a mroute yet */
|
|
|
|
if (PIM_DEBUG_MROUTE)
|
|
|
|
zlog_debug(
|
|
|
|
"%s(%s) %s mroute not ready to be installed; %s",
|
2019-11-15 20:09:13 +01:00
|
|
|
__func__, name,
|
2019-11-15 19:40:00 +01:00
|
|
|
pim_channel_oil_dump(c_oil, buf,
|
|
|
|
sizeof(buf)),
|
|
|
|
c_oil->installed ?
|
|
|
|
"uninstall" : "skip");
|
|
|
|
/* if already installed flush it out as we are going to stop
|
|
|
|
* updates to it leaving it in a stale state
|
|
|
|
*/
|
|
|
|
if (c_oil->installed)
|
|
|
|
pim_mroute_del(c_oil, name);
|
|
|
|
/* return success (skipped) */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pim_mroute_add(c_oil, name);
|
|
|
|
}
|
|
|
|
|
2019-11-15 20:12:41 +01:00
|
|
|
/* IIF associated with SGrpt entries are re-evaluated when the parent
|
|
|
|
* (*,G) entries IIF changes
|
|
|
|
*/
|
|
|
|
static void pim_upstream_all_sources_iif_update(struct pim_upstream *up)
|
|
|
|
{
|
|
|
|
struct listnode *listnode;
|
|
|
|
struct pim_upstream *child;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(up->sources, listnode,
|
|
|
|
child)) {
|
|
|
|
if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags))
|
|
|
|
pim_upstream_mroute_iif_update(child->channel_oil,
|
|
|
|
__func__);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-15 20:09:13 +01:00
|
|
|
/* In the case of "PIM state machine" added mroutes an upstream entry
|
|
|
|
* must be present to decide on the SPT-forwarding vs. RPT-forwarding.
|
|
|
|
*/
|
|
|
|
int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name)
|
|
|
|
{
|
2019-11-15 20:12:41 +01:00
|
|
|
vifi_t iif;
|
|
|
|
|
|
|
|
iif = pim_upstream_get_mroute_iif(c_oil, name);
|
|
|
|
|
2023-09-14 13:18:37 +02:00
|
|
|
if (*oil_incoming_vif(c_oil) != iif) {
|
|
|
|
*oil_incoming_vif(c_oil) = iif;
|
2022-01-18 14:33:04 +01:00
|
|
|
if (pim_addr_is_any(*oil_origin(c_oil)) &&
|
2019-11-15 20:12:41 +01:00
|
|
|
c_oil->up)
|
|
|
|
pim_upstream_all_sources_iif_update(c_oil->up);
|
|
|
|
} else {
|
2023-09-14 13:18:37 +02:00
|
|
|
*oil_incoming_vif(c_oil) = iif;
|
2019-11-15 20:12:41 +01:00
|
|
|
}
|
2019-11-15 20:09:13 +01:00
|
|
|
|
|
|
|
return pim_upstream_mroute_update(c_oil, name);
|
|
|
|
}
|
|
|
|
|
pimd: re-evaluated S,G OILs upon RP changes and for empty SG upstream oils
Topology:
TOR11 (FHR) --- LEAF-11---SPINE1 (RP)MSDP SPINE-2(RP)MSDP --- LEAF-12 -- TOR12 (LHR)
| | | | |
| -----------------------------------------------------(ECMP) |
| | | |
-----------------------------------------------------------------------(ECMP)
Issue:
In some triggers, S,G upstream is preserved even with the PP timer expiry, resulting
in S,G with NULL OILS. This could be because we create a dummy S,G upstream and
dummy channel_oif for *,G, where RPF is UNKNOWN. As a result, PIM+VXLAN traffic is never
forwarded downstream to LHR.
Fix:
when the S,G stream is running, Determine if a reevaluation of the outgoing interface
list (OIL) is required. S,G upstream should then inherit the OIL from *,G.
Testing:
- Evpn pim tests - TestEvpnPimSingleVtepOneMdt.test_02_broadcast_traffic_spt_zero
- pim-smoke
Ticket: #
Signed-off-by: Rajesh Varatharaj <rvaratharaj@nvidia.com>
2024-02-08 03:58:39 +01:00
|
|
|
/* Look for IIF changes and update the dataplane entry only if the IIF
|
2019-11-15 20:09:13 +01:00
|
|
|
* has changed.
|
|
|
|
*/
|
|
|
|
int pim_upstream_mroute_iif_update(struct channel_oil *c_oil, const char *name)
|
|
|
|
{
|
|
|
|
vifi_t iif;
|
|
|
|
char buf[1000];
|
|
|
|
|
|
|
|
iif = pim_upstream_get_mroute_iif(c_oil, name);
|
2023-09-14 13:18:37 +02:00
|
|
|
if (*oil_incoming_vif(c_oil) == iif) {
|
2019-11-15 20:09:13 +01:00
|
|
|
/* no change */
|
|
|
|
return 0;
|
|
|
|
}
|
2023-09-14 13:18:37 +02:00
|
|
|
*oil_incoming_vif(c_oil) = iif;
|
2019-11-15 20:09:13 +01:00
|
|
|
|
2022-01-18 14:33:04 +01:00
|
|
|
if (pim_addr_is_any(*oil_origin(c_oil)) &&
|
2019-11-15 20:12:41 +01:00
|
|
|
c_oil->up)
|
|
|
|
pim_upstream_all_sources_iif_update(c_oil->up);
|
|
|
|
|
2019-11-15 20:09:13 +01:00
|
|
|
if (PIM_DEBUG_MROUTE_DETAIL)
|
|
|
|
zlog_debug("%s(%s) %s mroute iif update %d",
|
|
|
|
__func__, name,
|
|
|
|
pim_channel_oil_dump(c_oil, buf,
|
|
|
|
sizeof(buf)), iif);
|
|
|
|
/* XXX: is this hack needed? */
|
|
|
|
c_oil->oil_inherited_rescan = 1;
|
|
|
|
return pim_upstream_mroute_update(c_oil, name);
|
|
|
|
}
|
|
|
|
|
2019-11-15 19:40:00 +01:00
|
|
|
int pim_static_mroute_add(struct channel_oil *c_oil, const char *name)
|
|
|
|
{
|
|
|
|
return pim_mroute_add(c_oil, name);
|
|
|
|
}
|
|
|
|
|
2019-11-15 20:09:13 +01:00
|
|
|
void pim_static_mroute_iif_update(struct channel_oil *c_oil,
|
|
|
|
int input_vif_index,
|
|
|
|
const char *name)
|
|
|
|
{
|
2023-09-14 13:18:37 +02:00
|
|
|
if (*oil_incoming_vif(c_oil) == input_vif_index)
|
2019-11-15 20:09:13 +01:00
|
|
|
return;
|
|
|
|
|
2023-09-14 13:18:37 +02:00
|
|
|
*oil_incoming_vif(c_oil) = input_vif_index;
|
2019-11-15 20:09:13 +01:00
|
|
|
if (input_vif_index == MAXVIFS)
|
|
|
|
pim_mroute_del(c_oil, name);
|
|
|
|
else
|
|
|
|
pim_static_mroute_add(c_oil, name);
|
|
|
|
}
|
|
|
|
|
2016-12-06 16:08:09 +01:00
|
|
|
int pim_mroute_del(struct channel_oil *c_oil, const char *name)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2017-05-21 15:16:49 +02:00
|
|
|
struct pim_instance *pim = c_oil->pim;
|
2015-02-04 07:01:14 +01:00
|
|
|
int err;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-18 23:58:40 +02:00
|
|
|
pim->mroute_del_last = pim_time_monotonic_sec();
|
|
|
|
++pim->mroute_del_events;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-27 05:13:42 +02:00
|
|
|
if (!c_oil->installed) {
|
2016-07-24 01:54:51 +02:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
2017-01-19 18:09:26 +01:00
|
|
|
char buf[1000];
|
2023-09-13 00:19:23 +02:00
|
|
|
struct interface *iifp =
|
2023-09-14 13:18:37 +02:00
|
|
|
pim_if_find_by_vif_index(pim, *oil_incoming_vif(
|
|
|
|
c_oil));
|
2023-09-13 00:19:23 +02:00
|
|
|
|
|
|
|
zlog_debug("%s %s: incoming interface %s for route is %s not installed, do not need to send del req. ",
|
|
|
|
__FILE__, __func__,
|
|
|
|
iifp ? iifp->name : "Unknown",
|
|
|
|
pim_channel_oil_dump(c_oil, buf,
|
|
|
|
sizeof(buf)));
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2015-02-04 07:01:14 +01:00
|
|
|
return -2;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2022-03-03 17:25:50 +01:00
|
|
|
err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_DEL_MFC,
|
2017-01-22 00:18:08 +01:00
|
|
|
&c_oil->oil, sizeof(c_oil->oil));
|
|
|
|
if (err) {
|
|
|
|
if (PIM_DEBUG_MROUTE)
|
|
|
|
zlog_warn(
|
2022-03-03 17:25:50 +01:00
|
|
|
"%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_MFC): errno=%d: %s",
|
2020-03-05 19:17:54 +01:00
|
|
|
__FILE__, __func__, pim->mroute_socket, errno,
|
2017-01-22 00:18:08 +01:00
|
|
|
safe_strerror(errno));
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
2016-09-27 00:39:54 +02:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
2017-01-19 18:09:26 +01:00
|
|
|
char buf[1000];
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__, name,
|
|
|
|
pim->vrf->name,
|
2017-08-01 00:02:23 +02:00
|
|
|
pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
|
2016-12-06 16:08:09 +01:00
|
|
|
}
|
2017-01-19 18:09:26 +01:00
|
|
|
|
pimd: Pim Nexthop Tracking support with ECMP
In this patch, PIM nexthop tracking uses locally populated nexthop cached list
to determine ECMP based nexthop (w/ ECMP knob enabled), otherwise picks
the first nexthop as RPF.
Introduced '[no] ip pim ecmp' command to enable/disable PIM ECMP knob.
By default, PIM ECMP is disabled.
Intorudced '[no] ip pim ecmp rebalance' command to provide existing mcache
entry to switch new path based on hash chosen path.
Introduced, show command to display pim registered addresses and respective nexthops.
Introuduce, show command to find nexthop and out interface for (S,G) or (RP,G).
Re-Register an address with nexthop when Interface UP event received,
to ensure the PIM nexthop cache is updated (being PIM enabled).
During PIM neighbor UP, traverse all RPs and Upstreams nexthop and determine, if
any of nexthop's IPv4 address changes/resolves due to neigbor UP event.
Testing Done: Run various LHR, RP and FHR related cases to resolve RPF using
nexthop cache with ECMP knob disabled, performed interface/PIM neighbor flap events.
Executed pim-smoke with knob disabled.
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2017-04-05 22:14:12 +02:00
|
|
|
// Reset kernel installed flag
|
2016-07-12 21:22:10 +02:00
|
|
|
c_oil->installed = 0;
|
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2016-07-13 17:41:41 +02:00
|
|
|
|
|
|
|
void pim_mroute_update_counters(struct channel_oil *c_oil)
|
|
|
|
{
|
2017-05-21 15:16:49 +02:00
|
|
|
struct pim_instance *pim = c_oil->pim;
|
2022-03-03 17:25:50 +01:00
|
|
|
pim_sioc_sg_req sgreq;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-13 17:41:41 +02:00
|
|
|
c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
|
|
|
|
c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
|
|
|
|
c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-27 05:13:42 +02:00
|
|
|
if (!c_oil->installed) {
|
2017-07-13 03:16:00 +02:00
|
|
|
c_oil->cc.lastused = 100 * pim->keep_alive_time;
|
2016-09-27 05:13:42 +02:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
2022-01-04 17:54:44 +01:00
|
|
|
pim_sgaddr sg;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-01-18 14:33:04 +01:00
|
|
|
sg.src = *oil_origin(c_oil);
|
|
|
|
sg.grp = *oil_mcastgrp(c_oil);
|
2022-01-04 21:24:48 +01:00
|
|
|
zlog_debug("Channel%pSG is not installed no need to collect data from kernel",
|
|
|
|
&sg);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
return;
|
2016-09-27 05:13:42 +02:00
|
|
|
}
|
|
|
|
|
2022-01-18 14:33:04 +01:00
|
|
|
|
2016-09-27 05:13:42 +02:00
|
|
|
memset(&sgreq, 0, sizeof(sgreq));
|
2022-03-03 17:25:50 +01:00
|
|
|
|
2022-04-05 16:55:22 +02:00
|
|
|
pim_zlookup_sg_statistics(c_oil);
|
|
|
|
|
2022-03-03 17:25:50 +01:00
|
|
|
#if PIM_IPV == 4
|
2022-01-18 14:33:04 +01:00
|
|
|
sgreq.src = *oil_origin(c_oil);
|
|
|
|
sgreq.grp = *oil_mcastgrp(c_oil);
|
2022-03-03 17:25:50 +01:00
|
|
|
#else
|
|
|
|
sgreq.src = c_oil->oil.mf6cc_origin;
|
|
|
|
sgreq.grp = c_oil->oil.mf6cc_mcastgrp;
|
|
|
|
#endif
|
|
|
|
if (ioctl(pim->mroute_socket, PIM_SIOCGETSGCNT, &sgreq)) {
|
2022-01-04 17:54:44 +01:00
|
|
|
pim_sgaddr sg;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-01-18 14:33:04 +01:00
|
|
|
sg.src = *oil_origin(c_oil);
|
|
|
|
sg.grp = *oil_mcastgrp(c_oil);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-03-03 17:25:50 +01:00
|
|
|
zlog_warn(
|
|
|
|
"ioctl(PIM_SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
|
|
|
|
(unsigned long)PIM_SIOCGETSGCNT, &sg, errno,
|
|
|
|
safe_strerror(errno));
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2016-09-27 05:13:42 +02:00
|
|
|
}
|
2016-07-13 17:41:41 +02:00
|
|
|
|
|
|
|
c_oil->cc.pktcnt = sgreq.pktcnt;
|
|
|
|
c_oil->cc.bytecnt = sgreq.bytecnt;
|
|
|
|
c_oil->cc.wrong_if = sgreq.wrong_if;
|
|
|
|
return;
|
|
|
|
}
|