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>
|
|
|
|
|
2016-06-18 02:43:21 +02:00
|
|
|
#include "if.h"
|
2016-07-27 22:33:41 +02:00
|
|
|
#include "log.h"
|
2016-09-13 21:41:33 +02:00
|
|
|
#include "prefix.h"
|
|
|
|
#include "vty.h"
|
|
|
|
#include "plist.h"
|
2016-06-18 02:43:21 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
#include "pimd.h"
|
2022-05-06 12:36:51 +02:00
|
|
|
#include "pim_instance.h"
|
2016-08-05 15:07:46 +02:00
|
|
|
#include "pim_vty.h"
|
2015-02-04 07:01:14 +01:00
|
|
|
#include "pim_pim.h"
|
|
|
|
#include "pim_msg.h"
|
|
|
|
#include "pim_util.h"
|
2016-07-27 22:33:41 +02:00
|
|
|
#include "pim_str.h"
|
2016-11-18 18:12:27 +01:00
|
|
|
#include "pim_iface.h"
|
2016-08-05 15:07:46 +02:00
|
|
|
#include "pim_rp.h"
|
2016-11-02 16:21:49 +01:00
|
|
|
#include "pim_rpf.h"
|
2017-01-12 04:36:50 +01:00
|
|
|
#include "pim_register.h"
|
2017-02-15 03:32:16 +01:00
|
|
|
#include "pim_jp_agg.h"
|
2017-05-22 17:18:22 +02:00
|
|
|
#include "pim_oil.h"
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2022-03-27 11:50:40 +02:00
|
|
|
void pim_msg_build_header(pim_addr src, pim_addr dst, uint8_t *pim_msg,
|
|
|
|
size_t pim_msg_size, uint8_t pim_msg_type,
|
|
|
|
bool no_fwd)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2017-02-09 19:47:42 +01:00
|
|
|
struct pim_msg_header *header = (struct pim_msg_header *)pim_msg;
|
2022-03-27 11:50:40 +02:00
|
|
|
struct iovec iov[2], *iovp = iov;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The checksum for Registers is done only on the first 8 bytes of the
|
|
|
|
* packet, including the PIM header and the next 4 bytes, excluding the
|
|
|
|
* data packet portion
|
|
|
|
*
|
|
|
|
* for IPv6, the pseudoheader upper-level protocol length is also
|
|
|
|
* truncated, so let's just set it here before everything else.
|
|
|
|
*/
|
|
|
|
if (pim_msg_type == PIM_MSG_TYPE_REGISTER)
|
|
|
|
pim_msg_size = PIM_MSG_REGISTER_LEN;
|
|
|
|
|
|
|
|
#if PIM_IPV == 6
|
|
|
|
struct ipv6_ph phdr = {
|
|
|
|
.src = src,
|
|
|
|
.dst = dst,
|
|
|
|
.ulpl = htonl(pim_msg_size),
|
|
|
|
.next_hdr = IPPROTO_PIM,
|
|
|
|
};
|
|
|
|
|
|
|
|
iovp->iov_base = &phdr;
|
|
|
|
iovp->iov_len = sizeof(phdr);
|
|
|
|
iovp++;
|
|
|
|
#endif
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/*
|
|
|
|
* Write header
|
|
|
|
*/
|
2017-02-09 19:47:42 +01:00
|
|
|
header->ver = PIM_PROTO_VERSION;
|
|
|
|
header->type = pim_msg_type;
|
2019-05-04 14:07:39 +02:00
|
|
|
header->Nbit = no_fwd;
|
2017-02-09 19:47:42 +01:00
|
|
|
header->reserved = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-02-09 19:47:42 +01:00
|
|
|
header->checksum = 0;
|
2022-03-27 11:50:40 +02:00
|
|
|
iovp->iov_base = header;
|
|
|
|
iovp->iov_len = pim_msg_size;
|
|
|
|
iovp++;
|
|
|
|
|
|
|
|
header->checksum = in_cksumv(iov, iovp - iov);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2017-02-10 19:46:52 +01:00
|
|
|
uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, struct in_addr addr)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
|
|
|
buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */
|
|
|
|
buf[1] = '\0'; /* native encoding */
|
|
|
|
memcpy(buf + 2, &addr, sizeof(struct in_addr));
|
|
|
|
|
2017-02-09 18:53:00 +01:00
|
|
|
return buf + PIM_ENCODED_IPV4_UCAST_SIZE;
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2017-02-10 19:46:52 +01:00
|
|
|
uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, struct in_addr addr)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
|
|
|
buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */
|
|
|
|
buf[1] = '\0'; /* native encoding */
|
|
|
|
buf[2] = '\0'; /* reserved */
|
|
|
|
buf[3] = 32; /* mask len */
|
|
|
|
memcpy(buf + 4, &addr, sizeof(struct in_addr));
|
|
|
|
|
2017-02-09 18:53:00 +01:00
|
|
|
return buf + PIM_ENCODED_IPV4_GROUP_SIZE;
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2017-02-10 19:46:52 +01:00
|
|
|
uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, struct in_addr addr,
|
|
|
|
uint8_t bits)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
|
|
|
buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */
|
|
|
|
buf[1] = '\0'; /* native encoding */
|
2016-07-27 21:27:52 +02:00
|
|
|
buf[2] = bits;
|
2015-02-04 07:01:14 +01:00
|
|
|
buf[3] = 32; /* mask len */
|
|
|
|
memcpy(buf + 4, &addr, sizeof(struct in_addr));
|
|
|
|
|
2017-02-09 18:53:00 +01:00
|
|
|
return buf + PIM_ENCODED_IPV4_SOURCE_SIZE;
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2016-07-27 22:33:41 +02:00
|
|
|
|
2022-01-14 14:57:21 +01:00
|
|
|
uint8_t *pim_msg_addr_encode_ipv6_source(uint8_t *buf, struct in6_addr addr,
|
|
|
|
uint8_t bits)
|
|
|
|
{
|
|
|
|
buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV6; /* addr family */
|
|
|
|
buf[1] = '\0'; /* native encoding */
|
|
|
|
buf[2] = bits;
|
|
|
|
buf[3] = 128; /* mask len */
|
|
|
|
buf += 4;
|
|
|
|
|
|
|
|
memcpy(buf, &addr, sizeof(addr));
|
|
|
|
buf += sizeof(addr);
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *pim_msg_addr_encode_ipv6_ucast(uint8_t *buf, struct in6_addr addr)
|
|
|
|
{
|
|
|
|
buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV6; /* addr family */
|
|
|
|
buf[1] = '\0'; /* native encoding */
|
|
|
|
buf += 2;
|
|
|
|
|
|
|
|
memcpy(buf, &addr, sizeof(addr));
|
|
|
|
buf += sizeof(addr);
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *pim_msg_addr_encode_ipv6_group(uint8_t *buf, struct in6_addr addr)
|
|
|
|
{
|
|
|
|
buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV6; /* addr family */
|
|
|
|
buf[1] = '\0'; /* native encoding */
|
|
|
|
buf[2] = '\0'; /* reserved */
|
|
|
|
buf[3] = 128; /* mask len */
|
|
|
|
buf += 4;
|
|
|
|
|
|
|
|
memcpy(buf, &addr, sizeof(addr));
|
|
|
|
buf += sizeof(addr);
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2022-01-21 16:47:18 +01:00
|
|
|
#if PIM_IPV == 4
|
2022-01-14 14:57:21 +01:00
|
|
|
#define pim_msg_addr_encode(what) pim_msg_addr_encode_ipv4_##what
|
|
|
|
#else
|
|
|
|
#define pim_msg_addr_encode(what) pim_msg_addr_encode_ipv6_##what
|
|
|
|
#endif
|
|
|
|
|
|
|
|
uint8_t *pim_msg_addr_encode_ucast(uint8_t *buf, pim_addr addr)
|
|
|
|
{
|
|
|
|
return pim_msg_addr_encode(ucast)(buf, addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *pim_msg_addr_encode_group(uint8_t *buf, pim_addr addr)
|
|
|
|
{
|
|
|
|
return pim_msg_addr_encode(group)(buf, addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *pim_msg_addr_encode_source(uint8_t *buf, pim_addr addr, uint8_t bits)
|
|
|
|
{
|
|
|
|
return pim_msg_addr_encode(source)(buf, addr, bits);
|
|
|
|
}
|
|
|
|
|
2017-02-15 03:32:16 +01:00
|
|
|
/*
|
|
|
|
* For the given 'struct pim_jp_sources' list
|
|
|
|
* determine the size_t it would take up.
|
|
|
|
*/
|
|
|
|
size_t pim_msg_get_jp_group_size(struct list *sources)
|
|
|
|
{
|
2017-03-07 03:08:12 +01:00
|
|
|
struct pim_jp_sources *js;
|
2017-02-15 03:32:16 +01:00
|
|
|
size_t size = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-11 02:00:07 +02:00
|
|
|
if (!sources)
|
|
|
|
return 0;
|
|
|
|
|
2022-01-14 14:57:21 +01:00
|
|
|
size += sizeof(pim_encoded_group);
|
2017-02-15 03:32:16 +01:00
|
|
|
size += 4; // Joined sources (2) + Pruned Sources (2)
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-01-14 14:57:21 +01:00
|
|
|
size += sizeof(pim_encoded_source) * sources->count;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-03-07 03:08:12 +01:00
|
|
|
js = listgetdata(listhead(sources));
|
2022-01-04 21:48:13 +01:00
|
|
|
if (js && pim_addr_is_any(js->up->sg.src) && js->is_join) {
|
2017-03-07 03:08:12 +01:00
|
|
|
struct pim_upstream *child, *up;
|
|
|
|
struct listnode *up_node;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-03-07 03:08:12 +01:00
|
|
|
up = js->up;
|
|
|
|
if (PIM_DEBUG_PIM_PACKETS)
|
|
|
|
zlog_debug(
|
|
|
|
"%s: Considering (%s) children for (S,G,rpt) prune",
|
2020-03-06 15:23:22 +01:00
|
|
|
__func__, up->sg_str);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-03-07 03:08:12 +01:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(up->sources, up_node, child)) {
|
2019-11-15 20:32:10 +01:00
|
|
|
if (!PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags)) {
|
|
|
|
/* If we are using SPT and the SPT and RPT IIFs
|
|
|
|
* are different we can prune the source off
|
|
|
|
* of the RPT.
|
|
|
|
* If RPF_interface(S) is not resolved hold
|
|
|
|
* decision to prune as SPT may end up on the
|
|
|
|
* same IIF as RPF_interface(RP).
|
|
|
|
*/
|
|
|
|
if (child->rpf.source_nexthop.interface &&
|
|
|
|
!pim_rpf_is_same(&up->rpf,
|
|
|
|
&child->rpf)) {
|
2022-01-14 14:57:21 +01:00
|
|
|
size += sizeof(pim_encoded_source);
|
2017-03-07 03:08:12 +01:00
|
|
|
PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(
|
|
|
|
child->flags);
|
|
|
|
if (PIM_DEBUG_PIM_PACKETS)
|
|
|
|
zlog_debug(
|
|
|
|
"%s: SPT Bit and RPF'(%s) != RPF'(S,G): Add Prune (%s,rpt) to compound message",
|
2020-03-06 15:23:22 +01:00
|
|
|
__func__, up->sg_str,
|
2017-03-07 03:08:12 +01:00
|
|
|
child->sg_str);
|
|
|
|
} else if (PIM_DEBUG_PIM_PACKETS)
|
|
|
|
zlog_debug(
|
|
|
|
"%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)",
|
2020-03-06 15:23:22 +01:00
|
|
|
__func__, up->sg_str,
|
2017-03-07 03:08:12 +01:00
|
|
|
child->sg_str);
|
2019-11-15 20:32:10 +01:00
|
|
|
} else if (pim_upstream_empty_inherited_olist(child)) {
|
|
|
|
/* S is supposed to be forwarded along the RPT
|
|
|
|
* but it's inherited OIL is empty. So just
|
|
|
|
* prune it off.
|
|
|
|
*/
|
2022-01-14 14:57:21 +01:00
|
|
|
size += sizeof(pim_encoded_source);
|
2019-11-15 20:32:10 +01:00
|
|
|
PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(
|
2017-03-07 03:08:12 +01:00
|
|
|
child->flags);
|
2019-11-15 20:32:10 +01:00
|
|
|
if (PIM_DEBUG_PIM_PACKETS)
|
|
|
|
zlog_debug(
|
2020-03-06 15:23:22 +01:00
|
|
|
"%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message",
|
|
|
|
__func__, child->sg_str);
|
2017-03-07 03:08:12 +01:00
|
|
|
} else if (PIM_DEBUG_PIM_PACKETS)
|
2019-11-15 20:32:10 +01:00
|
|
|
zlog_debug(
|
2020-03-06 15:23:22 +01:00
|
|
|
"%s: Do not add Prune %s to compound message %s",
|
|
|
|
__func__, child->sg_str, up->sg_str);
|
2017-03-07 03:08:12 +01:00
|
|
|
}
|
|
|
|
}
|
2017-02-15 03:32:16 +01:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2017-03-17 13:07:19 +01:00
|
|
|
size_t pim_msg_build_jp_groups(struct pim_jp_groups *grp,
|
|
|
|
struct pim_jp_agg_group *sgs, size_t size)
|
2017-02-15 03:32:16 +01:00
|
|
|
{
|
2017-02-15 03:32:16 +01:00
|
|
|
struct listnode *node, *nnode;
|
|
|
|
struct pim_jp_sources *source;
|
2017-03-07 03:08:12 +01:00
|
|
|
struct pim_upstream *up = NULL;
|
2022-01-14 14:57:21 +01:00
|
|
|
pim_addr stosend;
|
2017-02-15 03:32:16 +01:00
|
|
|
uint8_t bits;
|
2017-02-15 03:32:16 +01:00
|
|
|
uint8_t tgroups = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-02-15 03:32:16 +01:00
|
|
|
memset(grp, 0, size);
|
2022-01-14 14:57:21 +01:00
|
|
|
pim_msg_addr_encode_group((uint8_t *)&grp->g, sgs->group);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-02-15 03:32:16 +01:00
|
|
|
for (ALL_LIST_ELEMENTS(sgs->sources, node, nnode, source)) {
|
|
|
|
/* number of joined/pruned sources */
|
|
|
|
if (source->is_join)
|
|
|
|
grp->joins++;
|
|
|
|
else
|
|
|
|
grp->prunes++;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-01-04 21:48:13 +01:00
|
|
|
if (pim_addr_is_any(source->up->sg.src)) {
|
2017-05-22 17:18:22 +02:00
|
|
|
struct pim_instance *pim = source->up->channel_oil->pim;
|
|
|
|
struct pim_rpf *rpf = pim_rp_g(pim, source->up->sg.grp);
|
2017-02-15 03:32:16 +01:00
|
|
|
bits = PIM_ENCODE_SPARSE_BIT | PIM_ENCODE_WC_BIT
|
|
|
|
| PIM_ENCODE_RPT_BIT;
|
2022-04-27 10:29:11 +02:00
|
|
|
stosend = rpf->rpf_addr;
|
pimd: Fix WG/SGRpt & WG J/P processing
During processing of Join/Prune,
for a S,G entry, current state is SGRpt, when only *,G is
received, need to clear SGRpt and add/inherit the *,G OIF to S,G so
it can forward traffic to downstream where *,G is received.
Upon receiving SGRpt prune remove the inherited *,G OIF.
From, downstream router received *,G Prune along with SGRpt
prune. Avoid sending *,G and SGRpt Prune together.
Reset upstream_del reset ifchannel to NULL.
Testing Done:
Run failed smoke test of sending data packets, trigger SPT switchover,
*,G path received SGRpt later data traffic stopped S,G ages out from LHR, sends only
*,G join to upstream, verified S,G entry inherit the OIF.
Upon receiving SGRpt deletes inherited oif and retains in SGRpt state.
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
2017-04-22 00:08:03 +02:00
|
|
|
/* Only Send SGRpt in case of *,G Join */
|
|
|
|
if (source->is_join)
|
|
|
|
up = source->up;
|
2017-02-15 03:32:16 +01:00
|
|
|
} else {
|
|
|
|
bits = PIM_ENCODE_SPARSE_BIT;
|
|
|
|
stosend = source->up->sg.src;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-01-14 14:57:21 +01:00
|
|
|
pim_msg_addr_encode_source((uint8_t *)&grp->s[tgroups], stosend,
|
|
|
|
bits);
|
2017-02-15 03:32:16 +01:00
|
|
|
tgroups++;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-03-07 03:08:12 +01:00
|
|
|
if (up) {
|
2017-02-15 03:32:16 +01:00
|
|
|
struct pim_upstream *child;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-03-07 03:08:12 +01:00
|
|
|
for (ALL_LIST_ELEMENTS(up->sources, node, nnode, child)) {
|
|
|
|
if (PIM_UPSTREAM_FLAG_TEST_SEND_SG_RPT_PRUNE(
|
|
|
|
child->flags)) {
|
2022-01-14 14:57:21 +01:00
|
|
|
pim_msg_addr_encode_source(
|
2017-03-07 03:08:12 +01:00
|
|
|
(uint8_t *)&grp->s[tgroups],
|
|
|
|
child->sg.src,
|
2022-01-14 14:57:21 +01:00
|
|
|
PIM_ENCODE_SPARSE_BIT |
|
|
|
|
PIM_ENCODE_RPT_BIT);
|
2017-03-07 03:08:12 +01:00
|
|
|
tgroups++;
|
|
|
|
PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE(
|
|
|
|
child->flags);
|
|
|
|
grp->prunes++;
|
2017-02-15 03:32:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-03-07 03:08:12 +01:00
|
|
|
grp->joins = htons(grp->joins);
|
|
|
|
grp->prunes = htons(grp->prunes);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-02-15 03:32:16 +01:00
|
|
|
return size;
|
2016-07-27 22:33:41 +02:00
|
|
|
}
|