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 "if.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "prefix.h"
|
|
|
|
#include "zclient.h"
|
|
|
|
#include "stream.h"
|
|
|
|
#include "network.h"
|
2016-09-13 21:41:33 +02:00
|
|
|
#include "vty.h"
|
|
|
|
#include "plist.h"
|
2017-04-11 03:01:53 +02:00
|
|
|
#include "lib/bfd.h"
|
2015-02-04 07:01:14 +01:00
|
|
|
|
|
|
|
#include "pimd.h"
|
|
|
|
#include "pim_pim.h"
|
|
|
|
#include "pim_zebra.h"
|
|
|
|
#include "pim_iface.h"
|
|
|
|
#include "pim_str.h"
|
|
|
|
#include "pim_oil.h"
|
|
|
|
#include "pim_rpf.h"
|
|
|
|
#include "pim_time.h"
|
|
|
|
#include "pim_join.h"
|
|
|
|
#include "pim_zlookup.h"
|
|
|
|
#include "pim_ifchannel.h"
|
2015-09-30 14:41:18 +02:00
|
|
|
#include "pim_rp.h"
|
2016-07-11 22:22:14 +02:00
|
|
|
#include "pim_igmpv3.h"
|
2017-02-15 03:32:16 +01:00
|
|
|
#include "pim_jp_agg.h"
|
2017-02-22 16:28:36 +01:00
|
|
|
#include "pim_nht.h"
|
2017-03-17 19:51:13 +01:00
|
|
|
#include "pim_ssm.h"
|
2019-03-21 16:49:09 +01:00
|
|
|
#include "pim_vxlan.h"
|
2019-11-12 09:17:13 +01:00
|
|
|
#include "pim_mlag.h"
|
2015-02-04 07:01:14 +01:00
|
|
|
|
|
|
|
#undef PIM_DEBUG_IFADDR_DUMP
|
|
|
|
#define PIM_DEBUG_IFADDR_DUMP
|
|
|
|
|
2019-11-12 07:36:17 +01:00
|
|
|
struct zclient *zclient;
|
2016-12-09 17:08:45 +01:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
|
|
|
|
/* Router-id update message from zebra. */
|
2019-05-03 21:42:59 +02:00
|
|
|
static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
|
|
|
struct prefix router_id;
|
|
|
|
|
|
|
|
zebra_router_id_update_read(zclient->ibuf, &router_id);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-03 21:42:59 +02:00
|
|
|
static int pim_zebra_interface_vrf_update(ZAPI_CALLBACK_ARGS)
|
2019-02-02 21:52:14 +01:00
|
|
|
{
|
|
|
|
struct interface *ifp;
|
|
|
|
vrf_id_t new_vrf_id;
|
|
|
|
|
|
|
|
ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id,
|
|
|
|
&new_vrf_id);
|
|
|
|
if (!ifp)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (PIM_DEBUG_ZEBRA)
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug("%s: %s updating from %u to %u", __func__, ifp->name,
|
|
|
|
vrf_id, new_vrf_id);
|
2019-02-02 21:52:14 +01:00
|
|
|
|
2019-06-24 01:46:39 +02:00
|
|
|
if_update_to_new_vrf(ifp, new_vrf_id);
|
2019-02-02 21:52:14 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
#ifdef PIM_DEBUG_IFADDR_DUMP
|
|
|
|
static void dump_if_address(struct interface *ifp)
|
|
|
|
{
|
|
|
|
struct connected *ifc;
|
|
|
|
struct listnode *node;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-03-06 15:23:22 +01:00
|
|
|
zlog_debug("%s %s: interface %s addresses:", __FILE__, __func__,
|
|
|
|
ifp->name);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
|
|
|
|
struct prefix *p = ifc->address;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (p->family != AF_INET)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-10-22 16:01:20 +02:00
|
|
|
zlog_debug("%s %s: interface %s address %pI4 %s", __FILE__,
|
|
|
|
__func__, ifp->name, &p->u.prefix4,
|
2015-02-04 07:01:14 +01:00
|
|
|
CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)
|
|
|
|
? "secondary"
|
|
|
|
: "primary");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-05-03 21:42:59 +02:00
|
|
|
static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
|
|
|
struct connected *c;
|
|
|
|
struct prefix *p;
|
2016-11-18 18:12:27 +01:00
|
|
|
struct pim_interface *pim_ifp;
|
2018-05-11 21:04:10 +02:00
|
|
|
struct pim_instance *pim;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/*
|
|
|
|
zebra api notifies address adds/dels events by using the same call
|
|
|
|
interface_add_read below, see comments in lib/zclient.c
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
|
|
|
|
will add address to interface list by calling
|
|
|
|
connected_add_by_prefix()
|
|
|
|
*/
|
2019-05-03 21:42:59 +02:00
|
|
|
c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
|
2015-02-04 07:01:14 +01:00
|
|
|
if (!c)
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-18 18:12:27 +01:00
|
|
|
pim_ifp = c->ifp->info;
|
2015-02-04 07:01:14 +01:00
|
|
|
p = c->address;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (PIM_DEBUG_ZEBRA) {
|
2020-10-18 13:33:54 +02:00
|
|
|
zlog_debug("%s: %s(%u) connected IP address %pFX flags %u %s",
|
|
|
|
__func__, c->ifp->name, vrf_id, p, c->flags,
|
2017-06-13 14:59:32 +02:00
|
|
|
CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
|
|
|
|
? "secondary"
|
|
|
|
: "primary");
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
#ifdef PIM_DEBUG_IFADDR_DUMP
|
|
|
|
dump_if_address(c->ifp);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
|
|
|
|
/* trying to add primary address */
|
|
|
|
|
|
|
|
struct in_addr primary_addr = pim_find_primary_addr(c->ifp);
|
2017-03-30 15:10:05 +02:00
|
|
|
if (p->family != AF_INET
|
|
|
|
|| primary_addr.s_addr != p->u.prefix4.s_addr) {
|
2020-10-18 13:33:54 +02:00
|
|
|
if (PIM_DEBUG_ZEBRA)
|
2016-11-18 18:12:27 +01:00
|
|
|
zlog_warn(
|
2020-10-18 13:33:54 +02:00
|
|
|
"%s: %s : forcing secondary flag on %pFX",
|
|
|
|
__func__, c->ifp->name, p);
|
2015-02-04 07:01:14 +01:00
|
|
|
SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pim_if_addr_add(c);
|
2018-05-11 21:04:10 +02:00
|
|
|
if (pim_ifp) {
|
|
|
|
pim = pim_get_pim_instance(vrf_id);
|
|
|
|
pim_ifp->pim = pim;
|
|
|
|
|
2016-11-18 18:12:27 +01:00
|
|
|
pim_rp_check_on_if_add(pim_ifp);
|
2018-05-11 21:04:10 +02:00
|
|
|
}
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2016-09-07 15:06:47 +02:00
|
|
|
if (if_is_loopback(c->ifp)) {
|
2021-11-16 16:09:09 +01:00
|
|
|
struct vrf *vrf = vrf_lookup_by_id(vrf_id);
|
2016-09-07 15:06:47 +02:00
|
|
|
struct interface *ifp;
|
|
|
|
|
2017-10-06 20:25:58 +02:00
|
|
|
FOR_ALL_INTERFACES (vrf, ifp) {
|
2016-09-07 15:06:47 +02:00
|
|
|
if (!if_is_loopback(ifp) && if_is_operative(ifp))
|
|
|
|
pim_if_addr_add_all(ifp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-03 21:42:59 +02:00
|
|
|
static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
|
|
|
struct connected *c;
|
|
|
|
struct prefix *p;
|
2017-05-19 22:41:25 +02:00
|
|
|
struct vrf *vrf = vrf_lookup_by_id(vrf_id);
|
2017-10-25 19:30:45 +02:00
|
|
|
struct pim_instance *pim;
|
|
|
|
|
|
|
|
if (!vrf)
|
|
|
|
return 0;
|
|
|
|
pim = vrf->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/*
|
|
|
|
zebra api notifies address adds/dels events by using the same call
|
|
|
|
interface_add_read below, see comments in lib/zclient.c
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
|
|
|
|
will remove address from interface list by calling
|
|
|
|
connected_delete_by_prefix()
|
|
|
|
*/
|
2019-05-03 21:42:59 +02:00
|
|
|
c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
|
2015-02-04 07:01:14 +01:00
|
|
|
if (!c)
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
p = c->address;
|
2017-03-17 01:07:08 +01:00
|
|
|
if (p->family == AF_INET) {
|
|
|
|
if (PIM_DEBUG_ZEBRA) {
|
|
|
|
zlog_debug(
|
2020-10-18 13:33:54 +02:00
|
|
|
"%s: %s(%u) disconnected IP address %pFX flags %u %s",
|
|
|
|
__func__, c->ifp->name, vrf_id, p, c->flags,
|
2017-03-17 01:07:08 +01:00
|
|
|
CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)
|
|
|
|
? "secondary"
|
|
|
|
: "primary");
|
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
#ifdef PIM_DEBUG_IFADDR_DUMP
|
2017-03-17 01:07:08 +01:00
|
|
|
dump_if_address(c->ifp);
|
2015-02-04 07:01:14 +01:00
|
|
|
#endif
|
2017-03-17 01:07:08 +01:00
|
|
|
}
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2017-03-17 01:07:08 +01:00
|
|
|
pim_if_addr_del(c, 0);
|
2017-05-19 22:41:25 +02:00
|
|
|
pim_rp_setup(pim);
|
|
|
|
pim_i_am_rp_re_evaluate(pim);
|
2017-03-17 01:07:08 +01:00
|
|
|
}
|
|
|
|
|
2019-10-30 01:16:28 +01:00
|
|
|
connected_free(&c);
|
2015-02-04 07:01:14 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-07-31 23:40:37 +02:00
|
|
|
void pim_zebra_update_all_interfaces(struct pim_instance *pim)
|
|
|
|
{
|
|
|
|
struct interface *ifp;
|
|
|
|
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
|
|
struct pim_interface *pim_ifp = ifp->info;
|
|
|
|
struct pim_iface_upstream_switch *us;
|
|
|
|
struct listnode *node;
|
|
|
|
|
|
|
|
if (!pim_ifp)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->upstream_switch_list, node,
|
|
|
|
us)) {
|
|
|
|
struct pim_rpf rpf;
|
|
|
|
|
|
|
|
rpf.source_nexthop.interface = ifp;
|
|
|
|
rpf.rpf_addr.u.prefix4 = us->address;
|
|
|
|
pim_joinprune_send(&rpf, us->us);
|
|
|
|
pim_jp_agg_clear_group(us->us);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-01 00:27:54 +02:00
|
|
|
void pim_zebra_upstream_rpf_changed(struct pim_instance *pim,
|
|
|
|
struct pim_upstream *up,
|
|
|
|
struct pim_rpf *old)
|
|
|
|
{
|
2019-02-22 16:29:24 +01:00
|
|
|
if (old->source_nexthop.interface) {
|
|
|
|
struct pim_neighbor *nbr;
|
2018-08-01 00:27:54 +02:00
|
|
|
|
2019-02-22 16:29:24 +01:00
|
|
|
nbr = pim_neighbor_find(old->source_nexthop.interface,
|
|
|
|
old->rpf_addr.u.prefix4);
|
|
|
|
if (nbr)
|
2019-11-15 21:08:18 +01:00
|
|
|
pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr);
|
2018-08-01 00:27:54 +02:00
|
|
|
|
|
|
|
/*
|
2019-02-22 16:29:24 +01:00
|
|
|
* We have detected a case where we might need
|
|
|
|
* to rescan the inherited o_list so do it.
|
2018-08-01 00:27:54 +02:00
|
|
|
*/
|
2019-02-22 16:29:24 +01:00
|
|
|
if (up->channel_oil->oil_inherited_rescan) {
|
|
|
|
pim_upstream_inherited_olist_decide(pim, up);
|
|
|
|
up->channel_oil->oil_inherited_rescan = 0;
|
|
|
|
}
|
2018-08-01 00:27:54 +02:00
|
|
|
|
2019-02-22 16:29:24 +01:00
|
|
|
if (up->join_state == PIM_UPSTREAM_JOINED) {
|
|
|
|
/*
|
|
|
|
* If we come up real fast we can be here
|
|
|
|
* where the mroute has not been installed
|
|
|
|
* so install it.
|
|
|
|
*/
|
|
|
|
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__);
|
2019-02-22 16:29:24 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* RFC 4601: 4.5.7. Sending (S,G)
|
|
|
|
* Join/Prune Messages
|
|
|
|
*
|
|
|
|
* Transitions from Joined State
|
|
|
|
*
|
|
|
|
* RPF'(S,G) changes not due to an Assert
|
|
|
|
*
|
|
|
|
* The upstream (S,G) state machine remains
|
|
|
|
* in Joined state. Send Join(S,G) to the new
|
|
|
|
* upstream neighbor, which is the new value
|
|
|
|
* of RPF'(S,G). Send Prune(S,G) to the old
|
|
|
|
* upstream neighbor, which is the old value
|
|
|
|
* of RPF'(S,G). Set the Join Timer (JT) to
|
|
|
|
* expire after t_periodic seconds.
|
|
|
|
*/
|
|
|
|
pim_jp_agg_switch_interface(old, &up->rpf, up);
|
|
|
|
|
|
|
|
pim_upstream_join_timer_restart(up, old);
|
|
|
|
} /* up->join_state == PIM_UPSTREAM_JOINED */
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
2018-08-01 00:27:54 +02:00
|
|
|
/*
|
2019-02-22 16:29:24 +01:00
|
|
|
* We have detected a case where we might need
|
|
|
|
* to rescan the inherited o_list so do it.
|
2018-08-01 00:27:54 +02:00
|
|
|
*/
|
2019-02-22 16:29:24 +01:00
|
|
|
if (up->channel_oil->oil_inherited_rescan) {
|
|
|
|
pim_upstream_inherited_olist_decide(pim, up);
|
|
|
|
up->channel_oil->oil_inherited_rescan = 0;
|
|
|
|
}
|
2018-08-01 00:27:54 +02:00
|
|
|
|
2019-11-15 20:41:49 +01:00
|
|
|
if (up->join_state == PIM_UPSTREAM_JOINED)
|
|
|
|
pim_jp_agg_switch_interface(old, &up->rpf, up);
|
|
|
|
|
2019-02-22 16:29:24 +01:00
|
|
|
if (!up->channel_oil->installed)
|
2020-03-05 19:17:54 +01:00
|
|
|
pim_upstream_mroute_add(up->channel_oil, __func__);
|
2019-02-22 16:29:24 +01:00
|
|
|
}
|
2018-08-01 00:27:54 +02:00
|
|
|
|
2019-02-22 16:29:24 +01:00
|
|
|
/* FIXME can join_desired actually be changed by pim_rpf_update()
|
|
|
|
* returning PIM_RPF_CHANGED ?
|
|
|
|
*/
|
2018-08-01 00:27:54 +02:00
|
|
|
pim_upstream_update_join_desired(pim, up);
|
|
|
|
}
|
|
|
|
|
2019-05-03 21:42:59 +02:00
|
|
|
static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS)
|
2019-03-21 16:49:09 +01:00
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
struct pim_instance *pim;
|
2022-01-04 17:54:44 +01:00
|
|
|
pim_sgaddr sg;
|
|
|
|
size_t prefixlen;
|
2019-03-21 16:49:09 +01:00
|
|
|
|
|
|
|
pim = pim_get_pim_instance(vrf_id);
|
|
|
|
if (!pim)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
s = zclient->ibuf;
|
|
|
|
|
2022-01-04 17:54:44 +01:00
|
|
|
prefixlen = stream_getl(s);
|
|
|
|
stream_get(&sg.src.s_addr, s, prefixlen);
|
|
|
|
stream_get(&sg.grp.s_addr, s, prefixlen);
|
2019-03-21 16:49:09 +01:00
|
|
|
|
2022-01-04 21:10:37 +01:00
|
|
|
if (PIM_DEBUG_ZEBRA)
|
|
|
|
zlog_debug("%u:recv SG %s %pSG", vrf_id,
|
|
|
|
(cmd == ZEBRA_VXLAN_SG_ADD) ? "add" : "del", &sg);
|
2019-03-21 16:49:09 +01:00
|
|
|
|
2019-05-03 21:42:59 +02:00
|
|
|
if (cmd == ZEBRA_VXLAN_SG_ADD)
|
2019-03-21 16:49:09 +01:00
|
|
|
pim_vxlan_sg_add(pim, &sg);
|
|
|
|
else
|
|
|
|
pim_vxlan_sg_del(pim, &sg);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-02 20:20:34 +02:00
|
|
|
static void pim_zebra_vxlan_replay(void)
|
|
|
|
{
|
|
|
|
struct stream *s = NULL;
|
|
|
|
|
|
|
|
/* Check socket. */
|
|
|
|
if (!zclient || zclient->sock < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
s = zclient->obuf;
|
|
|
|
stream_reset(s);
|
|
|
|
|
|
|
|
zclient_create_header(s, ZEBRA_VXLAN_SG_REPLAY, VRF_DEFAULT);
|
|
|
|
stream_putw_at(s, 0, stream_get_endp(s));
|
|
|
|
|
|
|
|
zclient_send_message(zclient);
|
|
|
|
}
|
|
|
|
|
2018-03-18 02:13:09 +01:00
|
|
|
void pim_scan_oil(struct pim_instance *pim)
|
2016-06-27 21:06:46 +02:00
|
|
|
{
|
|
|
|
struct channel_oil *c_oil;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-18 02:34:55 +01:00
|
|
|
pim->scan_oil_last = pim_time_monotonic_sec();
|
|
|
|
++pim->scan_oil_events;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-12-21 04:12:19 +01:00
|
|
|
frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil)
|
2019-11-15 20:09:13 +01:00
|
|
|
pim_upstream_mroute_iif_update(c_oil, __func__);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int on_rpf_cache_refresh(struct thread *t)
|
|
|
|
{
|
2018-03-18 02:13:09 +01:00
|
|
|
struct pim_instance *pim = THREAD_ARG(t);
|
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/* update kernel multicast forwarding cache (MFC) */
|
2018-03-18 02:13:09 +01:00
|
|
|
pim_scan_oil(pim);
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2018-03-18 02:34:55 +01:00
|
|
|
pim->rpf_cache_refresh_last = pim_time_monotonic_sec();
|
|
|
|
++pim->rpf_cache_refresh_events;
|
2015-02-04 07:01:14 +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
|
|
|
// It is called as part of pim_neighbor_add
|
|
|
|
// pim_rp_setup ();
|
2015-02-04 07:01:14 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-18 02:13:09 +01:00
|
|
|
void sched_rpf_cache_refresh(struct pim_instance *pim)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2018-03-18 02:34:55 +01:00
|
|
|
++pim->rpf_cache_refresh_requests;
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2018-03-18 02:34:55 +01:00
|
|
|
pim_rpf_set_refresh_time(pim);
|
2016-10-27 17:54:55 +02:00
|
|
|
|
2018-03-18 02:13:09 +01:00
|
|
|
if (pim->rpf_cache_refresher) {
|
2015-02-04 07:01:14 +01:00
|
|
|
/* Refresh timer is already running */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Start refresh timer */
|
|
|
|
|
|
|
|
if (PIM_DEBUG_ZEBRA) {
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug("%s: triggering %ld msec timer", __func__,
|
2018-12-21 14:50:34 +01:00
|
|
|
router->rpf_cache_refresh_delay_msec);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2018-12-20 16:34:04 +01:00
|
|
|
thread_add_timer_msec(router->master, on_rpf_cache_refresh, pim,
|
2018-12-21 14:50:34 +01:00
|
|
|
router->rpf_cache_refresh_delay_msec,
|
2018-03-18 02:13:09 +01:00
|
|
|
&pim->rpf_cache_refresher);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2016-05-26 03:24:01 +02:00
|
|
|
static void pim_zebra_connected(struct zclient *zclient)
|
|
|
|
{
|
2017-04-11 03:01:53 +02:00
|
|
|
/* Send the client registration */
|
2019-03-26 14:29:13 +01:00
|
|
|
bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, router->vrf_id);
|
2017-04-11 03:01:53 +02:00
|
|
|
|
2018-12-21 15:23:36 +01:00
|
|
|
zclient_send_reg_requests(zclient, router->vrf_id);
|
2019-07-02 20:20:34 +02:00
|
|
|
|
|
|
|
/* request for VxLAN BUM group addresses */
|
|
|
|
pim_zebra_vxlan_replay();
|
2016-05-26 03:24:01 +02:00
|
|
|
}
|
2016-11-03 23:55:35 +01:00
|
|
|
|
2018-12-18 14:13:25 +01:00
|
|
|
static void pim_zebra_capabilities(struct zclient_capabilities *cap)
|
|
|
|
{
|
2020-02-06 18:30:36 +01:00
|
|
|
router->mlag_role = cap->role;
|
2018-12-18 14:13:25 +01:00
|
|
|
}
|
|
|
|
|
2021-10-20 13:07:47 +02:00
|
|
|
static zclient_handler *const pim_handlers[] = {
|
|
|
|
[ZEBRA_ROUTER_ID_UPDATE] = pim_router_id_update_zebra,
|
|
|
|
[ZEBRA_INTERFACE_ADDRESS_ADD] = pim_zebra_if_address_add,
|
|
|
|
[ZEBRA_INTERFACE_ADDRESS_DELETE] = pim_zebra_if_address_del,
|
|
|
|
[ZEBRA_INTERFACE_VRF_UPDATE] = pim_zebra_interface_vrf_update,
|
|
|
|
[ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update,
|
|
|
|
|
|
|
|
[ZEBRA_VXLAN_SG_ADD] = pim_zebra_vxlan_sg_proc,
|
|
|
|
[ZEBRA_VXLAN_SG_DEL] = pim_zebra_vxlan_sg_proc,
|
|
|
|
|
|
|
|
[ZEBRA_MLAG_PROCESS_UP] = pim_zebra_mlag_process_up,
|
|
|
|
[ZEBRA_MLAG_PROCESS_DOWN] = pim_zebra_mlag_process_down,
|
|
|
|
[ZEBRA_MLAG_FORWARD_MSG] = pim_zebra_mlag_handle_msg,
|
|
|
|
};
|
|
|
|
|
2016-11-13 09:48:56 +01:00
|
|
|
void pim_zebra_init(void)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
|
|
|
/* Socket for receiving updates from Zebra daemon */
|
2021-10-20 13:07:47 +02:00
|
|
|
zclient = zclient_new(router->master, &zclient_options_default,
|
|
|
|
pim_handlers, array_size(pim_handlers));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-12-18 14:13:25 +01:00
|
|
|
zclient->zebra_capabilities = pim_zebra_capabilities;
|
2016-12-09 17:08:45 +01:00
|
|
|
zclient->zebra_connected = pim_zebra_connected;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-10-11 16:37:20 +02:00
|
|
|
zclient_init(zclient, ZEBRA_ROUTE_PIM, 0, &pimd_privs);
|
2015-02-04 07:01:14 +01:00
|
|
|
if (PIM_DEBUG_PIM_TRACE) {
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_notice("%s: zclient socket initialized", __func__);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-08-09 21:04:23 +02:00
|
|
|
zclient_lookup_new();
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2017-05-21 14:57:18 +02:00
|
|
|
void igmp_anysource_forward_start(struct pim_instance *pim,
|
2021-12-03 18:41:52 +01:00
|
|
|
struct gm_group *group)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2021-12-03 18:33:53 +01:00
|
|
|
struct gm_source *source;
|
2016-06-06 18:27:11 +02:00
|
|
|
struct in_addr src_addr = {.s_addr = 0};
|
2015-02-04 07:01:14 +01:00
|
|
|
/* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
|
2021-04-23 11:23:57 +02:00
|
|
|
assert(group->group_filtermode_isexcl);
|
|
|
|
assert(listcount(group->group_source_list) < 1);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-08-24 18:17:05 +02:00
|
|
|
source = igmp_get_source_by_addr(group, src_addr, NULL);
|
2016-06-06 18:27:11 +02:00
|
|
|
if (!source) {
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_warn("%s: Failure to create * source", __func__);
|
2016-06-06 18:27:11 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-21 14:57:18 +02:00
|
|
|
igmp_source_forward_start(pim, source);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2021-12-03 18:41:52 +01:00
|
|
|
void igmp_anysource_forward_stop(struct gm_group *group)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2021-12-03 18:33:53 +01:00
|
|
|
struct gm_source *source;
|
2016-07-11 22:22:14 +02:00
|
|
|
struct in_addr star = {.s_addr = 0};
|
2015-02-04 07:01:14 +01:00
|
|
|
|
2016-07-11 22:22:14 +02:00
|
|
|
source = igmp_find_source_by_addr(group, star);
|
|
|
|
if (source)
|
|
|
|
igmp_source_forward_stop(source);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2017-05-21 15:30:02 +02:00
|
|
|
static void igmp_source_forward_reevaluate_one(struct pim_instance *pim,
|
2021-12-03 18:33:53 +01:00
|
|
|
struct gm_source *source)
|
2017-03-17 19:51:13 +01:00
|
|
|
{
|
2022-01-04 17:54:44 +01:00
|
|
|
pim_sgaddr sg;
|
2021-12-03 18:41:52 +01:00
|
|
|
struct gm_group *group = source->source_group;
|
2017-03-17 19:51:13 +01:00
|
|
|
struct pim_ifchannel *ch;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-03-17 19:51:13 +01:00
|
|
|
if ((source->source_addr.s_addr != INADDR_ANY)
|
|
|
|
|| !IGMP_SOURCE_TEST_FORWARDING(source->source_flags))
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-01-04 17:54:44 +01:00
|
|
|
memset(&sg, 0, sizeof(sg));
|
2017-03-17 19:51:13 +01:00
|
|
|
sg.src = source->source_addr;
|
|
|
|
sg.grp = group->group_addr;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-08-24 15:25:48 +02:00
|
|
|
ch = pim_ifchannel_find(group->interface, &sg);
|
2017-05-21 15:30:02 +02:00
|
|
|
if (pim_is_grp_ssm(pim, group->group_addr)) {
|
2017-03-17 19:51:13 +01:00
|
|
|
/* If SSM group withdraw local membership */
|
|
|
|
if (ch
|
|
|
|
&& (ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE)) {
|
|
|
|
if (PIM_DEBUG_PIM_EVENTS)
|
2022-01-04 21:24:48 +01:00
|
|
|
zlog_debug("local membership del for %pSG as G is now SSM",
|
|
|
|
&sg);
|
2021-08-27 10:45:16 +02:00
|
|
|
pim_ifchannel_local_membership_del(group->interface,
|
|
|
|
&sg);
|
2017-03-17 19:51:13 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* If ASM group add local membership */
|
|
|
|
if (!ch
|
|
|
|
|| (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO)) {
|
|
|
|
if (PIM_DEBUG_PIM_EVENTS)
|
2022-01-04 21:24:48 +01:00
|
|
|
zlog_debug("local membership add for %pSG as G is now ASM",
|
|
|
|
&sg);
|
2017-03-17 19:51:13 +01:00
|
|
|
pim_ifchannel_local_membership_add(
|
2021-08-27 10:45:16 +02:00
|
|
|
group->interface, &sg, false /*is_vxlan*/);
|
2017-03-17 19:51:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-18 02:16:42 +01:00
|
|
|
void igmp_source_forward_reevaluate_all(struct pim_instance *pim)
|
2017-03-17 19:51:13 +01:00
|
|
|
{
|
|
|
|
struct interface *ifp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-03-18 02:16:42 +01:00
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
|
|
struct pim_interface *pim_ifp = ifp->info;
|
2021-08-24 15:25:48 +02:00
|
|
|
struct listnode *grpnode;
|
2021-12-03 18:41:52 +01:00
|
|
|
struct gm_group *grp;
|
2021-10-26 16:03:58 +02:00
|
|
|
struct pim_ifchannel *ch, *ch_temp;
|
2018-03-18 02:16:42 +01:00
|
|
|
|
|
|
|
if (!pim_ifp)
|
2017-03-17 19:51:13 +01:00
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-08-24 15:25:48 +02:00
|
|
|
/* scan igmp groups */
|
2022-01-04 15:00:50 +01:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode,
|
2021-12-14 17:33:24 +01:00
|
|
|
grp)) {
|
2021-08-24 15:25:48 +02:00
|
|
|
struct listnode *srcnode;
|
2021-12-03 18:33:53 +01:00
|
|
|
struct gm_source *src;
|
2021-08-24 15:25:48 +02:00
|
|
|
|
|
|
|
/* scan group sources */
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
|
|
|
|
srcnode, src)) {
|
|
|
|
igmp_source_forward_reevaluate_one(pim, src);
|
2021-10-26 16:03:58 +02:00
|
|
|
} /* scan group sources */
|
|
|
|
} /* scan igmp groups */
|
|
|
|
|
|
|
|
RB_FOREACH_SAFE (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb,
|
|
|
|
ch_temp) {
|
|
|
|
if (pim_is_grp_ssm(pim, ch->sg.grp)) {
|
2022-01-04 21:48:13 +01:00
|
|
|
if (pim_addr_is_any(ch->sg.src))
|
2021-10-26 16:03:58 +02:00
|
|
|
pim_ifchannel_delete(ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* scan interfaces */
|
2017-03-17 19:51:13 +01:00
|
|
|
}
|
|
|
|
|
2017-05-21 14:57:18 +02:00
|
|
|
void igmp_source_forward_start(struct pim_instance *pim,
|
2021-12-03 18:33:53 +01:00
|
|
|
struct gm_source *source)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2018-07-09 15:22:56 +02:00
|
|
|
struct pim_interface *pim_oif;
|
2021-12-03 18:41:52 +01:00
|
|
|
struct gm_group *group;
|
2022-01-04 17:54:44 +01:00
|
|
|
pim_sgaddr sg;
|
2015-02-04 07:01:14 +01:00
|
|
|
int result;
|
|
|
|
int input_iface_vif_index = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-01-04 17:54:44 +01:00
|
|
|
memset(&sg, 0, sizeof(sg));
|
2016-08-05 19:08:06 +02:00
|
|
|
sg.src = source->source_addr;
|
|
|
|
sg.grp = source->source_group->group_addr;
|
2017-07-17 14:03:14 +02: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
|
|
|
if (PIM_DEBUG_IGMP_TRACE) {
|
2022-01-04 21:24:48 +01:00
|
|
|
zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
|
2021-08-27 10:45:16 +02:00
|
|
|
source->source_group->interface->name,
|
|
|
|
IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
|
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
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-04-27 20:01:32 +02:00
|
|
|
/* Prevent IGMP interface from installing multicast route multiple
|
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
|
|
|
times */
|
2016-11-03 23:55:35 +01:00
|
|
|
if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
|
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
group = source->source_group;
|
2021-08-24 15:25:48 +02:00
|
|
|
pim_oif = group->interface->info;
|
2018-07-09 15:22:56 +02:00
|
|
|
if (!pim_oif) {
|
|
|
|
if (PIM_DEBUG_IGMP_TRACE) {
|
2020-03-05 19:17:54 +01:00
|
|
|
zlog_debug("%s: multicast not enabled on oif=%s ?",
|
|
|
|
__func__,
|
2021-08-24 15:25:48 +02:00
|
|
|
source->source_group->interface->name);
|
2018-07-09 15:22:56 +02:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (!source->source_channel_oil) {
|
2015-09-30 14:41:18 +02:00
|
|
|
struct in_addr vif_source;
|
2019-04-16 20:28:10 +02:00
|
|
|
struct prefix src, grp;
|
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
|
|
|
struct pim_nexthop nexthop;
|
2017-04-27 20:01:32 +02:00
|
|
|
struct pim_upstream *up = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-05-21 14:57:18 +02:00
|
|
|
if (!pim_rp_set_upstream_addr(pim, &vif_source,
|
2019-02-22 12:05:29 +01:00
|
|
|
source->source_addr, sg.grp)) {
|
|
|
|
/*Create a dummy channel oil */
|
2020-03-05 19:17:54 +01:00
|
|
|
source->source_channel_oil =
|
|
|
|
pim_channel_oil_add(pim, &sg, __func__);
|
2019-02-22 12:05:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-22 12:05:29 +01:00
|
|
|
else {
|
|
|
|
src.family = AF_INET;
|
|
|
|
src.prefixlen = IPV4_MAX_BITLEN;
|
|
|
|
src.u.prefix4 = vif_source; // RP or Src address
|
|
|
|
grp.family = AF_INET;
|
|
|
|
grp.prefixlen = IPV4_MAX_BITLEN;
|
|
|
|
grp.u.prefix4 = sg.grp;
|
|
|
|
|
2019-04-02 15:40:41 +02:00
|
|
|
up = pim_upstream_find(pim, &sg);
|
|
|
|
if (up) {
|
|
|
|
memcpy(&nexthop, &up->rpf.source_nexthop,
|
|
|
|
sizeof(struct pim_nexthop));
|
|
|
|
pim_ecmp_nexthop_lookup(pim, &nexthop, &src,
|
|
|
|
&grp, 0);
|
|
|
|
if (nexthop.interface)
|
|
|
|
input_iface_vif_index =
|
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
|
|
|
pim_if_find_vifindex_by_ifindex(
|
2019-04-02 15:40:41 +02:00
|
|
|
pim,
|
|
|
|
nexthop.interface->ifindex);
|
2019-02-22 12:05:29 +01:00
|
|
|
} else
|
|
|
|
input_iface_vif_index =
|
2019-04-02 15:40:41 +02:00
|
|
|
pim_ecmp_fib_lookup_if_vif_index(
|
|
|
|
pim, &src, &grp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-22 12:05:29 +01:00
|
|
|
if (PIM_DEBUG_ZEBRA) {
|
|
|
|
char buf2[INET_ADDRSTRLEN];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-22 12:05:29 +01:00
|
|
|
pim_inet4_dump("<source?>", vif_source, buf2,
|
|
|
|
sizeof(buf2));
|
2022-01-04 21:24:48 +01:00
|
|
|
zlog_debug("%s: NHT %pSG vif_source %s vif_index:%d ",
|
|
|
|
__func__, &sg, buf2,
|
|
|
|
input_iface_vif_index);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2019-02-22 12:05:29 +01:00
|
|
|
if (input_iface_vif_index < 1) {
|
|
|
|
if (PIM_DEBUG_IGMP_TRACE) {
|
|
|
|
char source_str[INET_ADDRSTRLEN];
|
|
|
|
pim_inet4_dump("<source?>",
|
|
|
|
source->source_addr,
|
|
|
|
source_str, sizeof(source_str));
|
|
|
|
zlog_debug(
|
2020-03-05 19:17:54 +01:00
|
|
|
"%s %s: could not find input interface for source %s",
|
|
|
|
__FILE__, __func__, source_str);
|
2019-02-22 12:05:29 +01:00
|
|
|
}
|
|
|
|
source->source_channel_oil =
|
2020-03-05 19:17:54 +01:00
|
|
|
pim_channel_oil_add(pim, &sg, __func__);
|
2019-02-22 12:05:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* Protect IGMP against adding looped MFC
|
|
|
|
* entries created by both source and receiver
|
|
|
|
* attached to the same interface. See TODO
|
2019-05-20 19:01:34 +02:00
|
|
|
* T22. Block only when the intf is non DR
|
|
|
|
* DR must create upstream.
|
2019-02-22 12:05:29 +01:00
|
|
|
*/
|
2019-05-20 19:01:34 +02:00
|
|
|
if ((input_iface_vif_index ==
|
|
|
|
pim_oif->mroute_vif_index) &&
|
|
|
|
!(PIM_I_am_DR(pim_oif))) {
|
2019-02-22 12:05:29 +01:00
|
|
|
/* ignore request for looped MFC entry
|
|
|
|
*/
|
|
|
|
if (PIM_DEBUG_IGMP_TRACE) {
|
2022-01-04 21:24:48 +01:00
|
|
|
zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%pSG: oif=%s vif_index=%d",
|
|
|
|
__func__,
|
|
|
|
&sg,
|
|
|
|
source->source_group
|
|
|
|
->interface->name,
|
|
|
|
input_iface_vif_index);
|
2019-02-22 12:05:29 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
source->source_channel_oil =
|
2020-03-05 19:17:54 +01:00
|
|
|
pim_channel_oil_add(pim, &sg, __func__);
|
2019-02-22 12:05:29 +01:00
|
|
|
if (!source->source_channel_oil) {
|
|
|
|
if (PIM_DEBUG_IGMP_TRACE) {
|
2022-01-04 21:24:48 +01:00
|
|
|
zlog_debug("%s %s: could not create OIL for channel (S,G)=%pSG",
|
|
|
|
__FILE__, __func__,
|
|
|
|
&sg);
|
2019-02-22 12:05:29 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
2016-11-03 23:55:35 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-06-03 03:54:50 +02:00
|
|
|
if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) {
|
2019-11-04 16:55:52 +01:00
|
|
|
result = pim_channel_add_oif(source->source_channel_oil,
|
2021-08-24 15:25:48 +02:00
|
|
|
group->interface,
|
2019-11-15 17:47:33 +01:00
|
|
|
PIM_OIF_FLAG_PROTO_IGMP, __func__);
|
2019-11-04 16:55:52 +01:00
|
|
|
if (result) {
|
|
|
|
if (PIM_DEBUG_MROUTE) {
|
|
|
|
zlog_warn("%s: add_oif() failed with return=%d",
|
|
|
|
__func__, result);
|
|
|
|
}
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2019-11-04 16:55:52 +01:00
|
|
|
} else {
|
2018-09-21 16:28:57 +02:00
|
|
|
if (PIM_DEBUG_IGMP_TRACE)
|
2022-01-04 21:24:48 +01:00
|
|
|
zlog_debug("%s: %pSG was received on %s interface but we are not DR for that interface",
|
|
|
|
__func__, &sg,
|
|
|
|
group->interface->name);
|
2018-11-16 01:28:43 +01:00
|
|
|
|
2018-07-09 15:22:56 +02:00
|
|
|
return;
|
2018-09-21 16:28:57 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
/*
|
2015-10-28 19:00:37 +01:00
|
|
|
Feed IGMPv3-gathered local membership information into PIM
|
|
|
|
per-interface (S,G) state.
|
2015-02-04 07:01:14 +01:00
|
|
|
*/
|
2021-08-27 10:45:16 +02:00
|
|
|
if (!pim_ifchannel_local_membership_add(group->interface, &sg,
|
2020-02-06 18:30:51 +01:00
|
|
|
false /*is_vxlan*/)) {
|
2017-01-25 20:47:04 +01:00
|
|
|
if (PIM_DEBUG_MROUTE)
|
2022-01-04 21:24:48 +01:00
|
|
|
zlog_warn("%s: Failure to add local membership for %pSG",
|
|
|
|
__func__, &sg);
|
2018-11-16 01:28:43 +01:00
|
|
|
|
|
|
|
pim_channel_del_oif(source->source_channel_oil,
|
2021-08-27 10:45:16 +02:00
|
|
|
group->interface, PIM_OIF_FLAG_PROTO_IGMP,
|
|
|
|
__func__);
|
2017-01-25 20:47:04 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
IGMP_SOURCE_DO_FORWARDING(source->source_flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
igmp_source_forward_stop: stop fowarding, but keep the source
|
|
|
|
igmp_source_delete: stop fowarding, and delete the source
|
|
|
|
*/
|
2021-12-03 18:33:53 +01:00
|
|
|
void igmp_source_forward_stop(struct gm_source *source)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
2021-12-03 18:41:52 +01:00
|
|
|
struct gm_group *group;
|
2022-01-04 17:54:44 +01:00
|
|
|
pim_sgaddr sg;
|
2015-02-04 07:01:14 +01:00
|
|
|
int result;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-01-04 17:54:44 +01:00
|
|
|
memset(&sg, 0, sizeof(sg));
|
2016-08-02 10:38:11 +02:00
|
|
|
sg.src = source->source_addr;
|
|
|
|
sg.grp = source->source_group->group_addr;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (PIM_DEBUG_IGMP_TRACE) {
|
2022-01-04 21:24:48 +01:00
|
|
|
zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
|
2021-08-27 10:45:16 +02:00
|
|
|
source->source_group->interface->name,
|
|
|
|
IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/* Prevent IGMP interface from removing multicast route multiple
|
|
|
|
times */
|
|
|
|
if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
|
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
group = source->source_group;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/*
|
|
|
|
It appears that in certain circumstances that
|
|
|
|
igmp_source_forward_stop is called when IGMP forwarding
|
|
|
|
was not enabled in oif_flags for this outgoing interface.
|
|
|
|
Possibly because of multiple calls. When that happens, we
|
|
|
|
enter the below if statement and this function returns early
|
|
|
|
which in turn triggers the calling function to assert.
|
2017-03-23 12:47:41 +01:00
|
|
|
Making the call to pim_channel_del_oif and ignoring the return code
|
|
|
|
fixes the issue without ill effect, similar to
|
|
|
|
pim_forward_stop below.
|
2015-02-04 07:01:14 +01:00
|
|
|
*/
|
2017-03-23 12:47:41 +01:00
|
|
|
result = pim_channel_del_oif(source->source_channel_oil,
|
2021-08-27 10:45:16 +02:00
|
|
|
group->interface, PIM_OIF_FLAG_PROTO_IGMP,
|
|
|
|
__func__);
|
2015-02-04 07:01:14 +01:00
|
|
|
if (result) {
|
2016-11-03 23:55:35 +01:00
|
|
|
if (PIM_DEBUG_IGMP_TRACE)
|
2017-03-23 12:47:41 +01:00
|
|
|
zlog_debug(
|
|
|
|
"%s: pim_channel_del_oif() failed with return=%d",
|
2016-11-03 23:55:35 +01:00
|
|
|
__func__, result);
|
2015-02-04 07:01:14 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
/*
|
|
|
|
Feed IGMPv3-gathered local membership information into PIM
|
|
|
|
per-interface (S,G) state.
|
|
|
|
*/
|
2021-08-24 15:25:48 +02:00
|
|
|
pim_ifchannel_local_membership_del(group->interface, &sg);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
void pim_forward_start(struct pim_ifchannel *ch)
|
|
|
|
{
|
|
|
|
struct pim_upstream *up = ch->upstream;
|
pimd: fix OIL not removed after IGMP prune
Issue: Client1------LHR-----(int-1)RP(int-2)------client2
Client2 send IGMP join for group G.
Client1 send IGMP join for group G.
verify show ip mroute in RP, will have 2 OIL.
Client2 send IGMP leave.
Verify show ip mroute in RP, will still have 2.
Root cause: When RP receives IGMP join from client2, it creates
a (s,g) channel oil and add the interface int-2 into oil list and
set the flag PIM_OIF_FLAG_PROTO_IGMP to int-2
Client1 send IGMP join, LHR will send a (*,G) join to RP. RP will
add the interface int-1 into the oil list of (s,g) channel_oil and
will set the flag PIM_OIF_FLAG_PROTO_IGMP and PIM_OIF_FLAG_PROTO_PIM
to the int-1 and set PIM_OIF_FLAG_PROTO_PIM to int-2 as well. It is
happening because of the pim_upstream_inherited_olist_decide() and
forward_on() get all the oil and update the flag wrongly.
So now when client 2 sends IGMP prune, RP will not remove the int-2
from oil list since both PIM_OIF_FLAG_PROTO_PIM & PIM_OIF_FLAG_PROTO_IGMP
are set, it just unset the flag PIM_OIF_FLAG_PROTO_IGMP.
Fix: Introduced new flags in if_channel, PIM_IF_FLAG_MASK_PROTO_PIM
& PIM_IF_FLAG_MASK_PROTO_IGMP. If a if_channel is created because of
pim join or pim (s,g,rpt) prune received, then set the flag
PIM_IF_FLAG_MASK_PROTO_PIM. If a if_channel is created becuase of IGMP
join received, then set the flag PIM_IF_FLAG_MASK_PROTO_IGMP.
When an interface needs to be added into the oil list check if
PIM_IF_FLAG_MASK_PROTO_PIM or PIM_IF_FLAG_MASK_PROTO_IGMP is set, then
update oil flag accordingly.
Signed-off-by: Sarita Patra <saritap@vmware.com>
2020-03-02 09:55:22 +01:00
|
|
|
uint32_t mask = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-02-04 07:01:14 +01:00
|
|
|
if (PIM_DEBUG_PIM_TRACE) {
|
2016-10-20 16:09:30 +02:00
|
|
|
char source_str[INET_ADDRSTRLEN];
|
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
|
|
|
char group_str[INET_ADDRSTRLEN];
|
2016-10-20 16:09:30 +02:00
|
|
|
char upstream_str[INET_ADDRSTRLEN];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-08-02 10:38:11 +02:00
|
|
|
pim_inet4_dump("<source?>", ch->sg.src, source_str,
|
|
|
|
sizeof(source_str));
|
|
|
|
pim_inet4_dump("<group?>", ch->sg.grp, group_str,
|
|
|
|
sizeof(group_str));
|
2015-09-30 14:41:18 +02:00
|
|
|
pim_inet4_dump("<upstream?>", up->upstream_addr, upstream_str,
|
|
|
|
sizeof(upstream_str));
|
2020-10-22 16:01:20 +02:00
|
|
|
zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%pI4)", __func__,
|
2015-09-30 14:41:18 +02:00
|
|
|
source_str, group_str, ch->interface->name,
|
2020-10-22 16:01:20 +02:00
|
|
|
&up->upstream_addr);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
pimd: fix OIL not removed after IGMP prune
Issue: Client1------LHR-----(int-1)RP(int-2)------client2
Client2 send IGMP join for group G.
Client1 send IGMP join for group G.
verify show ip mroute in RP, will have 2 OIL.
Client2 send IGMP leave.
Verify show ip mroute in RP, will still have 2.
Root cause: When RP receives IGMP join from client2, it creates
a (s,g) channel oil and add the interface int-2 into oil list and
set the flag PIM_OIF_FLAG_PROTO_IGMP to int-2
Client1 send IGMP join, LHR will send a (*,G) join to RP. RP will
add the interface int-1 into the oil list of (s,g) channel_oil and
will set the flag PIM_OIF_FLAG_PROTO_IGMP and PIM_OIF_FLAG_PROTO_PIM
to the int-1 and set PIM_OIF_FLAG_PROTO_PIM to int-2 as well. It is
happening because of the pim_upstream_inherited_olist_decide() and
forward_on() get all the oil and update the flag wrongly.
So now when client 2 sends IGMP prune, RP will not remove the int-2
from oil list since both PIM_OIF_FLAG_PROTO_PIM & PIM_OIF_FLAG_PROTO_IGMP
are set, it just unset the flag PIM_OIF_FLAG_PROTO_IGMP.
Fix: Introduced new flags in if_channel, PIM_IF_FLAG_MASK_PROTO_PIM
& PIM_IF_FLAG_MASK_PROTO_IGMP. If a if_channel is created because of
pim join or pim (s,g,rpt) prune received, then set the flag
PIM_IF_FLAG_MASK_PROTO_PIM. If a if_channel is created becuase of IGMP
join received, then set the flag PIM_IF_FLAG_MASK_PROTO_IGMP.
When an interface needs to be added into the oil list check if
PIM_IF_FLAG_MASK_PROTO_PIM or PIM_IF_FLAG_MASK_PROTO_IGMP is set, then
update oil flag accordingly.
Signed-off-by: Sarita Patra <saritap@vmware.com>
2020-03-02 09:55:22 +01:00
|
|
|
if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
|
2017-01-25 20:47:04 +01:00
|
|
|
mask = PIM_OIF_FLAG_PROTO_IGMP;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
pimd: fix OIL not removed after IGMP prune
Issue: Client1------LHR-----(int-1)RP(int-2)------client2
Client2 send IGMP join for group G.
Client1 send IGMP join for group G.
verify show ip mroute in RP, will have 2 OIL.
Client2 send IGMP leave.
Verify show ip mroute in RP, will still have 2.
Root cause: When RP receives IGMP join from client2, it creates
a (s,g) channel oil and add the interface int-2 into oil list and
set the flag PIM_OIF_FLAG_PROTO_IGMP to int-2
Client1 send IGMP join, LHR will send a (*,G) join to RP. RP will
add the interface int-1 into the oil list of (s,g) channel_oil and
will set the flag PIM_OIF_FLAG_PROTO_IGMP and PIM_OIF_FLAG_PROTO_PIM
to the int-1 and set PIM_OIF_FLAG_PROTO_PIM to int-2 as well. It is
happening because of the pim_upstream_inherited_olist_decide() and
forward_on() get all the oil and update the flag wrongly.
So now when client 2 sends IGMP prune, RP will not remove the int-2
from oil list since both PIM_OIF_FLAG_PROTO_PIM & PIM_OIF_FLAG_PROTO_IGMP
are set, it just unset the flag PIM_OIF_FLAG_PROTO_IGMP.
Fix: Introduced new flags in if_channel, PIM_IF_FLAG_MASK_PROTO_PIM
& PIM_IF_FLAG_MASK_PROTO_IGMP. If a if_channel is created because of
pim join or pim (s,g,rpt) prune received, then set the flag
PIM_IF_FLAG_MASK_PROTO_PIM. If a if_channel is created becuase of IGMP
join received, then set the flag PIM_IF_FLAG_MASK_PROTO_IGMP.
When an interface needs to be added into the oil list check if
PIM_IF_FLAG_MASK_PROTO_PIM or PIM_IF_FLAG_MASK_PROTO_IGMP is set, then
update oil flag accordingly.
Signed-off-by: Sarita Patra <saritap@vmware.com>
2020-03-02 09:55:22 +01:00
|
|
|
if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
|
|
|
|
mask |= PIM_OIF_FLAG_PROTO_PIM;
|
|
|
|
|
2019-11-15 17:47:33 +01:00
|
|
|
pim_channel_add_oif(up->channel_oil, ch->interface,
|
|
|
|
mask, __func__);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2021-10-24 13:45:18 +02:00
|
|
|
void pim_forward_stop(struct pim_ifchannel *ch)
|
2015-02-04 07:01:14 +01:00
|
|
|
{
|
|
|
|
struct pim_upstream *up = ch->upstream;
|
|
|
|
|
|
|
|
if (PIM_DEBUG_PIM_TRACE) {
|
2021-10-24 13:45:18 +02:00
|
|
|
zlog_debug("%s: (S,G)=%s oif=%s installed: %d",
|
2020-03-05 19:17:54 +01:00
|
|
|
__func__, ch->sg_str, ch->interface->name,
|
2021-10-24 13:45:18 +02:00
|
|
|
up->channel_oil->installed);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
|
|
|
|
2019-04-24 10:33:37 +02:00
|
|
|
/*
|
|
|
|
* If a channel is being removed, check to see if we still need
|
|
|
|
* to inherit the interface. If so make sure it is added in
|
|
|
|
*/
|
|
|
|
if (pim_upstream_evaluate_join_desired_interface(up, ch, ch->parent))
|
|
|
|
pim_channel_add_oif(up->channel_oil, ch->interface,
|
2019-11-15 17:47:33 +01:00
|
|
|
PIM_OIF_FLAG_PROTO_PIM, __func__);
|
2019-04-24 10:33:37 +02:00
|
|
|
else
|
|
|
|
pim_channel_del_oif(up->channel_oil, ch->interface,
|
2019-11-15 17:47:33 +01:00
|
|
|
PIM_OIF_FLAG_PROTO_PIM, __func__);
|
2015-02-04 07:01:14 +01:00
|
|
|
}
|
2016-12-09 17:05:08 +01:00
|
|
|
|
|
|
|
void pim_zebra_zclient_update(struct vty *vty)
|
|
|
|
{
|
|
|
|
vty_out(vty, "Zclient update socket: ");
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-12-09 17:08:45 +01:00
|
|
|
if (zclient) {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "%d failures=%d\n", zclient->sock, zclient->fail);
|
2016-12-09 17:05:08 +01:00
|
|
|
} else {
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, "<null zclient>\n");
|
2016-12-09 17:05:08 +01:00
|
|
|
}
|
|
|
|
}
|
2017-02-22 16:28:36 +01:00
|
|
|
|
|
|
|
struct zclient *pim_zebra_zclient_get(void)
|
|
|
|
{
|
|
|
|
if (zclient)
|
|
|
|
return zclient;
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
2019-09-19 05:07:44 +02:00
|
|
|
|
|
|
|
void pim_zebra_interface_set_master(struct interface *vrf,
|
|
|
|
struct interface *ifp)
|
|
|
|
{
|
|
|
|
zclient_interface_set_master(zclient, vrf, ifp);
|
|
|
|
}
|