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
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
2015-02-04 07:01:14 +01:00
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
|
|
|
#include "log.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "linklist.h"
|
2016-06-18 02:43:21 +02:00
|
|
|
#include "if.h"
|
2016-10-13 14:34:48 +02:00
|
|
|
#include "hash.h"
|
|
|
|
#include "jhash.h"
|
2015-02-04 07:01:14 +01:00
|
|
|
|
|
|
|
#include "pimd.h"
|
|
|
|
#include "pim_oil.h"
|
|
|
|
#include "pim_str.h"
|
|
|
|
#include "pim_iface.h"
|
2015-10-28 20:22:22 +01:00
|
|
|
#include "pim_time.h"
|
2019-11-15 18:16:15 +01:00
|
|
|
#include "pim_vxlan.h"
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2019-11-15 18:57:05 +01:00
|
|
|
static void pim_channel_update_mute(struct channel_oil *c_oil);
|
|
|
|
|
2017-01-19 18:09:26 +01:00
|
|
|
char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size)
|
|
|
|
{
|
2018-08-18 04:33:38 +02:00
|
|
|
char *out;
|
2019-06-15 01:01:46 +02:00
|
|
|
struct interface *ifp;
|
2017-01-19 18:09:26 +01:00
|
|
|
struct prefix_sg sg;
|
|
|
|
int i;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-01-19 18:09:26 +01:00
|
|
|
sg.src = c_oil->oil.mfcc_origin;
|
|
|
|
sg.grp = c_oil->oil.mfcc_mcastgrp;
|
2019-06-15 01:01:46 +02:00
|
|
|
ifp = pim_if_find_by_vif_index(c_oil->pim, c_oil->oil.mfcc_parent);
|
|
|
|
snprintf(buf, size, "%s IIF: %s, OIFS: ", pim_str_sg_dump(&sg),
|
|
|
|
ifp ? ifp->name : "(?)");
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-08-18 04:33:38 +02:00
|
|
|
out = buf + strlen(buf);
|
2017-01-19 18:09:26 +01:00
|
|
|
for (i = 0; i < MAXVIFS; i++) {
|
|
|
|
if (c_oil->oil.mfcc_ttls[i] != 0) {
|
2019-06-15 01:01:46 +02:00
|
|
|
ifp = pim_if_find_by_vif_index(c_oil->pim, i);
|
|
|
|
snprintf(out, buf + size - out, "%s ",
|
|
|
|
ifp ? ifp->name : "(?)");
|
2018-08-18 04:33:38 +02:00
|
|
|
out += strlen(out);
|
2017-01-19 18:09:26 +01:00
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-01-19 18:09:26 +01:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2019-12-21 04:12:19 +01:00
|
|
|
int pim_channel_oil_compare(const struct channel_oil *c1,
|
|
|
|
const struct channel_oil *c2)
|
2016-10-13 14:34:48 +02:00
|
|
|
{
|
|
|
|
if (ntohl(c1->oil.mfcc_mcastgrp.s_addr)
|
|
|
|
< ntohl(c2->oil.mfcc_mcastgrp.s_addr))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ntohl(c1->oil.mfcc_mcastgrp.s_addr)
|
|
|
|
> ntohl(c2->oil.mfcc_mcastgrp.s_addr))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (ntohl(c1->oil.mfcc_origin.s_addr)
|
|
|
|
< ntohl(c2->oil.mfcc_origin.s_addr))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (ntohl(c1->oil.mfcc_origin.s_addr)
|
|
|
|
> ntohl(c2->oil.mfcc_origin.s_addr))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-21 14:45:46 +02:00
|
|
|
void pim_oil_init(struct pim_instance *pim)
|
2016-10-13 14:34:48 +02:00
|
|
|
{
|
2019-12-21 04:12:19 +01:00
|
|
|
rb_pim_oil_init(&pim->channel_oil_head);
|
2016-10-13 14:34:48 +02:00
|
|
|
}
|
|
|
|
|
2017-05-21 14:45:46 +02:00
|
|
|
void pim_oil_terminate(struct pim_instance *pim)
|
2016-10-13 14:34:48 +02:00
|
|
|
{
|
2019-12-21 04:12:19 +01:00
|
|
|
struct channel_oil *c_oil;
|
|
|
|
|
|
|
|
while ((c_oil = rb_pim_oil_pop(&pim->channel_oil_head)))
|
|
|
|
pim_channel_oil_free(c_oil);
|
2016-10-13 14:34:48 +02:00
|
|
|
|
2019-12-21 04:12:19 +01:00
|
|
|
rb_pim_oil_fini(&pim->channel_oil_head);
|
2016-10-13 14:34:48 +02:00
|
|
|
}
|
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
void pim_channel_oil_free(struct channel_oil *c_oil)
|
|
|
|
{
|
|
|
|
XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil);
|
|
|
|
}
|
|
|
|
|
2018-02-12 23:41:33 +01:00
|
|
|
struct channel_oil *pim_find_channel_oil(struct pim_instance *pim,
|
|
|
|
struct prefix_sg *sg)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2017-02-13 20:18:48 +01:00
|
|
|
struct channel_oil *c_oil = NULL;
|
|
|
|
struct channel_oil lookup;
|
|
|
|
|
|
|
|
lookup.oil.mfcc_mcastgrp = sg->grp;
|
|
|
|
lookup.oil.mfcc_origin = sg->src;
|
|
|
|
|
2019-12-21 04:12:19 +01:00
|
|
|
c_oil = rb_pim_oil_find(&pim->channel_oil_head, &lookup);
|
2017-02-13 20:18:48 +01:00
|
|
|
|
|
|
|
return c_oil;
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2017-05-21 14:45:46 +02:00
|
|
|
struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
|
|
|
|
struct prefix_sg *sg,
|
2019-11-15 20:09:13 +01:00
|
|
|
const char *name)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
|
|
|
struct channel_oil *c_oil;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-21 14:45:46 +02:00
|
|
|
c_oil = pim_find_channel_oil(pim, sg);
|
2017-02-13 20:18:48 +01:00
|
|
|
if (c_oil) {
|
|
|
|
++c_oil->oil_ref_count;
|
2019-11-15 18:57:05 +01:00
|
|
|
|
|
|
|
if (!c_oil->up) {
|
|
|
|
/* channel might be present prior to upstream */
|
|
|
|
c_oil->up = pim_upstream_find(
|
|
|
|
pim, sg);
|
|
|
|
/* if the upstream entry is being anchored to an
|
|
|
|
* already existing channel OIL we need to re-evaluate
|
|
|
|
* the "Mute" state on AA OIFs
|
|
|
|
*/
|
|
|
|
pim_channel_update_mute(c_oil);
|
|
|
|
}
|
2019-06-15 01:18:51 +02:00
|
|
|
|
2019-11-15 20:09:13 +01:00
|
|
|
/* check if the IIF has changed
|
|
|
|
* XXX - is this really needed
|
|
|
|
*/
|
|
|
|
pim_upstream_mroute_iif_update(c_oil, __func__);
|
|
|
|
|
2019-06-15 01:18:51 +02:00
|
|
|
if (PIM_DEBUG_MROUTE)
|
|
|
|
zlog_debug(
|
|
|
|
"%s(%s): Existing oil for %pSG4 Ref Count: %d (Post Increment)",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, name, sg, c_oil->oil_ref_count);
|
2017-02-13 20:18:48 +01:00
|
|
|
return c_oil;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-08-02 10:38:11 +02:00
|
|
|
c_oil->oil.mfcc_mcastgrp = sg->grp;
|
|
|
|
c_oil->oil.mfcc_origin = sg->src;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-11-15 20:09:13 +01:00
|
|
|
c_oil->oil.mfcc_parent = MAXVIFS;
|
2015-02-04 07:01:14 +01:00
|
|
|
c_oil->oil_ref_count = 1;
|
2016-07-12 21:22:10 +02:00
|
|
|
c_oil->installed = 0;
|
2017-05-21 14:45:46 +02:00
|
|
|
c_oil->up = pim_upstream_find(pim, sg);
|
|
|
|
c_oil->pim = pim;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-12-21 04:12:19 +01:00
|
|
|
rb_pim_oil_add(&pim->channel_oil_head, c_oil);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-06-15 01:18:51 +02:00
|
|
|
if (PIM_DEBUG_MROUTE)
|
2019-11-15 20:09:13 +01:00
|
|
|
zlog_debug("%s(%s): c_oil %s add",
|
|
|
|
__func__, name, pim_str_sg_dump(sg));
|
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
return c_oil;
|
|
|
|
}
|
|
|
|
|
2019-11-15 18:57:05 +01:00
|
|
|
struct channel_oil *pim_channel_oil_del(struct channel_oil *c_oil,
|
2020-02-19 15:52:17 +01:00
|
|
|
const char *name)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2019-06-15 01:18:51 +02:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
|
|
|
struct prefix_sg sg = {.src = c_oil->oil.mfcc_mcastgrp,
|
|
|
|
.grp = c_oil->oil.mfcc_origin};
|
|
|
|
|
|
|
|
zlog_debug(
|
|
|
|
"%s(%s): Del oil for %pSG4, Ref Count: %d (Predecrement)",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, name, &sg, c_oil->oil_ref_count);
|
2019-06-15 01:18:51 +02:00
|
|
|
}
|
2015-02-04 07:01:14 +01:00
|
|
|
--c_oil->oil_ref_count;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (c_oil->oil_ref_count < 1) {
|
2017-02-13 20:18:48 +01:00
|
|
|
/*
|
|
|
|
* notice that listnode_delete() can't be moved
|
|
|
|
* into pim_channel_oil_free() because the later is
|
|
|
|
* called by list_delete_all_node()
|
|
|
|
*/
|
2017-04-27 20:01:32 +02:00
|
|
|
c_oil->up = NULL;
|
2019-12-21 04:12:19 +01:00
|
|
|
rb_pim_oil_del(&c_oil->pim->channel_oil_head, c_oil);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-02-13 20:18:48 +01:00
|
|
|
pim_channel_oil_free(c_oil);
|
2019-11-15 18:57:05 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return c_oil;
|
|
|
|
}
|
|
|
|
|
|
|
|
void pim_channel_oil_upstream_deref(struct channel_oil *c_oil)
|
|
|
|
{
|
|
|
|
/* The upstream entry associated with a channel_oil is abt to be
|
|
|
|
* deleted. If the channel_oil is kept around because of other
|
|
|
|
* references we need to remove upstream based states out of it.
|
|
|
|
*/
|
|
|
|
c_oil = pim_channel_oil_del(c_oil, __func__);
|
|
|
|
if (c_oil) {
|
|
|
|
/* note: here we assume that c_oil->up has already been
|
|
|
|
* cleared
|
|
|
|
*/
|
|
|
|
pim_channel_update_mute(c_oil);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
}
|
2015-10-28 19:00:37 +01:00
|
|
|
|
2016-07-18 01:51:56 +02:00
|
|
|
int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif,
|
2019-11-15 17:47:33 +01:00
|
|
|
uint32_t proto_mask, const char *caller)
|
2016-07-18 01:51:56 +02:00
|
|
|
{
|
|
|
|
struct pim_interface *pim_ifp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-04-23 11:23:57 +02:00
|
|
|
assert(channel_oil);
|
|
|
|
assert(oif);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-18 01:51:56 +02:00
|
|
|
pim_ifp = oif->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-18 01:51:56 +02:00
|
|
|
/*
|
|
|
|
* Don't do anything if we've been asked to remove a source
|
|
|
|
* that is not actually on it.
|
|
|
|
*/
|
|
|
|
if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
|
2015-10-28 19:00:37 +01:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
2016-10-20 16:09:30 +02:00
|
|
|
char group_str[INET_ADDRSTRLEN];
|
|
|
|
char source_str[INET_ADDRSTRLEN];
|
2016-07-18 01:51:56 +02:00
|
|
|
pim_inet4_dump("<group?>",
|
|
|
|
channel_oil->oil.mfcc_mcastgrp,
|
|
|
|
group_str, sizeof(group_str));
|
|
|
|
pim_inet4_dump("<source?>",
|
|
|
|
channel_oil->oil.mfcc_origin, source_str,
|
|
|
|
sizeof(source_str));
|
|
|
|
zlog_debug(
|
2016-06-29 13:57:47 +02:00
|
|
|
"%s %s: no existing protocol mask %u(%u) for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
|
2020-03-05 19:17:54 +01:00
|
|
|
__FILE__, __func__, proto_mask,
|
2015-02-04 07:01:14 +01:00
|
|
|
channel_oil
|
2016-07-18 01:51:56 +02:00
|
|
|
->oif_flags[pim_ifp->mroute_vif_index],
|
|
|
|
oif->name, pim_ifp->mroute_vif_index,
|
2015-10-28 19:00:37 +01:00
|
|
|
channel_oil->oil
|
2016-07-18 01:51:56 +02:00
|
|
|
.mfcc_ttls[pim_ifp->mroute_vif_index],
|
|
|
|
source_str, group_str);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2016-07-18 01:51:56 +02:00
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2016-07-18 01:51:56 +02:00
|
|
|
channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-11-15 18:16:15 +01:00
|
|
|
if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] &
|
|
|
|
PIM_OIF_FLAG_PROTO_ANY) {
|
2016-07-18 01:51:56 +02:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
2016-10-20 16:09:30 +02:00
|
|
|
char group_str[INET_ADDRSTRLEN];
|
|
|
|
char source_str[INET_ADDRSTRLEN];
|
2016-07-18 01:51:56 +02:00
|
|
|
pim_inet4_dump("<group?>",
|
|
|
|
channel_oil->oil.mfcc_mcastgrp,
|
|
|
|
group_str, sizeof(group_str));
|
|
|
|
pim_inet4_dump("<source?>",
|
|
|
|
channel_oil->oil.mfcc_origin, source_str,
|
|
|
|
sizeof(source_str));
|
|
|
|
zlog_debug(
|
|
|
|
"%s %s: other protocol masks remain for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
|
2020-03-05 19:17:54 +01:00
|
|
|
__FILE__, __func__, oif->name,
|
2016-07-18 01:51:56 +02:00
|
|
|
pim_ifp->mroute_vif_index,
|
|
|
|
channel_oil->oil
|
|
|
|
.mfcc_ttls[pim_ifp->mroute_vif_index],
|
|
|
|
source_str, group_str);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2016-07-18 01:51:56 +02:00
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2016-07-18 01:51:56 +02:00
|
|
|
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
|
2019-11-15 18:16:15 +01:00
|
|
|
/* clear mute; will be re-evaluated when the OIF becomes valid again */
|
|
|
|
channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~PIM_OIF_FLAG_MUTE;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-03-05 19:17:54 +01:00
|
|
|
if (pim_upstream_mroute_add(channel_oil, __func__)) {
|
2015-10-28 19:00:37 +01:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
2016-12-05 23:53:49 +01:00
|
|
|
char group_str[INET_ADDRSTRLEN];
|
2016-07-18 01:51:56 +02:00
|
|
|
char source_str[INET_ADDRSTRLEN];
|
2016-12-05 23:53:49 +01:00
|
|
|
pim_inet4_dump("<group?>",
|
|
|
|
channel_oil->oil.mfcc_mcastgrp,
|
2016-07-18 01:51:56 +02:00
|
|
|
group_str, sizeof(group_str));
|
2016-12-05 23:53:49 +01:00
|
|
|
pim_inet4_dump("<source?>",
|
|
|
|
channel_oil->oil.mfcc_origin, source_str,
|
|
|
|
sizeof(source_str));
|
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>
(cherry picked from commit cba444817883b8b3b22a7ed9958dc9ed77f76230)
2017-04-05 22:14:12 +02:00
|
|
|
zlog_debug(
|
2016-07-18 01:51:56 +02:00
|
|
|
"%s %s: could not remove output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
|
2020-03-05 19:17:54 +01:00
|
|
|
__FILE__, __func__, oif->name,
|
2016-07-18 01:51:56 +02:00
|
|
|
pim_ifp->mroute_vif_index, source_str,
|
2016-12-05 23:53:49 +01:00
|
|
|
group_str);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2016-07-18 01:51:56 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-18 01:51:56 +02:00
|
|
|
--channel_oil->oil_size;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-18 01:51:56 +02:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
2016-10-20 16:09:30 +02:00
|
|
|
char group_str[INET_ADDRSTRLEN];
|
|
|
|
char source_str[INET_ADDRSTRLEN];
|
2016-07-18 01:51:56 +02:00
|
|
|
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp,
|
|
|
|
group_str, sizeof(group_str));
|
|
|
|
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin,
|
|
|
|
source_str, sizeof(source_str));
|
|
|
|
zlog_debug(
|
2019-11-15 17:47:33 +01:00
|
|
|
"%s(%s): (S,G)=(%s,%s): proto_mask=%u IIF:%d OIF=%s vif_index=%d",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, caller, source_str, group_str, proto_mask,
|
|
|
|
channel_oil->oil.mfcc_parent, oif->name,
|
2016-07-18 01:51:56 +02:00
|
|
|
pim_ifp->mroute_vif_index);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-18 01:51:56 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-15 20:43:27 +01:00
|
|
|
void pim_channel_del_inherited_oif(struct channel_oil *c_oil,
|
|
|
|
struct interface *oif, const char *caller)
|
|
|
|
{
|
|
|
|
struct pim_upstream *up = c_oil->up;
|
|
|
|
|
|
|
|
pim_channel_del_oif(c_oil, oif, PIM_OIF_FLAG_PROTO_STAR,
|
|
|
|
caller);
|
|
|
|
|
|
|
|
/* if an inherited OIF is being removed join-desired can change
|
|
|
|
* if the inherited OIL is now empty and KAT is running
|
|
|
|
*/
|
|
|
|
if (up && up->sg.src.s_addr != INADDR_ANY &&
|
|
|
|
pim_upstream_empty_inherited_olist(up))
|
|
|
|
pim_upstream_update_join_desired(up->pim, up);
|
|
|
|
}
|
2016-07-18 01:51:56 +02:00
|
|
|
|
2019-11-15 18:16:15 +01:00
|
|
|
static bool pim_channel_eval_oif_mute(struct channel_oil *c_oil,
|
|
|
|
struct pim_interface *pim_ifp)
|
|
|
|
{
|
|
|
|
struct pim_interface *pim_reg_ifp;
|
|
|
|
struct pim_interface *vxlan_ifp;
|
|
|
|
bool do_mute = false;
|
|
|
|
struct pim_instance *pim = c_oil->pim;
|
|
|
|
|
|
|
|
if (!c_oil->up)
|
|
|
|
return do_mute;
|
|
|
|
|
|
|
|
pim_reg_ifp = pim->regiface->info;
|
|
|
|
if (pim_ifp == pim_reg_ifp) {
|
|
|
|
/* suppress pimreg in the OIL if the mroute is not supposed to
|
|
|
|
* trigger register encapsulated data
|
|
|
|
*/
|
|
|
|
if (PIM_UPSTREAM_FLAG_TEST_NO_PIMREG_DATA(c_oil->up->flags))
|
|
|
|
do_mute = true;
|
|
|
|
|
|
|
|
return do_mute;
|
|
|
|
}
|
|
|
|
|
|
|
|
vxlan_ifp = pim_vxlan_get_term_ifp(pim);
|
|
|
|
if (pim_ifp == vxlan_ifp) {
|
|
|
|
/* 1. vxlan termination device must never be added to the
|
|
|
|
* origination mroute (and that can actually happen because
|
|
|
|
* of XG inheritance from the termination mroute) otherwise
|
|
|
|
* traffic will end up looping.
|
|
|
|
* PS: This check has also been extended to non-orig mroutes
|
|
|
|
* that have a local SIP as such mroutes can move back and
|
|
|
|
* forth between orig<=>non-orig type.
|
|
|
|
* 2. vxlan termination device should be removed from the non-DF
|
|
|
|
* to prevent duplicates to the overlay rxer
|
|
|
|
*/
|
|
|
|
if (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(c_oil->up->flags) ||
|
|
|
|
PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(c_oil->up->flags) ||
|
|
|
|
pim_vxlan_is_local_sip(c_oil->up))
|
|
|
|
do_mute = true;
|
|
|
|
|
|
|
|
return do_mute;
|
|
|
|
}
|
|
|
|
|
2020-06-03 18:12:32 +02:00
|
|
|
if (PIM_I_am_DualActive(pim_ifp)) {
|
|
|
|
struct pim_upstream *starup = c_oil->up->parent;
|
|
|
|
if (PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(c_oil->up->flags)
|
|
|
|
&& (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(c_oil->up->flags)))
|
|
|
|
do_mute = true;
|
|
|
|
|
|
|
|
/* In case entry is (S,G), Negotiation happens at (*.G) */
|
|
|
|
if (starup
|
|
|
|
|
|
|
|
&& PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(starup->flags)
|
|
|
|
&& (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(starup->flags)))
|
|
|
|
do_mute = true;
|
|
|
|
return do_mute;
|
|
|
|
}
|
2019-11-15 18:16:15 +01:00
|
|
|
return do_mute;
|
|
|
|
}
|
|
|
|
|
|
|
|
void pim_channel_update_oif_mute(struct channel_oil *c_oil,
|
|
|
|
struct pim_interface *pim_ifp)
|
|
|
|
{
|
|
|
|
bool old_mute;
|
|
|
|
bool new_mute;
|
|
|
|
|
|
|
|
/* If pim_ifp is not a part of the OIL there is nothing to do */
|
|
|
|
if (!c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])
|
|
|
|
return;
|
|
|
|
|
|
|
|
old_mute = !!(c_oil->oif_flags[pim_ifp->mroute_vif_index] &
|
|
|
|
PIM_OIF_FLAG_MUTE);
|
|
|
|
new_mute = pim_channel_eval_oif_mute(c_oil, pim_ifp);
|
|
|
|
if (old_mute == new_mute)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (new_mute)
|
|
|
|
c_oil->oif_flags[pim_ifp->mroute_vif_index] |=
|
|
|
|
PIM_OIF_FLAG_MUTE;
|
|
|
|
else
|
|
|
|
c_oil->oif_flags[pim_ifp->mroute_vif_index] &=
|
|
|
|
~PIM_OIF_FLAG_MUTE;
|
|
|
|
|
2020-03-05 19:17:54 +01:00
|
|
|
pim_upstream_mroute_add(c_oil, __func__);
|
2019-11-15 18:16:15 +01:00
|
|
|
}
|
|
|
|
|
2019-11-15 18:57:05 +01:00
|
|
|
/* pim_upstream has been set or cleared on the c_oil. re-eval mute state
|
|
|
|
* on all existing OIFs
|
|
|
|
*/
|
|
|
|
static void pim_channel_update_mute(struct channel_oil *c_oil)
|
|
|
|
{
|
|
|
|
struct pim_interface *pim_reg_ifp;
|
|
|
|
struct pim_interface *vxlan_ifp;
|
|
|
|
|
|
|
|
pim_reg_ifp = c_oil->pim->regiface->info;
|
|
|
|
if (pim_reg_ifp)
|
|
|
|
pim_channel_update_oif_mute(c_oil, pim_reg_ifp);
|
|
|
|
vxlan_ifp = pim_vxlan_get_term_ifp(c_oil->pim);
|
|
|
|
if (vxlan_ifp)
|
|
|
|
pim_channel_update_oif_mute(c_oil, vxlan_ifp);
|
|
|
|
}
|
|
|
|
|
2015-10-28 19:00:37 +01:00
|
|
|
int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
|
2019-11-15 17:47:33 +01:00
|
|
|
uint32_t proto_mask, const char *caller)
|
2015-10-28 19:00:37 +01:00
|
|
|
{
|
|
|
|
struct pim_interface *pim_ifp;
|
|
|
|
int old_ttl;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-08-24 17:23:41 +02:00
|
|
|
/*
|
|
|
|
* If we've gotten here we've gone bad, but let's
|
|
|
|
* not take down pim
|
|
|
|
*/
|
|
|
|
if (!channel_oil) {
|
|
|
|
zlog_warn("Attempt to Add OIF for non-existent channel oil");
|
|
|
|
return -1;
|
|
|
|
}
|
2015-10-28 19:00:37 +01:00
|
|
|
|
|
|
|
pim_ifp = oif->info;
|
|
|
|
|
|
|
|
/* Prevent single protocol from subscribing same interface to
|
|
|
|
channel (S,G) multiple times */
|
|
|
|
if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
|
2016-06-29 13:57:47 +02:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
2016-10-20 16:09:30 +02:00
|
|
|
char group_str[INET_ADDRSTRLEN];
|
|
|
|
char source_str[INET_ADDRSTRLEN];
|
2016-06-29 13:57:47 +02:00
|
|
|
pim_inet4_dump("<group?>",
|
|
|
|
channel_oil->oil.mfcc_mcastgrp,
|
|
|
|
group_str, sizeof(group_str));
|
|
|
|
pim_inet4_dump("<source?>",
|
|
|
|
channel_oil->oil.mfcc_origin, source_str,
|
|
|
|
sizeof(source_str));
|
|
|
|
zlog_debug(
|
|
|
|
"%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
|
2020-03-05 19:17:54 +01:00
|
|
|
__FILE__, __func__, proto_mask, oif->name,
|
|
|
|
pim_ifp->mroute_vif_index,
|
2016-06-29 13:57:47 +02:00
|
|
|
channel_oil->oil
|
|
|
|
.mfcc_ttls[pim_ifp->mroute_vif_index],
|
|
|
|
source_str, group_str);
|
|
|
|
}
|
2015-10-28 19:00:37 +01:00
|
|
|
return -3;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-10-28 19:00:37 +01:00
|
|
|
/* Allow other protocol to request subscription of same interface to
|
2017-01-19 18:09:26 +01:00
|
|
|
* channel (S,G), we need to note this information
|
|
|
|
*/
|
2015-10-28 19:00:37 +01:00
|
|
|
if (channel_oil->oif_flags[pim_ifp->mroute_vif_index]
|
|
|
|
& PIM_OIF_FLAG_PROTO_ANY) {
|
2017-07-17 14:03:14 +02:00
|
|
|
|
pimd: Don't refersh the oif_creation timer if S,G already present
Issue: Shut the RP interface in the router RP. LHR will get to know
RP becomes not-reachable, so it send a prune towards the RP. On
receiving the prune, RP clear the (*, G) entry, but (S, G) should
not get removed if present.
Now no-shut the RP interface in the router RP. LHR will send a (*, G)
join towards the RP. On receiving join FRR create the (*, G) entry.
Along with this, it also add the interface(join received) in the OIL
of (S, G) and also refresh the (S, G) timer.
Fix: Dont refresh the timer for S, G or (*, G), if the flag for the
channel OIL is PIM_OIF_FLAG_PROTO_ANY.
Signed-off-by: Sarita Patra <saritap@vmware.com>
2019-02-08 08:50:12 +01:00
|
|
|
/* Updating time here is not required as this time has to
|
|
|
|
* indicate when the interface is added
|
|
|
|
*/
|
|
|
|
|
2017-01-19 18:09:26 +01:00
|
|
|
channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
|
2015-10-28 19:00:37 +01:00
|
|
|
/* Check the OIF really exists before returning, and only log
|
|
|
|
warning otherwise */
|
|
|
|
if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
|
2017-01-19 18:09:26 +01:00
|
|
|
{
|
|
|
|
char group_str[INET_ADDRSTRLEN];
|
|
|
|
char source_str[INET_ADDRSTRLEN];
|
|
|
|
pim_inet4_dump("<group?>",
|
|
|
|
channel_oil->oil.mfcc_mcastgrp,
|
|
|
|
group_str, sizeof(group_str));
|
|
|
|
pim_inet4_dump("<source?>",
|
|
|
|
channel_oil->oil.mfcc_origin,
|
|
|
|
source_str, sizeof(source_str));
|
|
|
|
zlog_warn(
|
|
|
|
"%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
|
2020-03-05 19:17:54 +01:00
|
|
|
__FILE__, __func__, proto_mask,
|
|
|
|
oif->name, pim_ifp->mroute_vif_index,
|
2017-01-19 18:09:26 +01:00
|
|
|
channel_oil->oil.mfcc_ttls
|
|
|
|
[pim_ifp->mroute_vif_index],
|
|
|
|
source_str, group_str);
|
2015-10-28 19:00:37 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2019-10-14 21:41:33 +02:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
|
|
|
char group_str[INET_ADDRSTRLEN];
|
|
|
|
char source_str[INET_ADDRSTRLEN];
|
|
|
|
pim_inet4_dump("<group?>",
|
|
|
|
channel_oil->oil.mfcc_mcastgrp,
|
|
|
|
group_str, sizeof(group_str));
|
|
|
|
pim_inet4_dump("<source?>",
|
|
|
|
channel_oil->oil.mfcc_origin, source_str,
|
|
|
|
sizeof(source_str));
|
|
|
|
zlog_debug(
|
|
|
|
"%s(%s): (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d added to 0x%x",
|
|
|
|
__func__, caller, source_str, group_str,
|
|
|
|
proto_mask, oif->name,
|
|
|
|
pim_ifp->mroute_vif_index,
|
|
|
|
channel_oil
|
|
|
|
->oif_flags[pim_ifp->mroute_vif_index]);
|
|
|
|
}
|
2015-10-28 19:00:37 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-10-28 19:00:37 +01:00
|
|
|
old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-10-28 19:00:37 +01:00
|
|
|
if (old_ttl > 0) {
|
2016-06-29 13:57:47 +02:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
2016-10-20 16:09:30 +02:00
|
|
|
char group_str[INET_ADDRSTRLEN];
|
|
|
|
char source_str[INET_ADDRSTRLEN];
|
2016-06-29 13:57:47 +02:00
|
|
|
pim_inet4_dump("<group?>",
|
|
|
|
channel_oil->oil.mfcc_mcastgrp,
|
|
|
|
group_str, sizeof(group_str));
|
|
|
|
pim_inet4_dump("<source?>",
|
|
|
|
channel_oil->oil.mfcc_origin, source_str,
|
|
|
|
sizeof(source_str));
|
|
|
|
zlog_debug(
|
|
|
|
"%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
|
2020-03-05 19:17:54 +01:00
|
|
|
__FILE__, __func__, oif->name,
|
2016-06-29 13:57:47 +02:00
|
|
|
pim_ifp->mroute_vif_index, source_str,
|
|
|
|
group_str);
|
|
|
|
}
|
2015-10-28 19:00:37 +01:00
|
|
|
return -4;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-10-28 19:00:37 +01:00
|
|
|
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] =
|
|
|
|
PIM_MROUTE_MIN_TTL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-11-15 18:16:15 +01:00
|
|
|
/* Some OIFs are held in a muted state i.e. the PIM state machine
|
|
|
|
* decided to include the OIF but additional status check such as
|
|
|
|
* MLAG DF role prevent it from being activated for traffic
|
|
|
|
* forwarding.
|
|
|
|
*/
|
|
|
|
if (pim_channel_eval_oif_mute(channel_oil, pim_ifp))
|
|
|
|
channel_oil->oif_flags[pim_ifp->mroute_vif_index] |=
|
|
|
|
PIM_OIF_FLAG_MUTE;
|
|
|
|
else
|
|
|
|
channel_oil->oif_flags[pim_ifp->mroute_vif_index] &=
|
|
|
|
~PIM_OIF_FLAG_MUTE;
|
|
|
|
|
2019-03-19 04:22:04 +01:00
|
|
|
/* channel_oil->oil.mfcc_parent != MAXVIFS indicate this entry is not
|
|
|
|
* valid to get installed in kernel.
|
2019-02-22 12:31:56 +01:00
|
|
|
*/
|
2019-03-19 04:22:04 +01:00
|
|
|
if (channel_oil->oil.mfcc_parent != MAXVIFS) {
|
2020-03-05 19:17:54 +01:00
|
|
|
if (pim_upstream_mroute_add(channel_oil, __func__)) {
|
2019-02-22 12:31:56 +01:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
|
|
|
char group_str[INET_ADDRSTRLEN];
|
|
|
|
char source_str[INET_ADDRSTRLEN];
|
|
|
|
pim_inet4_dump("<group?>",
|
|
|
|
channel_oil->oil.mfcc_mcastgrp,
|
|
|
|
group_str, sizeof(group_str));
|
|
|
|
pim_inet4_dump("<source?>",
|
|
|
|
channel_oil->oil.mfcc_origin, source_str,
|
|
|
|
sizeof(source_str));
|
|
|
|
zlog_debug(
|
2020-03-05 19:17:54 +01:00
|
|
|
"%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
|
|
|
|
__FILE__, __func__, oif->name,
|
|
|
|
pim_ifp->mroute_vif_index, source_str,
|
|
|
|
group_str);
|
2019-02-22 12:31:56 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-22 12:31:56 +01:00
|
|
|
channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]
|
|
|
|
= old_ttl;
|
|
|
|
return -5;
|
|
|
|
}
|
2015-10-28 19:00:37 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-10-28 19:00:37 +01:00
|
|
|
channel_oil->oif_creation[pim_ifp->mroute_vif_index] =
|
|
|
|
pim_time_monotonic_sec();
|
|
|
|
++channel_oil->oil_size;
|
|
|
|
channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-10-28 19:00:37 +01:00
|
|
|
if (PIM_DEBUG_MROUTE) {
|
2016-10-20 16:09:30 +02:00
|
|
|
char group_str[INET_ADDRSTRLEN];
|
|
|
|
char source_str[INET_ADDRSTRLEN];
|
2015-10-28 19:00:37 +01:00
|
|
|
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp,
|
|
|
|
group_str, sizeof(group_str));
|
|
|
|
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin,
|
|
|
|
source_str, sizeof(source_str));
|
|
|
|
zlog_debug(
|
2019-11-15 17:47:33 +01:00
|
|
|
"%s(%s): (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, caller, source_str, group_str, proto_mask,
|
|
|
|
oif->name, pim_ifp->mroute_vif_index);
|
2015-10-28 19:00:37 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-10-28 19:00:37 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2016-11-10 15:41:28 +01:00
|
|
|
|
|
|
|
int pim_channel_oil_empty(struct channel_oil *c_oil)
|
|
|
|
{
|
2019-11-15 20:42:32 +01:00
|
|
|
static struct mfcctl null_oil;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-10 15:41:28 +01:00
|
|
|
if (!c_oil)
|
|
|
|
return 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-11-19 00:13:37 +01:00
|
|
|
/* 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] */
|
|
|
|
return !memcmp(&c_oil->oil.mfcc_ttls[1], &null_oil.mfcc_ttls[1],
|
|
|
|
sizeof(null_oil.mfcc_ttls) - sizeof(null_oil.mfcc_ttls[0]));
|
2016-11-10 15:41:28 +01:00
|
|
|
}
|