forked from Mirror/frr

VRF creation can happen from either cli or from knowledged about the vrf learned from zebra. In the case where we learn about the vrf from the cli, the vrf id is UNKNOWN. Upon actual creation of the vrf, lib/vrf.c touches up the vrf_id and calls pim_vrf_enable to turn it on properly. At this point in time we have a pim->vrf_id of UNKNOWN and the vrf->vrf_id of the right value. There is no point in duplicating this data. So just remove all pim->vrf_id and use the vrf->vrf_id instead since we keep a copy of the pim->vrf pointer. This will remove some crashes where we expect the pim->vrf_id to be usable and it's not. Signed-off-by: Donald Sharp <sharpd@nvidia.com>
11394 lines
304 KiB
C
11394 lines
304 KiB
C
/*
|
|
* 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
|
|
*/
|
|
|
|
#include <zebra.h>
|
|
|
|
#include "lib/json.h"
|
|
#include "command.h"
|
|
#include "if.h"
|
|
#include "prefix.h"
|
|
#include "zclient.h"
|
|
#include "plist.h"
|
|
#include "hash.h"
|
|
#include "nexthop.h"
|
|
#include "vrf.h"
|
|
#include "ferr.h"
|
|
|
|
#include "pimd.h"
|
|
#include "pim_mroute.h"
|
|
#include "pim_cmd.h"
|
|
#include "pim_iface.h"
|
|
#include "pim_vty.h"
|
|
#include "pim_mroute.h"
|
|
#include "pim_str.h"
|
|
#include "pim_igmp.h"
|
|
#include "pim_igmpv3.h"
|
|
#include "pim_sock.h"
|
|
#include "pim_time.h"
|
|
#include "pim_util.h"
|
|
#include "pim_oil.h"
|
|
#include "pim_neighbor.h"
|
|
#include "pim_pim.h"
|
|
#include "pim_ifchannel.h"
|
|
#include "pim_hello.h"
|
|
#include "pim_msg.h"
|
|
#include "pim_upstream.h"
|
|
#include "pim_rpf.h"
|
|
#include "pim_macro.h"
|
|
#include "pim_ssmpingd.h"
|
|
#include "pim_zebra.h"
|
|
#include "pim_static.h"
|
|
#include "pim_rp.h"
|
|
#include "pim_zlookup.h"
|
|
#include "pim_msdp.h"
|
|
#include "pim_ssm.h"
|
|
#include "pim_nht.h"
|
|
#include "pim_bfd.h"
|
|
#include "pim_vxlan.h"
|
|
#include "pim_mlag.h"
|
|
#include "bfd.h"
|
|
#include "pim_bsm.h"
|
|
#include "lib/northbound_cli.h"
|
|
#include "pim_errors.h"
|
|
#include "pim_nb.h"
|
|
|
|
#ifndef VTYSH_EXTRACT_PL
|
|
#include "pimd/pim_cmd_clippy.c"
|
|
#endif
|
|
|
|
static struct cmd_node interface_node = {
|
|
.name = "interface",
|
|
.node = INTERFACE_NODE,
|
|
.parent_node = CONFIG_NODE,
|
|
.prompt = "%s(config-if)# ",
|
|
.config_write = pim_interface_config_write,
|
|
};
|
|
|
|
static struct cmd_node debug_node = {
|
|
.name = "debug",
|
|
.node = DEBUG_NODE,
|
|
.prompt = "",
|
|
.config_write = pim_debug_config_write,
|
|
};
|
|
|
|
static struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[],
|
|
const int argc, int *idx)
|
|
{
|
|
struct vrf *vrf;
|
|
|
|
if (argv_find(argv, argc, "NAME", idx))
|
|
vrf = vrf_lookup_by_name(argv[*idx]->arg);
|
|
else
|
|
vrf = vrf_lookup_by_id(VRF_DEFAULT);
|
|
|
|
if (!vrf)
|
|
vty_out(vty, "Specified VRF: %s does not exist\n",
|
|
argv[*idx]->arg);
|
|
|
|
return vrf;
|
|
}
|
|
|
|
static void pim_show_assert_helper(struct vty *vty,
|
|
struct pim_interface *pim_ifp,
|
|
struct pim_ifchannel *ch, time_t now)
|
|
{
|
|
char ch_src_str[INET_ADDRSTRLEN];
|
|
char ch_grp_str[INET_ADDRSTRLEN];
|
|
char winner_str[INET_ADDRSTRLEN];
|
|
struct in_addr ifaddr;
|
|
char uptime[10];
|
|
char timer[10];
|
|
char buf[PREFIX_STRLEN];
|
|
|
|
ifaddr = pim_ifp->primary_address;
|
|
|
|
pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, sizeof(ch_src_str));
|
|
pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str));
|
|
pim_inet4_dump("<assrt_win?>", ch->ifassert_winner, winner_str,
|
|
sizeof(winner_str));
|
|
|
|
pim_time_uptime(uptime, sizeof(uptime), now - ch->ifassert_creation);
|
|
pim_time_timer_to_mmss(timer, sizeof(timer), ch->t_ifassert_timer);
|
|
|
|
vty_out(vty, "%-16s %-15s %-15s %-15s %-6s %-15s %-8s %-5s\n",
|
|
ch->interface->name,
|
|
inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)), ch_src_str,
|
|
ch_grp_str, pim_ifchannel_ifassert_name(ch->ifassert_state),
|
|
winner_str, uptime, timer);
|
|
}
|
|
|
|
static void pim_show_assert(struct pim_instance *pim, struct vty *vty)
|
|
{
|
|
struct pim_interface *pim_ifp;
|
|
struct pim_ifchannel *ch;
|
|
struct interface *ifp;
|
|
time_t now;
|
|
|
|
now = pim_time_monotonic_sec();
|
|
|
|
vty_out(vty,
|
|
"Interface Address Source Group State Winner Uptime Timer\n");
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
pim_ifp = ifp->info;
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
|
|
pim_show_assert_helper(vty, pim_ifp, ch, now);
|
|
} /* scan interface channels */
|
|
}
|
|
}
|
|
|
|
static void pim_show_assert_internal_helper(struct vty *vty,
|
|
struct pim_interface *pim_ifp,
|
|
struct pim_ifchannel *ch)
|
|
{
|
|
char ch_src_str[INET_ADDRSTRLEN];
|
|
char ch_grp_str[INET_ADDRSTRLEN];
|
|
struct in_addr ifaddr;
|
|
char buf[PREFIX_STRLEN];
|
|
|
|
ifaddr = pim_ifp->primary_address;
|
|
|
|
pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, sizeof(ch_src_str));
|
|
pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str));
|
|
vty_out(vty, "%-16s %-15s %-15s %-15s %-3s %-3s %-3s %-4s\n",
|
|
ch->interface->name,
|
|
inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)),
|
|
ch_src_str, ch_grp_str,
|
|
PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags) ? "yes" : "no",
|
|
pim_macro_ch_could_assert_eval(ch) ? "yes" : "no",
|
|
PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags) ? "yes"
|
|
: "no",
|
|
pim_macro_assert_tracking_desired_eval(ch) ? "yes" : "no");
|
|
}
|
|
|
|
static void pim_show_assert_internal(struct pim_instance *pim, struct vty *vty)
|
|
{
|
|
struct pim_interface *pim_ifp;
|
|
struct pim_ifchannel *ch;
|
|
struct interface *ifp;
|
|
|
|
vty_out(vty,
|
|
"CA: CouldAssert\n"
|
|
"ECA: Evaluate CouldAssert\n"
|
|
"ATD: AssertTrackingDesired\n"
|
|
"eATD: Evaluate AssertTrackingDesired\n\n");
|
|
|
|
vty_out(vty,
|
|
"Interface Address Source Group CA eCA ATD eATD\n");
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
pim_ifp = ifp->info;
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
|
|
pim_show_assert_internal_helper(vty, pim_ifp, ch);
|
|
} /* scan interface channels */
|
|
}
|
|
}
|
|
|
|
static void pim_show_assert_metric_helper(struct vty *vty,
|
|
struct pim_interface *pim_ifp,
|
|
struct pim_ifchannel *ch)
|
|
{
|
|
char ch_src_str[INET_ADDRSTRLEN];
|
|
char ch_grp_str[INET_ADDRSTRLEN];
|
|
char addr_str[INET_ADDRSTRLEN];
|
|
struct pim_assert_metric am;
|
|
struct in_addr ifaddr;
|
|
char buf[PREFIX_STRLEN];
|
|
|
|
ifaddr = pim_ifp->primary_address;
|
|
|
|
am = pim_macro_spt_assert_metric(&ch->upstream->rpf,
|
|
pim_ifp->primary_address);
|
|
|
|
pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, sizeof(ch_src_str));
|
|
pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str));
|
|
pim_inet4_dump("<addr?>", am.ip_address, addr_str, sizeof(addr_str));
|
|
|
|
vty_out(vty, "%-16s %-15s %-15s %-15s %-3s %4u %6u %-15s\n",
|
|
ch->interface->name,
|
|
inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)),
|
|
ch_src_str, ch_grp_str, am.rpt_bit_flag ? "yes" : "no",
|
|
am.metric_preference, am.route_metric, addr_str);
|
|
}
|
|
|
|
static void pim_show_assert_metric(struct pim_instance *pim, struct vty *vty)
|
|
{
|
|
struct pim_interface *pim_ifp;
|
|
struct pim_ifchannel *ch;
|
|
struct interface *ifp;
|
|
|
|
vty_out(vty,
|
|
"Interface Address Source Group RPT Pref Metric Address \n");
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
pim_ifp = ifp->info;
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
|
|
pim_show_assert_metric_helper(vty, pim_ifp, ch);
|
|
} /* scan interface channels */
|
|
}
|
|
}
|
|
|
|
static void pim_show_assert_winner_metric_helper(struct vty *vty,
|
|
struct pim_interface *pim_ifp,
|
|
struct pim_ifchannel *ch)
|
|
{
|
|
char ch_src_str[INET_ADDRSTRLEN];
|
|
char ch_grp_str[INET_ADDRSTRLEN];
|
|
char addr_str[INET_ADDRSTRLEN];
|
|
struct pim_assert_metric *am;
|
|
struct in_addr ifaddr;
|
|
char pref_str[16];
|
|
char metr_str[16];
|
|
char buf[PREFIX_STRLEN];
|
|
|
|
ifaddr = pim_ifp->primary_address;
|
|
|
|
am = &ch->ifassert_winner_metric;
|
|
|
|
pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, sizeof(ch_src_str));
|
|
pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str));
|
|
pim_inet4_dump("<addr?>", am->ip_address, addr_str, sizeof(addr_str));
|
|
|
|
if (am->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX)
|
|
snprintf(pref_str, sizeof(pref_str), "INFI");
|
|
else
|
|
snprintf(pref_str, sizeof(pref_str), "%4u",
|
|
am->metric_preference);
|
|
|
|
if (am->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX)
|
|
snprintf(metr_str, sizeof(metr_str), "INFI");
|
|
else
|
|
snprintf(metr_str, sizeof(metr_str), "%6u", am->route_metric);
|
|
|
|
vty_out(vty, "%-16s %-15s %-15s %-15s %-3s %-4s %-6s %-15s\n",
|
|
ch->interface->name,
|
|
inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)), ch_src_str,
|
|
ch_grp_str, am->rpt_bit_flag ? "yes" : "no", pref_str, metr_str,
|
|
addr_str);
|
|
}
|
|
|
|
static void pim_show_assert_winner_metric(struct pim_instance *pim,
|
|
struct vty *vty)
|
|
{
|
|
struct pim_interface *pim_ifp;
|
|
struct pim_ifchannel *ch;
|
|
struct interface *ifp;
|
|
|
|
vty_out(vty,
|
|
"Interface Address Source Group RPT Pref Metric Address \n");
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
pim_ifp = ifp->info;
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
|
|
pim_show_assert_winner_metric_helper(vty, pim_ifp, ch);
|
|
} /* scan interface channels */
|
|
}
|
|
}
|
|
|
|
static void json_object_pim_ifp_add(struct json_object *json,
|
|
struct interface *ifp)
|
|
{
|
|
struct pim_interface *pim_ifp;
|
|
char buf[PREFIX_STRLEN];
|
|
|
|
pim_ifp = ifp->info;
|
|
json_object_string_add(json, "name", ifp->name);
|
|
json_object_string_add(json, "state", if_is_up(ifp) ? "up" : "down");
|
|
json_object_string_add(json, "address",
|
|
inet_ntop(AF_INET, &pim_ifp->primary_address,
|
|
buf, sizeof(buf)));
|
|
json_object_int_add(json, "index", ifp->ifindex);
|
|
|
|
if (if_is_multicast(ifp))
|
|
json_object_boolean_true_add(json, "flagMulticast");
|
|
|
|
if (if_is_broadcast(ifp))
|
|
json_object_boolean_true_add(json, "flagBroadcast");
|
|
|
|
if (ifp->flags & IFF_ALLMULTI)
|
|
json_object_boolean_true_add(json, "flagAllMulticast");
|
|
|
|
if (ifp->flags & IFF_PROMISC)
|
|
json_object_boolean_true_add(json, "flagPromiscuous");
|
|
|
|
if (PIM_IF_IS_DELETED(ifp))
|
|
json_object_boolean_true_add(json, "flagDeleted");
|
|
|
|
if (pim_if_lan_delay_enabled(ifp))
|
|
json_object_boolean_true_add(json, "lanDelayEnabled");
|
|
}
|
|
|
|
static void pim_show_membership_helper(struct vty *vty,
|
|
struct pim_interface *pim_ifp,
|
|
struct pim_ifchannel *ch,
|
|
struct json_object *json)
|
|
{
|
|
char ch_src_str[INET_ADDRSTRLEN];
|
|
char ch_grp_str[INET_ADDRSTRLEN];
|
|
json_object *json_iface = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, sizeof(ch_src_str));
|
|
pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str));
|
|
|
|
json_object_object_get_ex(json, ch->interface->name, &json_iface);
|
|
if (!json_iface) {
|
|
json_iface = json_object_new_object();
|
|
json_object_pim_ifp_add(json_iface, ch->interface);
|
|
json_object_object_add(json, ch->interface->name, json_iface);
|
|
}
|
|
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "source", ch_src_str);
|
|
json_object_string_add(json_row, "group", ch_grp_str);
|
|
json_object_string_add(json_row, "localMembership",
|
|
ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO
|
|
? "NOINFO"
|
|
: "INCLUDE");
|
|
json_object_object_add(json_iface, ch_grp_str, json_row);
|
|
}
|
|
static void pim_show_membership(struct pim_instance *pim, struct vty *vty,
|
|
bool uj)
|
|
{
|
|
struct pim_interface *pim_ifp;
|
|
struct pim_ifchannel *ch;
|
|
struct interface *ifp;
|
|
enum json_type type;
|
|
json_object *json = NULL;
|
|
json_object *json_tmp = NULL;
|
|
|
|
json = json_object_new_object();
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
pim_ifp = ifp->info;
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
|
|
pim_show_membership_helper(vty, pim_ifp, ch, json);
|
|
} /* scan interface channels */
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
} else {
|
|
vty_out(vty,
|
|
"Interface Address Source Group Membership\n");
|
|
|
|
/*
|
|
* Example of the json data we are traversing
|
|
*
|
|
* {
|
|
* "swp3":{
|
|
* "name":"swp3",
|
|
* "state":"up",
|
|
* "address":"10.1.20.1",
|
|
* "index":5,
|
|
* "flagMulticast":true,
|
|
* "flagBroadcast":true,
|
|
* "lanDelayEnabled":true,
|
|
* "226.10.10.10":{
|
|
* "source":"*",
|
|
* "group":"226.10.10.10",
|
|
* "localMembership":"INCLUDE"
|
|
* }
|
|
* }
|
|
* }
|
|
*/
|
|
|
|
/* foreach interface */
|
|
json_object_object_foreach(json, key, val)
|
|
{
|
|
|
|
/* Find all of the keys where the val is an object. In
|
|
* the example
|
|
* above the only one is 226.10.10.10
|
|
*/
|
|
json_object_object_foreach(val, if_field_key,
|
|
if_field_val)
|
|
{
|
|
type = json_object_get_type(if_field_val);
|
|
|
|
if (type == json_type_object) {
|
|
vty_out(vty, "%-16s ", key);
|
|
|
|
json_object_object_get_ex(
|
|
val, "address", &json_tmp);
|
|
vty_out(vty, "%-15s ",
|
|
json_object_get_string(
|
|
json_tmp));
|
|
|
|
json_object_object_get_ex(if_field_val,
|
|
"source",
|
|
&json_tmp);
|
|
vty_out(vty, "%-15s ",
|
|
json_object_get_string(
|
|
json_tmp));
|
|
|
|
/* Group */
|
|
vty_out(vty, "%-15s ", if_field_key);
|
|
|
|
json_object_object_get_ex(
|
|
if_field_val, "localMembership",
|
|
&json_tmp);
|
|
vty_out(vty, "%-10s\n",
|
|
json_object_get_string(
|
|
json_tmp));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
json_object_free(json);
|
|
}
|
|
|
|
static void pim_print_ifp_flags(struct vty *vty, struct interface *ifp,
|
|
int mloop)
|
|
{
|
|
vty_out(vty, "Flags\n");
|
|
vty_out(vty, "-----\n");
|
|
vty_out(vty, "All Multicast : %s\n",
|
|
(ifp->flags & IFF_ALLMULTI) ? "yes" : "no");
|
|
vty_out(vty, "Broadcast : %s\n",
|
|
if_is_broadcast(ifp) ? "yes" : "no");
|
|
vty_out(vty, "Deleted : %s\n",
|
|
PIM_IF_IS_DELETED(ifp) ? "yes" : "no");
|
|
vty_out(vty, "Interface Index : %d\n", ifp->ifindex);
|
|
vty_out(vty, "Multicast : %s\n",
|
|
if_is_multicast(ifp) ? "yes" : "no");
|
|
vty_out(vty, "Multicast Loop : %d\n", mloop);
|
|
vty_out(vty, "Promiscuous : %s\n",
|
|
(ifp->flags & IFF_PROMISC) ? "yes" : "no");
|
|
vty_out(vty, "\n");
|
|
vty_out(vty, "\n");
|
|
}
|
|
|
|
static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty,
|
|
bool uj)
|
|
{
|
|
struct interface *ifp;
|
|
time_t now;
|
|
char buf[PREFIX_STRLEN];
|
|
json_object *json = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
now = pim_time_monotonic_sec();
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
else
|
|
vty_out(vty,
|
|
"Interface State Address V Querier Query Timer Uptime\n");
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
struct pim_interface *pim_ifp;
|
|
struct listnode *sock_node;
|
|
struct igmp_sock *igmp;
|
|
|
|
pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
|
|
igmp)) {
|
|
char uptime[10];
|
|
char query_hhmmss[10];
|
|
|
|
pim_time_uptime(uptime, sizeof(uptime),
|
|
now - igmp->sock_creation);
|
|
pim_time_timer_to_hhmmss(query_hhmmss,
|
|
sizeof(query_hhmmss),
|
|
igmp->t_igmp_query_timer);
|
|
|
|
if (uj) {
|
|
json_row = json_object_new_object();
|
|
json_object_pim_ifp_add(json_row, ifp);
|
|
json_object_string_add(json_row, "upTime",
|
|
uptime);
|
|
json_object_int_add(json_row, "version",
|
|
pim_ifp->igmp_version);
|
|
|
|
if (igmp->t_igmp_query_timer) {
|
|
json_object_boolean_true_add(json_row,
|
|
"querier");
|
|
json_object_string_add(json_row,
|
|
"queryTimer",
|
|
query_hhmmss);
|
|
}
|
|
|
|
json_object_object_add(json, ifp->name,
|
|
json_row);
|
|
|
|
if (igmp->mtrace_only) {
|
|
json_object_boolean_true_add(
|
|
json_row, "mtraceOnly");
|
|
}
|
|
} else {
|
|
vty_out(vty,
|
|
"%-16s %5s %15s %d %7s %11s %8s\n",
|
|
ifp->name,
|
|
if_is_up(ifp)
|
|
? (igmp->mtrace_only ? "mtrc"
|
|
: "up")
|
|
: "down",
|
|
inet_ntop(AF_INET, &igmp->ifaddr,
|
|
buf, sizeof(buf)),
|
|
pim_ifp->igmp_version,
|
|
igmp->t_igmp_query_timer ? "local"
|
|
: "other",
|
|
query_hhmmss, uptime);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void igmp_show_interfaces_single(struct pim_instance *pim,
|
|
struct vty *vty, const char *ifname,
|
|
bool uj)
|
|
{
|
|
struct igmp_sock *igmp;
|
|
struct interface *ifp;
|
|
struct listnode *sock_node;
|
|
struct pim_interface *pim_ifp;
|
|
char uptime[10];
|
|
char query_hhmmss[10];
|
|
char other_hhmmss[10];
|
|
int found_ifname = 0;
|
|
int sqi;
|
|
int mloop = 0;
|
|
long gmi_msec; /* Group Membership Interval */
|
|
long lmqt_msec;
|
|
long ohpi_msec;
|
|
long oqpi_msec; /* Other Querier Present Interval */
|
|
long qri_msec;
|
|
time_t now;
|
|
int lmqc;
|
|
|
|
json_object *json = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
|
|
now = pim_time_monotonic_sec();
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
if (strcmp(ifname, "detail") && strcmp(ifname, ifp->name))
|
|
continue;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
|
|
igmp)) {
|
|
found_ifname = 1;
|
|
pim_time_uptime(uptime, sizeof(uptime),
|
|
now - igmp->sock_creation);
|
|
pim_time_timer_to_hhmmss(query_hhmmss,
|
|
sizeof(query_hhmmss),
|
|
igmp->t_igmp_query_timer);
|
|
pim_time_timer_to_hhmmss(other_hhmmss,
|
|
sizeof(other_hhmmss),
|
|
igmp->t_other_querier_timer);
|
|
|
|
gmi_msec = PIM_IGMP_GMI_MSEC(
|
|
igmp->querier_robustness_variable,
|
|
igmp->querier_query_interval,
|
|
pim_ifp->igmp_query_max_response_time_dsec);
|
|
|
|
sqi = PIM_IGMP_SQI(
|
|
pim_ifp->igmp_default_query_interval);
|
|
|
|
oqpi_msec = PIM_IGMP_OQPI_MSEC(
|
|
igmp->querier_robustness_variable,
|
|
igmp->querier_query_interval,
|
|
pim_ifp->igmp_query_max_response_time_dsec);
|
|
|
|
lmqt_msec = PIM_IGMP_LMQT_MSEC(
|
|
pim_ifp->igmp_specific_query_max_response_time_dsec,
|
|
pim_ifp->igmp_last_member_query_count);
|
|
|
|
ohpi_msec =
|
|
PIM_IGMP_OHPI_DSEC(
|
|
igmp->querier_robustness_variable,
|
|
igmp->querier_query_interval,
|
|
pim_ifp->igmp_query_max_response_time_dsec)
|
|
* 100;
|
|
|
|
qri_msec = pim_ifp->igmp_query_max_response_time_dsec
|
|
* 100;
|
|
if (pim_ifp->pim_sock_fd >= 0)
|
|
mloop = pim_socket_mcastloop_get(
|
|
pim_ifp->pim_sock_fd);
|
|
else
|
|
mloop = 0;
|
|
lmqc = pim_ifp->igmp_last_member_query_count;
|
|
|
|
if (uj) {
|
|
json_row = json_object_new_object();
|
|
json_object_pim_ifp_add(json_row, ifp);
|
|
json_object_string_add(json_row, "upTime",
|
|
uptime);
|
|
json_object_string_add(json_row, "querier",
|
|
igmp->t_igmp_query_timer
|
|
? "local"
|
|
: "other");
|
|
json_object_int_add(json_row, "queryStartCount",
|
|
igmp->startup_query_count);
|
|
json_object_string_add(json_row,
|
|
"queryQueryTimer",
|
|
query_hhmmss);
|
|
json_object_string_add(json_row,
|
|
"queryOtherTimer",
|
|
other_hhmmss);
|
|
json_object_int_add(json_row, "version",
|
|
pim_ifp->igmp_version);
|
|
json_object_int_add(
|
|
json_row,
|
|
"timerGroupMembershipIntervalMsec",
|
|
gmi_msec);
|
|
json_object_int_add(json_row,
|
|
"lastMemberQueryCount",
|
|
lmqc);
|
|
json_object_int_add(json_row,
|
|
"timerLastMemberQueryMsec",
|
|
lmqt_msec);
|
|
json_object_int_add(
|
|
json_row,
|
|
"timerOlderHostPresentIntervalMsec",
|
|
ohpi_msec);
|
|
json_object_int_add(
|
|
json_row,
|
|
"timerOtherQuerierPresentIntervalMsec",
|
|
oqpi_msec);
|
|
json_object_int_add(
|
|
json_row, "timerQueryInterval",
|
|
igmp->querier_query_interval);
|
|
json_object_int_add(
|
|
json_row,
|
|
"timerQueryResponseIntervalMsec",
|
|
qri_msec);
|
|
json_object_int_add(
|
|
json_row, "timerRobustnessVariable",
|
|
igmp->querier_robustness_variable);
|
|
json_object_int_add(json_row,
|
|
"timerStartupQueryInterval",
|
|
sqi);
|
|
|
|
json_object_object_add(json, ifp->name,
|
|
json_row);
|
|
|
|
if (igmp->mtrace_only) {
|
|
json_object_boolean_true_add(
|
|
json_row, "mtraceOnly");
|
|
}
|
|
} else {
|
|
vty_out(vty, "Interface : %s\n", ifp->name);
|
|
vty_out(vty, "State : %s\n",
|
|
if_is_up(ifp) ? (igmp->mtrace_only ?
|
|
"mtrace"
|
|
: "up")
|
|
: "down");
|
|
vty_out(vty, "Address : %pI4\n",
|
|
&pim_ifp->primary_address);
|
|
vty_out(vty, "Uptime : %s\n", uptime);
|
|
vty_out(vty, "Version : %d\n",
|
|
pim_ifp->igmp_version);
|
|
vty_out(vty, "\n");
|
|
vty_out(vty, "\n");
|
|
|
|
vty_out(vty, "Querier\n");
|
|
vty_out(vty, "-------\n");
|
|
vty_out(vty, "Querier : %s\n",
|
|
igmp->t_igmp_query_timer ? "local"
|
|
: "other");
|
|
vty_out(vty, "Start Count : %d\n",
|
|
igmp->startup_query_count);
|
|
vty_out(vty, "Query Timer : %s\n",
|
|
query_hhmmss);
|
|
vty_out(vty, "Other Timer : %s\n",
|
|
other_hhmmss);
|
|
vty_out(vty, "\n");
|
|
vty_out(vty, "\n");
|
|
|
|
vty_out(vty, "Timers\n");
|
|
vty_out(vty, "------\n");
|
|
vty_out(vty,
|
|
"Group Membership Interval : %lis\n",
|
|
gmi_msec / 1000);
|
|
vty_out(vty,
|
|
"Last Member Query Count : %d\n",
|
|
lmqc);
|
|
vty_out(vty,
|
|
"Last Member Query Time : %lis\n",
|
|
lmqt_msec / 1000);
|
|
vty_out(vty,
|
|
"Older Host Present Interval : %lis\n",
|
|
ohpi_msec / 1000);
|
|
vty_out(vty,
|
|
"Other Querier Present Interval : %lis\n",
|
|
oqpi_msec / 1000);
|
|
vty_out(vty,
|
|
"Query Interval : %ds\n",
|
|
igmp->querier_query_interval);
|
|
vty_out(vty,
|
|
"Query Response Interval : %lis\n",
|
|
qri_msec / 1000);
|
|
vty_out(vty,
|
|
"Robustness Variable : %d\n",
|
|
igmp->querier_robustness_variable);
|
|
vty_out(vty,
|
|
"Startup Query Interval : %ds\n",
|
|
sqi);
|
|
vty_out(vty, "\n");
|
|
vty_out(vty, "\n");
|
|
|
|
pim_print_ifp_flags(vty, ifp, mloop);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
} else {
|
|
if (!found_ifname)
|
|
vty_out(vty, "%% No such interface\n");
|
|
}
|
|
}
|
|
|
|
static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty,
|
|
bool uj)
|
|
{
|
|
struct interface *ifp;
|
|
time_t now;
|
|
json_object *json = NULL;
|
|
json_object *json_iface = NULL;
|
|
json_object *json_grp = NULL;
|
|
json_object *json_grp_arr = NULL;
|
|
|
|
now = pim_time_monotonic_sec();
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
json_object_string_add(json, "vrf",
|
|
vrf_id_to_name(pim->vrf->vrf_id));
|
|
} else {
|
|
vty_out(vty,
|
|
"Interface Address Source Group Socket Uptime \n");
|
|
}
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
struct pim_interface *pim_ifp;
|
|
struct listnode *join_node;
|
|
struct igmp_join *ij;
|
|
struct in_addr pri_addr;
|
|
char pri_addr_str[INET_ADDRSTRLEN];
|
|
|
|
pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
if (!pim_ifp->igmp_join_list)
|
|
continue;
|
|
|
|
pri_addr = pim_find_primary_addr(ifp);
|
|
pim_inet4_dump("<pri?>", pri_addr, pri_addr_str,
|
|
sizeof(pri_addr_str));
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_join_list, join_node,
|
|
ij)) {
|
|
char group_str[INET_ADDRSTRLEN];
|
|
char source_str[INET_ADDRSTRLEN];
|
|
char uptime[10];
|
|
|
|
pim_time_uptime(uptime, sizeof(uptime),
|
|
now - ij->sock_creation);
|
|
pim_inet4_dump("<grp?>", ij->group_addr, group_str,
|
|
sizeof(group_str));
|
|
pim_inet4_dump("<src?>", ij->source_addr, source_str,
|
|
sizeof(source_str));
|
|
|
|
if (uj) {
|
|
json_object_object_get_ex(json, ifp->name,
|
|
&json_iface);
|
|
|
|
if (!json_iface) {
|
|
json_iface = json_object_new_object();
|
|
json_object_string_add(
|
|
json_iface, "name", ifp->name);
|
|
json_object_object_add(json, ifp->name,
|
|
json_iface);
|
|
json_grp_arr = json_object_new_array();
|
|
json_object_object_add(json_iface,
|
|
"groups",
|
|
json_grp_arr);
|
|
}
|
|
|
|
json_grp = json_object_new_object();
|
|
json_object_string_add(json_grp, "source",
|
|
source_str);
|
|
json_object_string_add(json_grp, "group",
|
|
group_str);
|
|
json_object_string_add(json_grp, "primaryAddr",
|
|
pri_addr_str);
|
|
json_object_int_add(json_grp, "sockFd",
|
|
ij->sock_fd);
|
|
json_object_string_add(json_grp, "upTime",
|
|
uptime);
|
|
json_object_array_add(json_grp_arr, json_grp);
|
|
} else {
|
|
vty_out(vty,
|
|
"%-16s %-15s %-15s %-15s %6d %8s\n",
|
|
ifp->name, pri_addr_str, source_str,
|
|
group_str, ij->sock_fd, uptime);
|
|
}
|
|
} /* for (pim_ifp->igmp_join_list) */
|
|
|
|
} /* for (iflist) */
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void pim_show_interfaces_single(struct pim_instance *pim,
|
|
struct vty *vty, const char *ifname,
|
|
bool mlag, bool uj)
|
|
{
|
|
struct in_addr ifaddr;
|
|
struct interface *ifp;
|
|
struct listnode *neighnode;
|
|
struct pim_interface *pim_ifp;
|
|
struct pim_neighbor *neigh;
|
|
struct pim_upstream *up;
|
|
time_t now;
|
|
char dr_str[INET_ADDRSTRLEN];
|
|
char dr_uptime[10];
|
|
char expire[10];
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
char hello_period[10];
|
|
char hello_timer[10];
|
|
char neigh_src_str[INET_ADDRSTRLEN];
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char stat_uptime[10];
|
|
char uptime[10];
|
|
int mloop = 0;
|
|
int found_ifname = 0;
|
|
int print_header;
|
|
char buf[PREFIX_STRLEN];
|
|
json_object *json = NULL;
|
|
json_object *json_row = NULL;
|
|
json_object *json_pim_neighbor = NULL;
|
|
json_object *json_pim_neighbors = NULL;
|
|
json_object *json_group = NULL;
|
|
json_object *json_group_source = NULL;
|
|
json_object *json_fhr_sources = NULL;
|
|
struct pim_secondary_addr *sec_addr;
|
|
struct listnode *sec_node;
|
|
|
|
now = pim_time_monotonic_sec();
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
if (mlag == true && pim_ifp->activeactive == false)
|
|
continue;
|
|
|
|
if (strcmp(ifname, "detail") && strcmp(ifname, ifp->name))
|
|
continue;
|
|
|
|
found_ifname = 1;
|
|
ifaddr = pim_ifp->primary_address;
|
|
pim_inet4_dump("<dr?>", pim_ifp->pim_dr_addr, dr_str,
|
|
sizeof(dr_str));
|
|
pim_time_uptime_begin(dr_uptime, sizeof(dr_uptime), now,
|
|
pim_ifp->pim_dr_election_last);
|
|
pim_time_timer_to_hhmmss(hello_timer, sizeof(hello_timer),
|
|
pim_ifp->t_pim_hello_timer);
|
|
pim_time_mmss(hello_period, sizeof(hello_period),
|
|
pim_ifp->pim_hello_period);
|
|
pim_time_uptime(stat_uptime, sizeof(stat_uptime),
|
|
now - pim_ifp->pim_ifstat_start);
|
|
if (pim_ifp->pim_sock_fd >= 0)
|
|
mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd);
|
|
else
|
|
mloop = 0;
|
|
|
|
if (uj) {
|
|
char pbuf[PREFIX2STR_BUFFER];
|
|
json_row = json_object_new_object();
|
|
json_object_pim_ifp_add(json_row, ifp);
|
|
|
|
if (pim_ifp->update_source.s_addr != INADDR_ANY) {
|
|
json_object_string_add(
|
|
json_row, "useSource",
|
|
inet_ntop(AF_INET,
|
|
&pim_ifp->update_source,
|
|
buf, sizeof(buf)));
|
|
}
|
|
if (pim_ifp->sec_addr_list) {
|
|
json_object *sec_list = NULL;
|
|
|
|
sec_list = json_object_new_array();
|
|
for (ALL_LIST_ELEMENTS_RO(
|
|
pim_ifp->sec_addr_list, sec_node,
|
|
sec_addr)) {
|
|
json_object_array_add(
|
|
sec_list,
|
|
json_object_new_string(
|
|
prefix2str(
|
|
&sec_addr->addr,
|
|
pbuf,
|
|
sizeof(pbuf))));
|
|
}
|
|
json_object_object_add(json_row,
|
|
"secondaryAddressList",
|
|
sec_list);
|
|
}
|
|
|
|
// PIM neighbors
|
|
if (pim_ifp->pim_neighbor_list->count) {
|
|
json_pim_neighbors = json_object_new_object();
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(
|
|
pim_ifp->pim_neighbor_list,
|
|
neighnode, neigh)) {
|
|
json_pim_neighbor =
|
|
json_object_new_object();
|
|
pim_inet4_dump("<src?>",
|
|
neigh->source_addr,
|
|
neigh_src_str,
|
|
sizeof(neigh_src_str));
|
|
pim_time_uptime(uptime, sizeof(uptime),
|
|
now - neigh->creation);
|
|
pim_time_timer_to_hhmmss(
|
|
expire, sizeof(expire),
|
|
neigh->t_expire_timer);
|
|
|
|
json_object_string_add(
|
|
json_pim_neighbor, "address",
|
|
neigh_src_str);
|
|
json_object_string_add(
|
|
json_pim_neighbor, "upTime",
|
|
uptime);
|
|
json_object_string_add(
|
|
json_pim_neighbor, "holdtime",
|
|
expire);
|
|
|
|
json_object_object_add(
|
|
json_pim_neighbors,
|
|
neigh_src_str,
|
|
json_pim_neighbor);
|
|
}
|
|
|
|
json_object_object_add(json_row, "neighbors",
|
|
json_pim_neighbors);
|
|
}
|
|
|
|
json_object_string_add(json_row, "drAddress", dr_str);
|
|
json_object_int_add(json_row, "drPriority",
|
|
pim_ifp->pim_dr_priority);
|
|
json_object_string_add(json_row, "drUptime", dr_uptime);
|
|
json_object_int_add(json_row, "drElections",
|
|
pim_ifp->pim_dr_election_count);
|
|
json_object_int_add(json_row, "drChanges",
|
|
pim_ifp->pim_dr_election_changes);
|
|
|
|
// FHR
|
|
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
|
|
if (ifp != up->rpf.source_nexthop.interface)
|
|
continue;
|
|
|
|
if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_FHR))
|
|
continue;
|
|
|
|
if (!json_fhr_sources)
|
|
json_fhr_sources =
|
|
json_object_new_object();
|
|
|
|
pim_inet4_dump("<src?>", up->sg.src, src_str,
|
|
sizeof(src_str));
|
|
pim_inet4_dump("<grp?>", up->sg.grp, grp_str,
|
|
sizeof(grp_str));
|
|
pim_time_uptime(uptime, sizeof(uptime),
|
|
now - up->state_transition);
|
|
|
|
/*
|
|
* Does this group live in json_fhr_sources?
|
|
* If not create it.
|
|
*/
|
|
json_object_object_get_ex(json_fhr_sources,
|
|
grp_str, &json_group);
|
|
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_object_add(json_fhr_sources,
|
|
grp_str,
|
|
json_group);
|
|
}
|
|
|
|
json_group_source = json_object_new_object();
|
|
json_object_string_add(json_group_source,
|
|
"source", src_str);
|
|
json_object_string_add(json_group_source,
|
|
"group", grp_str);
|
|
json_object_string_add(json_group_source,
|
|
"upTime", uptime);
|
|
json_object_object_add(json_group, src_str,
|
|
json_group_source);
|
|
}
|
|
|
|
if (json_fhr_sources) {
|
|
json_object_object_add(json_row,
|
|
"firstHopRouter",
|
|
json_fhr_sources);
|
|
}
|
|
|
|
json_object_int_add(json_row, "helloPeriod",
|
|
pim_ifp->pim_hello_period);
|
|
json_object_int_add(json_row, "holdTime",
|
|
PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
|
|
json_object_string_add(json_row, "helloTimer",
|
|
hello_timer);
|
|
json_object_string_add(json_row, "helloStatStart",
|
|
stat_uptime);
|
|
json_object_int_add(json_row, "helloReceived",
|
|
pim_ifp->pim_ifstat_hello_recv);
|
|
json_object_int_add(json_row, "helloReceivedFailed",
|
|
pim_ifp->pim_ifstat_hello_recvfail);
|
|
json_object_int_add(json_row, "helloSend",
|
|
pim_ifp->pim_ifstat_hello_sent);
|
|
json_object_int_add(json_row, "hellosendFailed",
|
|
pim_ifp->pim_ifstat_hello_sendfail);
|
|
json_object_int_add(json_row, "helloGenerationId",
|
|
pim_ifp->pim_generation_id);
|
|
json_object_int_add(json_row, "flagMulticastLoop",
|
|
mloop);
|
|
|
|
json_object_int_add(
|
|
json_row, "effectivePropagationDelay",
|
|
pim_if_effective_propagation_delay_msec(ifp));
|
|
json_object_int_add(
|
|
json_row, "effectiveOverrideInterval",
|
|
pim_if_effective_override_interval_msec(ifp));
|
|
json_object_int_add(
|
|
json_row, "joinPruneOverrideInterval",
|
|
pim_if_jp_override_interval_msec(ifp));
|
|
|
|
json_object_int_add(
|
|
json_row, "propagationDelay",
|
|
pim_ifp->pim_propagation_delay_msec);
|
|
json_object_int_add(
|
|
json_row, "propagationDelayHighest",
|
|
pim_ifp->pim_neighbors_highest_propagation_delay_msec);
|
|
json_object_int_add(
|
|
json_row, "overrideInterval",
|
|
pim_ifp->pim_override_interval_msec);
|
|
json_object_int_add(
|
|
json_row, "overrideIntervalHighest",
|
|
pim_ifp->pim_neighbors_highest_override_interval_msec);
|
|
json_object_object_add(json, ifp->name, json_row);
|
|
|
|
} else {
|
|
vty_out(vty, "Interface : %s\n", ifp->name);
|
|
vty_out(vty, "State : %s\n",
|
|
if_is_up(ifp) ? "up" : "down");
|
|
if (pim_ifp->update_source.s_addr != INADDR_ANY) {
|
|
vty_out(vty, "Use Source : %pI4\n",
|
|
&pim_ifp->update_source);
|
|
}
|
|
if (pim_ifp->sec_addr_list) {
|
|
vty_out(vty, "Address : %pI4 (primary)\n",
|
|
&ifaddr);
|
|
for (ALL_LIST_ELEMENTS_RO(
|
|
pim_ifp->sec_addr_list, sec_node,
|
|
sec_addr))
|
|
vty_out(vty, " %pFX\n",
|
|
&sec_addr->addr);
|
|
} else {
|
|
vty_out(vty, "Address : %pI4\n",
|
|
&ifaddr);
|
|
}
|
|
vty_out(vty, "\n");
|
|
|
|
// PIM neighbors
|
|
print_header = 1;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list,
|
|
neighnode, neigh)) {
|
|
|
|
if (print_header) {
|
|
vty_out(vty, "PIM Neighbors\n");
|
|
vty_out(vty, "-------------\n");
|
|
print_header = 0;
|
|
}
|
|
|
|
pim_inet4_dump("<src?>", neigh->source_addr,
|
|
neigh_src_str,
|
|
sizeof(neigh_src_str));
|
|
pim_time_uptime(uptime, sizeof(uptime),
|
|
now - neigh->creation);
|
|
pim_time_timer_to_hhmmss(expire, sizeof(expire),
|
|
neigh->t_expire_timer);
|
|
vty_out(vty,
|
|
"%-15s : up for %s, holdtime expires in %s\n",
|
|
neigh_src_str, uptime, expire);
|
|
}
|
|
|
|
if (!print_header) {
|
|
vty_out(vty, "\n");
|
|
vty_out(vty, "\n");
|
|
}
|
|
|
|
vty_out(vty, "Designated Router\n");
|
|
vty_out(vty, "-----------------\n");
|
|
vty_out(vty, "Address : %s\n", dr_str);
|
|
vty_out(vty, "Priority : %u(%d)\n",
|
|
pim_ifp->pim_dr_priority,
|
|
pim_ifp->pim_dr_num_nondrpri_neighbors);
|
|
vty_out(vty, "Uptime : %s\n", dr_uptime);
|
|
vty_out(vty, "Elections : %d\n",
|
|
pim_ifp->pim_dr_election_count);
|
|
vty_out(vty, "Changes : %d\n",
|
|
pim_ifp->pim_dr_election_changes);
|
|
vty_out(vty, "\n");
|
|
vty_out(vty, "\n");
|
|
|
|
// FHR
|
|
print_header = 1;
|
|
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
|
|
if (!up->rpf.source_nexthop.interface)
|
|
continue;
|
|
|
|
if (strcmp(ifp->name,
|
|
up->rpf.source_nexthop
|
|
.interface->name)
|
|
!= 0)
|
|
continue;
|
|
|
|
if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_FHR))
|
|
continue;
|
|
|
|
if (print_header) {
|
|
vty_out(vty,
|
|
"FHR - First Hop Router\n");
|
|
vty_out(vty,
|
|
"----------------------\n");
|
|
print_header = 0;
|
|
}
|
|
|
|
pim_inet4_dump("<src?>", up->sg.src, src_str,
|
|
sizeof(src_str));
|
|
pim_inet4_dump("<grp?>", up->sg.grp, grp_str,
|
|
sizeof(grp_str));
|
|
pim_time_uptime(uptime, sizeof(uptime),
|
|
now - up->state_transition);
|
|
vty_out(vty,
|
|
"%s : %s is a source, uptime is %s\n",
|
|
grp_str, src_str, uptime);
|
|
}
|
|
|
|
if (!print_header) {
|
|
vty_out(vty, "\n");
|
|
vty_out(vty, "\n");
|
|
}
|
|
|
|
vty_out(vty, "Hellos\n");
|
|
vty_out(vty, "------\n");
|
|
vty_out(vty, "Period : %d\n",
|
|
pim_ifp->pim_hello_period);
|
|
vty_out(vty, "HoldTime : %d\n",
|
|
PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
|
|
vty_out(vty, "Timer : %s\n", hello_timer);
|
|
vty_out(vty, "StatStart : %s\n", stat_uptime);
|
|
vty_out(vty, "Receive : %d\n",
|
|
pim_ifp->pim_ifstat_hello_recv);
|
|
vty_out(vty, "Receive Failed : %d\n",
|
|
pim_ifp->pim_ifstat_hello_recvfail);
|
|
vty_out(vty, "Send : %d\n",
|
|
pim_ifp->pim_ifstat_hello_sent);
|
|
vty_out(vty, "Send Failed : %d\n",
|
|
pim_ifp->pim_ifstat_hello_sendfail);
|
|
vty_out(vty, "Generation ID : %08x\n",
|
|
pim_ifp->pim_generation_id);
|
|
vty_out(vty, "\n");
|
|
vty_out(vty, "\n");
|
|
|
|
pim_print_ifp_flags(vty, ifp, mloop);
|
|
|
|
vty_out(vty, "Join Prune Interval\n");
|
|
vty_out(vty, "-------------------\n");
|
|
vty_out(vty, "LAN Delay : %s\n",
|
|
pim_if_lan_delay_enabled(ifp) ? "yes" : "no");
|
|
vty_out(vty, "Effective Propagation Delay : %d msec\n",
|
|
pim_if_effective_propagation_delay_msec(ifp));
|
|
vty_out(vty, "Effective Override Interval : %d msec\n",
|
|
pim_if_effective_override_interval_msec(ifp));
|
|
vty_out(vty, "Join Prune Override Interval : %d msec\n",
|
|
pim_if_jp_override_interval_msec(ifp));
|
|
vty_out(vty, "\n");
|
|
vty_out(vty, "\n");
|
|
|
|
vty_out(vty, "LAN Prune Delay\n");
|
|
vty_out(vty, "---------------\n");
|
|
vty_out(vty, "Propagation Delay : %d msec\n",
|
|
pim_ifp->pim_propagation_delay_msec);
|
|
vty_out(vty, "Propagation Delay (Highest) : %d msec\n",
|
|
pim_ifp->pim_neighbors_highest_propagation_delay_msec);
|
|
vty_out(vty, "Override Interval : %d msec\n",
|
|
pim_ifp->pim_override_interval_msec);
|
|
vty_out(vty, "Override Interval (Highest) : %d msec\n",
|
|
pim_ifp->pim_neighbors_highest_override_interval_msec);
|
|
vty_out(vty, "\n");
|
|
vty_out(vty, "\n");
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
} else {
|
|
if (!found_ifname)
|
|
vty_out(vty, "%% No such interface\n");
|
|
}
|
|
}
|
|
|
|
static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty,
|
|
const char *ifname, bool uj)
|
|
{
|
|
struct interface *ifp;
|
|
struct igmp_stats rx_stats;
|
|
|
|
igmp_stats_init(&rx_stats);
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
struct pim_interface *pim_ifp;
|
|
struct listnode *sock_node;
|
|
struct igmp_sock *igmp;
|
|
|
|
pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
if (ifname && strcmp(ifname, ifp->name))
|
|
continue;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
|
|
igmp)) {
|
|
igmp_stats_add(&rx_stats, &igmp->rx_stats);
|
|
}
|
|
}
|
|
if (uj) {
|
|
json_object *json = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
json = json_object_new_object();
|
|
json_row = json_object_new_object();
|
|
|
|
json_object_string_add(json_row, "name", ifname ? ifname :
|
|
"global");
|
|
json_object_int_add(json_row, "queryV1", rx_stats.query_v1);
|
|
json_object_int_add(json_row, "queryV2", rx_stats.query_v2);
|
|
json_object_int_add(json_row, "queryV3", rx_stats.query_v3);
|
|
json_object_int_add(json_row, "leaveV3", rx_stats.leave_v2);
|
|
json_object_int_add(json_row, "reportV1", rx_stats.report_v1);
|
|
json_object_int_add(json_row, "reportV2", rx_stats.report_v2);
|
|
json_object_int_add(json_row, "reportV3", rx_stats.report_v3);
|
|
json_object_int_add(json_row, "mtraceResponse",
|
|
rx_stats.mtrace_rsp);
|
|
json_object_int_add(json_row, "mtraceRequest",
|
|
rx_stats.mtrace_req);
|
|
json_object_int_add(json_row, "unsupported",
|
|
rx_stats.unsupported);
|
|
json_object_object_add(json, ifname ? ifname : "global",
|
|
json_row);
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
} else {
|
|
vty_out(vty, "IGMP RX statistics\n");
|
|
vty_out(vty, "Interface : %s\n",
|
|
ifname ? ifname : "global");
|
|
vty_out(vty, "V1 query : %u\n", rx_stats.query_v1);
|
|
vty_out(vty, "V2 query : %u\n", rx_stats.query_v2);
|
|
vty_out(vty, "V3 query : %u\n", rx_stats.query_v3);
|
|
vty_out(vty, "V2 leave : %u\n", rx_stats.leave_v2);
|
|
vty_out(vty, "V1 report : %u\n", rx_stats.report_v1);
|
|
vty_out(vty, "V2 report : %u\n", rx_stats.report_v2);
|
|
vty_out(vty, "V3 report : %u\n", rx_stats.report_v3);
|
|
vty_out(vty, "mtrace response : %u\n", rx_stats.mtrace_rsp);
|
|
vty_out(vty, "mtrace request : %u\n", rx_stats.mtrace_req);
|
|
vty_out(vty, "unsupported : %u\n", rx_stats.unsupported);
|
|
}
|
|
}
|
|
|
|
static void pim_show_interfaces(struct pim_instance *pim, struct vty *vty,
|
|
bool mlag, bool uj)
|
|
{
|
|
struct interface *ifp;
|
|
struct pim_interface *pim_ifp;
|
|
struct pim_upstream *up;
|
|
int fhr = 0;
|
|
int pim_nbrs = 0;
|
|
int pim_ifchannels = 0;
|
|
char buf[PREFIX_STRLEN];
|
|
json_object *json = NULL;
|
|
json_object *json_row = NULL;
|
|
json_object *json_tmp;
|
|
|
|
json = json_object_new_object();
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
if (mlag == true && pim_ifp->activeactive == false)
|
|
continue;
|
|
|
|
pim_nbrs = pim_ifp->pim_neighbor_list->count;
|
|
pim_ifchannels = pim_if_ifchannel_count(pim_ifp);
|
|
fhr = 0;
|
|
|
|
frr_each (rb_pim_upstream, &pim->upstream_head, up)
|
|
if (ifp == up->rpf.source_nexthop.interface)
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR)
|
|
fhr++;
|
|
|
|
json_row = json_object_new_object();
|
|
json_object_pim_ifp_add(json_row, ifp);
|
|
json_object_int_add(json_row, "pimNeighbors", pim_nbrs);
|
|
json_object_int_add(json_row, "pimIfChannels", pim_ifchannels);
|
|
json_object_int_add(json_row, "firstHopRouterCount", fhr);
|
|
json_object_string_add(json_row, "pimDesignatedRouter",
|
|
inet_ntop(AF_INET,
|
|
&pim_ifp->pim_dr_addr, buf,
|
|
sizeof(buf)));
|
|
|
|
if (pim_ifp->pim_dr_addr.s_addr
|
|
== pim_ifp->primary_address.s_addr)
|
|
json_object_boolean_true_add(
|
|
json_row, "pimDesignatedRouterLocal");
|
|
|
|
json_object_object_add(json, ifp->name, json_row);
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
} else {
|
|
vty_out(vty,
|
|
"Interface State Address PIM Nbrs PIM DR FHR IfChannels\n");
|
|
|
|
json_object_object_foreach(json, key, val)
|
|
{
|
|
vty_out(vty, "%-16s ", key);
|
|
|
|
json_object_object_get_ex(val, "state", &json_tmp);
|
|
vty_out(vty, "%5s ", json_object_get_string(json_tmp));
|
|
|
|
json_object_object_get_ex(val, "address", &json_tmp);
|
|
vty_out(vty, "%15s ",
|
|
json_object_get_string(json_tmp));
|
|
|
|
json_object_object_get_ex(val, "pimNeighbors",
|
|
&json_tmp);
|
|
vty_out(vty, "%8d ", json_object_get_int(json_tmp));
|
|
|
|
if (json_object_object_get_ex(
|
|
val, "pimDesignatedRouterLocal",
|
|
&json_tmp)) {
|
|
vty_out(vty, "%15s ", "local");
|
|
} else {
|
|
json_object_object_get_ex(
|
|
val, "pimDesignatedRouter", &json_tmp);
|
|
vty_out(vty, "%15s ",
|
|
json_object_get_string(json_tmp));
|
|
}
|
|
|
|
json_object_object_get_ex(val, "firstHopRouter",
|
|
&json_tmp);
|
|
vty_out(vty, "%3d ", json_object_get_int(json_tmp));
|
|
|
|
json_object_object_get_ex(val, "pimIfChannels",
|
|
&json_tmp);
|
|
vty_out(vty, "%9d\n", json_object_get_int(json_tmp));
|
|
}
|
|
}
|
|
|
|
json_object_free(json);
|
|
}
|
|
|
|
static void pim_show_interface_traffic(struct pim_instance *pim,
|
|
struct vty *vty, bool uj)
|
|
{
|
|
struct interface *ifp = NULL;
|
|
struct pim_interface *pim_ifp = NULL;
|
|
json_object *json = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
else {
|
|
vty_out(vty, "\n");
|
|
vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n",
|
|
"Interface", " HELLO", " JOIN",
|
|
" PRUNE", " REGISTER", "REGISTER-STOP",
|
|
" ASSERT", " BSM");
|
|
vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n", "",
|
|
" Rx/Tx", " Rx/Tx", " Rx/Tx",
|
|
" Rx/Tx", " Rx/Tx", " Rx/Tx",
|
|
" Rx/Tx");
|
|
vty_out(vty,
|
|
"---------------------------------------------------------------------------------------------------------------\n");
|
|
}
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
if (pim_ifp->pim_sock_fd < 0)
|
|
continue;
|
|
if (uj) {
|
|
json_row = json_object_new_object();
|
|
json_object_pim_ifp_add(json_row, ifp);
|
|
json_object_int_add(json_row, "helloRx",
|
|
pim_ifp->pim_ifstat_hello_recv);
|
|
json_object_int_add(json_row, "helloTx",
|
|
pim_ifp->pim_ifstat_hello_sent);
|
|
json_object_int_add(json_row, "joinRx",
|
|
pim_ifp->pim_ifstat_join_recv);
|
|
json_object_int_add(json_row, "joinTx",
|
|
pim_ifp->pim_ifstat_join_send);
|
|
json_object_int_add(json_row, "pruneTx",
|
|
pim_ifp->pim_ifstat_prune_send);
|
|
json_object_int_add(json_row, "pruneRx",
|
|
pim_ifp->pim_ifstat_prune_recv);
|
|
json_object_int_add(json_row, "registerRx",
|
|
pim_ifp->pim_ifstat_reg_recv);
|
|
json_object_int_add(json_row, "registerTx",
|
|
pim_ifp->pim_ifstat_reg_recv);
|
|
json_object_int_add(json_row, "registerStopRx",
|
|
pim_ifp->pim_ifstat_reg_stop_recv);
|
|
json_object_int_add(json_row, "registerStopTx",
|
|
pim_ifp->pim_ifstat_reg_stop_send);
|
|
json_object_int_add(json_row, "assertRx",
|
|
pim_ifp->pim_ifstat_assert_recv);
|
|
json_object_int_add(json_row, "assertTx",
|
|
pim_ifp->pim_ifstat_assert_send);
|
|
json_object_int_add(json_row, "bsmRx",
|
|
pim_ifp->pim_ifstat_bsm_rx);
|
|
json_object_int_add(json_row, "bsmTx",
|
|
pim_ifp->pim_ifstat_bsm_tx);
|
|
json_object_object_add(json, ifp->name, json_row);
|
|
} else {
|
|
vty_out(vty,
|
|
"%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7" PRIu64 "/%-7" PRIu64 "\n",
|
|
ifp->name, pim_ifp->pim_ifstat_hello_recv,
|
|
pim_ifp->pim_ifstat_hello_sent,
|
|
pim_ifp->pim_ifstat_join_recv,
|
|
pim_ifp->pim_ifstat_join_send,
|
|
pim_ifp->pim_ifstat_prune_recv,
|
|
pim_ifp->pim_ifstat_prune_send,
|
|
pim_ifp->pim_ifstat_reg_recv,
|
|
pim_ifp->pim_ifstat_reg_send,
|
|
pim_ifp->pim_ifstat_reg_stop_recv,
|
|
pim_ifp->pim_ifstat_reg_stop_send,
|
|
pim_ifp->pim_ifstat_assert_recv,
|
|
pim_ifp->pim_ifstat_assert_send,
|
|
pim_ifp->pim_ifstat_bsm_rx,
|
|
pim_ifp->pim_ifstat_bsm_tx);
|
|
}
|
|
}
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void pim_show_interface_traffic_single(struct pim_instance *pim,
|
|
struct vty *vty,
|
|
const char *ifname, bool uj)
|
|
{
|
|
struct interface *ifp = NULL;
|
|
struct pim_interface *pim_ifp = NULL;
|
|
json_object *json = NULL;
|
|
json_object *json_row = NULL;
|
|
uint8_t found_ifname = 0;
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
else {
|
|
vty_out(vty, "\n");
|
|
vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n",
|
|
"Interface", " HELLO", " JOIN", " PRUNE",
|
|
" REGISTER", " REGISTER-STOP", " ASSERT",
|
|
" BSM");
|
|
vty_out(vty, "%-14s%-18s%-17s%-17s%-17s%-17s%-17s%-17s\n", "",
|
|
" Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx",
|
|
" Rx/Tx", " Rx/Tx", " Rx/Tx");
|
|
vty_out(vty,
|
|
"-------------------------------------------------------------------------------------------------------------------------------\n");
|
|
}
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
if (strcmp(ifname, ifp->name))
|
|
continue;
|
|
|
|
pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
if (pim_ifp->pim_sock_fd < 0)
|
|
continue;
|
|
|
|
found_ifname = 1;
|
|
if (uj) {
|
|
json_row = json_object_new_object();
|
|
json_object_pim_ifp_add(json_row, ifp);
|
|
json_object_int_add(json_row, "helloRx",
|
|
pim_ifp->pim_ifstat_hello_recv);
|
|
json_object_int_add(json_row, "helloTx",
|
|
pim_ifp->pim_ifstat_hello_sent);
|
|
json_object_int_add(json_row, "joinRx",
|
|
pim_ifp->pim_ifstat_join_recv);
|
|
json_object_int_add(json_row, "joinTx",
|
|
pim_ifp->pim_ifstat_join_send);
|
|
json_object_int_add(json_row, "registerRx",
|
|
pim_ifp->pim_ifstat_reg_recv);
|
|
json_object_int_add(json_row, "registerTx",
|
|
pim_ifp->pim_ifstat_reg_recv);
|
|
json_object_int_add(json_row, "registerStopRx",
|
|
pim_ifp->pim_ifstat_reg_stop_recv);
|
|
json_object_int_add(json_row, "registerStopTx",
|
|
pim_ifp->pim_ifstat_reg_stop_send);
|
|
json_object_int_add(json_row, "assertRx",
|
|
pim_ifp->pim_ifstat_assert_recv);
|
|
json_object_int_add(json_row, "assertTx",
|
|
pim_ifp->pim_ifstat_assert_send);
|
|
json_object_int_add(json_row, "bsmRx",
|
|
pim_ifp->pim_ifstat_bsm_rx);
|
|
json_object_int_add(json_row, "bsmTx",
|
|
pim_ifp->pim_ifstat_bsm_tx);
|
|
|
|
json_object_object_add(json, ifp->name, json_row);
|
|
} else {
|
|
vty_out(vty,
|
|
"%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7" PRIu64 "/%-7" PRIu64 "\n",
|
|
ifp->name, pim_ifp->pim_ifstat_hello_recv,
|
|
pim_ifp->pim_ifstat_hello_sent,
|
|
pim_ifp->pim_ifstat_join_recv,
|
|
pim_ifp->pim_ifstat_join_send,
|
|
pim_ifp->pim_ifstat_prune_recv,
|
|
pim_ifp->pim_ifstat_prune_send,
|
|
pim_ifp->pim_ifstat_reg_recv,
|
|
pim_ifp->pim_ifstat_reg_send,
|
|
pim_ifp->pim_ifstat_reg_stop_recv,
|
|
pim_ifp->pim_ifstat_reg_stop_send,
|
|
pim_ifp->pim_ifstat_assert_recv,
|
|
pim_ifp->pim_ifstat_assert_send,
|
|
pim_ifp->pim_ifstat_bsm_rx,
|
|
pim_ifp->pim_ifstat_bsm_tx);
|
|
}
|
|
}
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
} else {
|
|
if (!found_ifname)
|
|
vty_out(vty, "%% No such interface\n");
|
|
}
|
|
}
|
|
|
|
static void pim_show_join_helper(struct vty *vty, struct pim_interface *pim_ifp,
|
|
struct pim_ifchannel *ch, json_object *json,
|
|
time_t now, bool uj)
|
|
{
|
|
char ch_src_str[INET_ADDRSTRLEN];
|
|
char ch_grp_str[INET_ADDRSTRLEN];
|
|
json_object *json_iface = NULL;
|
|
json_object *json_row = NULL;
|
|
json_object *json_grp = NULL;
|
|
struct in_addr ifaddr;
|
|
char uptime[10];
|
|
char expire[10];
|
|
char prune[10];
|
|
char buf[PREFIX_STRLEN];
|
|
|
|
ifaddr = pim_ifp->primary_address;
|
|
|
|
pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, sizeof(ch_src_str));
|
|
pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str));
|
|
|
|
pim_time_uptime_begin(uptime, sizeof(uptime), now, ch->ifjoin_creation);
|
|
pim_time_timer_to_mmss(expire, sizeof(expire),
|
|
ch->t_ifjoin_expiry_timer);
|
|
pim_time_timer_to_mmss(prune, sizeof(prune),
|
|
ch->t_ifjoin_prune_pending_timer);
|
|
|
|
if (uj) {
|
|
json_object_object_get_ex(json, ch->interface->name,
|
|
&json_iface);
|
|
|
|
if (!json_iface) {
|
|
json_iface = json_object_new_object();
|
|
json_object_pim_ifp_add(json_iface, ch->interface);
|
|
json_object_object_add(json, ch->interface->name,
|
|
json_iface);
|
|
}
|
|
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "source", ch_src_str);
|
|
json_object_string_add(json_row, "group", ch_grp_str);
|
|
json_object_string_add(json_row, "upTime", uptime);
|
|
json_object_string_add(json_row, "expire", expire);
|
|
json_object_string_add(json_row, "prune", prune);
|
|
json_object_string_add(
|
|
json_row, "channelJoinName",
|
|
pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags));
|
|
if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
|
|
json_object_int_add(json_row, "SGRpt", 1);
|
|
if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
|
|
json_object_int_add(json_row, "protocolPim", 1);
|
|
if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
|
|
json_object_int_add(json_row, "protocolIgmp", 1);
|
|
json_object_object_get_ex(json_iface, ch_grp_str, &json_grp);
|
|
if (!json_grp) {
|
|
json_grp = json_object_new_object();
|
|
json_object_object_add(json_grp, ch_src_str, json_row);
|
|
json_object_object_add(json_iface, ch_grp_str,
|
|
json_grp);
|
|
} else
|
|
json_object_object_add(json_grp, ch_src_str, json_row);
|
|
} else {
|
|
vty_out(vty, "%-16s %-15s %-15s %-15s %-10s %8s %-6s %5s\n",
|
|
ch->interface->name,
|
|
inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)),
|
|
ch_src_str, ch_grp_str,
|
|
pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags),
|
|
uptime, expire, prune);
|
|
}
|
|
}
|
|
|
|
static void pim_show_join(struct pim_instance *pim, struct vty *vty,
|
|
struct prefix_sg *sg, bool uj)
|
|
{
|
|
struct pim_interface *pim_ifp;
|
|
struct pim_ifchannel *ch;
|
|
struct interface *ifp;
|
|
time_t now;
|
|
json_object *json = NULL;
|
|
|
|
now = pim_time_monotonic_sec();
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
else
|
|
vty_out(vty,
|
|
"Interface Address Source Group State Uptime Expire Prune\n");
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
pim_ifp = ifp->info;
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
|
|
if (sg->grp.s_addr != INADDR_ANY
|
|
&& sg->grp.s_addr != ch->sg.grp.s_addr)
|
|
continue;
|
|
if (sg->src.s_addr != INADDR_ANY
|
|
&& sg->src.s_addr != ch->sg.src.s_addr)
|
|
continue;
|
|
pim_show_join_helper(vty, pim_ifp, ch, json, now, uj);
|
|
} /* scan interface channels */
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void pim_show_neighbors_single(struct pim_instance *pim, struct vty *vty,
|
|
const char *neighbor, bool uj)
|
|
{
|
|
struct listnode *neighnode;
|
|
struct interface *ifp;
|
|
struct pim_interface *pim_ifp;
|
|
struct pim_neighbor *neigh;
|
|
time_t now;
|
|
int found_neighbor = 0;
|
|
int option_address_list;
|
|
int option_dr_priority;
|
|
int option_generation_id;
|
|
int option_holdtime;
|
|
int option_lan_prune_delay;
|
|
int option_t_bit;
|
|
char uptime[10];
|
|
char expire[10];
|
|
char neigh_src_str[INET_ADDRSTRLEN];
|
|
|
|
json_object *json = NULL;
|
|
json_object *json_ifp = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
now = pim_time_monotonic_sec();
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
if (pim_ifp->pim_sock_fd < 0)
|
|
continue;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
|
|
neigh)) {
|
|
pim_inet4_dump("<src?>", neigh->source_addr,
|
|
neigh_src_str, sizeof(neigh_src_str));
|
|
|
|
/*
|
|
* The user can specify either the interface name or the
|
|
* PIM neighbor IP.
|
|
* If this pim_ifp matches neither then skip.
|
|
*/
|
|
if (strcmp(neighbor, "detail")
|
|
&& strcmp(neighbor, ifp->name)
|
|
&& strcmp(neighbor, neigh_src_str))
|
|
continue;
|
|
|
|
found_neighbor = 1;
|
|
pim_time_uptime(uptime, sizeof(uptime),
|
|
now - neigh->creation);
|
|
pim_time_timer_to_hhmmss(expire, sizeof(expire),
|
|
neigh->t_expire_timer);
|
|
|
|
option_address_list = 0;
|
|
option_dr_priority = 0;
|
|
option_generation_id = 0;
|
|
option_holdtime = 0;
|
|
option_lan_prune_delay = 0;
|
|
option_t_bit = 0;
|
|
|
|
if (PIM_OPTION_IS_SET(neigh->hello_options,
|
|
PIM_OPTION_MASK_ADDRESS_LIST))
|
|
option_address_list = 1;
|
|
|
|
if (PIM_OPTION_IS_SET(neigh->hello_options,
|
|
PIM_OPTION_MASK_DR_PRIORITY))
|
|
option_dr_priority = 1;
|
|
|
|
if (PIM_OPTION_IS_SET(neigh->hello_options,
|
|
PIM_OPTION_MASK_GENERATION_ID))
|
|
option_generation_id = 1;
|
|
|
|
if (PIM_OPTION_IS_SET(neigh->hello_options,
|
|
PIM_OPTION_MASK_HOLDTIME))
|
|
option_holdtime = 1;
|
|
|
|
if (PIM_OPTION_IS_SET(neigh->hello_options,
|
|
PIM_OPTION_MASK_LAN_PRUNE_DELAY))
|
|
option_lan_prune_delay = 1;
|
|
|
|
if (PIM_OPTION_IS_SET(
|
|
neigh->hello_options,
|
|
PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION))
|
|
option_t_bit = 1;
|
|
|
|
if (uj) {
|
|
|
|
/* Does this ifp live in json? If not create
|
|
* it. */
|
|
json_object_object_get_ex(json, ifp->name,
|
|
&json_ifp);
|
|
|
|
if (!json_ifp) {
|
|
json_ifp = json_object_new_object();
|
|
json_object_pim_ifp_add(json_ifp, ifp);
|
|
json_object_object_add(json, ifp->name,
|
|
json_ifp);
|
|
}
|
|
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "interface",
|
|
ifp->name);
|
|
json_object_string_add(json_row, "address",
|
|
neigh_src_str);
|
|
json_object_string_add(json_row, "upTime",
|
|
uptime);
|
|
json_object_string_add(json_row, "holdtime",
|
|
expire);
|
|
json_object_int_add(json_row, "drPriority",
|
|
neigh->dr_priority);
|
|
json_object_int_add(json_row, "generationId",
|
|
neigh->generation_id);
|
|
|
|
if (option_address_list)
|
|
json_object_boolean_true_add(
|
|
json_row,
|
|
"helloOptionAddressList");
|
|
|
|
if (option_dr_priority)
|
|
json_object_boolean_true_add(
|
|
json_row,
|
|
"helloOptionDrPriority");
|
|
|
|
if (option_generation_id)
|
|
json_object_boolean_true_add(
|
|
json_row,
|
|
"helloOptionGenerationId");
|
|
|
|
if (option_holdtime)
|
|
json_object_boolean_true_add(
|
|
json_row,
|
|
"helloOptionHoldtime");
|
|
|
|
if (option_lan_prune_delay)
|
|
json_object_boolean_true_add(
|
|
json_row,
|
|
"helloOptionLanPruneDelay");
|
|
|
|
if (option_t_bit)
|
|
json_object_boolean_true_add(
|
|
json_row, "helloOptionTBit");
|
|
|
|
json_object_object_add(json_ifp, neigh_src_str,
|
|
json_row);
|
|
|
|
} else {
|
|
vty_out(vty, "Interface : %s\n", ifp->name);
|
|
vty_out(vty, "Neighbor : %s\n", neigh_src_str);
|
|
vty_out(vty,
|
|
" Uptime : %s\n",
|
|
uptime);
|
|
vty_out(vty,
|
|
" Holdtime : %s\n",
|
|
expire);
|
|
vty_out(vty,
|
|
" DR Priority : %d\n",
|
|
neigh->dr_priority);
|
|
vty_out(vty,
|
|
" Generation ID : %08x\n",
|
|
neigh->generation_id);
|
|
vty_out(vty,
|
|
" Override Interval (msec) : %d\n",
|
|
neigh->override_interval_msec);
|
|
vty_out(vty,
|
|
" Propagation Delay (msec) : %d\n",
|
|
neigh->propagation_delay_msec);
|
|
vty_out(vty,
|
|
" Hello Option - Address List : %s\n",
|
|
option_address_list ? "yes" : "no");
|
|
vty_out(vty,
|
|
" Hello Option - DR Priority : %s\n",
|
|
option_dr_priority ? "yes" : "no");
|
|
vty_out(vty,
|
|
" Hello Option - Generation ID : %s\n",
|
|
option_generation_id ? "yes" : "no");
|
|
vty_out(vty,
|
|
" Hello Option - Holdtime : %s\n",
|
|
option_holdtime ? "yes" : "no");
|
|
vty_out(vty,
|
|
" Hello Option - LAN Prune Delay : %s\n",
|
|
option_lan_prune_delay ? "yes" : "no");
|
|
vty_out(vty,
|
|
" Hello Option - T-bit : %s\n",
|
|
option_t_bit ? "yes" : "no");
|
|
bfd_sess_show(vty, json_ifp,
|
|
neigh->bfd_session);
|
|
vty_out(vty, "\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
} else {
|
|
{
|
|
if (!found_neighbor)
|
|
vty_out(vty,
|
|
"%% No such interface or neighbor\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void pim_show_state(struct pim_instance *pim, struct vty *vty,
|
|
const char *src_or_group, const char *group, bool uj)
|
|
{
|
|
struct channel_oil *c_oil;
|
|
json_object *json = NULL;
|
|
json_object *json_group = NULL;
|
|
json_object *json_ifp_in = NULL;
|
|
json_object *json_ifp_out = NULL;
|
|
json_object *json_source = NULL;
|
|
time_t now;
|
|
int first_oif;
|
|
now = pim_time_monotonic_sec();
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
} else {
|
|
vty_out(vty,
|
|
"Codes: J -> Pim Join, I -> IGMP Report, S -> Source, * -> Inherited from (*,G), V -> VxLAN, M -> Muted");
|
|
vty_out(vty,
|
|
"\nActive Source Group RPT IIF OIL\n");
|
|
}
|
|
|
|
frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char in_ifname[INTERFACE_NAMSIZ + 1];
|
|
char out_ifname[INTERFACE_NAMSIZ + 1];
|
|
int oif_vif_index;
|
|
struct interface *ifp_in;
|
|
bool isRpt;
|
|
first_oif = 1;
|
|
|
|
if ((c_oil->up &&
|
|
PIM_UPSTREAM_FLAG_TEST_USE_RPT(c_oil->up->flags)) ||
|
|
c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
|
|
isRpt = true;
|
|
else
|
|
isRpt = false;
|
|
|
|
pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, grp_str,
|
|
sizeof(grp_str));
|
|
pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, src_str,
|
|
sizeof(src_str));
|
|
ifp_in = pim_if_find_by_vif_index(pim, c_oil->oil.mfcc_parent);
|
|
|
|
if (ifp_in)
|
|
strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
|
|
else
|
|
strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
|
|
|
|
if (src_or_group) {
|
|
if (strcmp(src_or_group, src_str)
|
|
&& strcmp(src_or_group, grp_str))
|
|
continue;
|
|
|
|
if (group && strcmp(group, grp_str))
|
|
continue;
|
|
}
|
|
|
|
if (uj) {
|
|
|
|
/* Find the group, create it if it doesn't exist */
|
|
json_object_object_get_ex(json, grp_str, &json_group);
|
|
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_object_add(json, grp_str,
|
|
json_group);
|
|
}
|
|
|
|
/* Find the source nested under the group, create it if
|
|
* it doesn't exist */
|
|
json_object_object_get_ex(json_group, src_str,
|
|
&json_source);
|
|
|
|
if (!json_source) {
|
|
json_source = json_object_new_object();
|
|
json_object_object_add(json_group, src_str,
|
|
json_source);
|
|
}
|
|
|
|
/* Find the inbound interface nested under the source,
|
|
* create it if it doesn't exist */
|
|
json_object_object_get_ex(json_source, in_ifname,
|
|
&json_ifp_in);
|
|
|
|
if (!json_ifp_in) {
|
|
json_ifp_in = json_object_new_object();
|
|
json_object_object_add(json_source, in_ifname,
|
|
json_ifp_in);
|
|
json_object_int_add(json_source, "Installed",
|
|
c_oil->installed);
|
|
if (isRpt)
|
|
json_object_boolean_true_add(
|
|
json_source, "isRpt");
|
|
else
|
|
json_object_boolean_false_add(
|
|
json_source, "isRpt");
|
|
json_object_int_add(json_source, "RefCount",
|
|
c_oil->oil_ref_count);
|
|
json_object_int_add(json_source, "OilListSize",
|
|
c_oil->oil_size);
|
|
json_object_int_add(
|
|
json_source, "OilRescan",
|
|
c_oil->oil_inherited_rescan);
|
|
json_object_int_add(json_source, "LastUsed",
|
|
c_oil->cc.lastused);
|
|
json_object_int_add(json_source, "PacketCount",
|
|
c_oil->cc.pktcnt);
|
|
json_object_int_add(json_source, "ByteCount",
|
|
c_oil->cc.bytecnt);
|
|
json_object_int_add(json_source,
|
|
"WrongInterface",
|
|
c_oil->cc.wrong_if);
|
|
}
|
|
} else {
|
|
vty_out(vty, "%-6d %-15s %-15s %-3s %-16s ",
|
|
c_oil->installed, src_str, grp_str,
|
|
isRpt ? "y" : "n", in_ifname);
|
|
}
|
|
|
|
for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
|
|
++oif_vif_index) {
|
|
struct interface *ifp_out;
|
|
char oif_uptime[10];
|
|
int ttl;
|
|
|
|
ttl = c_oil->oil.mfcc_ttls[oif_vif_index];
|
|
if (ttl < 1)
|
|
continue;
|
|
|
|
ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
|
|
pim_time_uptime(
|
|
oif_uptime, sizeof(oif_uptime),
|
|
now - c_oil->oif_creation[oif_vif_index]);
|
|
|
|
if (ifp_out)
|
|
strlcpy(out_ifname, ifp_out->name, sizeof(out_ifname));
|
|
else
|
|
strlcpy(out_ifname, "<oif?>", sizeof(out_ifname));
|
|
|
|
if (uj) {
|
|
json_ifp_out = json_object_new_object();
|
|
json_object_string_add(json_ifp_out, "source",
|
|
src_str);
|
|
json_object_string_add(json_ifp_out, "group",
|
|
grp_str);
|
|
json_object_string_add(json_ifp_out,
|
|
"inboundInterface",
|
|
in_ifname);
|
|
json_object_string_add(json_ifp_out,
|
|
"outboundInterface",
|
|
out_ifname);
|
|
json_object_int_add(json_ifp_out, "installed",
|
|
c_oil->installed);
|
|
|
|
json_object_object_add(json_ifp_in, out_ifname,
|
|
json_ifp_out);
|
|
} else {
|
|
if (first_oif) {
|
|
first_oif = 0;
|
|
vty_out(vty, "%s(%c%c%c%c%c)",
|
|
out_ifname,
|
|
(c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_IGMP)
|
|
? 'I'
|
|
: ' ',
|
|
(c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_PIM)
|
|
? 'J'
|
|
: ' ',
|
|
(c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_VXLAN)
|
|
? 'V'
|
|
: ' ',
|
|
(c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_STAR)
|
|
? '*'
|
|
: ' ',
|
|
(c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_MUTE)
|
|
? 'M'
|
|
: ' ');
|
|
} else
|
|
vty_out(vty, ", %s(%c%c%c%c%c)",
|
|
out_ifname,
|
|
(c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_IGMP)
|
|
? 'I'
|
|
: ' ',
|
|
(c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_PIM)
|
|
? 'J'
|
|
: ' ',
|
|
(c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_VXLAN)
|
|
? 'V'
|
|
: ' ',
|
|
(c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_STAR)
|
|
? '*'
|
|
: ' ',
|
|
(c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_MUTE)
|
|
? 'M'
|
|
: ' ');
|
|
}
|
|
}
|
|
|
|
if (!uj)
|
|
vty_out(vty, "\n");
|
|
}
|
|
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
} else {
|
|
vty_out(vty, "\n");
|
|
}
|
|
}
|
|
|
|
static void pim_show_neighbors(struct pim_instance *pim, struct vty *vty,
|
|
bool uj)
|
|
{
|
|
struct listnode *neighnode;
|
|
struct interface *ifp;
|
|
struct pim_interface *pim_ifp;
|
|
struct pim_neighbor *neigh;
|
|
time_t now;
|
|
char uptime[10];
|
|
char expire[10];
|
|
char neigh_src_str[INET_ADDRSTRLEN];
|
|
json_object *json = NULL;
|
|
json_object *json_ifp_rows = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
now = pim_time_monotonic_sec();
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
} else {
|
|
vty_out(vty,
|
|
"Interface Neighbor Uptime Holdtime DR Pri\n");
|
|
}
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
if (pim_ifp->pim_sock_fd < 0)
|
|
continue;
|
|
|
|
if (uj)
|
|
json_ifp_rows = json_object_new_object();
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
|
|
neigh)) {
|
|
pim_inet4_dump("<src?>", neigh->source_addr,
|
|
neigh_src_str, sizeof(neigh_src_str));
|
|
pim_time_uptime(uptime, sizeof(uptime),
|
|
now - neigh->creation);
|
|
pim_time_timer_to_hhmmss(expire, sizeof(expire),
|
|
neigh->t_expire_timer);
|
|
|
|
if (uj) {
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "interface",
|
|
ifp->name);
|
|
json_object_string_add(json_row, "neighbor",
|
|
neigh_src_str);
|
|
json_object_string_add(json_row, "upTime",
|
|
uptime);
|
|
json_object_string_add(json_row, "holdTime",
|
|
expire);
|
|
json_object_int_add(json_row, "holdTimeMax",
|
|
neigh->holdtime);
|
|
json_object_int_add(json_row, "drPriority",
|
|
neigh->dr_priority);
|
|
json_object_object_add(json_ifp_rows,
|
|
neigh_src_str, json_row);
|
|
|
|
} else {
|
|
vty_out(vty, "%-16s %15s %8s %8s %6d\n",
|
|
ifp->name, neigh_src_str, uptime,
|
|
expire, neigh->dr_priority);
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
json_object_object_add(json, ifp->name, json_ifp_rows);
|
|
json_ifp_rows = NULL;
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void pim_show_neighbors_secondary(struct pim_instance *pim,
|
|
struct vty *vty)
|
|
{
|
|
struct interface *ifp;
|
|
|
|
vty_out(vty,
|
|
"Interface Address Neighbor Secondary \n");
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
struct pim_interface *pim_ifp;
|
|
struct in_addr ifaddr;
|
|
struct listnode *neighnode;
|
|
struct pim_neighbor *neigh;
|
|
char buf[PREFIX_STRLEN];
|
|
|
|
pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
if (pim_ifp->pim_sock_fd < 0)
|
|
continue;
|
|
|
|
ifaddr = pim_ifp->primary_address;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
|
|
neigh)) {
|
|
char neigh_src_str[INET_ADDRSTRLEN];
|
|
struct listnode *prefix_node;
|
|
struct prefix *p;
|
|
|
|
if (!neigh->prefix_list)
|
|
continue;
|
|
|
|
pim_inet4_dump("<src?>", neigh->source_addr,
|
|
neigh_src_str, sizeof(neigh_src_str));
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list,
|
|
prefix_node, p))
|
|
vty_out(vty, "%-16s %-15s %-15s %-15pFX\n",
|
|
ifp->name,
|
|
inet_ntop(AF_INET, &ifaddr,
|
|
buf, sizeof(buf)),
|
|
neigh_src_str, p);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void json_object_pim_upstream_add(json_object *json,
|
|
struct pim_upstream *up)
|
|
{
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
|
|
json_object_boolean_true_add(json, "drJoinDesired");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
|
|
json_object_boolean_true_add(json, "drJoinDesiredUpdated");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR)
|
|
json_object_boolean_true_add(json, "firstHopRouter");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
|
|
json_object_boolean_true_add(json, "sourceIgmp");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
|
|
json_object_boolean_true_add(json, "sourcePim");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
|
|
json_object_boolean_true_add(json, "sourceStream");
|
|
|
|
/* XXX: need to print ths flag in the plain text display as well */
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
|
|
json_object_boolean_true_add(json, "sourceMsdp");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
|
|
json_object_boolean_true_add(json, "sendSGRptPrune");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
|
|
json_object_boolean_true_add(json, "lastHopRouter");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY)
|
|
json_object_boolean_true_add(json, "disableKATExpiry");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_STATIC_IIF)
|
|
json_object_boolean_true_add(json, "staticIncomingInterface");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL)
|
|
json_object_boolean_true_add(json,
|
|
"allowIncomingInterfaceinOil");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA)
|
|
json_object_boolean_true_add(json, "noPimRegistrationData");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG)
|
|
json_object_boolean_true_add(json, "forcePimRegistration");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG)
|
|
json_object_boolean_true_add(json, "sourceVxlanOrigination");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM)
|
|
json_object_boolean_true_add(json, "sourceVxlanTermination");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN)
|
|
json_object_boolean_true_add(json, "mlagVxlan");
|
|
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF)
|
|
json_object_boolean_true_add(json,
|
|
"mlagNonDesignatedForwarder");
|
|
}
|
|
|
|
static const char *
|
|
pim_upstream_state2brief_str(enum pim_upstream_state join_state,
|
|
char *state_str, size_t state_str_len)
|
|
{
|
|
switch (join_state) {
|
|
case PIM_UPSTREAM_NOTJOINED:
|
|
strlcpy(state_str, "NotJ", state_str_len);
|
|
break;
|
|
case PIM_UPSTREAM_JOINED:
|
|
strlcpy(state_str, "J", state_str_len);
|
|
break;
|
|
default:
|
|
strlcpy(state_str, "Unk", state_str_len);
|
|
}
|
|
return state_str;
|
|
}
|
|
|
|
static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state,
|
|
char *state_str, size_t state_str_len)
|
|
{
|
|
switch (reg_state) {
|
|
case PIM_REG_NOINFO:
|
|
strlcpy(state_str, "RegNI", state_str_len);
|
|
break;
|
|
case PIM_REG_JOIN:
|
|
strlcpy(state_str, "RegJ", state_str_len);
|
|
break;
|
|
case PIM_REG_JOIN_PENDING:
|
|
case PIM_REG_PRUNE:
|
|
strlcpy(state_str, "RegP", state_str_len);
|
|
break;
|
|
default:
|
|
strlcpy(state_str, "Unk", state_str_len);
|
|
}
|
|
return state_str;
|
|
}
|
|
|
|
static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
|
|
struct prefix_sg *sg, bool uj)
|
|
{
|
|
struct pim_upstream *up;
|
|
time_t now;
|
|
json_object *json = NULL;
|
|
json_object *json_group = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
now = pim_time_monotonic_sec();
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
else
|
|
vty_out(vty,
|
|
"Iif Source Group State Uptime JoinTimer RSTimer KATimer RefCnt\n");
|
|
|
|
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
char uptime[10];
|
|
char join_timer[10];
|
|
char rs_timer[10];
|
|
char ka_timer[10];
|
|
char msdp_reg_timer[10];
|
|
char state_str[PIM_REG_STATE_STR_LEN];
|
|
|
|
if (sg->grp.s_addr != INADDR_ANY
|
|
&& sg->grp.s_addr != up->sg.grp.s_addr)
|
|
continue;
|
|
if (sg->src.s_addr != INADDR_ANY
|
|
&& sg->src.s_addr != up->sg.src.s_addr)
|
|
continue;
|
|
|
|
pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
|
|
pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
|
|
pim_time_uptime(uptime, sizeof(uptime),
|
|
now - up->state_transition);
|
|
pim_time_timer_to_hhmmss(join_timer, sizeof(join_timer),
|
|
up->t_join_timer);
|
|
|
|
/*
|
|
* If the upstream is not dummy and it has a J/P timer for the
|
|
* neighbor display that
|
|
*/
|
|
if (!up->t_join_timer && up->rpf.source_nexthop.interface) {
|
|
struct pim_neighbor *nbr;
|
|
|
|
nbr = pim_neighbor_find(
|
|
up->rpf.source_nexthop.interface,
|
|
up->rpf.rpf_addr.u.prefix4);
|
|
if (nbr)
|
|
pim_time_timer_to_hhmmss(join_timer,
|
|
sizeof(join_timer),
|
|
nbr->jp_timer);
|
|
}
|
|
|
|
pim_time_timer_to_hhmmss(rs_timer, sizeof(rs_timer),
|
|
up->t_rs_timer);
|
|
pim_time_timer_to_hhmmss(ka_timer, sizeof(ka_timer),
|
|
up->t_ka_timer);
|
|
pim_time_timer_to_hhmmss(msdp_reg_timer, sizeof(msdp_reg_timer),
|
|
up->t_msdp_reg_timer);
|
|
|
|
pim_upstream_state2brief_str(up->join_state, state_str, sizeof(state_str));
|
|
if (up->reg_state != PIM_REG_NOINFO) {
|
|
char tmp_str[PIM_REG_STATE_STR_LEN];
|
|
char tmp[sizeof(state_str) + 1];
|
|
|
|
snprintf(tmp, sizeof(tmp), ",%s",
|
|
pim_reg_state2brief_str(up->reg_state, tmp_str,
|
|
sizeof(tmp_str)));
|
|
strlcat(state_str, tmp, sizeof(state_str));
|
|
}
|
|
|
|
if (uj) {
|
|
json_object_object_get_ex(json, grp_str, &json_group);
|
|
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_object_add(json, grp_str,
|
|
json_group);
|
|
}
|
|
|
|
json_row = json_object_new_object();
|
|
json_object_pim_upstream_add(json_row, up);
|
|
json_object_string_add(
|
|
json_row, "inboundInterface",
|
|
up->rpf.source_nexthop.interface
|
|
? up->rpf.source_nexthop.interface->name
|
|
: "Unknown");
|
|
|
|
/*
|
|
* The RPF address we use is slightly different
|
|
* based upon what we are looking up.
|
|
* If we have a S, list that unless
|
|
* we are the FHR, else we just put
|
|
* the RP as the rpfAddress
|
|
*/
|
|
if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR
|
|
|| up->sg.src.s_addr == INADDR_ANY) {
|
|
char rpf[PREFIX_STRLEN];
|
|
struct pim_rpf *rpg;
|
|
|
|
rpg = RP(pim, up->sg.grp);
|
|
pim_inet4_dump("<rpf?>",
|
|
rpg->rpf_addr.u.prefix4, rpf,
|
|
sizeof(rpf));
|
|
json_object_string_add(json_row, "rpfAddress",
|
|
rpf);
|
|
} else {
|
|
json_object_string_add(json_row, "rpfAddress",
|
|
src_str);
|
|
}
|
|
|
|
json_object_string_add(json_row, "source", src_str);
|
|
json_object_string_add(json_row, "group", grp_str);
|
|
json_object_string_add(json_row, "state", state_str);
|
|
json_object_string_add(
|
|
json_row, "joinState",
|
|
pim_upstream_state2str(up->join_state));
|
|
json_object_string_add(
|
|
json_row, "regState",
|
|
pim_reg_state2str(up->reg_state, state_str, sizeof(state_str)));
|
|
json_object_string_add(json_row, "upTime", uptime);
|
|
json_object_string_add(json_row, "joinTimer",
|
|
join_timer);
|
|
json_object_string_add(json_row, "resetTimer",
|
|
rs_timer);
|
|
json_object_string_add(json_row, "keepaliveTimer",
|
|
ka_timer);
|
|
json_object_string_add(json_row, "msdpRegTimer",
|
|
msdp_reg_timer);
|
|
json_object_int_add(json_row, "refCount",
|
|
up->ref_count);
|
|
json_object_int_add(json_row, "sptBit", up->sptbit);
|
|
json_object_object_add(json_group, src_str, json_row);
|
|
} else {
|
|
vty_out(vty,
|
|
"%-16s%-15s %-15s %-11s %-8s %-9s %-9s %-9s %6d\n",
|
|
up->rpf.source_nexthop.interface
|
|
? up->rpf.source_nexthop.interface->name
|
|
: "Unknown",
|
|
src_str, grp_str, state_str, uptime, join_timer,
|
|
rs_timer, ka_timer, up->ref_count);
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void pim_show_channel_helper(struct pim_instance *pim,
|
|
struct vty *vty,
|
|
struct pim_interface *pim_ifp,
|
|
struct pim_ifchannel *ch,
|
|
json_object *json, bool uj)
|
|
{
|
|
struct pim_upstream *up = ch->upstream;
|
|
json_object *json_group = NULL;
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
json_object *json_row = NULL;
|
|
|
|
pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
|
|
pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
|
|
|
|
if (uj) {
|
|
json_object_object_get_ex(json, grp_str, &json_group);
|
|
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_object_add(json, grp_str, json_group);
|
|
}
|
|
|
|
json_row = json_object_new_object();
|
|
json_object_pim_upstream_add(json_row, up);
|
|
json_object_string_add(json_row, "interface",
|
|
ch->interface->name);
|
|
json_object_string_add(json_row, "source", src_str);
|
|
json_object_string_add(json_row, "group", grp_str);
|
|
|
|
if (pim_macro_ch_lost_assert(ch))
|
|
json_object_boolean_true_add(json_row, "lostAssert");
|
|
|
|
if (pim_macro_chisin_joins(ch))
|
|
json_object_boolean_true_add(json_row, "joins");
|
|
|
|
if (pim_macro_chisin_pim_include(ch))
|
|
json_object_boolean_true_add(json_row, "pimInclude");
|
|
|
|
if (pim_upstream_evaluate_join_desired(pim, up))
|
|
json_object_boolean_true_add(json_row,
|
|
"evaluateJoinDesired");
|
|
|
|
json_object_object_add(json_group, src_str, json_row);
|
|
|
|
} else {
|
|
vty_out(vty, "%-16s %-15s %-15s %-10s %-5s %-10s %-11s %-6s\n",
|
|
ch->interface->name, src_str, grp_str,
|
|
pim_macro_ch_lost_assert(ch) ? "yes" : "no",
|
|
pim_macro_chisin_joins(ch) ? "yes" : "no",
|
|
pim_macro_chisin_pim_include(ch) ? "yes" : "no",
|
|
PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags)
|
|
? "yes"
|
|
: "no",
|
|
pim_upstream_evaluate_join_desired(pim, up) ? "yes"
|
|
: "no");
|
|
}
|
|
}
|
|
|
|
static void pim_show_channel(struct pim_instance *pim, struct vty *vty,
|
|
bool uj)
|
|
{
|
|
struct pim_interface *pim_ifp;
|
|
struct pim_ifchannel *ch;
|
|
struct interface *ifp;
|
|
|
|
json_object *json = NULL;
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
else
|
|
vty_out(vty,
|
|
"Interface Source Group LostAssert Joins PimInclude JoinDesired EvalJD\n");
|
|
|
|
/* scan per-interface (S,G) state */
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
pim_ifp = ifp->info;
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
|
|
RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
|
|
/* scan all interfaces */
|
|
pim_show_channel_helper(pim, vty, pim_ifp, ch,
|
|
json, uj);
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void pim_show_join_desired_helper(struct pim_instance *pim,
|
|
struct vty *vty,
|
|
struct pim_upstream *up,
|
|
json_object *json, bool uj)
|
|
{
|
|
json_object *json_group = NULL;
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
json_object *json_row = NULL;
|
|
|
|
pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
|
|
pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
|
|
|
|
if (uj) {
|
|
json_object_object_get_ex(json, grp_str, &json_group);
|
|
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_object_add(json, grp_str, json_group);
|
|
}
|
|
|
|
json_row = json_object_new_object();
|
|
json_object_pim_upstream_add(json_row, up);
|
|
json_object_string_add(json_row, "source", src_str);
|
|
json_object_string_add(json_row, "group", grp_str);
|
|
|
|
if (pim_upstream_evaluate_join_desired(pim, up))
|
|
json_object_boolean_true_add(json_row,
|
|
"evaluateJoinDesired");
|
|
|
|
json_object_object_add(json_group, src_str, json_row);
|
|
|
|
} else {
|
|
vty_out(vty, "%-15s %-15s %-6s\n",
|
|
src_str, grp_str,
|
|
pim_upstream_evaluate_join_desired(pim, up) ? "yes"
|
|
: "no");
|
|
}
|
|
}
|
|
|
|
static void pim_show_join_desired(struct pim_instance *pim, struct vty *vty,
|
|
bool uj)
|
|
{
|
|
struct pim_upstream *up;
|
|
|
|
json_object *json = NULL;
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
else
|
|
vty_out(vty,
|
|
"Source Group EvalJD\n");
|
|
|
|
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
|
|
/* scan all interfaces */
|
|
pim_show_join_desired_helper(pim, vty, up,
|
|
json, uj);
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty,
|
|
bool uj)
|
|
{
|
|
struct pim_upstream *up;
|
|
json_object *json = NULL;
|
|
json_object *json_group = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
else
|
|
vty_out(vty,
|
|
"Source Group RpfIface RibNextHop RpfAddress \n");
|
|
|
|
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
char rpf_nexthop_str[PREFIX_STRLEN];
|
|
char rpf_addr_str[PREFIX_STRLEN];
|
|
struct pim_rpf *rpf;
|
|
const char *rpf_ifname;
|
|
|
|
rpf = &up->rpf;
|
|
|
|
pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
|
|
pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
|
|
pim_addr_dump("<nexthop?>",
|
|
&rpf->source_nexthop.mrib_nexthop_addr,
|
|
rpf_nexthop_str, sizeof(rpf_nexthop_str));
|
|
pim_addr_dump("<rpf?>", &rpf->rpf_addr, rpf_addr_str,
|
|
sizeof(rpf_addr_str));
|
|
|
|
rpf_ifname = rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<ifname?>";
|
|
|
|
if (uj) {
|
|
json_object_object_get_ex(json, grp_str, &json_group);
|
|
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_object_add(json, grp_str,
|
|
json_group);
|
|
}
|
|
|
|
json_row = json_object_new_object();
|
|
json_object_pim_upstream_add(json_row, up);
|
|
json_object_string_add(json_row, "source", src_str);
|
|
json_object_string_add(json_row, "group", grp_str);
|
|
json_object_string_add(json_row, "rpfInterface",
|
|
rpf_ifname);
|
|
json_object_string_add(json_row, "ribNexthop",
|
|
rpf_nexthop_str);
|
|
json_object_string_add(json_row, "rpfAddress",
|
|
rpf_addr_str);
|
|
json_object_object_add(json_group, src_str, json_row);
|
|
} else {
|
|
vty_out(vty, "%-15s %-15s %-16s %-15s %-15s\n", src_str,
|
|
grp_str, rpf_ifname, rpf_nexthop_str,
|
|
rpf_addr_str);
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void show_rpf_refresh_stats(struct vty *vty, struct pim_instance *pim,
|
|
time_t now, json_object *json)
|
|
{
|
|
char refresh_uptime[10];
|
|
|
|
pim_time_uptime_begin(refresh_uptime, sizeof(refresh_uptime), now,
|
|
pim->rpf_cache_refresh_last);
|
|
|
|
if (json) {
|
|
json_object_int_add(json, "rpfCacheRefreshDelayMsecs",
|
|
router->rpf_cache_refresh_delay_msec);
|
|
json_object_int_add(
|
|
json, "rpfCacheRefreshTimer",
|
|
pim_time_timer_remain_msec(pim->rpf_cache_refresher));
|
|
json_object_int_add(json, "rpfCacheRefreshRequests",
|
|
pim->rpf_cache_refresh_requests);
|
|
json_object_int_add(json, "rpfCacheRefreshEvents",
|
|
pim->rpf_cache_refresh_events);
|
|
json_object_string_add(json, "rpfCacheRefreshLast",
|
|
refresh_uptime);
|
|
json_object_int_add(json, "nexthopLookups",
|
|
pim->nexthop_lookups);
|
|
json_object_int_add(json, "nexthopLookupsAvoided",
|
|
pim->nexthop_lookups_avoided);
|
|
} else {
|
|
vty_out(vty,
|
|
"RPF Cache Refresh Delay: %ld msecs\n"
|
|
"RPF Cache Refresh Timer: %ld msecs\n"
|
|
"RPF Cache Refresh Requests: %lld\n"
|
|
"RPF Cache Refresh Events: %lld\n"
|
|
"RPF Cache Refresh Last: %s\n"
|
|
"Nexthop Lookups: %lld\n"
|
|
"Nexthop Lookups Avoided: %lld\n",
|
|
router->rpf_cache_refresh_delay_msec,
|
|
pim_time_timer_remain_msec(pim->rpf_cache_refresher),
|
|
(long long)pim->rpf_cache_refresh_requests,
|
|
(long long)pim->rpf_cache_refresh_events,
|
|
refresh_uptime, (long long)pim->nexthop_lookups,
|
|
(long long)pim->nexthop_lookups_avoided);
|
|
}
|
|
}
|
|
|
|
static void show_scan_oil_stats(struct pim_instance *pim, struct vty *vty,
|
|
time_t now)
|
|
{
|
|
char uptime_scan_oil[10];
|
|
char uptime_mroute_add[10];
|
|
char uptime_mroute_del[10];
|
|
|
|
pim_time_uptime_begin(uptime_scan_oil, sizeof(uptime_scan_oil), now,
|
|
pim->scan_oil_last);
|
|
pim_time_uptime_begin(uptime_mroute_add, sizeof(uptime_mroute_add), now,
|
|
pim->mroute_add_last);
|
|
pim_time_uptime_begin(uptime_mroute_del, sizeof(uptime_mroute_del), now,
|
|
pim->mroute_del_last);
|
|
|
|
vty_out(vty,
|
|
"Scan OIL - Last: %s Events: %lld\n"
|
|
"MFC Add - Last: %s Events: %lld\n"
|
|
"MFC Del - Last: %s Events: %lld\n",
|
|
uptime_scan_oil, (long long)pim->scan_oil_events,
|
|
uptime_mroute_add, (long long)pim->mroute_add_events,
|
|
uptime_mroute_del, (long long)pim->mroute_del_events);
|
|
}
|
|
|
|
static void pim_show_rpf(struct pim_instance *pim, struct vty *vty, bool uj)
|
|
{
|
|
struct pim_upstream *up;
|
|
time_t now = pim_time_monotonic_sec();
|
|
json_object *json = NULL;
|
|
json_object *json_group = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
show_rpf_refresh_stats(vty, pim, now, json);
|
|
} else {
|
|
show_rpf_refresh_stats(vty, pim, now, json);
|
|
vty_out(vty, "\n");
|
|
vty_out(vty,
|
|
"Source Group RpfIface RpfAddress RibNextHop Metric Pref\n");
|
|
}
|
|
|
|
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
char rpf_addr_str[PREFIX_STRLEN];
|
|
char rib_nexthop_str[PREFIX_STRLEN];
|
|
const char *rpf_ifname;
|
|
struct pim_rpf *rpf = &up->rpf;
|
|
|
|
pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
|
|
pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
|
|
pim_addr_dump("<rpf?>", &rpf->rpf_addr, rpf_addr_str,
|
|
sizeof(rpf_addr_str));
|
|
pim_addr_dump("<nexthop?>",
|
|
&rpf->source_nexthop.mrib_nexthop_addr,
|
|
rib_nexthop_str, sizeof(rib_nexthop_str));
|
|
|
|
rpf_ifname = rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "<ifname?>";
|
|
|
|
if (uj) {
|
|
json_object_object_get_ex(json, grp_str, &json_group);
|
|
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_object_add(json, grp_str,
|
|
json_group);
|
|
}
|
|
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "source", src_str);
|
|
json_object_string_add(json_row, "group", grp_str);
|
|
json_object_string_add(json_row, "rpfInterface",
|
|
rpf_ifname);
|
|
json_object_string_add(json_row, "rpfAddress",
|
|
rpf_addr_str);
|
|
json_object_string_add(json_row, "ribNexthop",
|
|
rib_nexthop_str);
|
|
json_object_int_add(
|
|
json_row, "routeMetric",
|
|
rpf->source_nexthop.mrib_route_metric);
|
|
json_object_int_add(
|
|
json_row, "routePreference",
|
|
rpf->source_nexthop.mrib_metric_preference);
|
|
json_object_object_add(json_group, src_str, json_row);
|
|
|
|
} else {
|
|
vty_out(vty, "%-15s %-15s %-16s %-15s %-15s %6d %4d\n",
|
|
src_str, grp_str, rpf_ifname, rpf_addr_str,
|
|
rib_nexthop_str,
|
|
rpf->source_nexthop.mrib_route_metric,
|
|
rpf->source_nexthop.mrib_metric_preference);
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
struct pnc_cache_walk_data {
|
|
struct vty *vty;
|
|
struct pim_instance *pim;
|
|
};
|
|
|
|
static int pim_print_pnc_cache_walkcb(struct hash_bucket *bucket, void *arg)
|
|
{
|
|
struct pim_nexthop_cache *pnc = bucket->data;
|
|
struct pnc_cache_walk_data *cwd = arg;
|
|
struct vty *vty = cwd->vty;
|
|
struct pim_instance *pim = cwd->pim;
|
|
struct nexthop *nh_node = NULL;
|
|
ifindex_t first_ifindex;
|
|
struct interface *ifp = NULL;
|
|
char buf[PREFIX_STRLEN];
|
|
|
|
for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
|
|
first_ifindex = nh_node->ifindex;
|
|
ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
|
|
|
|
vty_out(vty, "%-15s ", inet_ntop(AF_INET,
|
|
&pnc->rpf.rpf_addr.u.prefix4,
|
|
buf, sizeof(buf)));
|
|
vty_out(vty, "%-16s ", ifp ? ifp->name : "NULL");
|
|
vty_out(vty, "%pI4 ", &nh_node->gate.ipv4);
|
|
vty_out(vty, "\n");
|
|
}
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
static void pim_show_nexthop(struct pim_instance *pim, struct vty *vty)
|
|
{
|
|
struct pnc_cache_walk_data cwd;
|
|
|
|
cwd.vty = vty;
|
|
cwd.pim = pim;
|
|
vty_out(vty, "Number of registered addresses: %lu\n",
|
|
pim->rpf_hash->count);
|
|
vty_out(vty, "Address Interface Nexthop\n");
|
|
vty_out(vty, "---------------------------------------------\n");
|
|
|
|
hash_walk(pim->rpf_hash, pim_print_pnc_cache_walkcb, &cwd);
|
|
}
|
|
|
|
/* Display the bsm database details */
|
|
static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
|
|
{
|
|
int count = 0;
|
|
int fragment = 1;
|
|
struct bsm_frag *bsfrag;
|
|
json_object *json = NULL;
|
|
json_object *json_group = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
count = bsm_frags_count(pim->global_scope.bsm_frags);
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
json_object_int_add(json, "Number of the fragments", count);
|
|
} else {
|
|
vty_out(vty, "Scope Zone: Global\n");
|
|
vty_out(vty, "Number of the fragments: %d\n", count);
|
|
vty_out(vty, "\n");
|
|
}
|
|
|
|
frr_each (bsm_frags, pim->global_scope.bsm_frags, bsfrag) {
|
|
char grp_str[PREFIX_STRLEN];
|
|
char rp_str[INET_ADDRSTRLEN];
|
|
char bsr_str[INET_ADDRSTRLEN];
|
|
struct bsmmsg_grpinfo *group;
|
|
struct bsmmsg_rpinfo *rpaddr;
|
|
struct prefix grp;
|
|
struct bsm_hdr *hdr;
|
|
uint32_t offset = 0;
|
|
uint8_t *buf;
|
|
uint32_t len = 0;
|
|
uint32_t frag_rp_cnt = 0;
|
|
|
|
buf = bsfrag->data;
|
|
len = bsfrag->size;
|
|
|
|
/* skip pim header */
|
|
buf += PIM_MSG_HEADER_LEN;
|
|
len -= PIM_MSG_HEADER_LEN;
|
|
|
|
hdr = (struct bsm_hdr *)buf;
|
|
|
|
/* BSM starts with bsr header */
|
|
buf += sizeof(struct bsm_hdr);
|
|
len -= sizeof(struct bsm_hdr);
|
|
|
|
pim_inet4_dump("<BSR Address?>", hdr->bsr_addr.addr, bsr_str,
|
|
sizeof(bsr_str));
|
|
|
|
|
|
if (uj) {
|
|
json_object_string_add(json, "BSR address", bsr_str);
|
|
json_object_int_add(json, "BSR priority",
|
|
hdr->bsr_prio);
|
|
json_object_int_add(json, "Hashmask Length",
|
|
hdr->hm_len);
|
|
json_object_int_add(json, "Fragment Tag",
|
|
ntohs(hdr->frag_tag));
|
|
} else {
|
|
vty_out(vty, "BSM Fragment : %d\n", fragment);
|
|
vty_out(vty, "------------------\n");
|
|
vty_out(vty, "%-15s %-15s %-15s %-15s\n", "BSR-Address",
|
|
"BSR-Priority", "Hashmask-len", "Fragment-Tag");
|
|
vty_out(vty, "%-15s %-15d %-15d %-15d\n", bsr_str,
|
|
hdr->bsr_prio, hdr->hm_len,
|
|
ntohs(hdr->frag_tag));
|
|
}
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
while (offset < len) {
|
|
group = (struct bsmmsg_grpinfo *)buf;
|
|
|
|
if (group->group.family == PIM_MSG_ADDRESS_FAMILY_IPV4)
|
|
grp.family = AF_INET;
|
|
|
|
grp.prefixlen = group->group.mask;
|
|
grp.u.prefix4.s_addr = group->group.addr.s_addr;
|
|
|
|
prefix2str(&grp, grp_str, sizeof(grp_str));
|
|
|
|
buf += sizeof(struct bsmmsg_grpinfo);
|
|
offset += sizeof(struct bsmmsg_grpinfo);
|
|
|
|
if (uj) {
|
|
json_object_object_get_ex(json, grp_str,
|
|
&json_group);
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_int_add(json_group,
|
|
"Rp Count",
|
|
group->rp_count);
|
|
json_object_int_add(
|
|
json_group, "Fragment Rp count",
|
|
group->frag_rp_count);
|
|
json_object_object_add(json, grp_str,
|
|
json_group);
|
|
}
|
|
} else {
|
|
vty_out(vty, "Group : %s\n", grp_str);
|
|
vty_out(vty, "-------------------\n");
|
|
vty_out(vty, "Rp Count:%d\n", group->rp_count);
|
|
vty_out(vty, "Fragment Rp Count : %d\n",
|
|
group->frag_rp_count);
|
|
}
|
|
|
|
frag_rp_cnt = group->frag_rp_count;
|
|
|
|
if (!frag_rp_cnt)
|
|
continue;
|
|
|
|
if (!uj)
|
|
vty_out(vty,
|
|
"RpAddress HoldTime Priority\n");
|
|
|
|
while (frag_rp_cnt--) {
|
|
rpaddr = (struct bsmmsg_rpinfo *)buf;
|
|
|
|
buf += sizeof(struct bsmmsg_rpinfo);
|
|
offset += sizeof(struct bsmmsg_rpinfo);
|
|
|
|
pim_inet4_dump("<Rp addr?>",
|
|
rpaddr->rpaddr.addr, rp_str,
|
|
sizeof(rp_str));
|
|
|
|
if (uj) {
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(
|
|
json_row, "Rp Address", rp_str);
|
|
json_object_int_add(
|
|
json_row, "Rp HoldTime",
|
|
ntohs(rpaddr->rp_holdtime));
|
|
json_object_int_add(json_row,
|
|
"Rp Priority",
|
|
rpaddr->rp_pri);
|
|
json_object_object_add(
|
|
json_group, rp_str, json_row);
|
|
} else {
|
|
vty_out(vty, "%-15s %-12d %d\n", rp_str,
|
|
ntohs(rpaddr->rp_holdtime),
|
|
rpaddr->rp_pri);
|
|
}
|
|
}
|
|
vty_out(vty, "\n");
|
|
}
|
|
|
|
fragment++;
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
/*Display the group-rp mappings */
|
|
static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
|
|
struct vty *vty, bool uj)
|
|
{
|
|
struct bsgrp_node *bsgrp;
|
|
struct bsm_rpinfo *bsm_rp;
|
|
struct route_node *rn;
|
|
char bsr_str[INET_ADDRSTRLEN];
|
|
json_object *json = NULL;
|
|
json_object *json_group = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
if (pim->global_scope.current_bsr.s_addr == INADDR_ANY)
|
|
strlcpy(bsr_str, "0.0.0.0", sizeof(bsr_str));
|
|
|
|
else
|
|
pim_inet4_dump("<bsr?>", pim->global_scope.current_bsr, bsr_str,
|
|
sizeof(bsr_str));
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
json_object_string_add(json, "BSR Address", bsr_str);
|
|
} else {
|
|
vty_out(vty, "BSR Address %s\n", bsr_str);
|
|
}
|
|
|
|
for (rn = route_top(pim->global_scope.bsrp_table); rn;
|
|
rn = route_next(rn)) {
|
|
bsgrp = (struct bsgrp_node *)rn->info;
|
|
|
|
if (!bsgrp)
|
|
continue;
|
|
|
|
char grp_str[PREFIX_STRLEN];
|
|
|
|
prefix2str(&bsgrp->group, grp_str, sizeof(grp_str));
|
|
|
|
if (uj) {
|
|
json_object_object_get_ex(json, grp_str, &json_group);
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_object_add(json, grp_str,
|
|
json_group);
|
|
}
|
|
} else {
|
|
vty_out(vty, "Group Address %pFX\n", &bsgrp->group);
|
|
vty_out(vty, "--------------------------\n");
|
|
vty_out(vty, "%-15s %-15s %-15s %-15s\n", "Rp Address",
|
|
"priority", "Holdtime", "Hash");
|
|
|
|
vty_out(vty, "(ACTIVE)\n");
|
|
}
|
|
|
|
frr_each (bsm_rpinfos, bsgrp->bsrp_list, bsm_rp) {
|
|
char rp_str[INET_ADDRSTRLEN];
|
|
|
|
pim_inet4_dump("<Rp Address?>", bsm_rp->rp_address,
|
|
rp_str, sizeof(rp_str));
|
|
|
|
if (uj) {
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "Rp Address",
|
|
rp_str);
|
|
json_object_int_add(json_row, "Rp HoldTime",
|
|
bsm_rp->rp_holdtime);
|
|
json_object_int_add(json_row, "Rp Priority",
|
|
bsm_rp->rp_prio);
|
|
json_object_int_add(json_row, "Hash Val",
|
|
bsm_rp->hash);
|
|
json_object_object_add(json_group, rp_str,
|
|
json_row);
|
|
|
|
} else {
|
|
vty_out(vty, "%-15s %-15u %-15u %-15u\n",
|
|
rp_str, bsm_rp->rp_prio,
|
|
bsm_rp->rp_holdtime, bsm_rp->hash);
|
|
}
|
|
}
|
|
if (!bsm_rpinfos_count(bsgrp->bsrp_list) && !uj)
|
|
vty_out(vty, "Active List is empty.\n");
|
|
|
|
if (uj) {
|
|
json_object_int_add(json_group, "Pending RP count",
|
|
bsgrp->pend_rp_cnt);
|
|
} else {
|
|
vty_out(vty, "(PENDING)\n");
|
|
vty_out(vty, "Pending RP count :%d\n",
|
|
bsgrp->pend_rp_cnt);
|
|
if (bsgrp->pend_rp_cnt)
|
|
vty_out(vty, "%-15s %-15s %-15s %-15s\n",
|
|
"Rp Address", "priority", "Holdtime",
|
|
"Hash");
|
|
}
|
|
|
|
frr_each (bsm_rpinfos, bsgrp->partial_bsrp_list, bsm_rp) {
|
|
char rp_str[INET_ADDRSTRLEN];
|
|
|
|
pim_inet4_dump("<Rp Addr?>", bsm_rp->rp_address, rp_str,
|
|
sizeof(rp_str));
|
|
|
|
if (uj) {
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "Rp Address",
|
|
rp_str);
|
|
json_object_int_add(json_row, "Rp HoldTime",
|
|
bsm_rp->rp_holdtime);
|
|
json_object_int_add(json_row, "Rp Priority",
|
|
bsm_rp->rp_prio);
|
|
json_object_int_add(json_row, "Hash Val",
|
|
bsm_rp->hash);
|
|
json_object_object_add(json_group, rp_str,
|
|
json_row);
|
|
} else {
|
|
vty_out(vty, "%-15s %-15u %-15u %-15u\n",
|
|
rp_str, bsm_rp->rp_prio,
|
|
bsm_rp->rp_holdtime, bsm_rp->hash);
|
|
}
|
|
}
|
|
if (!bsm_rpinfos_count(bsgrp->partial_bsrp_list) && !uj)
|
|
vty_out(vty, "Partial List is empty\n");
|
|
|
|
if (!uj)
|
|
vty_out(vty, "\n");
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
/* pim statistics - just adding only bsm related now.
|
|
* We can continue to add all pim related stats here.
|
|
*/
|
|
static void pim_show_statistics(struct pim_instance *pim, struct vty *vty,
|
|
const char *ifname, bool uj)
|
|
{
|
|
json_object *json = NULL;
|
|
struct interface *ifp;
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
json_object_int_add(json, "bsmRx", pim->bsm_rcvd);
|
|
json_object_int_add(json, "bsmTx", pim->bsm_sent);
|
|
json_object_int_add(json, "bsmDropped", pim->bsm_dropped);
|
|
} else {
|
|
vty_out(vty, "BSM Statistics :\n");
|
|
vty_out(vty, "----------------\n");
|
|
vty_out(vty, "Number of Received BSMs : %" PRIu64 "\n",
|
|
pim->bsm_rcvd);
|
|
vty_out(vty, "Number of Forwared BSMs : %" PRIu64 "\n",
|
|
pim->bsm_sent);
|
|
vty_out(vty, "Number of Dropped BSMs : %" PRIu64 "\n",
|
|
pim->bsm_dropped);
|
|
}
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
/* scan interfaces */
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
struct pim_interface *pim_ifp = ifp->info;
|
|
|
|
if (ifname && strcmp(ifname, ifp->name))
|
|
continue;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
if (!uj) {
|
|
vty_out(vty, "Interface : %s\n", ifp->name);
|
|
vty_out(vty, "-------------------\n");
|
|
vty_out(vty,
|
|
"Number of BSMs dropped due to config miss : %u\n",
|
|
pim_ifp->pim_ifstat_bsm_cfg_miss);
|
|
vty_out(vty, "Number of unicast BSMs dropped : %u\n",
|
|
pim_ifp->pim_ifstat_ucast_bsm_cfg_miss);
|
|
vty_out(vty,
|
|
"Number of BSMs dropped due to invalid scope zone : %u\n",
|
|
pim_ifp->pim_ifstat_bsm_invalid_sz);
|
|
} else {
|
|
|
|
json_object *json_row = NULL;
|
|
|
|
json_row = json_object_new_object();
|
|
|
|
json_object_string_add(json_row, "If Name", ifp->name);
|
|
json_object_int_add(json_row, "bsmDroppedConfig",
|
|
pim_ifp->pim_ifstat_bsm_cfg_miss);
|
|
json_object_int_add(
|
|
json_row, "bsmDroppedUnicast",
|
|
pim_ifp->pim_ifstat_ucast_bsm_cfg_miss);
|
|
json_object_int_add(json_row,
|
|
"bsmDroppedInvalidScopeZone",
|
|
pim_ifp->pim_ifstat_bsm_invalid_sz);
|
|
json_object_object_add(json, ifp->name, json_row);
|
|
}
|
|
vty_out(vty, "\n");
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void clear_pim_statistics(struct pim_instance *pim)
|
|
{
|
|
struct interface *ifp;
|
|
|
|
pim->bsm_rcvd = 0;
|
|
pim->bsm_sent = 0;
|
|
pim->bsm_dropped = 0;
|
|
|
|
/* scan interfaces */
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
struct pim_interface *pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
pim_ifp->pim_ifstat_bsm_cfg_miss = 0;
|
|
pim_ifp->pim_ifstat_ucast_bsm_cfg_miss = 0;
|
|
pim_ifp->pim_ifstat_bsm_invalid_sz = 0;
|
|
}
|
|
}
|
|
|
|
static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj)
|
|
{
|
|
struct interface *ifp;
|
|
time_t now;
|
|
json_object *json = NULL;
|
|
json_object *json_iface = NULL;
|
|
json_object *json_group = NULL;
|
|
json_object *json_groups = NULL;
|
|
|
|
now = pim_time_monotonic_sec();
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
json_object_int_add(json, "totalGroups", pim->igmp_group_count);
|
|
json_object_int_add(json, "watermarkLimit",
|
|
pim->igmp_watermark_limit);
|
|
} else {
|
|
vty_out(vty, "Total IGMP groups: %u\n", pim->igmp_group_count);
|
|
vty_out(vty, "Watermark warn limit(%s): %u\n",
|
|
pim->igmp_watermark_limit ? "Set" : "Not Set",
|
|
pim->igmp_watermark_limit);
|
|
vty_out(vty,
|
|
"Interface Address Group Mode Timer Srcs V Uptime \n");
|
|
}
|
|
|
|
/* scan interfaces */
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
struct pim_interface *pim_ifp = ifp->info;
|
|
struct listnode *sock_node;
|
|
struct igmp_sock *igmp;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
/* scan igmp sockets */
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
|
|
igmp)) {
|
|
char ifaddr_str[INET_ADDRSTRLEN];
|
|
struct listnode *grpnode;
|
|
struct igmp_group *grp;
|
|
|
|
pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
|
|
sizeof(ifaddr_str));
|
|
|
|
/* scan igmp groups */
|
|
for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list,
|
|
grpnode, grp)) {
|
|
char group_str[INET_ADDRSTRLEN];
|
|
char hhmmss[10];
|
|
char uptime[10];
|
|
|
|
pim_inet4_dump("<group?>", grp->group_addr,
|
|
group_str, sizeof(group_str));
|
|
pim_time_timer_to_hhmmss(hhmmss, sizeof(hhmmss),
|
|
grp->t_group_timer);
|
|
pim_time_uptime(uptime, sizeof(uptime),
|
|
now - grp->group_creation);
|
|
|
|
if (uj) {
|
|
json_object_object_get_ex(
|
|
json, ifp->name, &json_iface);
|
|
|
|
if (!json_iface) {
|
|
json_iface =
|
|
json_object_new_object();
|
|
json_object_pim_ifp_add(
|
|
json_iface, ifp);
|
|
json_object_object_add(
|
|
json, ifp->name,
|
|
json_iface);
|
|
json_groups =
|
|
json_object_new_array();
|
|
json_object_object_add(
|
|
json_iface,
|
|
"groups",
|
|
json_groups);
|
|
}
|
|
|
|
json_group = json_object_new_object();
|
|
json_object_string_add(json_group,
|
|
"source",
|
|
ifaddr_str);
|
|
json_object_string_add(json_group,
|
|
"group",
|
|
group_str);
|
|
|
|
if (grp->igmp_version == 3)
|
|
json_object_string_add(
|
|
json_group, "mode",
|
|
grp->group_filtermode_isexcl
|
|
? "EXCLUDE"
|
|
: "INCLUDE");
|
|
|
|
json_object_string_add(json_group,
|
|
"timer", hhmmss);
|
|
json_object_int_add(
|
|
json_group, "sourcesCount",
|
|
grp->group_source_list
|
|
? listcount(
|
|
grp->group_source_list)
|
|
: 0);
|
|
json_object_int_add(
|
|
json_group, "version",
|
|
grp->igmp_version);
|
|
json_object_string_add(
|
|
json_group, "uptime", uptime);
|
|
json_object_array_add(json_groups,
|
|
json_group);
|
|
} else {
|
|
vty_out(vty,
|
|
"%-16s %-15s %-15s %4s %8s %4d %d %8s\n",
|
|
ifp->name, ifaddr_str,
|
|
group_str,
|
|
grp->igmp_version == 3
|
|
? (grp->group_filtermode_isexcl
|
|
? "EXCL"
|
|
: "INCL")
|
|
: "----",
|
|
hhmmss,
|
|
grp->group_source_list
|
|
? listcount(
|
|
grp->group_source_list)
|
|
: 0,
|
|
grp->igmp_version, uptime);
|
|
}
|
|
} /* scan igmp groups */
|
|
} /* scan igmp sockets */
|
|
} /* scan interfaces */
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void igmp_show_group_retransmission(struct pim_instance *pim,
|
|
struct vty *vty)
|
|
{
|
|
struct interface *ifp;
|
|
|
|
vty_out(vty,
|
|
"Interface Address Group RetTimer Counter RetSrcs\n");
|
|
|
|
/* scan interfaces */
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
struct pim_interface *pim_ifp = ifp->info;
|
|
struct listnode *sock_node;
|
|
struct igmp_sock *igmp;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
/* scan igmp sockets */
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
|
|
igmp)) {
|
|
char ifaddr_str[INET_ADDRSTRLEN];
|
|
struct listnode *grpnode;
|
|
struct igmp_group *grp;
|
|
|
|
pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
|
|
sizeof(ifaddr_str));
|
|
|
|
/* scan igmp groups */
|
|
for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list,
|
|
grpnode, grp)) {
|
|
char group_str[INET_ADDRSTRLEN];
|
|
char grp_retr_mmss[10];
|
|
struct listnode *src_node;
|
|
struct igmp_source *src;
|
|
int grp_retr_sources = 0;
|
|
|
|
pim_inet4_dump("<group?>", grp->group_addr,
|
|
group_str, sizeof(group_str));
|
|
pim_time_timer_to_mmss(
|
|
grp_retr_mmss, sizeof(grp_retr_mmss),
|
|
grp->t_group_query_retransmit_timer);
|
|
|
|
|
|
/* count group sources with retransmission state
|
|
*/
|
|
for (ALL_LIST_ELEMENTS_RO(
|
|
grp->group_source_list, src_node,
|
|
src)) {
|
|
if (src->source_query_retransmit_count
|
|
> 0) {
|
|
++grp_retr_sources;
|
|
}
|
|
}
|
|
|
|
vty_out(vty, "%-16s %-15s %-15s %-8s %7d %7d\n",
|
|
ifp->name, ifaddr_str, group_str,
|
|
grp_retr_mmss,
|
|
grp->group_specific_query_retransmit_count,
|
|
grp_retr_sources);
|
|
|
|
} /* scan igmp groups */
|
|
} /* scan igmp sockets */
|
|
} /* scan interfaces */
|
|
}
|
|
|
|
static void igmp_show_sources(struct pim_instance *pim, struct vty *vty)
|
|
{
|
|
struct interface *ifp;
|
|
time_t now;
|
|
|
|
now = pim_time_monotonic_sec();
|
|
|
|
vty_out(vty,
|
|
"Interface Address Group Source Timer Fwd Uptime \n");
|
|
|
|
/* scan interfaces */
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
struct pim_interface *pim_ifp = ifp->info;
|
|
struct listnode *sock_node;
|
|
struct igmp_sock *igmp;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
/* scan igmp sockets */
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
|
|
igmp)) {
|
|
char ifaddr_str[INET_ADDRSTRLEN];
|
|
struct listnode *grpnode;
|
|
struct igmp_group *grp;
|
|
|
|
pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
|
|
sizeof(ifaddr_str));
|
|
|
|
/* scan igmp groups */
|
|
for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list,
|
|
grpnode, grp)) {
|
|
char group_str[INET_ADDRSTRLEN];
|
|
struct listnode *srcnode;
|
|
struct igmp_source *src;
|
|
|
|
pim_inet4_dump("<group?>", grp->group_addr,
|
|
group_str, sizeof(group_str));
|
|
|
|
/* scan group sources */
|
|
for (ALL_LIST_ELEMENTS_RO(
|
|
grp->group_source_list, srcnode,
|
|
src)) {
|
|
char source_str[INET_ADDRSTRLEN];
|
|
char mmss[10];
|
|
char uptime[10];
|
|
|
|
pim_inet4_dump(
|
|
"<source?>", src->source_addr,
|
|
source_str, sizeof(source_str));
|
|
|
|
pim_time_timer_to_mmss(
|
|
mmss, sizeof(mmss),
|
|
src->t_source_timer);
|
|
|
|
pim_time_uptime(
|
|
uptime, sizeof(uptime),
|
|
now - src->source_creation);
|
|
|
|
vty_out(vty,
|
|
"%-16s %-15s %-15s %-15s %5s %3s %8s\n",
|
|
ifp->name, ifaddr_str,
|
|
group_str, source_str, mmss,
|
|
IGMP_SOURCE_TEST_FORWARDING(
|
|
src->source_flags)
|
|
? "Y"
|
|
: "N",
|
|
uptime);
|
|
|
|
} /* scan group sources */
|
|
} /* scan igmp groups */
|
|
} /* scan igmp sockets */
|
|
} /* scan interfaces */
|
|
}
|
|
|
|
static void igmp_show_source_retransmission(struct pim_instance *pim,
|
|
struct vty *vty)
|
|
{
|
|
struct interface *ifp;
|
|
|
|
vty_out(vty,
|
|
"Interface Address Group Source Counter\n");
|
|
|
|
/* scan interfaces */
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
struct pim_interface *pim_ifp = ifp->info;
|
|
struct listnode *sock_node;
|
|
struct igmp_sock *igmp;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
/* scan igmp sockets */
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
|
|
igmp)) {
|
|
char ifaddr_str[INET_ADDRSTRLEN];
|
|
struct listnode *grpnode;
|
|
struct igmp_group *grp;
|
|
|
|
pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
|
|
sizeof(ifaddr_str));
|
|
|
|
/* scan igmp groups */
|
|
for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list,
|
|
grpnode, grp)) {
|
|
char group_str[INET_ADDRSTRLEN];
|
|
struct listnode *srcnode;
|
|
struct igmp_source *src;
|
|
|
|
pim_inet4_dump("<group?>", grp->group_addr,
|
|
group_str, sizeof(group_str));
|
|
|
|
/* scan group sources */
|
|
for (ALL_LIST_ELEMENTS_RO(
|
|
grp->group_source_list, srcnode,
|
|
src)) {
|
|
char source_str[INET_ADDRSTRLEN];
|
|
|
|
pim_inet4_dump(
|
|
"<source?>", src->source_addr,
|
|
source_str, sizeof(source_str));
|
|
|
|
vty_out(vty,
|
|
"%-16s %-15s %-15s %-15s %7d\n",
|
|
ifp->name, ifaddr_str,
|
|
group_str, source_str,
|
|
src->source_query_retransmit_count);
|
|
|
|
} /* scan group sources */
|
|
} /* scan igmp groups */
|
|
} /* scan igmp sockets */
|
|
} /* scan interfaces */
|
|
}
|
|
|
|
static void pim_show_bsr(struct pim_instance *pim,
|
|
struct vty *vty,
|
|
bool uj)
|
|
{
|
|
char uptime[10];
|
|
char last_bsm_seen[10];
|
|
time_t now;
|
|
char bsr_state[20];
|
|
char bsr_str[PREFIX_STRLEN];
|
|
json_object *json = NULL;
|
|
|
|
if (pim->global_scope.current_bsr.s_addr == INADDR_ANY) {
|
|
strlcpy(bsr_str, "0.0.0.0", sizeof(bsr_str));
|
|
pim_time_uptime(uptime, sizeof(uptime),
|
|
pim->global_scope.current_bsr_first_ts);
|
|
pim_time_uptime(last_bsm_seen, sizeof(last_bsm_seen),
|
|
pim->global_scope.current_bsr_last_ts);
|
|
}
|
|
|
|
else {
|
|
pim_inet4_dump("<bsr?>", pim->global_scope.current_bsr,
|
|
bsr_str, sizeof(bsr_str));
|
|
now = pim_time_monotonic_sec();
|
|
pim_time_uptime(uptime, sizeof(uptime),
|
|
(now - pim->global_scope.current_bsr_first_ts));
|
|
pim_time_uptime(last_bsm_seen, sizeof(last_bsm_seen),
|
|
now - pim->global_scope.current_bsr_last_ts);
|
|
}
|
|
|
|
switch (pim->global_scope.state) {
|
|
case NO_INFO:
|
|
strlcpy(bsr_state, "NO_INFO", sizeof(bsr_state));
|
|
break;
|
|
case ACCEPT_ANY:
|
|
strlcpy(bsr_state, "ACCEPT_ANY", sizeof(bsr_state));
|
|
break;
|
|
case ACCEPT_PREFERRED:
|
|
strlcpy(bsr_state, "ACCEPT_PREFERRED", sizeof(bsr_state));
|
|
break;
|
|
default:
|
|
strlcpy(bsr_state, "", sizeof(bsr_state));
|
|
}
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
json_object_string_add(json, "bsr", bsr_str);
|
|
json_object_int_add(json, "priority",
|
|
pim->global_scope.current_bsr_prio);
|
|
json_object_int_add(json, "fragmentTag",
|
|
pim->global_scope.bsm_frag_tag);
|
|
json_object_string_add(json, "state", bsr_state);
|
|
json_object_string_add(json, "upTime", uptime);
|
|
json_object_string_add(json, "lastBsmSeen", last_bsm_seen);
|
|
}
|
|
|
|
else {
|
|
vty_out(vty, "PIMv2 Bootstrap information\n");
|
|
vty_out(vty, "Current preferred BSR address: %s\n", bsr_str);
|
|
vty_out(vty,
|
|
"Priority Fragment-Tag State UpTime\n");
|
|
vty_out(vty, " %-12d %-12d %-13s %7s\n",
|
|
pim->global_scope.current_bsr_prio,
|
|
pim->global_scope.bsm_frag_tag,
|
|
bsr_state,
|
|
uptime);
|
|
vty_out(vty, "Last BSM seen: %s\n", last_bsm_seen);
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void clear_igmp_interfaces(struct pim_instance *pim)
|
|
{
|
|
struct interface *ifp;
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp)
|
|
pim_if_addr_del_all_igmp(ifp);
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp)
|
|
pim_if_addr_add_all(ifp);
|
|
}
|
|
|
|
static void clear_pim_interfaces(struct pim_instance *pim)
|
|
{
|
|
struct interface *ifp;
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
if (ifp->info) {
|
|
pim_neighbor_delete_all(ifp, "interface cleared");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void clear_interfaces(struct pim_instance *pim)
|
|
{
|
|
clear_igmp_interfaces(pim);
|
|
clear_pim_interfaces(pim);
|
|
}
|
|
|
|
#define PIM_GET_PIM_INTERFACE(pim_ifp, ifp) \
|
|
pim_ifp = ifp->info; \
|
|
if (!pim_ifp) { \
|
|
vty_out(vty, \
|
|
"%% Enable PIM and/or IGMP on this interface first\n"); \
|
|
return CMD_WARNING_CONFIG_FAILED; \
|
|
}
|
|
|
|
/**
|
|
* Get current node VRF name.
|
|
*
|
|
* NOTE:
|
|
* In case of failure it will print error message to user.
|
|
*
|
|
* \returns name or NULL if failed to get VRF.
|
|
*/
|
|
static const char *pim_cli_get_vrf_name(struct vty *vty)
|
|
{
|
|
const struct lyd_node *vrf_node;
|
|
|
|
/* Not inside any VRF context. */
|
|
if (vty->xpath_index == 0)
|
|
return VRF_DEFAULT_NAME;
|
|
|
|
vrf_node = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
|
|
if (vrf_node == NULL) {
|
|
vty_out(vty, "%% Failed to get vrf dnode in configuration\n");
|
|
return NULL;
|
|
}
|
|
|
|
return yang_dnode_get_string(vrf_node, "./name");
|
|
}
|
|
|
|
DEFUN (clear_ip_interfaces,
|
|
clear_ip_interfaces_cmd,
|
|
"clear ip interfaces [vrf NAME]",
|
|
CLEAR_STR
|
|
IP_STR
|
|
"Reset interfaces\n"
|
|
VRF_CMD_HELP_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
clear_interfaces(vrf->info);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (clear_ip_igmp_interfaces,
|
|
clear_ip_igmp_interfaces_cmd,
|
|
"clear ip igmp [vrf NAME] interfaces",
|
|
CLEAR_STR
|
|
IP_STR
|
|
CLEAR_IP_IGMP_STR
|
|
VRF_CMD_HELP_STR
|
|
"Reset IGMP interfaces\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
clear_igmp_interfaces(vrf->info);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (clear_ip_pim_statistics,
|
|
clear_ip_pim_statistics_cmd,
|
|
"clear ip pim statistics [vrf NAME]",
|
|
CLEAR_STR
|
|
IP_STR
|
|
CLEAR_IP_PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"Reset PIM statistics\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
clear_pim_statistics(vrf->info);
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
static void clear_mroute(struct pim_instance *pim)
|
|
{
|
|
struct pim_upstream *up;
|
|
struct interface *ifp;
|
|
|
|
/* scan interfaces */
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
struct pim_interface *pim_ifp = ifp->info;
|
|
struct listnode *sock_node;
|
|
struct igmp_sock *igmp;
|
|
struct pim_ifchannel *ch;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
/* deleting all ifchannels */
|
|
while (!RB_EMPTY(pim_ifchannel_rb, &pim_ifp->ifchannel_rb)) {
|
|
ch = RB_ROOT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb);
|
|
|
|
pim_ifchannel_delete(ch);
|
|
}
|
|
|
|
/* clean up all igmp groups */
|
|
/* scan igmp sockets */
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
|
|
igmp)) {
|
|
|
|
struct igmp_group *grp;
|
|
|
|
if (igmp->igmp_group_list) {
|
|
while (igmp->igmp_group_list->count) {
|
|
grp = listnode_head(
|
|
igmp->igmp_group_list);
|
|
igmp_group_delete(grp);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/* clean up all upstreams*/
|
|
while ((up = rb_pim_upstream_first(&pim->upstream_head)))
|
|
pim_upstream_del(pim, up, __func__);
|
|
|
|
}
|
|
|
|
DEFUN (clear_ip_mroute,
|
|
clear_ip_mroute_cmd,
|
|
"clear ip mroute [vrf NAME]",
|
|
CLEAR_STR
|
|
IP_STR
|
|
"Reset multicast routes\n"
|
|
VRF_CMD_HELP_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
clear_mroute(vrf->info);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (clear_ip_pim_interfaces,
|
|
clear_ip_pim_interfaces_cmd,
|
|
"clear ip pim [vrf NAME] interfaces",
|
|
CLEAR_STR
|
|
IP_STR
|
|
CLEAR_IP_PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"Reset PIM interfaces\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
clear_pim_interfaces(vrf->info);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (clear_ip_pim_interface_traffic,
|
|
clear_ip_pim_interface_traffic_cmd,
|
|
"clear ip pim [vrf NAME] interface traffic",
|
|
"Reset functions\n"
|
|
"IP information\n"
|
|
"PIM clear commands\n"
|
|
VRF_CMD_HELP_STR
|
|
"Reset PIM interfaces\n"
|
|
"Reset Protocol Packet counters\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
struct interface *ifp = NULL;
|
|
struct pim_interface *pim_ifp = NULL;
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
FOR_ALL_INTERFACES (vrf, ifp) {
|
|
pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
pim_ifp->pim_ifstat_hello_recv = 0;
|
|
pim_ifp->pim_ifstat_hello_sent = 0;
|
|
pim_ifp->pim_ifstat_join_recv = 0;
|
|
pim_ifp->pim_ifstat_join_send = 0;
|
|
pim_ifp->pim_ifstat_prune_recv = 0;
|
|
pim_ifp->pim_ifstat_prune_send = 0;
|
|
pim_ifp->pim_ifstat_reg_recv = 0;
|
|
pim_ifp->pim_ifstat_reg_send = 0;
|
|
pim_ifp->pim_ifstat_reg_stop_recv = 0;
|
|
pim_ifp->pim_ifstat_reg_stop_send = 0;
|
|
pim_ifp->pim_ifstat_assert_recv = 0;
|
|
pim_ifp->pim_ifstat_assert_send = 0;
|
|
pim_ifp->pim_ifstat_bsm_rx = 0;
|
|
pim_ifp->pim_ifstat_bsm_tx = 0;
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (clear_ip_pim_oil,
|
|
clear_ip_pim_oil_cmd,
|
|
"clear ip pim [vrf NAME] oil",
|
|
CLEAR_STR
|
|
IP_STR
|
|
CLEAR_IP_PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"Rescan PIM OIL (output interface list)\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_scan_oil(vrf->info);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
static void clear_pim_bsr_db(struct pim_instance *pim)
|
|
{
|
|
struct route_node *rn;
|
|
struct route_node *rpnode;
|
|
struct bsgrp_node *bsgrp;
|
|
struct prefix nht_p;
|
|
struct prefix g_all;
|
|
struct rp_info *rp_all;
|
|
struct pim_upstream *up;
|
|
struct rp_info *rp_info;
|
|
bool is_bsr_tracking = true;
|
|
|
|
/* Remove next hop tracking for the bsr */
|
|
nht_p.family = AF_INET;
|
|
nht_p.prefixlen = IPV4_MAX_BITLEN;
|
|
nht_p.u.prefix4 = pim->global_scope.current_bsr;
|
|
if (PIM_DEBUG_BSM) {
|
|
zlog_debug("%s: Deregister BSR addr %pFX with Zebra NHT",
|
|
__func__, &nht_p);
|
|
}
|
|
pim_delete_tracked_nexthop(pim, &nht_p, NULL, NULL, is_bsr_tracking);
|
|
|
|
/* Reset scope zone data */
|
|
pim->global_scope.accept_nofwd_bsm = false;
|
|
pim->global_scope.state = ACCEPT_ANY;
|
|
pim->global_scope.current_bsr.s_addr = INADDR_ANY;
|
|
pim->global_scope.current_bsr_prio = 0;
|
|
pim->global_scope.current_bsr_first_ts = 0;
|
|
pim->global_scope.current_bsr_last_ts = 0;
|
|
pim->global_scope.bsm_frag_tag = 0;
|
|
pim_bsm_frags_free(&pim->global_scope);
|
|
|
|
pim_bs_timer_stop(&pim->global_scope);
|
|
|
|
for (rn = route_top(pim->global_scope.bsrp_table); rn;
|
|
rn = route_next(rn)) {
|
|
bsgrp = rn->info;
|
|
if (!bsgrp)
|
|
continue;
|
|
|
|
rpnode = route_node_lookup(pim->rp_table, &bsgrp->group);
|
|
|
|
if (!rpnode) {
|
|
pim_free_bsgrp_node(bsgrp->scope->bsrp_table,
|
|
&bsgrp->group);
|
|
pim_free_bsgrp_data(bsgrp);
|
|
continue;
|
|
}
|
|
|
|
rp_info = (struct rp_info *)rpnode->info;
|
|
|
|
if ((!rp_info) || (rp_info->rp_src != RP_SRC_BSR)) {
|
|
pim_free_bsgrp_node(bsgrp->scope->bsrp_table,
|
|
&bsgrp->group);
|
|
pim_free_bsgrp_data(bsgrp);
|
|
continue;
|
|
}
|
|
|
|
/* Deregister addr with Zebra NHT */
|
|
nht_p.family = AF_INET;
|
|
nht_p.prefixlen = IPV4_MAX_BITLEN;
|
|
nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
|
|
|
|
if (PIM_DEBUG_PIM_NHT_RP) {
|
|
zlog_debug("%s: Deregister RP addr %pFX with Zebra ",
|
|
__func__, &nht_p);
|
|
}
|
|
|
|
pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info, false);
|
|
|
|
if (!str2prefix("224.0.0.0/4", &g_all))
|
|
return;
|
|
|
|
rp_all = pim_rp_find_match_group(pim, &g_all);
|
|
|
|
if (rp_all == rp_info) {
|
|
rp_all->rp.rpf_addr.family = AF_INET;
|
|
rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE;
|
|
rp_all->i_am_rp = 0;
|
|
} else {
|
|
/* Delete the rp_info from rp-list */
|
|
listnode_delete(pim->rp_list, rp_info);
|
|
|
|
/* Delete the rp node from rp_table */
|
|
rpnode->info = NULL;
|
|
route_unlock_node(rpnode);
|
|
route_unlock_node(rpnode);
|
|
}
|
|
|
|
XFREE(MTYPE_PIM_RP, rp_info);
|
|
|
|
pim_free_bsgrp_node(bsgrp->scope->bsrp_table, &bsgrp->group);
|
|
pim_free_bsgrp_data(bsgrp);
|
|
}
|
|
pim_rp_refresh_group_to_rp_mapping(pim);
|
|
|
|
|
|
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
|
|
/* Find the upstream (*, G) whose upstream address is same as
|
|
* the RP
|
|
*/
|
|
if (up->sg.src.s_addr != INADDR_ANY)
|
|
continue;
|
|
|
|
struct prefix grp;
|
|
struct rp_info *trp_info;
|
|
|
|
grp.family = AF_INET;
|
|
grp.prefixlen = IPV4_MAX_BITLEN;
|
|
grp.u.prefix4 = up->sg.grp;
|
|
|
|
trp_info = pim_rp_find_match_group(pim, &grp);
|
|
|
|
/* RP not found for the group grp */
|
|
if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) {
|
|
pim_upstream_rpf_clear(pim, up);
|
|
pim_rp_set_upstream_addr(pim, &up->upstream_addr,
|
|
up->sg.src, up->sg.grp);
|
|
} else {
|
|
/* RP found for the group grp */
|
|
pim_upstream_update(pim, up);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DEFUN (clear_ip_pim_bsr_db,
|
|
clear_ip_pim_bsr_db_cmd,
|
|
"clear ip pim [vrf NAME] bsr-data",
|
|
CLEAR_STR
|
|
IP_STR
|
|
CLEAR_IP_PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"Reset pim bsr data\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
clear_pim_bsr_db(vrf->info);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_igmp_interface,
|
|
show_ip_igmp_interface_cmd,
|
|
"show ip igmp [vrf NAME] interface [detail|WORD] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
IGMP_STR
|
|
VRF_CMD_HELP_STR
|
|
"IGMP interface information\n"
|
|
"Detailed output\n"
|
|
"interface name\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
if (argv_find(argv, argc, "detail", &idx)
|
|
|| argv_find(argv, argc, "WORD", &idx))
|
|
igmp_show_interfaces_single(vrf->info, vty, argv[idx]->arg, uj);
|
|
else
|
|
igmp_show_interfaces(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_igmp_interface_vrf_all,
|
|
show_ip_igmp_interface_vrf_all_cmd,
|
|
"show ip igmp vrf all interface [detail|WORD] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
IGMP_STR
|
|
VRF_CMD_HELP_STR
|
|
"IGMP interface information\n"
|
|
"Detailed output\n"
|
|
"interface name\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
if (argv_find(argv, argc, "detail", &idx)
|
|
|| argv_find(argv, argc, "WORD", &idx))
|
|
igmp_show_interfaces_single(vrf->info, vty,
|
|
argv[idx]->arg, uj);
|
|
else
|
|
igmp_show_interfaces(vrf->info, vty, uj);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_igmp_join,
|
|
show_ip_igmp_join_cmd,
|
|
"show ip igmp [vrf NAME] join [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
IGMP_STR
|
|
VRF_CMD_HELP_STR
|
|
"IGMP static join information\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
igmp_show_interface_join(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_igmp_join_vrf_all,
|
|
show_ip_igmp_join_vrf_all_cmd,
|
|
"show ip igmp vrf all join [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
IGMP_STR
|
|
VRF_CMD_HELP_STR
|
|
"IGMP static join information\n"
|
|
JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
igmp_show_interface_join(vrf->info, vty, uj);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_igmp_groups,
|
|
show_ip_igmp_groups_cmd,
|
|
"show ip igmp [vrf NAME] groups [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
IGMP_STR
|
|
VRF_CMD_HELP_STR
|
|
IGMP_GROUP_STR
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
igmp_show_groups(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_igmp_groups_vrf_all,
|
|
show_ip_igmp_groups_vrf_all_cmd,
|
|
"show ip igmp vrf all groups [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
IGMP_STR
|
|
VRF_CMD_HELP_STR
|
|
IGMP_GROUP_STR
|
|
JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
igmp_show_groups(vrf->info, vty, uj);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_igmp_groups_retransmissions,
|
|
show_ip_igmp_groups_retransmissions_cmd,
|
|
"show ip igmp [vrf NAME] groups retransmissions",
|
|
SHOW_STR
|
|
IP_STR
|
|
IGMP_STR
|
|
VRF_CMD_HELP_STR
|
|
IGMP_GROUP_STR
|
|
"IGMP group retransmissions\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
igmp_show_group_retransmission(vrf->info, vty);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_igmp_sources,
|
|
show_ip_igmp_sources_cmd,
|
|
"show ip igmp [vrf NAME] sources",
|
|
SHOW_STR
|
|
IP_STR
|
|
IGMP_STR
|
|
VRF_CMD_HELP_STR
|
|
IGMP_SOURCE_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
igmp_show_sources(vrf->info, vty);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_igmp_sources_retransmissions,
|
|
show_ip_igmp_sources_retransmissions_cmd,
|
|
"show ip igmp [vrf NAME] sources retransmissions",
|
|
SHOW_STR
|
|
IP_STR
|
|
IGMP_STR
|
|
VRF_CMD_HELP_STR
|
|
IGMP_SOURCE_STR
|
|
"IGMP source retransmissions\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
igmp_show_source_retransmission(vrf->info, vty);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_igmp_statistics,
|
|
show_ip_igmp_statistics_cmd,
|
|
"show ip igmp [vrf NAME] statistics [interface WORD] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
IGMP_STR
|
|
VRF_CMD_HELP_STR
|
|
"IGMP statistics\n"
|
|
"interface\n"
|
|
"IGMP interface\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
if (argv_find(argv, argc, "WORD", &idx))
|
|
igmp_show_statistics(vrf->info, vty, argv[idx]->arg, uj);
|
|
else
|
|
igmp_show_statistics(vrf->info, vty, NULL, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_mlag_summary,
|
|
show_ip_pim_mlag_summary_cmd,
|
|
"show ip pim mlag summary [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"MLAG\n"
|
|
"status and stats\n"
|
|
JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
char role_buf[MLAG_ROLE_STRSIZE];
|
|
char addr_buf[INET_ADDRSTRLEN];
|
|
|
|
if (uj) {
|
|
json_object *json = NULL;
|
|
json_object *json_stat = NULL;
|
|
|
|
json = json_object_new_object();
|
|
if (router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)
|
|
json_object_boolean_true_add(json, "mlagConnUp");
|
|
if (router->mlag_flags & PIM_MLAGF_PEER_CONN_UP)
|
|
json_object_boolean_true_add(json, "mlagPeerConnUp");
|
|
if (router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP)
|
|
json_object_boolean_true_add(json, "mlagPeerZebraUp");
|
|
json_object_string_add(json, "mlagRole",
|
|
mlag_role2str(router->mlag_role,
|
|
role_buf, sizeof(role_buf)));
|
|
inet_ntop(AF_INET, &router->local_vtep_ip,
|
|
addr_buf, INET_ADDRSTRLEN);
|
|
json_object_string_add(json, "localVtepIp", addr_buf);
|
|
inet_ntop(AF_INET, &router->anycast_vtep_ip,
|
|
addr_buf, INET_ADDRSTRLEN);
|
|
json_object_string_add(json, "anycastVtepIp", addr_buf);
|
|
json_object_string_add(json, "peerlinkRif",
|
|
router->peerlink_rif);
|
|
|
|
json_stat = json_object_new_object();
|
|
json_object_int_add(json_stat, "mlagConnFlaps",
|
|
router->mlag_stats.mlagd_session_downs);
|
|
json_object_int_add(json_stat, "mlagPeerConnFlaps",
|
|
router->mlag_stats.peer_session_downs);
|
|
json_object_int_add(json_stat, "mlagPeerZebraFlaps",
|
|
router->mlag_stats.peer_zebra_downs);
|
|
json_object_int_add(json_stat, "mrouteAddRx",
|
|
router->mlag_stats.msg.mroute_add_rx);
|
|
json_object_int_add(json_stat, "mrouteAddTx",
|
|
router->mlag_stats.msg.mroute_add_tx);
|
|
json_object_int_add(json_stat, "mrouteDelRx",
|
|
router->mlag_stats.msg.mroute_del_rx);
|
|
json_object_int_add(json_stat, "mrouteDelTx",
|
|
router->mlag_stats.msg.mroute_del_tx);
|
|
json_object_int_add(json_stat, "mlagStatusUpdates",
|
|
router->mlag_stats.msg.mlag_status_updates);
|
|
json_object_int_add(json_stat, "peerZebraStatusUpdates",
|
|
router->mlag_stats.msg.peer_zebra_status_updates);
|
|
json_object_int_add(json_stat, "pimStatusUpdates",
|
|
router->mlag_stats.msg.pim_status_updates);
|
|
json_object_int_add(json_stat, "vxlanUpdates",
|
|
router->mlag_stats.msg.vxlan_updates);
|
|
json_object_object_add(json, "connStats", json_stat);
|
|
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
vty_out(vty, "MLAG daemon connection: %s\n",
|
|
(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)
|
|
? "up" : "down");
|
|
vty_out(vty, "MLAG peer state: %s\n",
|
|
(router->mlag_flags & PIM_MLAGF_PEER_CONN_UP)
|
|
? "up" : "down");
|
|
vty_out(vty, "Zebra peer state: %s\n",
|
|
(router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP)
|
|
? "up" : "down");
|
|
vty_out(vty, "MLAG role: %s\n",
|
|
mlag_role2str(router->mlag_role, role_buf, sizeof(role_buf)));
|
|
inet_ntop(AF_INET, &router->local_vtep_ip,
|
|
addr_buf, INET_ADDRSTRLEN);
|
|
vty_out(vty, "Local VTEP IP: %s\n", addr_buf);
|
|
inet_ntop(AF_INET, &router->anycast_vtep_ip,
|
|
addr_buf, INET_ADDRSTRLEN);
|
|
vty_out(vty, "Anycast VTEP IP: %s\n", addr_buf);
|
|
vty_out(vty, "Peerlink: %s\n", router->peerlink_rif);
|
|
vty_out(vty, "Session flaps: mlagd: %d mlag-peer: %d zebra-peer: %d\n",
|
|
router->mlag_stats.mlagd_session_downs,
|
|
router->mlag_stats.peer_session_downs,
|
|
router->mlag_stats.peer_zebra_downs);
|
|
vty_out(vty, "Message Statistics:\n");
|
|
vty_out(vty, " mroute adds: rx: %d, tx: %d\n",
|
|
router->mlag_stats.msg.mroute_add_rx,
|
|
router->mlag_stats.msg.mroute_add_tx);
|
|
vty_out(vty, " mroute dels: rx: %d, tx: %d\n",
|
|
router->mlag_stats.msg.mroute_del_rx,
|
|
router->mlag_stats.msg.mroute_del_tx);
|
|
vty_out(vty, " peer zebra status updates: %d\n",
|
|
router->mlag_stats.msg.peer_zebra_status_updates);
|
|
vty_out(vty, " PIM status updates: %d\n",
|
|
router->mlag_stats.msg.pim_status_updates);
|
|
vty_out(vty, " VxLAN updates: %d\n",
|
|
router->mlag_stats.msg.vxlan_updates);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_assert,
|
|
show_ip_pim_assert_cmd,
|
|
"show ip pim [vrf NAME] assert",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM interface assert\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_show_assert(vrf->info, vty);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_assert_internal,
|
|
show_ip_pim_assert_internal_cmd,
|
|
"show ip pim [vrf NAME] assert-internal",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM interface internal assert state\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_show_assert_internal(vrf->info, vty);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_assert_metric,
|
|
show_ip_pim_assert_metric_cmd,
|
|
"show ip pim [vrf NAME] assert-metric",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM interface assert metric\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_show_assert_metric(vrf->info, vty);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_assert_winner_metric,
|
|
show_ip_pim_assert_winner_metric_cmd,
|
|
"show ip pim [vrf NAME] assert-winner-metric",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM interface assert winner metric\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_show_assert_winner_metric(vrf->info, vty);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_interface,
|
|
show_ip_pim_interface_cmd,
|
|
"show ip pim [mlag] [vrf NAME] interface [detail|WORD] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"MLAG\n"
|
|
VRF_CMD_HELP_STR
|
|
"PIM interface information\n"
|
|
"Detailed output\n"
|
|
"interface name\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
bool mlag = false;
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
if (argv_find(argv, argc, "mlag", &idx))
|
|
mlag = true;
|
|
|
|
if (argv_find(argv, argc, "WORD", &idx)
|
|
|| argv_find(argv, argc, "detail", &idx))
|
|
pim_show_interfaces_single(vrf->info, vty, argv[idx]->arg, mlag,
|
|
uj);
|
|
else
|
|
pim_show_interfaces(vrf->info, vty, mlag, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_interface_vrf_all,
|
|
show_ip_pim_interface_vrf_all_cmd,
|
|
"show ip pim [mlag] vrf all interface [detail|WORD] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"MLAG\n"
|
|
VRF_CMD_HELP_STR
|
|
"PIM interface information\n"
|
|
"Detailed output\n"
|
|
"interface name\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
bool mlag = false;
|
|
|
|
if (argv_find(argv, argc, "mlag", &idx))
|
|
mlag = true;
|
|
|
|
idx = 6;
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
if (argv_find(argv, argc, "WORD", &idx)
|
|
|| argv_find(argv, argc, "detail", &idx))
|
|
pim_show_interfaces_single(vrf->info, vty,
|
|
argv[idx]->arg, mlag, uj);
|
|
else
|
|
pim_show_interfaces(vrf->info, vty, mlag, uj);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY (show_ip_pim_join,
|
|
show_ip_pim_join_cmd,
|
|
"show ip pim [vrf NAME] join [A.B.C.D$s_or_g [A.B.C.D$g]] [json$json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM interface join information\n"
|
|
"The Source or Group\n"
|
|
"The Group\n"
|
|
JSON_STR)
|
|
{
|
|
struct prefix_sg sg = {0};
|
|
struct vrf *v;
|
|
bool uj = !!json;
|
|
struct pim_instance *pim;
|
|
|
|
v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
|
|
|
|
if (!v) {
|
|
vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
|
|
return CMD_WARNING;
|
|
}
|
|
pim = pim_get_pim_instance(v->vrf_id);
|
|
|
|
if (!pim) {
|
|
vty_out(vty, "%% Unable to find pim instance\n");
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
if (s_or_g.s_addr != INADDR_ANY) {
|
|
if (g.s_addr != INADDR_ANY) {
|
|
sg.src = s_or_g;
|
|
sg.grp = g;
|
|
} else
|
|
sg.grp = s_or_g;
|
|
}
|
|
|
|
pim_show_join(pim, vty, &sg, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_join_vrf_all,
|
|
show_ip_pim_join_vrf_all_cmd,
|
|
"show ip pim vrf all join [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM interface join information\n"
|
|
JSON_STR)
|
|
{
|
|
struct prefix_sg sg = {0};
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
pim_show_join(vrf->info, vty, &sg, uj);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
static void pim_show_jp_agg_helper(struct vty *vty,
|
|
struct interface *ifp,
|
|
struct pim_neighbor *neigh,
|
|
struct pim_upstream *up,
|
|
int is_join)
|
|
{
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
char rpf_str[INET_ADDRSTRLEN];
|
|
|
|
pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
|
|
pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
|
|
/* pius->address.s_addr */
|
|
pim_inet4_dump("<rpf?>", neigh->source_addr, rpf_str, sizeof(rpf_str));
|
|
|
|
vty_out(vty, "%-16s %-15s %-15s %-15s %5s\n",
|
|
ifp->name, rpf_str, src_str,
|
|
grp_str, is_join?"J":"P");
|
|
}
|
|
|
|
static void pim_show_jp_agg_list(struct pim_instance *pim, struct vty *vty)
|
|
{
|
|
struct interface *ifp;
|
|
struct pim_interface *pim_ifp;
|
|
struct listnode *n_node;
|
|
struct pim_neighbor *neigh;
|
|
struct listnode *jag_node;
|
|
struct pim_jp_agg_group *jag;
|
|
struct listnode *js_node;
|
|
struct pim_jp_sources *js;
|
|
|
|
vty_out(vty,
|
|
"Interface RPF Nbr Source Group State\n");
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
pim_ifp = ifp->info;
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list,
|
|
n_node, neigh)) {
|
|
for (ALL_LIST_ELEMENTS_RO(neigh->upstream_jp_agg,
|
|
jag_node, jag)) {
|
|
for (ALL_LIST_ELEMENTS_RO(jag->sources,
|
|
js_node, js)) {
|
|
pim_show_jp_agg_helper(vty,
|
|
ifp, neigh, js->up,
|
|
js->is_join);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DEFPY (show_ip_pim_jp_agg,
|
|
show_ip_pim_jp_agg_cmd,
|
|
"show ip pim [vrf NAME] jp-agg",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"join prune aggregation list\n")
|
|
{
|
|
struct vrf *v;
|
|
struct pim_instance *pim;
|
|
|
|
v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
|
|
|
|
if (!v) {
|
|
vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
|
|
return CMD_WARNING;
|
|
}
|
|
pim = pim_get_pim_instance(v->vrf_id);
|
|
|
|
if (!pim) {
|
|
vty_out(vty, "%% Unable to find pim instance\n");
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
pim_show_jp_agg_list(pim, vty);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_local_membership,
|
|
show_ip_pim_local_membership_cmd,
|
|
"show ip pim [vrf NAME] local-membership [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM interface local-membership\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_show_membership(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
static void pim_show_mlag_up_entry_detail(struct vrf *vrf,
|
|
struct vty *vty,
|
|
struct pim_upstream *up,
|
|
char *src_str, char *grp_str,
|
|
json_object *json)
|
|
{
|
|
if (json) {
|
|
json_object *json_row = NULL;
|
|
json_object *own_list = NULL;
|
|
json_object *json_group = NULL;
|
|
|
|
|
|
json_object_object_get_ex(json, grp_str, &json_group);
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_object_add(json, grp_str,
|
|
json_group);
|
|
}
|
|
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "source", src_str);
|
|
json_object_string_add(json_row, "group", grp_str);
|
|
|
|
own_list = json_object_new_array();
|
|
if (pim_up_mlag_is_local(up))
|
|
json_object_array_add(own_list,
|
|
json_object_new_string("local"));
|
|
if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER))
|
|
json_object_array_add(own_list,
|
|
json_object_new_string("peer"));
|
|
if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
|
|
json_object_array_add(
|
|
own_list, json_object_new_string("Interface"));
|
|
json_object_object_add(json_row, "owners", own_list);
|
|
|
|
json_object_int_add(json_row, "localCost",
|
|
pim_up_mlag_local_cost(up));
|
|
json_object_int_add(json_row, "peerCost",
|
|
pim_up_mlag_peer_cost(up));
|
|
if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags))
|
|
json_object_boolean_false_add(json_row, "df");
|
|
else
|
|
json_object_boolean_true_add(json_row, "df");
|
|
json_object_object_add(json_group, src_str, json_row);
|
|
} else {
|
|
char own_str[6];
|
|
|
|
own_str[0] = '\0';
|
|
if (pim_up_mlag_is_local(up))
|
|
strlcat(own_str, "L", sizeof(own_str));
|
|
if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER))
|
|
strlcat(own_str, "P", sizeof(own_str));
|
|
if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
|
|
strlcat(own_str, "I", sizeof(own_str));
|
|
/* XXX - fixup, print paragraph output */
|
|
vty_out(vty,
|
|
"%-15s %-15s %-6s %-11u %-10d %2s\n",
|
|
src_str, grp_str, own_str,
|
|
pim_up_mlag_local_cost(up),
|
|
pim_up_mlag_peer_cost(up),
|
|
PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)
|
|
? "n" : "y");
|
|
}
|
|
}
|
|
|
|
static void pim_show_mlag_up_detail(struct vrf *vrf,
|
|
struct vty *vty, const char *src_or_group,
|
|
const char *group, bool uj)
|
|
{
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
struct pim_upstream *up;
|
|
struct pim_instance *pim = vrf->info;
|
|
json_object *json = NULL;
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
else
|
|
vty_out(vty,
|
|
"Source Group Owner Local-cost Peer-cost DF\n");
|
|
|
|
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
|
|
if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)
|
|
&& !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)
|
|
&& !pim_up_mlag_is_local(up))
|
|
continue;
|
|
|
|
pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
|
|
pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
|
|
/* XXX: strcmps are clearly inefficient. we should do uint comps
|
|
* here instead.
|
|
*/
|
|
if (group) {
|
|
if (strcmp(src_str, src_or_group) ||
|
|
strcmp(grp_str, group))
|
|
continue;
|
|
} else {
|
|
if (strcmp(src_str, src_or_group) &&
|
|
strcmp(grp_str, src_or_group))
|
|
continue;
|
|
}
|
|
pim_show_mlag_up_entry_detail(vrf, vty, up,
|
|
src_str, grp_str, json);
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void pim_show_mlag_up_vrf(struct vrf *vrf, struct vty *vty, bool uj)
|
|
{
|
|
json_object *json = NULL;
|
|
json_object *json_row;
|
|
struct pim_upstream *up;
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
struct pim_instance *pim = vrf->info;
|
|
json_object *json_group = NULL;
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
} else {
|
|
vty_out(vty,
|
|
"Source Group Owner Local-cost Peer-cost DF\n");
|
|
}
|
|
|
|
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
|
|
if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)
|
|
&& !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)
|
|
&& !pim_up_mlag_is_local(up))
|
|
continue;
|
|
pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
|
|
pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
|
|
if (uj) {
|
|
json_object *own_list = NULL;
|
|
|
|
json_object_object_get_ex(json, grp_str, &json_group);
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_object_add(json, grp_str,
|
|
json_group);
|
|
}
|
|
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "vrf", vrf->name);
|
|
json_object_string_add(json_row, "source", src_str);
|
|
json_object_string_add(json_row, "group", grp_str);
|
|
|
|
own_list = json_object_new_array();
|
|
if (pim_up_mlag_is_local(up)) {
|
|
|
|
json_object_array_add(own_list,
|
|
json_object_new_string(
|
|
"local"));
|
|
}
|
|
if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)) {
|
|
json_object_array_add(own_list,
|
|
json_object_new_string(
|
|
"peer"));
|
|
}
|
|
json_object_object_add(json_row, "owners", own_list);
|
|
|
|
json_object_int_add(json_row, "localCost",
|
|
pim_up_mlag_local_cost(up));
|
|
json_object_int_add(json_row, "peerCost",
|
|
pim_up_mlag_peer_cost(up));
|
|
if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags))
|
|
json_object_boolean_false_add(json_row, "df");
|
|
else
|
|
json_object_boolean_true_add(json_row, "df");
|
|
json_object_object_add(json_group, src_str, json_row);
|
|
} else {
|
|
char own_str[6];
|
|
|
|
own_str[0] = '\0';
|
|
if (pim_up_mlag_is_local(up))
|
|
strlcat(own_str, "L", sizeof(own_str));
|
|
if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER))
|
|
strlcat(own_str, "P", sizeof(own_str));
|
|
if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
|
|
strlcat(own_str, "I", sizeof(own_str));
|
|
vty_out(vty,
|
|
"%-15s %-15s %-6s %-11u %-10u %2s\n",
|
|
src_str, grp_str, own_str,
|
|
pim_up_mlag_local_cost(up),
|
|
pim_up_mlag_peer_cost(up),
|
|
PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)
|
|
? "n" : "y");
|
|
}
|
|
}
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void pim_show_mlag_help_string(struct vty *vty, bool uj)
|
|
{
|
|
if (!uj) {
|
|
vty_out(vty, "Owner codes:\n");
|
|
vty_out(vty,
|
|
"L: EVPN-MLAG Entry, I:PIM-MLAG Entry, P: Peer Entry\n");
|
|
}
|
|
}
|
|
|
|
|
|
DEFUN(show_ip_pim_mlag_up, show_ip_pim_mlag_up_cmd,
|
|
"show ip pim [vrf NAME] mlag upstream [A.B.C.D [A.B.C.D]] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"MLAG\n"
|
|
"upstream\n"
|
|
"Unicast or Multicast address\n"
|
|
"Multicast address\n" JSON_STR)
|
|
{
|
|
const char *src_or_group = NULL;
|
|
const char *group = NULL;
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf || !vrf->info) {
|
|
vty_out(vty, "%s: VRF or Info missing\n", __func__);
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
if (uj)
|
|
argc--;
|
|
|
|
if (argv_find(argv, argc, "A.B.C.D", &idx)) {
|
|
src_or_group = argv[idx]->arg;
|
|
if (idx + 1 < argc)
|
|
group = argv[idx + 1]->arg;
|
|
}
|
|
|
|
pim_show_mlag_help_string(vty, uj);
|
|
|
|
if (src_or_group)
|
|
pim_show_mlag_up_detail(vrf, vty, src_or_group, group, uj);
|
|
else
|
|
pim_show_mlag_up_vrf(vrf, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
|
|
DEFUN(show_ip_pim_mlag_up_vrf_all, show_ip_pim_mlag_up_vrf_all_cmd,
|
|
"show ip pim vrf all mlag upstream [json]",
|
|
SHOW_STR IP_STR PIM_STR VRF_CMD_HELP_STR
|
|
"MLAG\n"
|
|
"upstream\n" JSON_STR)
|
|
{
|
|
struct vrf *vrf;
|
|
bool uj = use_json(argc, argv);
|
|
|
|
pim_show_mlag_help_string(vty, uj);
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
pim_show_mlag_up_vrf(vrf, vty, uj);
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_neighbor,
|
|
show_ip_pim_neighbor_cmd,
|
|
"show ip pim [vrf NAME] neighbor [detail|WORD] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM neighbor information\n"
|
|
"Detailed output\n"
|
|
"Name of interface or neighbor\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
if (argv_find(argv, argc, "detail", &idx)
|
|
|| argv_find(argv, argc, "WORD", &idx))
|
|
pim_show_neighbors_single(vrf->info, vty, argv[idx]->arg, uj);
|
|
else
|
|
pim_show_neighbors(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_neighbor_vrf_all,
|
|
show_ip_pim_neighbor_vrf_all_cmd,
|
|
"show ip pim vrf all neighbor [detail|WORD] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM neighbor information\n"
|
|
"Detailed output\n"
|
|
"Name of interface or neighbor\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
if (argv_find(argv, argc, "detail", &idx)
|
|
|| argv_find(argv, argc, "WORD", &idx))
|
|
pim_show_neighbors_single(vrf->info, vty,
|
|
argv[idx]->arg, uj);
|
|
else
|
|
pim_show_neighbors(vrf->info, vty, uj);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_secondary,
|
|
show_ip_pim_secondary_cmd,
|
|
"show ip pim [vrf NAME] secondary",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM neighbor addresses\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_show_neighbors_secondary(vrf->info, vty);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_state,
|
|
show_ip_pim_state_cmd,
|
|
"show ip pim [vrf NAME] state [A.B.C.D [A.B.C.D]] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM state information\n"
|
|
"Unicast or Multicast address\n"
|
|
"Multicast address\n"
|
|
JSON_STR)
|
|
{
|
|
const char *src_or_group = NULL;
|
|
const char *group = NULL;
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
if (uj)
|
|
argc--;
|
|
|
|
if (argv_find(argv, argc, "A.B.C.D", &idx)) {
|
|
src_or_group = argv[idx]->arg;
|
|
if (idx + 1 < argc)
|
|
group = argv[idx + 1]->arg;
|
|
}
|
|
|
|
pim_show_state(vrf->info, vty, src_or_group, group, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_state_vrf_all,
|
|
show_ip_pim_state_vrf_all_cmd,
|
|
"show ip pim vrf all state [A.B.C.D [A.B.C.D]] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM state information\n"
|
|
"Unicast or Multicast address\n"
|
|
"Multicast address\n"
|
|
JSON_STR)
|
|
{
|
|
const char *src_or_group = NULL;
|
|
const char *group = NULL;
|
|
int idx = 2;
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
|
|
if (uj) {
|
|
vty_out(vty, "{ ");
|
|
argc--;
|
|
}
|
|
|
|
if (argv_find(argv, argc, "A.B.C.D", &idx)) {
|
|
src_or_group = argv[idx]->arg;
|
|
if (idx + 1 < argc)
|
|
group = argv[idx + 1]->arg;
|
|
}
|
|
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
pim_show_state(vrf->info, vty, src_or_group, group, uj);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY (show_ip_pim_upstream,
|
|
show_ip_pim_upstream_cmd,
|
|
"show ip pim [vrf NAME] upstream [A.B.C.D$s_or_g [A.B.C.D$g]] [json$json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM upstream information\n"
|
|
"The Source or Group\n"
|
|
"The Group\n"
|
|
JSON_STR)
|
|
{
|
|
struct prefix_sg sg = {0};
|
|
struct vrf *v;
|
|
bool uj = !!json;
|
|
struct pim_instance *pim;
|
|
|
|
v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
|
|
|
|
if (!v) {
|
|
vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
|
|
return CMD_WARNING;
|
|
}
|
|
pim = pim_get_pim_instance(v->vrf_id);
|
|
|
|
if (!pim) {
|
|
vty_out(vty, "%% Unable to find pim instance\n");
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
if (s_or_g.s_addr != INADDR_ANY) {
|
|
if (g.s_addr != INADDR_ANY) {
|
|
sg.src = s_or_g;
|
|
sg.grp = g;
|
|
} else
|
|
sg.grp = s_or_g;
|
|
}
|
|
pim_show_upstream(pim, vty, &sg, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_upstream_vrf_all,
|
|
show_ip_pim_upstream_vrf_all_cmd,
|
|
"show ip pim vrf all upstream [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM upstream information\n"
|
|
JSON_STR)
|
|
{
|
|
struct prefix_sg sg = {0};
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
pim_show_upstream(vrf->info, vty, &sg, uj);
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_channel,
|
|
show_ip_pim_channel_cmd,
|
|
"show ip pim [vrf NAME] channel [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM downstream channel info\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_show_channel(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_upstream_join_desired,
|
|
show_ip_pim_upstream_join_desired_cmd,
|
|
"show ip pim [vrf NAME] upstream-join-desired [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM upstream join-desired\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_show_join_desired(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_upstream_rpf,
|
|
show_ip_pim_upstream_rpf_cmd,
|
|
"show ip pim [vrf NAME] upstream-rpf [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM upstream source rpf\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_show_upstream_rpf(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_rp,
|
|
show_ip_pim_rp_cmd,
|
|
"show ip pim [vrf NAME] rp-info [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM RP information\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_rp_show_information(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_rp_vrf_all,
|
|
show_ip_pim_rp_vrf_all_cmd,
|
|
"show ip pim vrf all rp-info [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM RP information\n"
|
|
JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
pim_rp_show_information(vrf->info, vty, uj);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_rpf,
|
|
show_ip_pim_rpf_cmd,
|
|
"show ip pim [vrf NAME] rpf [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM cached source rpf information\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_show_rpf(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_rpf_vrf_all,
|
|
show_ip_pim_rpf_vrf_all_cmd,
|
|
"show ip pim vrf all rpf [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM cached source rpf information\n"
|
|
JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
pim_show_rpf(vrf->info, vty, uj);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_nexthop,
|
|
show_ip_pim_nexthop_cmd,
|
|
"show ip pim [vrf NAME] nexthop",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM cached nexthop rpf information\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_show_nexthop(vrf->info, vty);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_nexthop_lookup,
|
|
show_ip_pim_nexthop_lookup_cmd,
|
|
"show ip pim [vrf NAME] nexthop-lookup A.B.C.D A.B.C.D",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM cached nexthop rpf lookup\n"
|
|
"Source/RP address\n"
|
|
"Multicast Group address\n")
|
|
{
|
|
struct prefix nht_p;
|
|
int result = 0;
|
|
struct in_addr src_addr, grp_addr;
|
|
struct in_addr vif_source;
|
|
const char *addr_str, *addr_str1;
|
|
struct prefix grp;
|
|
struct pim_nexthop nexthop;
|
|
char nexthop_addr_str[PREFIX_STRLEN];
|
|
char grp_str[PREFIX_STRLEN];
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
argv_find(argv, argc, "A.B.C.D", &idx);
|
|
addr_str = argv[idx]->arg;
|
|
result = inet_pton(AF_INET, addr_str, &src_addr);
|
|
if (result <= 0) {
|
|
vty_out(vty, "Bad unicast address %s: errno=%d: %s\n", addr_str,
|
|
errno, safe_strerror(errno));
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
if (pim_is_group_224_4(src_addr)) {
|
|
vty_out(vty,
|
|
"Invalid argument. Expected Valid Source Address.\n");
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
addr_str1 = argv[idx + 1]->arg;
|
|
result = inet_pton(AF_INET, addr_str1, &grp_addr);
|
|
if (result <= 0) {
|
|
vty_out(vty, "Bad unicast address %s: errno=%d: %s\n", addr_str,
|
|
errno, safe_strerror(errno));
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
if (!pim_is_group_224_4(grp_addr)) {
|
|
vty_out(vty,
|
|
"Invalid argument. Expected Valid Multicast Group Address.\n");
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
if (!pim_rp_set_upstream_addr(vrf->info, &vif_source, src_addr,
|
|
grp_addr))
|
|
return CMD_SUCCESS;
|
|
|
|
nht_p.family = AF_INET;
|
|
nht_p.prefixlen = IPV4_MAX_BITLEN;
|
|
nht_p.u.prefix4 = vif_source;
|
|
grp.family = AF_INET;
|
|
grp.prefixlen = IPV4_MAX_BITLEN;
|
|
grp.u.prefix4 = grp_addr;
|
|
memset(&nexthop, 0, sizeof(nexthop));
|
|
|
|
result = pim_ecmp_nexthop_lookup(vrf->info, &nexthop, &nht_p, &grp, 0);
|
|
|
|
if (!result) {
|
|
vty_out(vty,
|
|
"Nexthop Lookup failed, no usable routes returned.\n");
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
pim_addr_dump("<grp?>", &grp, grp_str, sizeof(grp_str));
|
|
pim_addr_dump("<nexthop?>", &nexthop.mrib_nexthop_addr,
|
|
nexthop_addr_str, sizeof(nexthop_addr_str));
|
|
vty_out(vty, "Group %s --- Nexthop %s Interface %s \n", grp_str,
|
|
nexthop_addr_str, nexthop.interface->name);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_interface_traffic,
|
|
show_ip_pim_interface_traffic_cmd,
|
|
"show ip pim [vrf NAME] interface traffic [WORD] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM interface information\n"
|
|
"Protocol Packet counters\n"
|
|
"Interface name\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
if (argv_find(argv, argc, "WORD", &idx))
|
|
pim_show_interface_traffic_single(vrf->info, vty,
|
|
argv[idx]->arg, uj);
|
|
else
|
|
pim_show_interface_traffic(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_bsm_db,
|
|
show_ip_pim_bsm_db_cmd,
|
|
"show ip pim bsm-database [vrf NAME] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"PIM cached bsm packets information\n"
|
|
VRF_CMD_HELP_STR
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_show_bsm_db(vrf->info, vty, uj);
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_bsrp,
|
|
show_ip_pim_bsrp_cmd,
|
|
"show ip pim bsrp-info [vrf NAME] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"PIM cached group-rp mappings information\n"
|
|
VRF_CMD_HELP_STR
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_show_group_rp_mappings_info(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_statistics,
|
|
show_ip_pim_statistics_cmd,
|
|
"show ip pim [vrf NAME] statistics [interface WORD] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM statistics\n"
|
|
INTERFACE_STR
|
|
"PIM interface\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
if (argv_find(argv, argc, "WORD", &idx))
|
|
pim_show_statistics(vrf->info, vty, argv[idx]->arg, uj);
|
|
else
|
|
pim_show_statistics(vrf->info, vty, NULL, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
static void show_multicast_interfaces(struct pim_instance *pim, struct vty *vty,
|
|
bool uj)
|
|
{
|
|
struct interface *ifp;
|
|
char buf[PREFIX_STRLEN];
|
|
json_object *json = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
else
|
|
vty_out(vty,
|
|
"Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut\n");
|
|
|
|
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
|
struct pim_interface *pim_ifp;
|
|
struct in_addr ifaddr;
|
|
struct sioc_vif_req vreq;
|
|
|
|
pim_ifp = ifp->info;
|
|
|
|
if (!pim_ifp)
|
|
continue;
|
|
|
|
memset(&vreq, 0, sizeof(vreq));
|
|
vreq.vifi = pim_ifp->mroute_vif_index;
|
|
|
|
if (ioctl(pim->mroute_socket, SIOCGETVIFCNT, &vreq)) {
|
|
zlog_warn(
|
|
"ioctl(SIOCGETVIFCNT=%lu) failure for interface %s vif_index=%d: errno=%d: %s",
|
|
(unsigned long)SIOCGETVIFCNT, ifp->name,
|
|
pim_ifp->mroute_vif_index, errno,
|
|
safe_strerror(errno));
|
|
}
|
|
|
|
ifaddr = pim_ifp->primary_address;
|
|
if (uj) {
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "name", ifp->name);
|
|
json_object_string_add(json_row, "state",
|
|
if_is_up(ifp) ? "up" : "down");
|
|
json_object_string_add(
|
|
json_row, "address",
|
|
inet_ntop(AF_INET, &pim_ifp->primary_address,
|
|
buf, sizeof(buf)));
|
|
json_object_int_add(json_row, "ifIndex", ifp->ifindex);
|
|
json_object_int_add(json_row, "vif",
|
|
pim_ifp->mroute_vif_index);
|
|
json_object_int_add(json_row, "pktsIn",
|
|
(unsigned long)vreq.icount);
|
|
json_object_int_add(json_row, "pktsOut",
|
|
(unsigned long)vreq.ocount);
|
|
json_object_int_add(json_row, "bytesIn",
|
|
(unsigned long)vreq.ibytes);
|
|
json_object_int_add(json_row, "bytesOut",
|
|
(unsigned long)vreq.obytes);
|
|
json_object_object_add(json, ifp->name, json_row);
|
|
} else {
|
|
vty_out(vty,
|
|
"%-16s %-15s %3d %3d %7lu %7lu %10lu %10lu\n",
|
|
ifp->name,
|
|
inet_ntop(AF_INET, &ifaddr, buf, sizeof(buf)),
|
|
ifp->ifindex, pim_ifp->mroute_vif_index,
|
|
(unsigned long)vreq.icount,
|
|
(unsigned long)vreq.ocount,
|
|
(unsigned long)vreq.ibytes,
|
|
(unsigned long)vreq.obytes);
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n",
|
|
json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void pim_cmd_show_ip_multicast_helper(struct pim_instance *pim,
|
|
struct vty *vty)
|
|
{
|
|
struct vrf *vrf = pim->vrf;
|
|
time_t now = pim_time_monotonic_sec();
|
|
char uptime[10];
|
|
char mlag_role[80];
|
|
|
|
pim = vrf->info;
|
|
|
|
vty_out(vty, "Router MLAG Role: %s\n",
|
|
mlag_role2str(router->mlag_role, mlag_role, sizeof(mlag_role)));
|
|
vty_out(vty, "Mroute socket descriptor:");
|
|
|
|
vty_out(vty, " %d(%s)\n", pim->mroute_socket, vrf->name);
|
|
|
|
pim_time_uptime(uptime, sizeof(uptime),
|
|
now - pim->mroute_socket_creation);
|
|
vty_out(vty, "Mroute socket uptime: %s\n", uptime);
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
pim_zebra_zclient_update(vty);
|
|
pim_zlookup_show_ip_multicast(vty);
|
|
|
|
vty_out(vty, "\n");
|
|
vty_out(vty, "Maximum highest VifIndex: %d\n", PIM_MAX_USABLE_VIFS);
|
|
|
|
vty_out(vty, "\n");
|
|
vty_out(vty, "Upstream Join Timer: %d secs\n", router->t_periodic);
|
|
vty_out(vty, "Join/Prune Holdtime: %d secs\n", PIM_JP_HOLDTIME);
|
|
vty_out(vty, "PIM ECMP: %s\n", pim->ecmp_enable ? "Enable" : "Disable");
|
|
vty_out(vty, "PIM ECMP Rebalance: %s\n",
|
|
pim->ecmp_rebalance_enable ? "Enable" : "Disable");
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
show_rpf_refresh_stats(vty, pim, now, NULL);
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
show_scan_oil_stats(pim, vty, now);
|
|
|
|
show_multicast_interfaces(pim, vty, false);
|
|
}
|
|
|
|
DEFUN (show_ip_multicast,
|
|
show_ip_multicast_cmd,
|
|
"show ip multicast [vrf NAME]",
|
|
SHOW_STR
|
|
IP_STR
|
|
VRF_CMD_HELP_STR
|
|
"Multicast global information\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_cmd_show_ip_multicast_helper(vrf->info, vty);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_multicast_vrf_all,
|
|
show_ip_multicast_vrf_all_cmd,
|
|
"show ip multicast vrf all",
|
|
SHOW_STR
|
|
IP_STR
|
|
VRF_CMD_HELP_STR
|
|
"Multicast global information\n")
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
pim_cmd_show_ip_multicast_helper(vrf->info, vty);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN(show_ip_multicast_count,
|
|
show_ip_multicast_count_cmd,
|
|
"show ip multicast count [vrf NAME] [json]",
|
|
SHOW_STR IP_STR
|
|
"Multicast global information\n"
|
|
"Data packet count\n"
|
|
VRF_CMD_HELP_STR JSON_STR)
|
|
{
|
|
int idx = 3;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
show_multicast_interfaces(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN(show_ip_multicast_count_vrf_all,
|
|
show_ip_multicast_count_vrf_all_cmd,
|
|
"show ip multicast count vrf all [json]",
|
|
SHOW_STR IP_STR
|
|
"Multicast global information\n"
|
|
"Data packet count\n"
|
|
VRF_CMD_HELP_STR JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
|
|
show_multicast_interfaces(vrf->info, vty, uj);
|
|
}
|
|
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
static void show_mroute(struct pim_instance *pim, struct vty *vty,
|
|
struct prefix_sg *sg, bool fill, bool uj)
|
|
{
|
|
struct listnode *node;
|
|
struct channel_oil *c_oil;
|
|
struct static_route *s_route;
|
|
time_t now;
|
|
json_object *json = NULL;
|
|
json_object *json_group = NULL;
|
|
json_object *json_source = NULL;
|
|
json_object *json_oil = NULL;
|
|
json_object *json_ifp_out = NULL;
|
|
int found_oif;
|
|
int first;
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char in_ifname[INTERFACE_NAMSIZ + 1];
|
|
char out_ifname[INTERFACE_NAMSIZ + 1];
|
|
int oif_vif_index;
|
|
struct interface *ifp_in;
|
|
char proto[100];
|
|
char state_str[PIM_REG_STATE_STR_LEN];
|
|
char mroute_uptime[10];
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
} else {
|
|
vty_out(vty, "IP Multicast Routing Table\n");
|
|
vty_out(vty, "Flags: S - Sparse, C - Connected, P - Pruned\n");
|
|
vty_out(vty,
|
|
" R - SGRpt Pruned, F - Register flag, T - SPT-bit set\n");
|
|
vty_out(vty,
|
|
"\nSource Group Flags Proto Input Output TTL Uptime\n");
|
|
}
|
|
|
|
now = pim_time_monotonic_sec();
|
|
|
|
/* print list of PIM and IGMP routes */
|
|
frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
|
|
found_oif = 0;
|
|
first = 1;
|
|
if (!c_oil->installed)
|
|
continue;
|
|
|
|
if (sg->grp.s_addr != INADDR_ANY
|
|
&& sg->grp.s_addr != c_oil->oil.mfcc_mcastgrp.s_addr)
|
|
continue;
|
|
if (sg->src.s_addr != INADDR_ANY
|
|
&& sg->src.s_addr != c_oil->oil.mfcc_origin.s_addr)
|
|
continue;
|
|
|
|
pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, grp_str,
|
|
sizeof(grp_str));
|
|
pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, src_str,
|
|
sizeof(src_str));
|
|
|
|
strlcpy(state_str, "S", sizeof(state_str));
|
|
/* When a non DR receives a igmp join, it creates a (*,G)
|
|
* channel_oil without any upstream creation */
|
|
if (c_oil->up) {
|
|
if (PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(c_oil->up->flags))
|
|
strlcat(state_str, "C", sizeof(state_str));
|
|
if (pim_upstream_is_sg_rpt(c_oil->up))
|
|
strlcat(state_str, "R", sizeof(state_str));
|
|
if (PIM_UPSTREAM_FLAG_TEST_FHR(c_oil->up->flags))
|
|
strlcat(state_str, "F", sizeof(state_str));
|
|
if (c_oil->up->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
|
|
strlcat(state_str, "T", sizeof(state_str));
|
|
}
|
|
if (pim_channel_oil_empty(c_oil))
|
|
strlcat(state_str, "P", sizeof(state_str));
|
|
|
|
ifp_in = pim_if_find_by_vif_index(pim, c_oil->oil.mfcc_parent);
|
|
|
|
if (ifp_in)
|
|
strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
|
|
else
|
|
strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
|
|
|
|
|
|
pim_time_uptime(mroute_uptime, sizeof(mroute_uptime),
|
|
now - c_oil->mroute_creation);
|
|
|
|
if (uj) {
|
|
|
|
/* Find the group, create it if it doesn't exist */
|
|
json_object_object_get_ex(json, grp_str, &json_group);
|
|
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_object_add(json, grp_str,
|
|
json_group);
|
|
}
|
|
|
|
/* Find the source nested under the group, create it if
|
|
* it doesn't exist
|
|
*/
|
|
json_object_object_get_ex(json_group, src_str,
|
|
&json_source);
|
|
|
|
if (!json_source) {
|
|
json_source = json_object_new_object();
|
|
json_object_object_add(json_group, src_str,
|
|
json_source);
|
|
}
|
|
|
|
/* Find the inbound interface nested under the source,
|
|
* create it if it doesn't exist */
|
|
json_object_int_add(json_source, "installed",
|
|
c_oil->installed);
|
|
json_object_int_add(json_source, "refCount",
|
|
c_oil->oil_ref_count);
|
|
json_object_int_add(json_source, "oilSize",
|
|
c_oil->oil_size);
|
|
json_object_int_add(json_source, "OilInheritedRescan",
|
|
c_oil->oil_inherited_rescan);
|
|
json_object_string_add(json_source, "iif", in_ifname);
|
|
json_object_string_add(json_source, "upTime",
|
|
mroute_uptime);
|
|
json_oil = NULL;
|
|
}
|
|
|
|
for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
|
|
++oif_vif_index) {
|
|
struct interface *ifp_out;
|
|
int ttl;
|
|
|
|
ttl = c_oil->oil.mfcc_ttls[oif_vif_index];
|
|
if (ttl < 1)
|
|
continue;
|
|
|
|
/* do not display muted OIFs */
|
|
if (c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_MUTE)
|
|
continue;
|
|
|
|
if (c_oil->oil.mfcc_parent == oif_vif_index &&
|
|
!pim_mroute_allow_iif_in_oil(c_oil,
|
|
oif_vif_index))
|
|
continue;
|
|
|
|
ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
|
|
found_oif = 1;
|
|
|
|
if (ifp_out)
|
|
strlcpy(out_ifname, ifp_out->name, sizeof(out_ifname));
|
|
else
|
|
strlcpy(out_ifname, "<oif?>", sizeof(out_ifname));
|
|
|
|
if (uj) {
|
|
json_ifp_out = json_object_new_object();
|
|
json_object_string_add(json_ifp_out, "source",
|
|
src_str);
|
|
json_object_string_add(json_ifp_out, "group",
|
|
grp_str);
|
|
|
|
if (c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_PIM)
|
|
json_object_boolean_true_add(
|
|
json_ifp_out, "protocolPim");
|
|
|
|
if (c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_IGMP)
|
|
json_object_boolean_true_add(
|
|
json_ifp_out, "protocolIgmp");
|
|
|
|
if (c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_VXLAN)
|
|
json_object_boolean_true_add(
|
|
json_ifp_out, "protocolVxlan");
|
|
|
|
if (c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_STAR)
|
|
json_object_boolean_true_add(
|
|
json_ifp_out,
|
|
"protocolInherited");
|
|
|
|
json_object_string_add(json_ifp_out,
|
|
"inboundInterface",
|
|
in_ifname);
|
|
json_object_int_add(json_ifp_out, "iVifI",
|
|
c_oil->oil.mfcc_parent);
|
|
json_object_string_add(json_ifp_out,
|
|
"outboundInterface",
|
|
out_ifname);
|
|
json_object_int_add(json_ifp_out, "oVifI",
|
|
oif_vif_index);
|
|
json_object_int_add(json_ifp_out, "ttl", ttl);
|
|
json_object_string_add(json_ifp_out, "upTime",
|
|
mroute_uptime);
|
|
json_object_string_add(json_source, "flags",
|
|
state_str);
|
|
if (!json_oil) {
|
|
json_oil = json_object_new_object();
|
|
json_object_object_add(json_source,
|
|
"oil", json_oil);
|
|
}
|
|
json_object_object_add(json_oil, out_ifname,
|
|
json_ifp_out);
|
|
} else {
|
|
proto[0] = '\0';
|
|
if (c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_PIM) {
|
|
strlcpy(proto, "PIM", sizeof(proto));
|
|
}
|
|
|
|
if (c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_IGMP) {
|
|
strlcpy(proto, "IGMP", sizeof(proto));
|
|
}
|
|
|
|
if (c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_VXLAN) {
|
|
strlcpy(proto, "VxLAN", sizeof(proto));
|
|
}
|
|
|
|
if (c_oil->oif_flags[oif_vif_index]
|
|
& PIM_OIF_FLAG_PROTO_STAR) {
|
|
strlcpy(proto, "STAR", sizeof(proto));
|
|
}
|
|
|
|
vty_out(vty,
|
|
"%-15s %-15s %-8s %-6s %-16s %-16s %-3d %8s\n",
|
|
src_str, grp_str, state_str, proto,
|
|
in_ifname, out_ifname, ttl,
|
|
mroute_uptime);
|
|
|
|
if (first) {
|
|
src_str[0] = '\0';
|
|
grp_str[0] = '\0';
|
|
in_ifname[0] = '\0';
|
|
state_str[0] = '\0';
|
|
mroute_uptime[0] = '\0';
|
|
first = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!uj && !found_oif) {
|
|
vty_out(vty,
|
|
"%-15s %-15s %-15s %-6s %-16s %-16s %-3d %8s\n",
|
|
src_str, grp_str, state_str, "none", in_ifname,
|
|
"none", 0, "--:--:--");
|
|
}
|
|
}
|
|
|
|
/* Print list of static routes */
|
|
for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
|
|
first = 1;
|
|
|
|
if (!s_route->c_oil.installed)
|
|
continue;
|
|
|
|
pim_inet4_dump("<group?>", s_route->group, grp_str,
|
|
sizeof(grp_str));
|
|
pim_inet4_dump("<source?>", s_route->source, src_str,
|
|
sizeof(src_str));
|
|
ifp_in = pim_if_find_by_vif_index(pim, s_route->iif);
|
|
found_oif = 0;
|
|
|
|
if (ifp_in)
|
|
strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
|
|
else
|
|
strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
|
|
|
|
if (uj) {
|
|
|
|
/* Find the group, create it if it doesn't exist */
|
|
json_object_object_get_ex(json, grp_str, &json_group);
|
|
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_object_add(json, grp_str,
|
|
json_group);
|
|
}
|
|
|
|
/* Find the source nested under the group, create it if
|
|
* it doesn't exist */
|
|
json_object_object_get_ex(json_group, src_str,
|
|
&json_source);
|
|
|
|
if (!json_source) {
|
|
json_source = json_object_new_object();
|
|
json_object_object_add(json_group, src_str,
|
|
json_source);
|
|
}
|
|
|
|
json_object_string_add(json_source, "iif", in_ifname);
|
|
json_oil = NULL;
|
|
} else {
|
|
strlcpy(proto, "STATIC", sizeof(proto));
|
|
}
|
|
|
|
for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
|
|
++oif_vif_index) {
|
|
struct interface *ifp_out;
|
|
char oif_uptime[10];
|
|
int ttl;
|
|
|
|
ttl = s_route->oif_ttls[oif_vif_index];
|
|
if (ttl < 1)
|
|
continue;
|
|
|
|
ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
|
|
pim_time_uptime(
|
|
oif_uptime, sizeof(oif_uptime),
|
|
now
|
|
- s_route->c_oil
|
|
.oif_creation[oif_vif_index]);
|
|
found_oif = 1;
|
|
|
|
if (ifp_out)
|
|
strlcpy(out_ifname, ifp_out->name, sizeof(out_ifname));
|
|
else
|
|
strlcpy(out_ifname, "<oif?>", sizeof(out_ifname));
|
|
|
|
if (uj) {
|
|
json_ifp_out = json_object_new_object();
|
|
json_object_string_add(json_ifp_out, "source",
|
|
src_str);
|
|
json_object_string_add(json_ifp_out, "group",
|
|
grp_str);
|
|
json_object_boolean_true_add(json_ifp_out,
|
|
"protocolStatic");
|
|
json_object_string_add(json_ifp_out,
|
|
"inboundInterface",
|
|
in_ifname);
|
|
json_object_int_add(
|
|
json_ifp_out, "iVifI",
|
|
s_route->c_oil.oil.mfcc_parent);
|
|
json_object_string_add(json_ifp_out,
|
|
"outboundInterface",
|
|
out_ifname);
|
|
json_object_int_add(json_ifp_out, "oVifI",
|
|
oif_vif_index);
|
|
json_object_int_add(json_ifp_out, "ttl", ttl);
|
|
json_object_string_add(json_ifp_out, "upTime",
|
|
oif_uptime);
|
|
if (!json_oil) {
|
|
json_oil = json_object_new_object();
|
|
json_object_object_add(json_source,
|
|
"oil", json_oil);
|
|
}
|
|
json_object_object_add(json_oil, out_ifname,
|
|
json_ifp_out);
|
|
} else {
|
|
vty_out(vty,
|
|
"%-15s %-15s %-6s %-16s %-16s %-3d %8s %s\n",
|
|
src_str, grp_str, proto, in_ifname,
|
|
out_ifname, ttl, oif_uptime,
|
|
pim->vrf->name);
|
|
if (first && !fill) {
|
|
src_str[0] = '\0';
|
|
grp_str[0] = '\0';
|
|
in_ifname[0] = '\0';
|
|
first = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!uj && !found_oif) {
|
|
vty_out(vty,
|
|
"%-15s %-15s %-6s %-16s %-16s %-3d %8s %s\n",
|
|
src_str, grp_str, proto, in_ifname, "none", 0,
|
|
"--:--:--", pim->vrf->name);
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
DEFPY (show_ip_mroute,
|
|
show_ip_mroute_cmd,
|
|
"show ip mroute [vrf NAME] [A.B.C.D$s_or_g [A.B.C.D$g]] [fill$fill] [json$json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
MROUTE_STR
|
|
VRF_CMD_HELP_STR
|
|
"The Source or Group\n"
|
|
"The Group\n"
|
|
"Fill in Assumed data\n"
|
|
JSON_STR)
|
|
{
|
|
struct prefix_sg sg = {0};
|
|
struct pim_instance *pim;
|
|
struct vrf *v;
|
|
|
|
v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
|
|
|
|
if (!v) {
|
|
vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
|
|
return CMD_WARNING;
|
|
}
|
|
pim = pim_get_pim_instance(v->vrf_id);
|
|
|
|
if (!pim) {
|
|
vty_out(vty, "%% Unable to find pim instance\n");
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
if (s_or_g.s_addr != INADDR_ANY) {
|
|
if (g.s_addr != INADDR_ANY) {
|
|
sg.src = s_or_g;
|
|
sg.grp = g;
|
|
} else
|
|
sg.grp = s_or_g;
|
|
}
|
|
show_mroute(pim, vty, &sg, !!fill, !!json);
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_mroute_vrf_all,
|
|
show_ip_mroute_vrf_all_cmd,
|
|
"show ip mroute vrf all [fill] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
MROUTE_STR
|
|
VRF_CMD_HELP_STR
|
|
"Fill in Assumed data\n"
|
|
JSON_STR)
|
|
{
|
|
struct prefix_sg sg = {0};
|
|
bool uj = use_json(argc, argv);
|
|
int idx = 4;
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
bool fill = false;
|
|
|
|
if (argv_find(argv, argc, "fill", &idx))
|
|
fill = true;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
show_mroute(vrf->info, vty, &sg, fill, uj);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (clear_ip_mroute_count,
|
|
clear_ip_mroute_count_cmd,
|
|
"clear ip mroute [vrf NAME] count",
|
|
CLEAR_STR
|
|
IP_STR
|
|
MROUTE_STR
|
|
VRF_CMD_HELP_STR
|
|
"Route and packet count data\n")
|
|
{
|
|
int idx = 2;
|
|
struct listnode *node;
|
|
struct channel_oil *c_oil;
|
|
struct static_route *sr;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
struct pim_instance *pim;
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim = vrf->info;
|
|
frr_each(rb_pim_oil, &pim->channel_oil_head, c_oil) {
|
|
if (!c_oil->installed)
|
|
continue;
|
|
|
|
pim_mroute_update_counters(c_oil);
|
|
c_oil->cc.origpktcnt = c_oil->cc.pktcnt;
|
|
c_oil->cc.origbytecnt = c_oil->cc.bytecnt;
|
|
c_oil->cc.origwrong_if = c_oil->cc.wrong_if;
|
|
}
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sr)) {
|
|
if (!sr->c_oil.installed)
|
|
continue;
|
|
|
|
pim_mroute_update_counters(&sr->c_oil);
|
|
|
|
sr->c_oil.cc.origpktcnt = sr->c_oil.cc.pktcnt;
|
|
sr->c_oil.cc.origbytecnt = sr->c_oil.cc.bytecnt;
|
|
sr->c_oil.cc.origwrong_if = sr->c_oil.cc.wrong_if;
|
|
}
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
static void show_mroute_count_per_channel_oil(struct channel_oil *c_oil,
|
|
json_object *json,
|
|
struct vty *vty)
|
|
{
|
|
char group_str[INET_ADDRSTRLEN];
|
|
char source_str[INET_ADDRSTRLEN];
|
|
json_object *json_group = NULL;
|
|
json_object *json_source = NULL;
|
|
|
|
if (!c_oil->installed)
|
|
return;
|
|
|
|
pim_mroute_update_counters(c_oil);
|
|
|
|
pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str,
|
|
sizeof(group_str));
|
|
pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str,
|
|
sizeof(source_str));
|
|
|
|
if (json) {
|
|
json_object_object_get_ex(json, group_str, &json_group);
|
|
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_object_add(json, group_str, json_group);
|
|
}
|
|
|
|
json_source = json_object_new_object();
|
|
json_object_object_add(json_group, source_str, json_source);
|
|
json_object_int_add(json_source, "lastUsed",
|
|
c_oil->cc.lastused / 100);
|
|
json_object_int_add(json_source, "packets", c_oil->cc.pktcnt);
|
|
json_object_int_add(json_source, "bytes", c_oil->cc.bytecnt);
|
|
json_object_int_add(json_source, "wrongIf", c_oil->cc.wrong_if);
|
|
|
|
} else {
|
|
vty_out(vty, "%-15s %-15s %-8llu %-7ld %-10ld %-7ld\n",
|
|
source_str, group_str, c_oil->cc.lastused / 100,
|
|
c_oil->cc.pktcnt - c_oil->cc.origpktcnt,
|
|
c_oil->cc.bytecnt - c_oil->cc.origbytecnt,
|
|
c_oil->cc.wrong_if - c_oil->cc.origwrong_if);
|
|
}
|
|
}
|
|
|
|
static void show_mroute_count(struct pim_instance *pim, struct vty *vty,
|
|
bool uj)
|
|
{
|
|
struct listnode *node;
|
|
struct channel_oil *c_oil;
|
|
struct static_route *sr;
|
|
json_object *json = NULL;
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
else {
|
|
vty_out(vty, "\n");
|
|
|
|
vty_out(vty,
|
|
"Source Group LastUsed Packets Bytes WrongIf \n");
|
|
}
|
|
|
|
/* Print PIM and IGMP route counts */
|
|
frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil)
|
|
show_mroute_count_per_channel_oil(c_oil, json, vty);
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sr))
|
|
show_mroute_count_per_channel_oil(&sr->c_oil, json, vty);
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n",
|
|
json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
DEFUN (show_ip_mroute_count,
|
|
show_ip_mroute_count_cmd,
|
|
"show ip mroute [vrf NAME] count [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
MROUTE_STR
|
|
VRF_CMD_HELP_STR
|
|
"Route and packet count data\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
show_mroute_count(vrf->info, vty, uj);
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_mroute_count_vrf_all,
|
|
show_ip_mroute_count_vrf_all_cmd,
|
|
"show ip mroute vrf all count [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
MROUTE_STR
|
|
VRF_CMD_HELP_STR
|
|
"Route and packet count data\n"
|
|
JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
show_mroute_count(vrf->info, vty, uj);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
static void show_mroute_summary(struct pim_instance *pim, struct vty *vty,
|
|
json_object *json)
|
|
{
|
|
struct listnode *node;
|
|
struct channel_oil *c_oil;
|
|
struct static_route *s_route;
|
|
uint32_t starg_sw_mroute_cnt = 0;
|
|
uint32_t sg_sw_mroute_cnt = 0;
|
|
uint32_t starg_hw_mroute_cnt = 0;
|
|
uint32_t sg_hw_mroute_cnt = 0;
|
|
json_object *json_starg = NULL;
|
|
json_object *json_sg = NULL;
|
|
|
|
if (!json)
|
|
vty_out(vty, "Mroute Type Installed/Total\n");
|
|
|
|
frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
|
|
if (!c_oil->installed) {
|
|
if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
|
|
starg_sw_mroute_cnt++;
|
|
else
|
|
sg_sw_mroute_cnt++;
|
|
} else {
|
|
if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
|
|
starg_hw_mroute_cnt++;
|
|
else
|
|
sg_hw_mroute_cnt++;
|
|
}
|
|
}
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
|
|
if (!s_route->c_oil.installed) {
|
|
if (s_route->c_oil.oil.mfcc_origin.s_addr == INADDR_ANY)
|
|
starg_sw_mroute_cnt++;
|
|
else
|
|
sg_sw_mroute_cnt++;
|
|
} else {
|
|
if (s_route->c_oil.oil.mfcc_origin.s_addr == INADDR_ANY)
|
|
starg_hw_mroute_cnt++;
|
|
else
|
|
sg_hw_mroute_cnt++;
|
|
}
|
|
}
|
|
|
|
if (!json) {
|
|
vty_out(vty, "%-20s %u/%u\n", "(*, G)", starg_hw_mroute_cnt,
|
|
starg_sw_mroute_cnt + starg_hw_mroute_cnt);
|
|
vty_out(vty, "%-20s %u/%u\n", "(S, G)", sg_hw_mroute_cnt,
|
|
sg_sw_mroute_cnt + sg_hw_mroute_cnt);
|
|
vty_out(vty, "------\n");
|
|
vty_out(vty, "%-20s %u/%u\n", "Total",
|
|
(starg_hw_mroute_cnt + sg_hw_mroute_cnt),
|
|
(starg_sw_mroute_cnt + starg_hw_mroute_cnt
|
|
+ sg_sw_mroute_cnt + sg_hw_mroute_cnt));
|
|
} else {
|
|
/* (*,G) route details */
|
|
json_starg = json_object_new_object();
|
|
json_object_object_add(json, "wildcardGroup", json_starg);
|
|
|
|
json_object_int_add(json_starg, "installed",
|
|
starg_hw_mroute_cnt);
|
|
json_object_int_add(json_starg, "total",
|
|
starg_sw_mroute_cnt + starg_hw_mroute_cnt);
|
|
|
|
/* (S, G) route details */
|
|
json_sg = json_object_new_object();
|
|
json_object_object_add(json, "sourceGroup", json_sg);
|
|
|
|
json_object_int_add(json_sg, "installed", sg_hw_mroute_cnt);
|
|
json_object_int_add(json_sg, "total",
|
|
sg_sw_mroute_cnt + sg_hw_mroute_cnt);
|
|
|
|
json_object_int_add(json, "totalNumOfInstalledMroutes",
|
|
starg_hw_mroute_cnt + sg_hw_mroute_cnt);
|
|
json_object_int_add(json, "totalNumOfMroutes",
|
|
starg_sw_mroute_cnt + starg_hw_mroute_cnt
|
|
+ sg_sw_mroute_cnt
|
|
+ sg_hw_mroute_cnt);
|
|
}
|
|
}
|
|
|
|
DEFUN (show_ip_mroute_summary,
|
|
show_ip_mroute_summary_cmd,
|
|
"show ip mroute [vrf NAME] summary [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
MROUTE_STR
|
|
VRF_CMD_HELP_STR
|
|
"Summary of all mroutes\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
json_object *json = NULL;
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
show_mroute_summary(vrf->info, vty, json);
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n",
|
|
json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_mroute_summary_vrf_all,
|
|
show_ip_mroute_summary_vrf_all_cmd,
|
|
"show ip mroute vrf all summary [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
MROUTE_STR
|
|
VRF_CMD_HELP_STR
|
|
"Summary of all mroutes\n"
|
|
JSON_STR)
|
|
{
|
|
struct vrf *vrf;
|
|
bool uj = use_json(argc, argv);
|
|
json_object *json = NULL;
|
|
json_object *json_vrf = NULL;
|
|
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj)
|
|
json_vrf = json_object_new_object();
|
|
else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
|
|
show_mroute_summary(vrf->info, vty, json_vrf);
|
|
|
|
if (uj)
|
|
json_object_object_add(json, vrf->name, json_vrf);
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n",
|
|
json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_rib,
|
|
show_ip_rib_cmd,
|
|
"show ip rib [vrf NAME] A.B.C.D",
|
|
SHOW_STR
|
|
IP_STR
|
|
RIB_STR
|
|
VRF_CMD_HELP_STR
|
|
"Unicast address\n")
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
struct in_addr addr;
|
|
const char *addr_str;
|
|
struct pim_nexthop nexthop;
|
|
char nexthop_addr_str[PREFIX_STRLEN];
|
|
int result;
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
memset(&nexthop, 0, sizeof(nexthop));
|
|
argv_find(argv, argc, "A.B.C.D", &idx);
|
|
addr_str = argv[idx]->arg;
|
|
result = inet_pton(AF_INET, addr_str, &addr);
|
|
if (result <= 0) {
|
|
vty_out(vty, "Bad unicast address %s: errno=%d: %s\n", addr_str,
|
|
errno, safe_strerror(errno));
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
if (!pim_nexthop_lookup(vrf->info, &nexthop, addr, 0)) {
|
|
vty_out(vty,
|
|
"Failure querying RIB nexthop for unicast address %s\n",
|
|
addr_str);
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
vty_out(vty,
|
|
"Address NextHop Interface Metric Preference\n");
|
|
|
|
pim_addr_dump("<nexthop?>", &nexthop.mrib_nexthop_addr,
|
|
nexthop_addr_str, sizeof(nexthop_addr_str));
|
|
|
|
vty_out(vty, "%-15s %-15s %-9s %6d %10d\n", addr_str, nexthop_addr_str,
|
|
nexthop.interface ? nexthop.interface->name : "<ifname?>",
|
|
nexthop.mrib_route_metric, nexthop.mrib_metric_preference);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
static void show_ssmpingd(struct pim_instance *pim, struct vty *vty)
|
|
{
|
|
struct listnode *node;
|
|
struct ssmpingd_sock *ss;
|
|
time_t now;
|
|
|
|
vty_out(vty,
|
|
"Source Socket Address Port Uptime Requests\n");
|
|
|
|
if (!pim->ssmpingd_list)
|
|
return;
|
|
|
|
now = pim_time_monotonic_sec();
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim->ssmpingd_list, node, ss)) {
|
|
char source_str[INET_ADDRSTRLEN];
|
|
char ss_uptime[10];
|
|
struct sockaddr_in bind_addr;
|
|
socklen_t len = sizeof(bind_addr);
|
|
char bind_addr_str[INET_ADDRSTRLEN];
|
|
|
|
pim_inet4_dump("<src?>", ss->source_addr, source_str,
|
|
sizeof(source_str));
|
|
|
|
if (pim_socket_getsockname(
|
|
ss->sock_fd, (struct sockaddr *)&bind_addr, &len)) {
|
|
vty_out(vty,
|
|
"%% Failure reading socket name for ssmpingd source %s on fd=%d\n",
|
|
source_str, ss->sock_fd);
|
|
}
|
|
|
|
pim_inet4_dump("<addr?>", bind_addr.sin_addr, bind_addr_str,
|
|
sizeof(bind_addr_str));
|
|
pim_time_uptime(ss_uptime, sizeof(ss_uptime),
|
|
now - ss->creation);
|
|
|
|
vty_out(vty, "%-15s %6d %-15s %5d %8s %8lld\n", source_str,
|
|
ss->sock_fd, bind_addr_str, ntohs(bind_addr.sin_port),
|
|
ss_uptime, (long long)ss->requests);
|
|
}
|
|
}
|
|
|
|
DEFUN (show_ip_ssmpingd,
|
|
show_ip_ssmpingd_cmd,
|
|
"show ip ssmpingd [vrf NAME]",
|
|
SHOW_STR
|
|
IP_STR
|
|
SHOW_SSMPINGD_STR
|
|
VRF_CMD_HELP_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
show_ssmpingd(vrf->info, vty);
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (ip_pim_spt_switchover_infinity,
|
|
ip_pim_spt_switchover_infinity_cmd,
|
|
"ip pim spt-switchover infinity-and-beyond",
|
|
IP_STR
|
|
PIM_STR
|
|
"SPT-Switchover\n"
|
|
"Never switch to SPT Tree\n")
|
|
{
|
|
const char *vrfname;
|
|
char spt_plist_xpath[XPATH_MAXLEN];
|
|
char spt_action_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
|
|
FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
|
|
"frr-routing:ipv4");
|
|
strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
|
|
sizeof(spt_plist_xpath));
|
|
|
|
snprintf(spt_action_xpath, sizeof(spt_action_xpath),
|
|
FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
|
|
"frr-routing:ipv4");
|
|
strlcat(spt_action_xpath, "/spt-switchover/spt-action",
|
|
sizeof(spt_action_xpath));
|
|
|
|
if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath))
|
|
nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY,
|
|
NULL);
|
|
nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
|
|
"PIM_SPT_INFINITY");
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (ip_pim_spt_switchover_infinity_plist,
|
|
ip_pim_spt_switchover_infinity_plist_cmd,
|
|
"ip pim spt-switchover infinity-and-beyond prefix-list WORD",
|
|
IP_STR
|
|
PIM_STR
|
|
"SPT-Switchover\n"
|
|
"Never switch to SPT Tree\n"
|
|
"Prefix-List to control which groups to switch\n"
|
|
"Prefix-List name\n")
|
|
{
|
|
const char *vrfname;
|
|
char spt_plist_xpath[XPATH_MAXLEN];
|
|
char spt_action_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
|
|
FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
|
|
"frr-routing:ipv4");
|
|
strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
|
|
sizeof(spt_plist_xpath));
|
|
|
|
snprintf(spt_action_xpath, sizeof(spt_action_xpath),
|
|
FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
|
|
"frr-routing:ipv4");
|
|
strlcat(spt_action_xpath, "/spt-switchover/spt-action",
|
|
sizeof(spt_action_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
|
|
"PIM_SPT_INFINITY");
|
|
nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY,
|
|
argv[5]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_pim_spt_switchover_infinity,
|
|
no_ip_pim_spt_switchover_infinity_cmd,
|
|
"no ip pim spt-switchover infinity-and-beyond",
|
|
NO_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"SPT_Switchover\n"
|
|
"Never switch to SPT Tree\n")
|
|
{
|
|
const char *vrfname;
|
|
char spt_plist_xpath[XPATH_MAXLEN];
|
|
char spt_action_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
|
|
FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
|
|
"frr-routing:ipv4");
|
|
strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
|
|
sizeof(spt_plist_xpath));
|
|
|
|
snprintf(spt_action_xpath, sizeof(spt_action_xpath),
|
|
FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
|
|
"frr-routing:ipv4");
|
|
strlcat(spt_action_xpath, "/spt-switchover/spt-action",
|
|
sizeof(spt_action_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL);
|
|
nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
|
|
"PIM_SPT_IMMEDIATE");
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_pim_spt_switchover_infinity_plist,
|
|
no_ip_pim_spt_switchover_infinity_plist_cmd,
|
|
"no ip pim spt-switchover infinity-and-beyond prefix-list WORD",
|
|
NO_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"SPT_Switchover\n"
|
|
"Never switch to SPT Tree\n"
|
|
"Prefix-List to control which groups to switch\n"
|
|
"Prefix-List name\n")
|
|
{
|
|
const char *vrfname;
|
|
char spt_plist_xpath[XPATH_MAXLEN];
|
|
char spt_action_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
|
|
FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
|
|
"frr-routing:ipv4");
|
|
strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
|
|
sizeof(spt_plist_xpath));
|
|
|
|
snprintf(spt_action_xpath, sizeof(spt_action_xpath),
|
|
FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
|
|
"frr-routing:ipv4");
|
|
strlcat(spt_action_xpath, "/spt-switchover/spt-action",
|
|
sizeof(spt_action_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL);
|
|
nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
|
|
"PIM_SPT_IMMEDIATE");
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFPY (pim_register_accept_list,
|
|
pim_register_accept_list_cmd,
|
|
"[no] ip pim register-accept-list WORD$word",
|
|
NO_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"Only accept registers from a specific source prefix list\n"
|
|
"Prefix-List name\n")
|
|
{
|
|
const char *vrfname;
|
|
char reg_alist_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(reg_alist_xpath, sizeof(reg_alist_xpath),
|
|
FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname,
|
|
"frr-routing:ipv4");
|
|
strlcat(reg_alist_xpath, "/register-accept-list",
|
|
sizeof(reg_alist_xpath));
|
|
|
|
if (no)
|
|
nb_cli_enqueue_change(vty, reg_alist_xpath,
|
|
NB_OP_DESTROY, NULL);
|
|
else
|
|
nb_cli_enqueue_change(vty, reg_alist_xpath,
|
|
NB_OP_MODIFY, word);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (ip_pim_joinprune_time,
|
|
ip_pim_joinprune_time_cmd,
|
|
"ip pim join-prune-interval (60-600)",
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Join Prune Send Interval\n"
|
|
"Seconds\n")
|
|
{
|
|
nb_cli_enqueue_change(vty, "/frr-pim:pim/join-prune-interval",
|
|
NB_OP_MODIFY, argv[3]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_pim_joinprune_time,
|
|
no_ip_pim_joinprune_time_cmd,
|
|
"no ip pim join-prune-interval (60-600)",
|
|
NO_STR
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Join Prune Send Interval\n"
|
|
"Seconds\n")
|
|
{
|
|
char jp_default_timer[5];
|
|
|
|
snprintf(jp_default_timer, sizeof(jp_default_timer), "%d",
|
|
PIM_DEFAULT_T_PERIODIC);
|
|
|
|
nb_cli_enqueue_change(vty, "/frr-pim:pim/join-prune-interval",
|
|
NB_OP_MODIFY, jp_default_timer);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (ip_pim_register_suppress,
|
|
ip_pim_register_suppress_cmd,
|
|
"ip pim register-suppress-time (5-60000)",
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Register Suppress Timer\n"
|
|
"Seconds\n")
|
|
{
|
|
nb_cli_enqueue_change(vty, "/frr-pim:pim/register-suppress-time",
|
|
NB_OP_MODIFY, argv[3]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_pim_register_suppress,
|
|
no_ip_pim_register_suppress_cmd,
|
|
"no ip pim register-suppress-time (5-60000)",
|
|
NO_STR
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Register Suppress Timer\n"
|
|
"Seconds\n")
|
|
{
|
|
char rs_default_timer[5];
|
|
|
|
snprintf(rs_default_timer, sizeof(rs_default_timer), "%d",
|
|
PIM_REGISTER_SUPPRESSION_TIME_DEFAULT);
|
|
|
|
nb_cli_enqueue_change(vty, "/frr-pim:pim/register-suppress-time",
|
|
NB_OP_MODIFY, rs_default_timer);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (ip_pim_rp_keep_alive,
|
|
ip_pim_rp_keep_alive_cmd,
|
|
"ip pim rp keep-alive-timer (31-60000)",
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Rendevous Point\n"
|
|
"Keep alive Timer\n"
|
|
"Seconds\n")
|
|
{
|
|
const char *vrfname;
|
|
char rp_ka_timer_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
|
|
FRR_PIM_XPATH, "frr-pim:pimd", "pim", vrfname);
|
|
strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
|
|
sizeof(rp_ka_timer_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
|
|
argv[4]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_pim_rp_keep_alive,
|
|
no_ip_pim_rp_keep_alive_cmd,
|
|
"no ip pim rp keep-alive-timer (31-60000)",
|
|
NO_STR
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Rendevous Point\n"
|
|
"Keep alive Timer\n"
|
|
"Seconds\n")
|
|
{
|
|
const char *vrfname;
|
|
char rp_ka_timer[5];
|
|
char rp_ka_timer_xpath[XPATH_MAXLEN];
|
|
|
|
snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%d",
|
|
PIM_RP_KEEPALIVE_PERIOD);
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
|
|
FRR_PIM_XPATH, "frr-pim:pimd", "pim", vrfname);
|
|
strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
|
|
sizeof(rp_ka_timer_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
|
|
rp_ka_timer);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (ip_pim_keep_alive,
|
|
ip_pim_keep_alive_cmd,
|
|
"ip pim keep-alive-timer (31-60000)",
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Keep alive Timer\n"
|
|
"Seconds\n")
|
|
{
|
|
const char *vrfname;
|
|
char ka_timer_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname);
|
|
strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY,
|
|
argv[3]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_pim_keep_alive,
|
|
no_ip_pim_keep_alive_cmd,
|
|
"no ip pim keep-alive-timer (31-60000)",
|
|
NO_STR
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Keep alive Timer\n"
|
|
"Seconds\n")
|
|
{
|
|
const char *vrfname;
|
|
char ka_timer[5];
|
|
char ka_timer_xpath[XPATH_MAXLEN];
|
|
|
|
snprintf(ka_timer, sizeof(ka_timer), "%d", PIM_KEEPALIVE_PERIOD);
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname);
|
|
strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY,
|
|
ka_timer);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (ip_pim_packets,
|
|
ip_pim_packets_cmd,
|
|
"ip pim packets (1-100)",
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"packets to process at one time per fd\n"
|
|
"Number of packets\n")
|
|
{
|
|
nb_cli_enqueue_change(vty, "/frr-pim:pim/packets", NB_OP_MODIFY,
|
|
argv[3]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_pim_packets,
|
|
no_ip_pim_packets_cmd,
|
|
"no ip pim packets (1-100)",
|
|
NO_STR
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"packets to process at one time per fd\n"
|
|
"Number of packets\n")
|
|
{
|
|
char default_packet[3];
|
|
|
|
snprintf(default_packet, sizeof(default_packet), "%d",
|
|
PIM_DEFAULT_PACKET_PROCESS);
|
|
|
|
nb_cli_enqueue_change(vty, "/frr-pim:pim/packets", NB_OP_MODIFY,
|
|
default_packet);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFPY (igmp_group_watermark,
|
|
igmp_group_watermark_cmd,
|
|
"ip igmp watermark-warn (10-60000)$limit",
|
|
IP_STR
|
|
IGMP_STR
|
|
"Configure group limit for watermark warning\n"
|
|
"Group count to generate watermark warning\n")
|
|
{
|
|
PIM_DECLVAR_CONTEXT(vrf, pim);
|
|
pim->igmp_watermark_limit = limit;
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY (no_igmp_group_watermark,
|
|
no_igmp_group_watermark_cmd,
|
|
"no ip igmp watermark-warn [(10-60000)$limit]",
|
|
NO_STR
|
|
IP_STR
|
|
IGMP_STR
|
|
"Unconfigure group limit for watermark warning\n"
|
|
"Group count to generate watermark warning\n")
|
|
{
|
|
PIM_DECLVAR_CONTEXT(vrf, pim);
|
|
pim->igmp_watermark_limit = 0;
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (ip_pim_v6_secondary,
|
|
ip_pim_v6_secondary_cmd,
|
|
"ip pim send-v6-secondary",
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Send v6 secondary addresses\n")
|
|
{
|
|
const char *vrfname;
|
|
char send_v6_secondary_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(send_v6_secondary_xpath, "/send-v6-secondary",
|
|
sizeof(send_v6_secondary_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY,
|
|
"true");
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_pim_v6_secondary,
|
|
no_ip_pim_v6_secondary_cmd,
|
|
"no ip pim send-v6-secondary",
|
|
NO_STR
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Send v6 secondary addresses\n")
|
|
{
|
|
const char *vrfname;
|
|
char send_v6_secondary_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(send_v6_secondary_xpath, "/send-v6-secondary",
|
|
sizeof(send_v6_secondary_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY,
|
|
"false");
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (ip_pim_rp,
|
|
ip_pim_rp_cmd,
|
|
"ip pim rp A.B.C.D [A.B.C.D/M]",
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Rendevous Point\n"
|
|
"ip address of RP\n"
|
|
"Group Address range to cover\n")
|
|
{
|
|
const char *vrfname;
|
|
int idx_rp = 3, idx_group = 4;
|
|
char rp_group_xpath[XPATH_MAXLEN];
|
|
int result = 0;
|
|
struct prefix group;
|
|
struct in_addr rp_addr;
|
|
const char *group_str =
|
|
(argc == 5) ? argv[idx_group]->arg : "224.0.0.0/4";
|
|
|
|
result = str2prefix(group_str, &group);
|
|
if (result) {
|
|
struct prefix temp;
|
|
|
|
prefix_copy(&temp, &group);
|
|
apply_mask(&temp);
|
|
if (!prefix_same(&group, &temp)) {
|
|
vty_out(vty, "%% Inconsistent address and mask: %s\n",
|
|
group_str);
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
}
|
|
}
|
|
|
|
if (!result) {
|
|
vty_out(vty, "%% Bad group address specified: %s\n",
|
|
group_str);
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
}
|
|
|
|
result = inet_pton(AF_INET, argv[idx_rp]->arg, &rp_addr);
|
|
if (result <= 0) {
|
|
vty_out(vty, "%% Bad RP address specified: %s\n",
|
|
argv[idx_rp]->arg);
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
}
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(rp_group_xpath, sizeof(rp_group_xpath),
|
|
FRR_PIM_STATIC_RP_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4",
|
|
argv[idx_rp]->arg);
|
|
strlcat(rp_group_xpath, "/group-list", sizeof(rp_group_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, rp_group_xpath, NB_OP_CREATE, group_str);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (ip_pim_rp_prefix_list,
|
|
ip_pim_rp_prefix_list_cmd,
|
|
"ip pim rp A.B.C.D prefix-list WORD",
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Rendevous Point\n"
|
|
"ip address of RP\n"
|
|
"group prefix-list filter\n"
|
|
"Name of a prefix-list\n")
|
|
{
|
|
int idx_rp = 3, idx_plist = 5;
|
|
const char *vrfname;
|
|
char rp_plist_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(rp_plist_xpath, sizeof(rp_plist_xpath),
|
|
FRR_PIM_STATIC_RP_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4",
|
|
argv[idx_rp]->arg);
|
|
strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY,
|
|
argv[idx_plist]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_pim_rp,
|
|
no_ip_pim_rp_cmd,
|
|
"no ip pim rp A.B.C.D [A.B.C.D/M]",
|
|
NO_STR
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Rendevous Point\n"
|
|
"ip address of RP\n"
|
|
"Group Address range to cover\n")
|
|
{
|
|
int idx_rp = 4, idx_group = 5;
|
|
const char *group_str =
|
|
(argc == 6) ? argv[idx_group]->arg : "224.0.0.0/4";
|
|
char group_list_xpath[XPATH_MAXLEN + 32];
|
|
char group_xpath[XPATH_MAXLEN + 64];
|
|
char rp_xpath[XPATH_MAXLEN];
|
|
const char *vrfname;
|
|
const struct lyd_node *group_dnode;
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4",
|
|
argv[idx_rp]->arg);
|
|
|
|
snprintf(group_list_xpath, sizeof(group_list_xpath), "%s/group-list",
|
|
rp_xpath);
|
|
|
|
snprintf(group_xpath, sizeof(group_xpath), "%s[.='%s']",
|
|
group_list_xpath, group_str);
|
|
|
|
if (!yang_dnode_exists(vty->candidate_config->dnode, group_xpath)) {
|
|
vty_out(vty, "%% Unable to find specified RP\n");
|
|
return NB_OK;
|
|
}
|
|
|
|
group_dnode = yang_dnode_get(vty->candidate_config->dnode, group_xpath);
|
|
|
|
if (yang_is_last_list_dnode(group_dnode))
|
|
nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL);
|
|
else
|
|
nb_cli_enqueue_change(vty, group_list_xpath, NB_OP_DESTROY,
|
|
group_str);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_pim_rp_prefix_list,
|
|
no_ip_pim_rp_prefix_list_cmd,
|
|
"no ip pim rp A.B.C.D prefix-list WORD",
|
|
NO_STR
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Rendevous Point\n"
|
|
"ip address of RP\n"
|
|
"group prefix-list filter\n"
|
|
"Name of a prefix-list\n")
|
|
{
|
|
int idx_rp = 4;
|
|
int idx_plist = 6;
|
|
char rp_xpath[XPATH_MAXLEN];
|
|
char plist_xpath[XPATH_MAXLEN];
|
|
const char *vrfname;
|
|
const struct lyd_node *plist_dnode;
|
|
const char *plist;
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4",
|
|
argv[idx_rp]->arg);
|
|
|
|
snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4",
|
|
argv[idx_rp]->arg);
|
|
strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath));
|
|
|
|
plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath);
|
|
if (!plist_dnode) {
|
|
vty_out(vty, "%% Unable to find specified RP\n");
|
|
return NB_OK;
|
|
}
|
|
|
|
plist = yang_dnode_get_string(plist_dnode, plist_xpath);
|
|
if (strcmp(argv[idx_plist]->arg, plist)) {
|
|
vty_out(vty, "%% Unable to find specified RP\n");
|
|
return NB_OK;
|
|
}
|
|
|
|
nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (ip_pim_ssm_prefix_list,
|
|
ip_pim_ssm_prefix_list_cmd,
|
|
"ip pim ssm prefix-list WORD",
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Source Specific Multicast\n"
|
|
"group range prefix-list filter\n"
|
|
"Name of a prefix-list\n")
|
|
{
|
|
const char *vrfname;
|
|
char ssm_plist_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, argv[4]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_pim_ssm_prefix_list,
|
|
no_ip_pim_ssm_prefix_list_cmd,
|
|
"no ip pim ssm prefix-list",
|
|
NO_STR
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Source Specific Multicast\n"
|
|
"group range prefix-list filter\n")
|
|
{
|
|
const char *vrfname;
|
|
char ssm_plist_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_pim_ssm_prefix_list_name,
|
|
no_ip_pim_ssm_prefix_list_name_cmd,
|
|
"no ip pim ssm prefix-list WORD",
|
|
NO_STR
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Source Specific Multicast\n"
|
|
"group range prefix-list filter\n"
|
|
"Name of a prefix-list\n")
|
|
{
|
|
const char *vrfname;
|
|
const struct lyd_node *ssm_plist_dnode;
|
|
char ssm_plist_xpath[XPATH_MAXLEN];
|
|
const char *ssm_plist_name;
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath));
|
|
ssm_plist_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
|
ssm_plist_xpath);
|
|
|
|
if (!ssm_plist_dnode) {
|
|
vty_out(vty,
|
|
"%% pim ssm prefix-list %s doesn't exist\n",
|
|
argv[5]->arg);
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
}
|
|
|
|
ssm_plist_name = yang_dnode_get_string(ssm_plist_dnode, ".");
|
|
|
|
if (ssm_plist_name && !strcmp(ssm_plist_name, argv[5]->arg)) {
|
|
nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY,
|
|
NULL);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", argv[5]->arg);
|
|
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
}
|
|
|
|
static void ip_pim_ssm_show_group_range(struct pim_instance *pim,
|
|
struct vty *vty, bool uj)
|
|
{
|
|
struct pim_ssm *ssm = pim->ssm_info;
|
|
const char *range_str =
|
|
ssm->plist_name ? ssm->plist_name : PIM_SSM_STANDARD_RANGE;
|
|
|
|
if (uj) {
|
|
json_object *json;
|
|
json = json_object_new_object();
|
|
json_object_string_add(json, "ssmGroups", range_str);
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
} else
|
|
vty_out(vty, "SSM group range : %s\n", range_str);
|
|
}
|
|
|
|
DEFUN (show_ip_pim_ssm_range,
|
|
show_ip_pim_ssm_range_cmd,
|
|
"show ip pim [vrf NAME] group-type [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"PIM group type\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
ip_pim_ssm_show_group_range(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
static void ip_pim_ssm_show_group_type(struct pim_instance *pim,
|
|
struct vty *vty, bool uj,
|
|
const char *group)
|
|
{
|
|
struct in_addr group_addr;
|
|
const char *type_str;
|
|
int result;
|
|
|
|
result = inet_pton(AF_INET, group, &group_addr);
|
|
if (result <= 0)
|
|
type_str = "invalid";
|
|
else {
|
|
if (pim_is_group_224_4(group_addr))
|
|
type_str =
|
|
pim_is_grp_ssm(pim, group_addr) ? "SSM" : "ASM";
|
|
else
|
|
type_str = "not-multicast";
|
|
}
|
|
|
|
if (uj) {
|
|
json_object *json;
|
|
json = json_object_new_object();
|
|
json_object_string_add(json, "groupType", type_str);
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
} else
|
|
vty_out(vty, "Group type : %s\n", type_str);
|
|
}
|
|
|
|
DEFUN (show_ip_pim_group_type,
|
|
show_ip_pim_group_type_cmd,
|
|
"show ip pim [vrf NAME] group-type A.B.C.D [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"multicast group type\n"
|
|
"group address\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
argv_find(argv, argc, "A.B.C.D", &idx);
|
|
ip_pim_ssm_show_group_type(vrf->info, vty, uj, argv[idx]->arg);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_pim_bsr,
|
|
show_ip_pim_bsr_cmd,
|
|
"show ip pim bsr [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"boot-strap router information\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
bool uj = use_json(argc, argv);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_show_bsr(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (ip_ssmpingd,
|
|
ip_ssmpingd_cmd,
|
|
"ip ssmpingd [A.B.C.D]",
|
|
IP_STR
|
|
CONF_SSMPINGD_STR
|
|
"Source address\n")
|
|
{
|
|
int idx_ipv4 = 2;
|
|
const char *source_str = (argc == 3) ? argv[idx_ipv4]->arg : "0.0.0.0";
|
|
const char *vrfname;
|
|
char ssmpingd_ip_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(ssmpingd_ip_xpath, "/ssm-pingd-source-ip",
|
|
sizeof(ssmpingd_ip_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, ssmpingd_ip_xpath, NB_OP_CREATE,
|
|
source_str);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_ssmpingd,
|
|
no_ip_ssmpingd_cmd,
|
|
"no ip ssmpingd [A.B.C.D]",
|
|
NO_STR
|
|
IP_STR
|
|
CONF_SSMPINGD_STR
|
|
"Source address\n")
|
|
{
|
|
const char *vrfname;
|
|
int idx_ipv4 = 3;
|
|
const char *source_str = (argc == 4) ? argv[idx_ipv4]->arg : "0.0.0.0";
|
|
char ssmpingd_ip_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(ssmpingd_ip_xpath, "/ssm-pingd-source-ip",
|
|
sizeof(ssmpingd_ip_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, ssmpingd_ip_xpath, NB_OP_DESTROY,
|
|
source_str);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (ip_pim_ecmp,
|
|
ip_pim_ecmp_cmd,
|
|
"ip pim ecmp",
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Enable PIM ECMP \n")
|
|
{
|
|
const char *vrfname;
|
|
char ecmp_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname);
|
|
strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true");
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_pim_ecmp,
|
|
no_ip_pim_ecmp_cmd,
|
|
"no ip pim ecmp",
|
|
NO_STR
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Disable PIM ECMP \n")
|
|
{
|
|
const char *vrfname;
|
|
char ecmp_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname);
|
|
strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "false");
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (ip_pim_ecmp_rebalance,
|
|
ip_pim_ecmp_rebalance_cmd,
|
|
"ip pim ecmp rebalance",
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Enable PIM ECMP \n"
|
|
"Enable PIM ECMP Rebalance\n")
|
|
{
|
|
const char *vrfname;
|
|
char ecmp_xpath[XPATH_MAXLEN];
|
|
char ecmp_rebalance_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname);
|
|
strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath));
|
|
snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath),
|
|
FRR_PIM_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname);
|
|
strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance",
|
|
sizeof(ecmp_rebalance_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true");
|
|
nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "true");
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_pim_ecmp_rebalance,
|
|
no_ip_pim_ecmp_rebalance_cmd,
|
|
"no ip pim ecmp rebalance",
|
|
NO_STR
|
|
IP_STR
|
|
"pim multicast routing\n"
|
|
"Disable PIM ECMP \n"
|
|
"Disable PIM ECMP Rebalance\n")
|
|
{
|
|
const char *vrfname;
|
|
char ecmp_rebalance_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath),
|
|
FRR_PIM_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname);
|
|
strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance",
|
|
sizeof(ecmp_rebalance_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "false");
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (interface_ip_igmp,
|
|
interface_ip_igmp_cmd,
|
|
"ip igmp",
|
|
IP_STR
|
|
IFACE_IGMP_STR)
|
|
{
|
|
nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, "true");
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
|
|
}
|
|
|
|
DEFUN (interface_no_ip_igmp,
|
|
interface_no_ip_igmp_cmd,
|
|
"no ip igmp",
|
|
NO_STR
|
|
IP_STR
|
|
IFACE_IGMP_STR)
|
|
{
|
|
const struct lyd_node *pim_enable_dnode;
|
|
char pim_if_xpath[XPATH_MAXLEN + 20];
|
|
|
|
snprintf(pim_if_xpath, sizeof(pim_if_xpath),
|
|
"%s/frr-pim:pim", VTY_CURR_XPATH);
|
|
|
|
pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
|
"%s/pim-enable", pim_if_xpath);
|
|
if (!pim_enable_dnode) {
|
|
nb_cli_enqueue_change(vty, pim_if_xpath, NB_OP_DESTROY, NULL);
|
|
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
|
|
} else {
|
|
if (!yang_dnode_get_bool(pim_enable_dnode, ".")) {
|
|
nb_cli_enqueue_change(vty, pim_if_xpath, NB_OP_DESTROY,
|
|
NULL);
|
|
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
|
|
} else
|
|
nb_cli_enqueue_change(vty, "./igmp-enable",
|
|
NB_OP_MODIFY, "false");
|
|
}
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
|
|
}
|
|
|
|
DEFUN (interface_ip_igmp_join,
|
|
interface_ip_igmp_join_cmd,
|
|
"ip igmp join A.B.C.D [A.B.C.D]",
|
|
IP_STR
|
|
IFACE_IGMP_STR
|
|
"IGMP join multicast group\n"
|
|
"Multicast group address\n"
|
|
"Source address\n")
|
|
{
|
|
int idx_group = 3;
|
|
int idx_source = 4;
|
|
const char *source_str;
|
|
char xpath[XPATH_MAXLEN];
|
|
|
|
if (argc == 5) {
|
|
source_str = argv[idx_source]->arg;
|
|
|
|
if (strcmp(source_str, "0.0.0.0") == 0) {
|
|
vty_out(vty, "Bad source address %s\n",
|
|
argv[idx_source]->arg);
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
}
|
|
} else
|
|
source_str = "0.0.0.0";
|
|
|
|
snprintf(xpath, sizeof(xpath), FRR_IGMP_JOIN_XPATH,
|
|
"frr-routing:ipv4", argv[idx_group]->arg, source_str);
|
|
|
|
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (interface_no_ip_igmp_join,
|
|
interface_no_ip_igmp_join_cmd,
|
|
"no ip igmp join A.B.C.D [A.B.C.D]",
|
|
NO_STR
|
|
IP_STR
|
|
IFACE_IGMP_STR
|
|
"IGMP join multicast group\n"
|
|
"Multicast group address\n"
|
|
"Source address\n")
|
|
{
|
|
int idx_group = 4;
|
|
int idx_source = 5;
|
|
const char *source_str;
|
|
char xpath[XPATH_MAXLEN];
|
|
|
|
if (argc == 6) {
|
|
source_str = argv[idx_source]->arg;
|
|
|
|
if (strcmp(source_str, "0.0.0.0") == 0) {
|
|
vty_out(vty, "Bad source address %s\n",
|
|
argv[idx_source]->arg);
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
}
|
|
} else
|
|
source_str = "0.0.0.0";
|
|
|
|
snprintf(xpath, sizeof(xpath), FRR_IGMP_JOIN_XPATH,
|
|
"frr-routing:ipv4", argv[idx_group]->arg, source_str);
|
|
|
|
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (interface_ip_igmp_query_interval,
|
|
interface_ip_igmp_query_interval_cmd,
|
|
"ip igmp query-interval (1-1800)",
|
|
IP_STR
|
|
IFACE_IGMP_STR
|
|
IFACE_IGMP_QUERY_INTERVAL_STR
|
|
"Query interval in seconds\n")
|
|
{
|
|
const struct lyd_node *pim_enable_dnode;
|
|
|
|
pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
|
"%s/frr-pim:pim/pim-enable",
|
|
VTY_CURR_XPATH);
|
|
if (!pim_enable_dnode) {
|
|
nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
|
|
"true");
|
|
} else {
|
|
if (!yang_dnode_get_bool(pim_enable_dnode, "."))
|
|
nb_cli_enqueue_change(vty, "./igmp-enable",
|
|
NB_OP_MODIFY, "true");
|
|
}
|
|
|
|
nb_cli_enqueue_change(vty, "./query-interval", NB_OP_MODIFY,
|
|
argv[3]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
|
|
}
|
|
|
|
DEFUN (interface_no_ip_igmp_query_interval,
|
|
interface_no_ip_igmp_query_interval_cmd,
|
|
"no ip igmp query-interval",
|
|
NO_STR
|
|
IP_STR
|
|
IFACE_IGMP_STR
|
|
IFACE_IGMP_QUERY_INTERVAL_STR)
|
|
{
|
|
char default_query_interval[5];
|
|
|
|
snprintf(default_query_interval, sizeof(default_query_interval), "%d",
|
|
IGMP_GENERAL_QUERY_INTERVAL);
|
|
|
|
nb_cli_enqueue_change(vty, "./query-interval", NB_OP_MODIFY,
|
|
default_query_interval);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
|
|
}
|
|
|
|
DEFUN (interface_ip_igmp_version,
|
|
interface_ip_igmp_version_cmd,
|
|
"ip igmp version (2-3)",
|
|
IP_STR
|
|
IFACE_IGMP_STR
|
|
"IGMP version\n"
|
|
"IGMP version number\n")
|
|
{
|
|
nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
|
|
"true");
|
|
nb_cli_enqueue_change(vty, "./version", NB_OP_MODIFY, argv[3]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
|
|
}
|
|
|
|
DEFUN (interface_no_ip_igmp_version,
|
|
interface_no_ip_igmp_version_cmd,
|
|
"no ip igmp version (2-3)",
|
|
NO_STR
|
|
IP_STR
|
|
IFACE_IGMP_STR
|
|
"IGMP version\n"
|
|
"IGMP version number\n")
|
|
{
|
|
nb_cli_enqueue_change(vty, "./version", NB_OP_DESTROY, NULL);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
|
|
}
|
|
|
|
DEFUN (interface_ip_igmp_query_max_response_time,
|
|
interface_ip_igmp_query_max_response_time_cmd,
|
|
"ip igmp query-max-response-time (10-250)",
|
|
IP_STR
|
|
IFACE_IGMP_STR
|
|
IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR
|
|
"Query response value in deci-seconds\n")
|
|
{
|
|
const struct lyd_node *pim_enable_dnode;
|
|
|
|
pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
|
"%s/frr-pim:pim/pim-enable",
|
|
VTY_CURR_XPATH);
|
|
|
|
if (!pim_enable_dnode) {
|
|
nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
|
|
"true");
|
|
} else {
|
|
if (!yang_dnode_get_bool(pim_enable_dnode, "."))
|
|
nb_cli_enqueue_change(vty, "./igmp-enable",
|
|
NB_OP_MODIFY, "true");
|
|
}
|
|
|
|
nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
|
|
argv[3]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
|
|
}
|
|
|
|
DEFUN (interface_no_ip_igmp_query_max_response_time,
|
|
interface_no_ip_igmp_query_max_response_time_cmd,
|
|
"no ip igmp query-max-response-time (10-250)",
|
|
NO_STR
|
|
IP_STR
|
|
IFACE_IGMP_STR
|
|
IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR
|
|
"Time for response in deci-seconds\n")
|
|
{
|
|
char default_query_max_response_time[4];
|
|
|
|
snprintf(default_query_max_response_time,
|
|
sizeof(default_query_max_response_time),
|
|
"%d", IGMP_QUERY_MAX_RESPONSE_TIME_DSEC);
|
|
|
|
nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
|
|
default_query_max_response_time);
|
|
return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
|
|
}
|
|
|
|
DEFUN_HIDDEN (interface_ip_igmp_query_max_response_time_dsec,
|
|
interface_ip_igmp_query_max_response_time_dsec_cmd,
|
|
"ip igmp query-max-response-time-dsec (10-250)",
|
|
IP_STR
|
|
IFACE_IGMP_STR
|
|
IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR
|
|
"Query response value in deciseconds\n")
|
|
{
|
|
const struct lyd_node *pim_enable_dnode;
|
|
|
|
pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
|
"%s/frr-pim:pim/pim-enable",
|
|
VTY_CURR_XPATH);
|
|
if (!pim_enable_dnode) {
|
|
nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
|
|
"true");
|
|
} else {
|
|
if (!yang_dnode_get_bool(pim_enable_dnode, "."))
|
|
nb_cli_enqueue_change(vty, "./igmp-enable",
|
|
NB_OP_MODIFY, "true");
|
|
}
|
|
|
|
nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
|
|
argv[3]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
|
|
}
|
|
|
|
DEFUN_HIDDEN (interface_no_ip_igmp_query_max_response_time_dsec,
|
|
interface_no_ip_igmp_query_max_response_time_dsec_cmd,
|
|
"no ip igmp query-max-response-time-dsec",
|
|
NO_STR
|
|
IP_STR
|
|
IFACE_IGMP_STR
|
|
IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR)
|
|
{
|
|
char default_query_max_response_time[4];
|
|
|
|
snprintf(default_query_max_response_time,
|
|
sizeof(default_query_max_response_time),
|
|
"%d", IGMP_QUERY_MAX_RESPONSE_TIME_DSEC);
|
|
|
|
nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
|
|
default_query_max_response_time);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
|
|
}
|
|
|
|
DEFUN (interface_ip_igmp_last_member_query_count,
|
|
interface_ip_igmp_last_member_query_count_cmd,
|
|
"ip igmp last-member-query-count (1-7)",
|
|
IP_STR
|
|
IFACE_IGMP_STR
|
|
IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR
|
|
"Last member query count\n")
|
|
{
|
|
const struct lyd_node *pim_enable_dnode;
|
|
|
|
pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
|
"%s/frr-pim:pim/pim-enable",
|
|
VTY_CURR_XPATH);
|
|
if (!pim_enable_dnode) {
|
|
nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
|
|
"true");
|
|
} else {
|
|
if (!yang_dnode_get_bool(pim_enable_dnode, "."))
|
|
nb_cli_enqueue_change(vty, "./igmp-enable",
|
|
NB_OP_MODIFY, "true");
|
|
}
|
|
|
|
nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_MODIFY,
|
|
argv[3]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
|
|
}
|
|
|
|
DEFUN (interface_no_ip_igmp_last_member_query_count,
|
|
interface_no_ip_igmp_last_member_query_count_cmd,
|
|
"no ip igmp last-member-query-count",
|
|
NO_STR
|
|
IP_STR
|
|
IFACE_IGMP_STR
|
|
IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR)
|
|
{
|
|
char default_robustness[2];
|
|
|
|
snprintf(default_robustness, sizeof(default_robustness), "%d",
|
|
IGMP_DEFAULT_ROBUSTNESS_VARIABLE);
|
|
|
|
nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_MODIFY,
|
|
default_robustness);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
|
|
}
|
|
|
|
DEFUN (interface_ip_igmp_last_member_query_interval,
|
|
interface_ip_igmp_last_member_query_interval_cmd,
|
|
"ip igmp last-member-query-interval (1-255)",
|
|
IP_STR
|
|
IFACE_IGMP_STR
|
|
IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR
|
|
"Last member query interval in deciseconds\n")
|
|
{
|
|
const struct lyd_node *pim_enable_dnode;
|
|
|
|
pim_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
|
"%s/frr-pim:pim/pim-enable",
|
|
VTY_CURR_XPATH);
|
|
if (!pim_enable_dnode) {
|
|
nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY,
|
|
"true");
|
|
} else {
|
|
if (!yang_dnode_get_bool(pim_enable_dnode, "."))
|
|
nb_cli_enqueue_change(vty, "./igmp-enable",
|
|
NB_OP_MODIFY, "true");
|
|
}
|
|
|
|
nb_cli_enqueue_change(vty, "./last-member-query-interval", NB_OP_MODIFY,
|
|
argv[3]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
|
|
}
|
|
|
|
DEFUN (interface_no_ip_igmp_last_member_query_interval,
|
|
interface_no_ip_igmp_last_member_query_interval_cmd,
|
|
"no ip igmp last-member-query-interval",
|
|
NO_STR
|
|
IP_STR
|
|
IFACE_IGMP_STR
|
|
IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR)
|
|
{
|
|
char default_last_member_query_count[4];
|
|
|
|
snprintf(default_last_member_query_count,
|
|
sizeof(default_last_member_query_count),
|
|
"%d", IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC);
|
|
|
|
nb_cli_enqueue_change(vty, "./last-member-query-interval", NB_OP_MODIFY,
|
|
default_last_member_query_count);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-igmp:igmp");
|
|
}
|
|
|
|
DEFUN (interface_ip_pim_drprio,
|
|
interface_ip_pim_drprio_cmd,
|
|
"ip pim drpriority (1-4294967295)",
|
|
IP_STR
|
|
PIM_STR
|
|
"Set the Designated Router Election Priority\n"
|
|
"Value of the new DR Priority\n")
|
|
{
|
|
int idx_number = 3;
|
|
|
|
nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY,
|
|
argv[idx_number]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
DEFUN (interface_no_ip_pim_drprio,
|
|
interface_no_ip_pim_drprio_cmd,
|
|
"no ip pim drpriority [(1-4294967295)]",
|
|
NO_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"Revert the Designated Router Priority to default\n"
|
|
"Old Value of the Priority\n")
|
|
{
|
|
char default_priority[10];
|
|
|
|
snprintf(default_priority, sizeof(default_priority), "%d",
|
|
PIM_DEFAULT_DR_PRIORITY);
|
|
|
|
nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY,
|
|
default_priority);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
DEFPY_HIDDEN (interface_ip_igmp_query_generate,
|
|
interface_ip_igmp_query_generate_cmd,
|
|
"ip igmp generate-query-once [version (2-3)]",
|
|
IP_STR
|
|
IFACE_IGMP_STR
|
|
"Generate igmp general query once\n"
|
|
"IGMP version\n"
|
|
"IGMP version number\n")
|
|
{
|
|
VTY_DECLVAR_CONTEXT(interface, ifp);
|
|
int igmp_version = 2;
|
|
|
|
if (!ifp->info) {
|
|
vty_out(vty, "IGMP/PIM is not enabled on the interface %s\n",
|
|
ifp->name);
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
}
|
|
|
|
if (argc > 3)
|
|
igmp_version = atoi(argv[4]->arg);
|
|
|
|
igmp_send_query_on_intf(ifp, igmp_version);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY_HIDDEN (pim_test_sg_keepalive,
|
|
pim_test_sg_keepalive_cmd,
|
|
"test pim [vrf NAME$name] keepalive-reset A.B.C.D$source A.B.C.D$group",
|
|
"Test code\n"
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"Reset the Keepalive Timer\n"
|
|
"The Source we are resetting\n"
|
|
"The Group we are resetting\n")
|
|
{
|
|
struct pim_upstream *up;
|
|
struct pim_instance *pim;
|
|
struct prefix_sg sg;
|
|
|
|
sg.src = source;
|
|
sg.grp = group;
|
|
|
|
if (!name)
|
|
pim = pim_get_pim_instance(VRF_DEFAULT);
|
|
else {
|
|
struct vrf *vrf = vrf_lookup_by_name(name);
|
|
|
|
if (!vrf) {
|
|
vty_out(vty, "%% Vrf specified: %s does not exist\n",
|
|
name);
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
pim = pim_get_pim_instance(vrf->vrf_id);
|
|
}
|
|
|
|
if (!pim) {
|
|
vty_out(vty, "%% Unable to find pim instance\n");
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
up = pim_upstream_find(pim, &sg);
|
|
if (!up) {
|
|
vty_out(vty, "%% Unable to find %s specified\n",
|
|
pim_str_sg_dump(&sg));
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
vty_out(vty, "Setting %s to current keep alive time: %d\n",
|
|
pim_str_sg_dump(&sg), pim->keep_alive_time);
|
|
pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY (interface_ip_pim_activeactive,
|
|
interface_ip_pim_activeactive_cmd,
|
|
"[no$no] ip pim active-active",
|
|
NO_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"Mark interface as Active-Active for MLAG operations, Hidden because not finished yet\n")
|
|
{
|
|
if (no)
|
|
nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY,
|
|
"false");
|
|
else {
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
|
|
"true");
|
|
|
|
nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY,
|
|
"true");
|
|
}
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
DEFUN_HIDDEN (interface_ip_pim_ssm,
|
|
interface_ip_pim_ssm_cmd,
|
|
"ip pim ssm",
|
|
IP_STR
|
|
PIM_STR
|
|
IFACE_PIM_STR)
|
|
{
|
|
int ret;
|
|
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true");
|
|
|
|
ret = nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
|
|
if (ret != NB_OK)
|
|
return ret;
|
|
|
|
vty_out(vty,
|
|
"WARN: Enabled PIM SM on interface; configure PIM SSM range if needed\n");
|
|
|
|
return NB_OK;
|
|
}
|
|
|
|
DEFUN_HIDDEN (interface_ip_pim_sm,
|
|
interface_ip_pim_sm_cmd,
|
|
"ip pim sm",
|
|
IP_STR
|
|
PIM_STR
|
|
IFACE_PIM_SM_STR)
|
|
{
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true");
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
DEFUN (interface_ip_pim,
|
|
interface_ip_pim_cmd,
|
|
"ip pim",
|
|
IP_STR
|
|
PIM_STR)
|
|
{
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true");
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
DEFUN_HIDDEN (interface_no_ip_pim_ssm,
|
|
interface_no_ip_pim_ssm_cmd,
|
|
"no ip pim ssm",
|
|
NO_STR
|
|
IP_STR
|
|
PIM_STR
|
|
IFACE_PIM_STR)
|
|
{
|
|
const struct lyd_node *igmp_enable_dnode;
|
|
char igmp_if_xpath[XPATH_MAXLEN + 20];
|
|
|
|
snprintf(igmp_if_xpath, sizeof(igmp_if_xpath),
|
|
"%s/frr-igmp:igmp", VTY_CURR_XPATH);
|
|
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
|
"%s/igmp-enable", igmp_if_xpath);
|
|
|
|
if (!igmp_enable_dnode) {
|
|
nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL);
|
|
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
|
|
} else {
|
|
if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) {
|
|
nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY,
|
|
NULL);
|
|
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
|
|
} else
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
|
|
"false");
|
|
}
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
DEFUN_HIDDEN (interface_no_ip_pim_sm,
|
|
interface_no_ip_pim_sm_cmd,
|
|
"no ip pim sm",
|
|
NO_STR
|
|
IP_STR
|
|
PIM_STR
|
|
IFACE_PIM_SM_STR)
|
|
{
|
|
const struct lyd_node *igmp_enable_dnode;
|
|
char igmp_if_xpath[XPATH_MAXLEN + 20];
|
|
|
|
snprintf(igmp_if_xpath, sizeof(igmp_if_xpath),
|
|
"%s/frr-igmp:igmp", VTY_CURR_XPATH);
|
|
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
|
"%s/igmp-enable", igmp_if_xpath);
|
|
|
|
if (!igmp_enable_dnode) {
|
|
nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL);
|
|
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
|
|
} else {
|
|
if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) {
|
|
nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY,
|
|
NULL);
|
|
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
|
|
} else
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
|
|
"false");
|
|
}
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
DEFUN (interface_no_ip_pim,
|
|
interface_no_ip_pim_cmd,
|
|
"no ip pim",
|
|
NO_STR
|
|
IP_STR
|
|
PIM_STR)
|
|
{
|
|
const struct lyd_node *igmp_enable_dnode;
|
|
char igmp_if_xpath[XPATH_MAXLEN + 20];
|
|
|
|
snprintf(igmp_if_xpath, sizeof(igmp_if_xpath),
|
|
"%s/frr-igmp:igmp", VTY_CURR_XPATH);
|
|
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
|
"%s/igmp-enable", igmp_if_xpath);
|
|
|
|
if (!igmp_enable_dnode) {
|
|
nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL);
|
|
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
|
|
} else {
|
|
if (!yang_dnode_get_bool(igmp_enable_dnode, ".")) {
|
|
nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY,
|
|
NULL);
|
|
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
|
|
} else
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
|
|
"false");
|
|
}
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
/* boundaries */
|
|
DEFUN(interface_ip_pim_boundary_oil,
|
|
interface_ip_pim_boundary_oil_cmd,
|
|
"ip multicast boundary oil WORD",
|
|
IP_STR
|
|
"Generic multicast configuration options\n"
|
|
"Define multicast boundary\n"
|
|
"Filter OIL by group using prefix list\n"
|
|
"Prefix list to filter OIL with\n")
|
|
{
|
|
nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_MODIFY,
|
|
argv[4]->arg);
|
|
|
|
return nb_cli_apply_changes(vty,
|
|
"./frr-pim:pim/address-family[address-family='%s']",
|
|
"frr-routing:ipv4");
|
|
|
|
}
|
|
|
|
DEFUN(interface_no_ip_pim_boundary_oil,
|
|
interface_no_ip_pim_boundary_oil_cmd,
|
|
"no ip multicast boundary oil [WORD]",
|
|
NO_STR
|
|
IP_STR
|
|
"Generic multicast configuration options\n"
|
|
"Define multicast boundary\n"
|
|
"Filter OIL by group using prefix list\n"
|
|
"Prefix list to filter OIL with\n")
|
|
{
|
|
nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_DESTROY,
|
|
NULL);
|
|
|
|
return nb_cli_apply_changes(vty,
|
|
"./frr-pim:pim/address-family[address-family='%s']",
|
|
"frr-routing:ipv4");
|
|
}
|
|
|
|
DEFUN (interface_ip_mroute,
|
|
interface_ip_mroute_cmd,
|
|
"ip mroute INTERFACE A.B.C.D [A.B.C.D]",
|
|
IP_STR
|
|
"Add multicast route\n"
|
|
"Outgoing interface name\n"
|
|
"Group address\n"
|
|
"Source address\n")
|
|
{
|
|
int idx_interface = 2;
|
|
int idx_ipv4 = 3;
|
|
const char *source_str;
|
|
|
|
if (argc == (idx_ipv4 + 1))
|
|
source_str = "0.0.0.0";
|
|
else
|
|
source_str = argv[idx_ipv4 + 1]->arg;
|
|
|
|
nb_cli_enqueue_change(vty, "./oif", NB_OP_MODIFY,
|
|
argv[idx_interface]->arg);
|
|
|
|
return nb_cli_apply_changes(vty,
|
|
"./frr-pim:pim/address-family[address-family='%s']/mroute[source-addr='%s'][group-addr='%s']",
|
|
"frr-routing:ipv4", source_str,
|
|
argv[idx_ipv4]->arg);
|
|
}
|
|
|
|
DEFUN (interface_no_ip_mroute,
|
|
interface_no_ip_mroute_cmd,
|
|
"no ip mroute INTERFACE A.B.C.D [A.B.C.D]",
|
|
NO_STR
|
|
IP_STR
|
|
"Add multicast route\n"
|
|
"Outgoing interface name\n"
|
|
"Group Address\n"
|
|
"Source Address\n")
|
|
{
|
|
int idx_ipv4 = 4;
|
|
const char *source_str;
|
|
|
|
if (argc == (idx_ipv4 + 1))
|
|
source_str = "0.0.0.0";
|
|
else
|
|
source_str = argv[idx_ipv4 + 1]->arg;
|
|
|
|
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
|
|
|
|
return nb_cli_apply_changes(vty,
|
|
"./frr-pim:pim/address-family[address-family='%s']/mroute[source-addr='%s'][group-addr='%s']",
|
|
"frr-routing:ipv4", source_str,
|
|
argv[idx_ipv4]->arg);
|
|
}
|
|
|
|
DEFUN (interface_ip_pim_hello,
|
|
interface_ip_pim_hello_cmd,
|
|
"ip pim hello (1-180) [(1-180)]",
|
|
IP_STR
|
|
PIM_STR
|
|
IFACE_PIM_HELLO_STR
|
|
IFACE_PIM_HELLO_TIME_STR
|
|
IFACE_PIM_HELLO_HOLD_STR)
|
|
{
|
|
int idx_time = 3;
|
|
int idx_hold = 4;
|
|
const struct lyd_node *igmp_enable_dnode;
|
|
|
|
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
|
"%s/frr-igmp:igmp/igmp-enable",
|
|
VTY_CURR_XPATH);
|
|
if (!igmp_enable_dnode) {
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
|
|
"true");
|
|
} else {
|
|
if (!yang_dnode_get_bool(igmp_enable_dnode, "."))
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
|
|
"true");
|
|
}
|
|
|
|
nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_MODIFY,
|
|
argv[idx_time]->arg);
|
|
|
|
if (argc == idx_hold + 1)
|
|
nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_MODIFY,
|
|
argv[idx_hold]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
DEFUN (interface_no_ip_pim_hello,
|
|
interface_no_ip_pim_hello_cmd,
|
|
"no ip pim hello [(1-180) [(1-180)]]",
|
|
NO_STR
|
|
IP_STR
|
|
PIM_STR
|
|
IFACE_PIM_HELLO_STR
|
|
IFACE_PIM_HELLO_TIME_STR
|
|
IFACE_PIM_HELLO_HOLD_STR)
|
|
{
|
|
char hello_default_timer[3];
|
|
|
|
snprintf(hello_default_timer, sizeof(hello_default_timer), "%d",
|
|
PIM_DEFAULT_HELLO_PERIOD);
|
|
|
|
nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_MODIFY,
|
|
hello_default_timer);
|
|
nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_DESTROY, NULL);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
DEFUN (debug_igmp,
|
|
debug_igmp_cmd,
|
|
"debug igmp",
|
|
DEBUG_STR
|
|
DEBUG_IGMP_STR)
|
|
{
|
|
PIM_DO_DEBUG_IGMP_EVENTS;
|
|
PIM_DO_DEBUG_IGMP_PACKETS;
|
|
PIM_DO_DEBUG_IGMP_TRACE;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_igmp,
|
|
no_debug_igmp_cmd,
|
|
"no debug igmp",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_IGMP_STR)
|
|
{
|
|
PIM_DONT_DEBUG_IGMP_EVENTS;
|
|
PIM_DONT_DEBUG_IGMP_PACKETS;
|
|
PIM_DONT_DEBUG_IGMP_TRACE;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
|
|
DEFUN (debug_igmp_events,
|
|
debug_igmp_events_cmd,
|
|
"debug igmp events",
|
|
DEBUG_STR
|
|
DEBUG_IGMP_STR
|
|
DEBUG_IGMP_EVENTS_STR)
|
|
{
|
|
PIM_DO_DEBUG_IGMP_EVENTS;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_igmp_events,
|
|
no_debug_igmp_events_cmd,
|
|
"no debug igmp events",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_IGMP_STR
|
|
DEBUG_IGMP_EVENTS_STR)
|
|
{
|
|
PIM_DONT_DEBUG_IGMP_EVENTS;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
|
|
DEFUN (debug_igmp_packets,
|
|
debug_igmp_packets_cmd,
|
|
"debug igmp packets",
|
|
DEBUG_STR
|
|
DEBUG_IGMP_STR
|
|
DEBUG_IGMP_PACKETS_STR)
|
|
{
|
|
PIM_DO_DEBUG_IGMP_PACKETS;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_igmp_packets,
|
|
no_debug_igmp_packets_cmd,
|
|
"no debug igmp packets",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_IGMP_STR
|
|
DEBUG_IGMP_PACKETS_STR)
|
|
{
|
|
PIM_DONT_DEBUG_IGMP_PACKETS;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
|
|
DEFUN (debug_igmp_trace,
|
|
debug_igmp_trace_cmd,
|
|
"debug igmp trace",
|
|
DEBUG_STR
|
|
DEBUG_IGMP_STR
|
|
DEBUG_IGMP_TRACE_STR)
|
|
{
|
|
PIM_DO_DEBUG_IGMP_TRACE;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_igmp_trace,
|
|
no_debug_igmp_trace_cmd,
|
|
"no debug igmp trace",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_IGMP_STR
|
|
DEBUG_IGMP_TRACE_STR)
|
|
{
|
|
PIM_DONT_DEBUG_IGMP_TRACE;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
|
|
DEFUN (debug_mroute,
|
|
debug_mroute_cmd,
|
|
"debug mroute",
|
|
DEBUG_STR
|
|
DEBUG_MROUTE_STR)
|
|
{
|
|
PIM_DO_DEBUG_MROUTE;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_mroute_detail,
|
|
debug_mroute_detail_cmd,
|
|
"debug mroute detail",
|
|
DEBUG_STR
|
|
DEBUG_MROUTE_STR
|
|
"detailed\n")
|
|
{
|
|
PIM_DO_DEBUG_MROUTE_DETAIL;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_mroute,
|
|
no_debug_mroute_cmd,
|
|
"no debug mroute",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_MROUTE_STR)
|
|
{
|
|
PIM_DONT_DEBUG_MROUTE;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_mroute_detail,
|
|
no_debug_mroute_detail_cmd,
|
|
"no debug mroute detail",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_MROUTE_STR
|
|
"detailed\n")
|
|
{
|
|
PIM_DONT_DEBUG_MROUTE_DETAIL;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_pim_static,
|
|
debug_pim_static_cmd,
|
|
"debug pim static",
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_STATIC_STR)
|
|
{
|
|
PIM_DO_DEBUG_STATIC;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_pim_static,
|
|
no_debug_pim_static_cmd,
|
|
"no debug pim static",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_STATIC_STR)
|
|
{
|
|
PIM_DONT_DEBUG_STATIC;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
|
|
DEFUN (debug_pim,
|
|
debug_pim_cmd,
|
|
"debug pim",
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR)
|
|
{
|
|
PIM_DO_DEBUG_PIM_EVENTS;
|
|
PIM_DO_DEBUG_PIM_PACKETS;
|
|
PIM_DO_DEBUG_PIM_TRACE;
|
|
PIM_DO_DEBUG_MSDP_EVENTS;
|
|
PIM_DO_DEBUG_MSDP_PACKETS;
|
|
PIM_DO_DEBUG_BSM;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_pim,
|
|
no_debug_pim_cmd,
|
|
"no debug pim",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR)
|
|
{
|
|
PIM_DONT_DEBUG_PIM_EVENTS;
|
|
PIM_DONT_DEBUG_PIM_PACKETS;
|
|
PIM_DONT_DEBUG_PIM_TRACE;
|
|
PIM_DONT_DEBUG_MSDP_EVENTS;
|
|
PIM_DONT_DEBUG_MSDP_PACKETS;
|
|
|
|
PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND;
|
|
PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV;
|
|
PIM_DONT_DEBUG_BSM;
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_pim_nht,
|
|
debug_pim_nht_cmd,
|
|
"debug pim nht",
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
"Nexthop Tracking\n")
|
|
{
|
|
PIM_DO_DEBUG_PIM_NHT;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_pim_nht,
|
|
no_debug_pim_nht_cmd,
|
|
"no debug pim nht",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
"Nexthop Tracking\n")
|
|
{
|
|
PIM_DONT_DEBUG_PIM_NHT;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_pim_nht_rp,
|
|
debug_pim_nht_rp_cmd,
|
|
"debug pim nht rp",
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
"Nexthop Tracking\n"
|
|
"RP Nexthop Tracking\n")
|
|
{
|
|
PIM_DO_DEBUG_PIM_NHT_RP;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_pim_nht_rp,
|
|
no_debug_pim_nht_rp_cmd,
|
|
"no debug pim nht rp",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
"Nexthop Tracking\n"
|
|
"RP Nexthop Tracking\n")
|
|
{
|
|
PIM_DONT_DEBUG_PIM_NHT_RP;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_pim_events,
|
|
debug_pim_events_cmd,
|
|
"debug pim events",
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_EVENTS_STR)
|
|
{
|
|
PIM_DO_DEBUG_PIM_EVENTS;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_pim_events,
|
|
no_debug_pim_events_cmd,
|
|
"no debug pim events",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_EVENTS_STR)
|
|
{
|
|
PIM_DONT_DEBUG_PIM_EVENTS;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_pim_packets,
|
|
debug_pim_packets_cmd,
|
|
"debug pim packets [<hello|joins|register>]",
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_PACKETS_STR
|
|
DEBUG_PIM_HELLO_PACKETS_STR
|
|
DEBUG_PIM_J_P_PACKETS_STR
|
|
DEBUG_PIM_PIM_REG_PACKETS_STR)
|
|
{
|
|
int idx = 0;
|
|
if (argv_find(argv, argc, "hello", &idx)) {
|
|
PIM_DO_DEBUG_PIM_HELLO;
|
|
vty_out(vty, "PIM Hello debugging is on\n");
|
|
} else if (argv_find(argv, argc, "joins", &idx)) {
|
|
PIM_DO_DEBUG_PIM_J_P;
|
|
vty_out(vty, "PIM Join/Prune debugging is on\n");
|
|
} else if (argv_find(argv, argc, "register", &idx)) {
|
|
PIM_DO_DEBUG_PIM_REG;
|
|
vty_out(vty, "PIM Register debugging is on\n");
|
|
} else {
|
|
PIM_DO_DEBUG_PIM_PACKETS;
|
|
vty_out(vty, "PIM Packet debugging is on \n");
|
|
}
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_pim_packets,
|
|
no_debug_pim_packets_cmd,
|
|
"no debug pim packets [<hello|joins|register>]",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_PACKETS_STR
|
|
DEBUG_PIM_HELLO_PACKETS_STR
|
|
DEBUG_PIM_J_P_PACKETS_STR
|
|
DEBUG_PIM_PIM_REG_PACKETS_STR)
|
|
{
|
|
int idx = 0;
|
|
if (argv_find(argv, argc, "hello", &idx)) {
|
|
PIM_DONT_DEBUG_PIM_HELLO;
|
|
vty_out(vty, "PIM Hello debugging is off \n");
|
|
} else if (argv_find(argv, argc, "joins", &idx)) {
|
|
PIM_DONT_DEBUG_PIM_J_P;
|
|
vty_out(vty, "PIM Join/Prune debugging is off \n");
|
|
} else if (argv_find(argv, argc, "register", &idx)) {
|
|
PIM_DONT_DEBUG_PIM_REG;
|
|
vty_out(vty, "PIM Register debugging is off\n");
|
|
} else
|
|
PIM_DONT_DEBUG_PIM_PACKETS;
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
|
|
DEFUN (debug_pim_packetdump_send,
|
|
debug_pim_packetdump_send_cmd,
|
|
"debug pim packet-dump send",
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_PACKETDUMP_STR
|
|
DEBUG_PIM_PACKETDUMP_SEND_STR)
|
|
{
|
|
PIM_DO_DEBUG_PIM_PACKETDUMP_SEND;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_pim_packetdump_send,
|
|
no_debug_pim_packetdump_send_cmd,
|
|
"no debug pim packet-dump send",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_PACKETDUMP_STR
|
|
DEBUG_PIM_PACKETDUMP_SEND_STR)
|
|
{
|
|
PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_pim_packetdump_recv,
|
|
debug_pim_packetdump_recv_cmd,
|
|
"debug pim packet-dump receive",
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_PACKETDUMP_STR
|
|
DEBUG_PIM_PACKETDUMP_RECV_STR)
|
|
{
|
|
PIM_DO_DEBUG_PIM_PACKETDUMP_RECV;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_pim_packetdump_recv,
|
|
no_debug_pim_packetdump_recv_cmd,
|
|
"no debug pim packet-dump receive",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_PACKETDUMP_STR
|
|
DEBUG_PIM_PACKETDUMP_RECV_STR)
|
|
{
|
|
PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_pim_trace,
|
|
debug_pim_trace_cmd,
|
|
"debug pim trace",
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_TRACE_STR)
|
|
{
|
|
PIM_DO_DEBUG_PIM_TRACE;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_pim_trace_detail,
|
|
debug_pim_trace_detail_cmd,
|
|
"debug pim trace detail",
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_TRACE_STR
|
|
"Detailed Information\n")
|
|
{
|
|
PIM_DO_DEBUG_PIM_TRACE_DETAIL;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_pim_trace,
|
|
no_debug_pim_trace_cmd,
|
|
"no debug pim trace",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_TRACE_STR)
|
|
{
|
|
PIM_DONT_DEBUG_PIM_TRACE;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_pim_trace_detail,
|
|
no_debug_pim_trace_detail_cmd,
|
|
"no debug pim trace detail",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_TRACE_STR
|
|
"Detailed Information\n")
|
|
{
|
|
PIM_DONT_DEBUG_PIM_TRACE_DETAIL;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_ssmpingd,
|
|
debug_ssmpingd_cmd,
|
|
"debug ssmpingd",
|
|
DEBUG_STR
|
|
DEBUG_SSMPINGD_STR)
|
|
{
|
|
PIM_DO_DEBUG_SSMPINGD;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_ssmpingd,
|
|
no_debug_ssmpingd_cmd,
|
|
"no debug ssmpingd",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_SSMPINGD_STR)
|
|
{
|
|
PIM_DONT_DEBUG_SSMPINGD;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_pim_zebra,
|
|
debug_pim_zebra_cmd,
|
|
"debug pim zebra",
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_ZEBRA_STR)
|
|
{
|
|
PIM_DO_DEBUG_ZEBRA;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_pim_zebra,
|
|
no_debug_pim_zebra_cmd,
|
|
"no debug pim zebra",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_ZEBRA_STR)
|
|
{
|
|
PIM_DONT_DEBUG_ZEBRA;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN(debug_pim_mlag, debug_pim_mlag_cmd, "debug pim mlag",
|
|
DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR)
|
|
{
|
|
PIM_DO_DEBUG_MLAG;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN(no_debug_pim_mlag, no_debug_pim_mlag_cmd, "no debug pim mlag",
|
|
NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR)
|
|
{
|
|
PIM_DONT_DEBUG_MLAG;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_pim_vxlan,
|
|
debug_pim_vxlan_cmd,
|
|
"debug pim vxlan",
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_VXLAN_STR)
|
|
{
|
|
PIM_DO_DEBUG_VXLAN;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_pim_vxlan,
|
|
no_debug_pim_vxlan_cmd,
|
|
"no debug pim vxlan",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_VXLAN_STR)
|
|
{
|
|
PIM_DONT_DEBUG_VXLAN;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_msdp,
|
|
debug_msdp_cmd,
|
|
"debug msdp",
|
|
DEBUG_STR
|
|
DEBUG_MSDP_STR)
|
|
{
|
|
PIM_DO_DEBUG_MSDP_EVENTS;
|
|
PIM_DO_DEBUG_MSDP_PACKETS;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_msdp,
|
|
no_debug_msdp_cmd,
|
|
"no debug msdp",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_MSDP_STR)
|
|
{
|
|
PIM_DONT_DEBUG_MSDP_EVENTS;
|
|
PIM_DONT_DEBUG_MSDP_PACKETS;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_msdp_events,
|
|
debug_msdp_events_cmd,
|
|
"debug msdp events",
|
|
DEBUG_STR
|
|
DEBUG_MSDP_STR
|
|
DEBUG_MSDP_EVENTS_STR)
|
|
{
|
|
PIM_DO_DEBUG_MSDP_EVENTS;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_msdp_events,
|
|
no_debug_msdp_events_cmd,
|
|
"no debug msdp events",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_MSDP_STR
|
|
DEBUG_MSDP_EVENTS_STR)
|
|
{
|
|
PIM_DONT_DEBUG_MSDP_EVENTS;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_msdp_packets,
|
|
debug_msdp_packets_cmd,
|
|
"debug msdp packets",
|
|
DEBUG_STR
|
|
DEBUG_MSDP_STR
|
|
DEBUG_MSDP_PACKETS_STR)
|
|
{
|
|
PIM_DO_DEBUG_MSDP_PACKETS;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_msdp_packets,
|
|
no_debug_msdp_packets_cmd,
|
|
"no debug msdp packets",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_MSDP_STR
|
|
DEBUG_MSDP_PACKETS_STR)
|
|
{
|
|
PIM_DONT_DEBUG_MSDP_PACKETS;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_mtrace,
|
|
debug_mtrace_cmd,
|
|
"debug mtrace",
|
|
DEBUG_STR
|
|
DEBUG_MTRACE_STR)
|
|
{
|
|
PIM_DO_DEBUG_MTRACE;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_mtrace,
|
|
no_debug_mtrace_cmd,
|
|
"no debug mtrace",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_MTRACE_STR)
|
|
{
|
|
PIM_DONT_DEBUG_MTRACE;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (debug_bsm,
|
|
debug_bsm_cmd,
|
|
"debug pim bsm",
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_BSM_STR)
|
|
{
|
|
PIM_DO_DEBUG_BSM;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (no_debug_bsm,
|
|
no_debug_bsm_cmd,
|
|
"no debug pim bsm",
|
|
NO_STR
|
|
DEBUG_STR
|
|
DEBUG_PIM_STR
|
|
DEBUG_PIM_BSM_STR)
|
|
{
|
|
PIM_DONT_DEBUG_BSM;
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
|
|
DEFUN_NOSH (show_debugging_pim,
|
|
show_debugging_pim_cmd,
|
|
"show debugging [pim]",
|
|
SHOW_STR
|
|
DEBUG_STR
|
|
PIM_STR)
|
|
{
|
|
vty_out(vty, "PIM debugging status\n");
|
|
|
|
pim_debug_config_write(vty);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (interface_pim_use_source,
|
|
interface_pim_use_source_cmd,
|
|
"ip pim use-source A.B.C.D",
|
|
IP_STR
|
|
PIM_STR
|
|
"Configure primary IP address\n"
|
|
"source ip address\n")
|
|
{
|
|
nb_cli_enqueue_change(vty, "./use-source", NB_OP_MODIFY, argv[3]->arg);
|
|
|
|
return nb_cli_apply_changes(vty,
|
|
"./frr-pim:pim/address-family[address-family='%s']",
|
|
"frr-routing:ipv4");
|
|
}
|
|
|
|
DEFUN (interface_no_pim_use_source,
|
|
interface_no_pim_use_source_cmd,
|
|
"no ip pim use-source [A.B.C.D]",
|
|
NO_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"Delete source IP address\n"
|
|
"source ip address\n")
|
|
{
|
|
nb_cli_enqueue_change(vty, "./use-source", NB_OP_MODIFY, "0.0.0.0");
|
|
|
|
return nb_cli_apply_changes(vty,
|
|
"./frr-pim:pim/address-family[address-family='%s']",
|
|
"frr-routing:ipv4");
|
|
}
|
|
|
|
DEFPY (ip_pim_bfd,
|
|
ip_pim_bfd_cmd,
|
|
"ip pim bfd [profile BFDPROF$prof]",
|
|
IP_STR
|
|
PIM_STR
|
|
"Enables BFD support\n"
|
|
"Use BFD profile\n"
|
|
"Use BFD profile name\n")
|
|
{
|
|
const struct lyd_node *igmp_enable_dnode;
|
|
|
|
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
|
"%s/frr-igmp:igmp/igmp-enable",
|
|
VTY_CURR_XPATH);
|
|
if (!igmp_enable_dnode)
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
|
|
"true");
|
|
else {
|
|
if (!yang_dnode_get_bool(igmp_enable_dnode, "."))
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
|
|
"true");
|
|
}
|
|
|
|
nb_cli_enqueue_change(vty, "./bfd", NB_OP_CREATE, NULL);
|
|
if (prof)
|
|
nb_cli_enqueue_change(vty, "./bfd/profile", NB_OP_MODIFY, prof);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
DEFPY(no_ip_pim_bfd_profile, no_ip_pim_bfd_profile_cmd,
|
|
"no ip pim bfd profile [BFDPROF]",
|
|
NO_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"Enables BFD support\n"
|
|
"Disable BFD profile\n"
|
|
"BFD Profile name\n")
|
|
{
|
|
nb_cli_enqueue_change(vty, "./bfd/profile", NB_OP_DESTROY, NULL);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
DEFUN (no_ip_pim_bfd,
|
|
no_ip_pim_bfd_cmd,
|
|
"no ip pim bfd",
|
|
NO_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"Disables BFD support\n")
|
|
{
|
|
nb_cli_enqueue_change(vty, "./bfd", NB_OP_DESTROY, NULL);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
DEFUN (ip_pim_bsm,
|
|
ip_pim_bsm_cmd,
|
|
"ip pim bsm",
|
|
IP_STR
|
|
PIM_STR
|
|
"Enables BSM support on the interface\n")
|
|
{
|
|
const struct lyd_node *igmp_enable_dnode;
|
|
|
|
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
|
"%s/frr-igmp:igmp/igmp-enable",
|
|
VTY_CURR_XPATH);
|
|
if (!igmp_enable_dnode)
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
|
|
"true");
|
|
else {
|
|
if (!yang_dnode_get_bool(igmp_enable_dnode, "."))
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
|
|
"true");
|
|
}
|
|
|
|
nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "true");
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
DEFUN (no_ip_pim_bsm,
|
|
no_ip_pim_bsm_cmd,
|
|
"no ip pim bsm",
|
|
NO_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"Disables BSM support\n")
|
|
{
|
|
nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "false");
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
DEFUN (ip_pim_ucast_bsm,
|
|
ip_pim_ucast_bsm_cmd,
|
|
"ip pim unicast-bsm",
|
|
IP_STR
|
|
PIM_STR
|
|
"Accept/Send unicast BSM on the interface\n")
|
|
{
|
|
const struct lyd_node *igmp_enable_dnode;
|
|
|
|
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
|
"%s/frr-igmp:igmp/igmp-enable",
|
|
VTY_CURR_XPATH);
|
|
if (!igmp_enable_dnode)
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
|
|
"true");
|
|
else {
|
|
if (!yang_dnode_get_bool(igmp_enable_dnode, "."))
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
|
|
"true");
|
|
}
|
|
|
|
nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "true");
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
DEFUN (no_ip_pim_ucast_bsm,
|
|
no_ip_pim_ucast_bsm_cmd,
|
|
"no ip pim unicast-bsm",
|
|
NO_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"Block send/receive unicast BSM on this interface\n")
|
|
{
|
|
nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "false");
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
#if HAVE_BFDD > 0
|
|
DEFUN_HIDDEN(
|
|
ip_pim_bfd_param,
|
|
ip_pim_bfd_param_cmd,
|
|
"ip pim bfd (2-255) (50-60000) (50-60000)",
|
|
IP_STR
|
|
PIM_STR
|
|
"Enables BFD support\n"
|
|
"Detect Multiplier\n"
|
|
"Required min receive interval\n"
|
|
"Desired min transmit interval\n")
|
|
#else
|
|
DEFUN(
|
|
ip_pim_bfd_param,
|
|
ip_pim_bfd_param_cmd,
|
|
"ip pim bfd (2-255) (50-60000) (50-60000)",
|
|
IP_STR
|
|
PIM_STR
|
|
"Enables BFD support\n"
|
|
"Detect Multiplier\n"
|
|
"Required min receive interval\n"
|
|
"Desired min transmit interval\n")
|
|
#endif /* HAVE_BFDD */
|
|
{
|
|
int idx_number = 3;
|
|
int idx_number_2 = 4;
|
|
int idx_number_3 = 5;
|
|
const struct lyd_node *igmp_enable_dnode;
|
|
|
|
igmp_enable_dnode = yang_dnode_get(vty->candidate_config->dnode,
|
|
"%s/frr-igmp:igmp/igmp-enable",
|
|
VTY_CURR_XPATH);
|
|
if (!igmp_enable_dnode)
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
|
|
"true");
|
|
else {
|
|
if (!yang_dnode_get_bool(igmp_enable_dnode, "."))
|
|
nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
|
|
"true");
|
|
}
|
|
|
|
nb_cli_enqueue_change(vty, "./bfd", NB_OP_CREATE, NULL);
|
|
nb_cli_enqueue_change(vty, "./bfd/min-rx-interval", NB_OP_MODIFY,
|
|
argv[idx_number_2]->arg);
|
|
nb_cli_enqueue_change(vty, "./bfd/min-tx-interval", NB_OP_MODIFY,
|
|
argv[idx_number_3]->arg);
|
|
nb_cli_enqueue_change(vty, "./bfd/detect_mult", NB_OP_MODIFY,
|
|
argv[idx_number]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, "./frr-pim:pim");
|
|
}
|
|
|
|
#if HAVE_BFDD == 0
|
|
ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd,
|
|
"no ip pim bfd (2-255) (50-60000) (50-60000)", NO_STR IP_STR PIM_STR
|
|
"Enables BFD support\n"
|
|
"Detect Multiplier\n"
|
|
"Required min receive interval\n"
|
|
"Desired min transmit interval\n")
|
|
#endif /* !HAVE_BFDD */
|
|
|
|
DEFUN (ip_msdp_peer,
|
|
ip_msdp_peer_cmd,
|
|
"ip msdp peer A.B.C.D source A.B.C.D",
|
|
IP_STR
|
|
CFG_MSDP_STR
|
|
"Configure MSDP peer\n"
|
|
"peer ip address\n"
|
|
"Source address for TCP connection\n"
|
|
"local ip address\n")
|
|
{
|
|
const char *vrfname;
|
|
char temp_xpath[XPATH_MAXLEN];
|
|
char msdp_peer_source_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
snprintf(temp_xpath, sizeof(temp_xpath),
|
|
"/msdp-peer[peer-ip='%s']/source-ip",
|
|
argv[3]->arg);
|
|
strlcat(msdp_peer_source_xpath, temp_xpath,
|
|
sizeof(msdp_peer_source_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY,
|
|
argv[5]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_msdp_peer,
|
|
no_ip_msdp_peer_cmd,
|
|
"no ip msdp peer A.B.C.D",
|
|
NO_STR
|
|
IP_STR
|
|
CFG_MSDP_STR
|
|
"Delete MSDP peer\n"
|
|
"peer ip address\n")
|
|
{
|
|
const char *vrfname;
|
|
char msdp_peer_xpath[XPATH_MAXLEN];
|
|
char temp_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
snprintf(temp_xpath, sizeof(temp_xpath),
|
|
"/msdp-peer[peer-ip='%s']",
|
|
argv[4]->arg);
|
|
|
|
strlcat(msdp_peer_xpath, temp_xpath, sizeof(msdp_peer_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (ip_msdp_mesh_group_member,
|
|
ip_msdp_mesh_group_member_cmd,
|
|
"ip msdp mesh-group WORD member A.B.C.D",
|
|
IP_STR
|
|
CFG_MSDP_STR
|
|
"Configure MSDP mesh-group\n"
|
|
"mesh group name\n"
|
|
"mesh group member\n"
|
|
"peer ip address\n")
|
|
{
|
|
const char *vrfname;
|
|
char msdp_mesh_group_name_xpath[XPATH_MAXLEN];
|
|
char msdp_mesh_group_member_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(msdp_mesh_group_name_xpath, sizeof(msdp_mesh_group_name_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(msdp_mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name",
|
|
sizeof(msdp_mesh_group_name_xpath));
|
|
snprintf(msdp_mesh_group_member_xpath,
|
|
sizeof(msdp_mesh_group_member_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(msdp_mesh_group_member_xpath, "/msdp-mesh-group/member-ip",
|
|
sizeof(msdp_mesh_group_member_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, msdp_mesh_group_name_xpath, NB_OP_MODIFY,
|
|
argv[3]->arg);
|
|
nb_cli_enqueue_change(vty, msdp_mesh_group_member_xpath, NB_OP_CREATE,
|
|
argv[5]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_msdp_mesh_group_member,
|
|
no_ip_msdp_mesh_group_member_cmd,
|
|
"no ip msdp mesh-group WORD member A.B.C.D",
|
|
NO_STR
|
|
IP_STR
|
|
CFG_MSDP_STR
|
|
"Delete MSDP mesh-group member\n"
|
|
"mesh group name\n"
|
|
"mesh group member\n"
|
|
"peer ip address\n")
|
|
{
|
|
const char *vrfname;
|
|
char pim_af_xpath[XPATH_MAXLEN];
|
|
char mesh_group_xpath[XPATH_MAXLEN + 32];
|
|
char group_member_list_xpath[XPATH_MAXLEN + 64];
|
|
char group_member_xpath[XPATH_MAXLEN + 128];
|
|
char source_xpath[XPATH_MAXLEN + 64];
|
|
char mesh_group_name_xpath[XPATH_MAXLEN + 64];
|
|
const char *mesh_group_name;
|
|
const struct lyd_node *member_dnode;
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(pim_af_xpath, sizeof(pim_af_xpath), FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
|
|
snprintf(mesh_group_xpath, sizeof(mesh_group_xpath),
|
|
"%s/msdp-mesh-group", pim_af_xpath);
|
|
|
|
snprintf(group_member_list_xpath, sizeof(group_member_list_xpath),
|
|
"%s/msdp-mesh-group/member-ip", pim_af_xpath);
|
|
|
|
snprintf(group_member_xpath, sizeof(group_member_xpath), "%s[.='%s']",
|
|
group_member_list_xpath, argv[6]->arg);
|
|
|
|
snprintf(source_xpath, sizeof(source_xpath),
|
|
"%s/msdp-mesh-group/source-ip", pim_af_xpath);
|
|
|
|
snprintf(mesh_group_name_xpath, sizeof(mesh_group_name_xpath),
|
|
"%s/msdp-mesh-group/mesh-group-name", pim_af_xpath);
|
|
|
|
if (yang_dnode_exists(running_config->dnode, mesh_group_name_xpath)
|
|
== true) {
|
|
mesh_group_name = yang_dnode_get_string(running_config->dnode,
|
|
mesh_group_name_xpath);
|
|
if (strcmp(mesh_group_name, argv[4]->arg)) {
|
|
vty_out(vty, "%% mesh-group does not exist\n");
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
}
|
|
}
|
|
|
|
if (yang_dnode_exists(vty->candidate_config->dnode,
|
|
group_member_xpath)) {
|
|
if (!yang_dnode_exists(vty->candidate_config->dnode,
|
|
source_xpath)) {
|
|
member_dnode = yang_dnode_get(
|
|
vty->candidate_config->dnode,
|
|
group_member_xpath);
|
|
if (yang_is_last_list_dnode(member_dnode)) {
|
|
nb_cli_enqueue_change(vty, mesh_group_xpath,
|
|
NB_OP_DESTROY, NULL);
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
nb_cli_enqueue_change(vty, group_member_list_xpath,
|
|
NB_OP_DESTROY, argv[6]->arg);
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
nb_cli_enqueue_change(vty, group_member_list_xpath,
|
|
NB_OP_DESTROY, argv[6]->arg);
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
vty_out(vty, "%% mesh-group member does not exist\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (ip_msdp_mesh_group_source,
|
|
ip_msdp_mesh_group_source_cmd,
|
|
"ip msdp mesh-group WORD source A.B.C.D",
|
|
IP_STR
|
|
CFG_MSDP_STR
|
|
"Configure MSDP mesh-group\n"
|
|
"mesh group name\n"
|
|
"mesh group local address\n"
|
|
"source ip address for the TCP connection\n")
|
|
{
|
|
const char *vrfname;
|
|
char msdp_mesh_source_ip_xpath[XPATH_MAXLEN];
|
|
char msdp_mesh_group_name_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(msdp_mesh_group_name_xpath, sizeof(msdp_mesh_group_name_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(msdp_mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name",
|
|
sizeof(msdp_mesh_group_name_xpath));
|
|
|
|
snprintf(msdp_mesh_source_ip_xpath, sizeof(msdp_mesh_source_ip_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(msdp_mesh_source_ip_xpath, "/msdp-mesh-group/source-ip",
|
|
sizeof(msdp_mesh_source_ip_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, msdp_mesh_group_name_xpath, NB_OP_MODIFY,
|
|
argv[3]->arg);
|
|
nb_cli_enqueue_change(vty, msdp_mesh_source_ip_xpath, NB_OP_MODIFY,
|
|
argv[5]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_msdp_mesh_group_source,
|
|
no_ip_msdp_mesh_group_source_cmd,
|
|
"no ip msdp mesh-group WORD source [A.B.C.D]",
|
|
NO_STR
|
|
IP_STR
|
|
CFG_MSDP_STR
|
|
"Delete MSDP mesh-group source\n"
|
|
"mesh group name\n"
|
|
"mesh group source\n"
|
|
"mesh group local address\n")
|
|
{
|
|
const char *vrfname;
|
|
char msdp_mesh_xpath[XPATH_MAXLEN];
|
|
char source_xpath[XPATH_MAXLEN];
|
|
char group_member_xpath[XPATH_MAXLEN];
|
|
char mesh_group_name_xpath[XPATH_MAXLEN];
|
|
const char *mesh_group_name;
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
snprintf(msdp_mesh_xpath, sizeof(msdp_mesh_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(msdp_mesh_xpath, "/msdp-mesh-group", sizeof(msdp_mesh_xpath));
|
|
|
|
snprintf(source_xpath, sizeof(source_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(source_xpath, "/msdp-mesh-group/source-ip",
|
|
sizeof(source_xpath));
|
|
|
|
snprintf(group_member_xpath,
|
|
sizeof(group_member_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(group_member_xpath, "/msdp-mesh-group/member-ip",
|
|
sizeof(group_member_xpath));
|
|
|
|
snprintf(mesh_group_name_xpath, sizeof(mesh_group_name_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name",
|
|
sizeof(mesh_group_name_xpath));
|
|
|
|
if (yang_dnode_exists(running_config->dnode, mesh_group_name_xpath)
|
|
== true) {
|
|
mesh_group_name = yang_dnode_get_string(running_config->dnode,
|
|
mesh_group_name_xpath);
|
|
if (strcmp(mesh_group_name, argv[4]->arg)) {
|
|
vty_out(vty, "%% mesh-group does not exist\n");
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
}
|
|
}
|
|
|
|
if (!yang_dnode_exists(vty->candidate_config->dnode,
|
|
group_member_xpath)) {
|
|
nb_cli_enqueue_change(vty, msdp_mesh_xpath, NB_OP_DESTROY,
|
|
NULL);
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
nb_cli_enqueue_change(vty, source_xpath, NB_OP_DESTROY, NULL);
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN (no_ip_msdp_mesh_group,
|
|
no_ip_msdp_mesh_group_cmd,
|
|
"no ip msdp mesh-group [WORD]",
|
|
NO_STR
|
|
IP_STR
|
|
CFG_MSDP_STR
|
|
"Delete MSDP mesh-group\n"
|
|
"mesh group name")
|
|
{
|
|
const char *vrfname;
|
|
const char *mesh_group_name;
|
|
char xpath[XPATH_MAXLEN];
|
|
char msdp_mesh_xpath[XPATH_MAXLEN];
|
|
|
|
vrfname = pim_cli_get_vrf_name(vty);
|
|
if (vrfname == NULL)
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
|
|
if (argc == 5) {
|
|
snprintf(xpath, sizeof(xpath), FRR_PIM_AF_XPATH, "frr-pim:pimd",
|
|
"pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(xpath, "/msdp-mesh-group/mesh-group-name",
|
|
sizeof(xpath));
|
|
|
|
if (yang_dnode_exists(running_config->dnode, xpath) == true) {
|
|
mesh_group_name =
|
|
yang_dnode_get_string(running_config->dnode,
|
|
xpath);
|
|
|
|
if (strcmp(mesh_group_name, argv[4]->arg)) {
|
|
vty_out(vty, "%% mesh-group does not exist\n");
|
|
return CMD_WARNING_CONFIG_FAILED;
|
|
}
|
|
}
|
|
}
|
|
|
|
snprintf(msdp_mesh_xpath, sizeof(msdp_mesh_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
|
|
strlcat(msdp_mesh_xpath, "/msdp-mesh-group", sizeof(msdp_mesh_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, msdp_mesh_xpath, NB_OP_DESTROY, NULL);
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
static void print_empty_json_obj(struct vty *vty)
|
|
{
|
|
json_object *json;
|
|
json = json_object_new_object();
|
|
vty_out(vty, "%s\n",
|
|
json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
|
|
static void ip_msdp_show_mesh_group(struct pim_instance *pim, struct vty *vty,
|
|
bool uj)
|
|
{
|
|
struct listnode *mbrnode;
|
|
struct pim_msdp_mg_mbr *mbr;
|
|
struct pim_msdp_mg *mg = pim->msdp.mg;
|
|
char mbr_str[INET_ADDRSTRLEN];
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char state_str[PIM_MSDP_STATE_STRLEN];
|
|
enum pim_msdp_peer_state state;
|
|
json_object *json = NULL;
|
|
json_object *json_mg_row = NULL;
|
|
json_object *json_members = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
if (!mg) {
|
|
if (uj)
|
|
print_empty_json_obj(vty);
|
|
return;
|
|
}
|
|
|
|
pim_inet4_dump("<source?>", mg->src_ip, src_str, sizeof(src_str));
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
/* currently there is only one mesh group but we should still
|
|
* make
|
|
* it a dict with mg-name as key */
|
|
json_mg_row = json_object_new_object();
|
|
json_object_string_add(json_mg_row, "name",
|
|
mg->mesh_group_name);
|
|
json_object_string_add(json_mg_row, "source", src_str);
|
|
} else {
|
|
vty_out(vty, "Mesh group : %s\n", mg->mesh_group_name);
|
|
vty_out(vty, " Source : %s\n", src_str);
|
|
vty_out(vty, " Member State\n");
|
|
}
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) {
|
|
pim_inet4_dump("<mbr?>", mbr->mbr_ip, mbr_str, sizeof(mbr_str));
|
|
if (mbr->mp) {
|
|
state = mbr->mp->state;
|
|
} else {
|
|
state = PIM_MSDP_DISABLED;
|
|
}
|
|
pim_msdp_state_dump(state, state_str, sizeof(state_str));
|
|
if (uj) {
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "member", mbr_str);
|
|
json_object_string_add(json_row, "state", state_str);
|
|
if (!json_members) {
|
|
json_members = json_object_new_object();
|
|
json_object_object_add(json_mg_row, "members",
|
|
json_members);
|
|
}
|
|
json_object_object_add(json_members, mbr_str, json_row);
|
|
} else {
|
|
vty_out(vty, " %-15s %11s\n", mbr_str, state_str);
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
json_object_object_add(json, mg->mesh_group_name, json_mg_row);
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
DEFUN (show_ip_msdp_mesh_group,
|
|
show_ip_msdp_mesh_group_cmd,
|
|
"show ip msdp [vrf NAME] mesh-group [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
MSDP_STR
|
|
VRF_CMD_HELP_STR
|
|
"MSDP mesh-group information\n"
|
|
JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
ip_msdp_show_mesh_group(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_msdp_mesh_group_vrf_all,
|
|
show_ip_msdp_mesh_group_vrf_all_cmd,
|
|
"show ip msdp vrf all mesh-group [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
MSDP_STR
|
|
VRF_CMD_HELP_STR
|
|
"MSDP mesh-group information\n"
|
|
JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
ip_msdp_show_mesh_group(vrf->info, vty, uj);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
static void ip_msdp_show_peers(struct pim_instance *pim, struct vty *vty,
|
|
bool uj)
|
|
{
|
|
struct listnode *mpnode;
|
|
struct pim_msdp_peer *mp;
|
|
char peer_str[INET_ADDRSTRLEN];
|
|
char local_str[INET_ADDRSTRLEN];
|
|
char state_str[PIM_MSDP_STATE_STRLEN];
|
|
char timebuf[PIM_MSDP_UPTIME_STRLEN];
|
|
int64_t now;
|
|
json_object *json = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
} else {
|
|
vty_out(vty,
|
|
"Peer Local State Uptime SaCnt\n");
|
|
}
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
|
|
if (mp->state == PIM_MSDP_ESTABLISHED) {
|
|
now = pim_time_monotonic_sec();
|
|
pim_time_uptime(timebuf, sizeof(timebuf),
|
|
now - mp->uptime);
|
|
} else {
|
|
strlcpy(timebuf, "-", sizeof(timebuf));
|
|
}
|
|
pim_inet4_dump("<peer?>", mp->peer, peer_str, sizeof(peer_str));
|
|
pim_inet4_dump("<local?>", mp->local, local_str,
|
|
sizeof(local_str));
|
|
pim_msdp_state_dump(mp->state, state_str, sizeof(state_str));
|
|
if (uj) {
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "peer", peer_str);
|
|
json_object_string_add(json_row, "local", local_str);
|
|
json_object_string_add(json_row, "state", state_str);
|
|
json_object_string_add(json_row, "upTime", timebuf);
|
|
json_object_int_add(json_row, "saCount", mp->sa_cnt);
|
|
json_object_object_add(json, peer_str, json_row);
|
|
} else {
|
|
vty_out(vty, "%-15s %15s %11s %8s %6d\n", peer_str,
|
|
local_str, state_str, timebuf, mp->sa_cnt);
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void ip_msdp_show_peers_detail(struct pim_instance *pim, struct vty *vty,
|
|
const char *peer, bool uj)
|
|
{
|
|
struct listnode *mpnode;
|
|
struct pim_msdp_peer *mp;
|
|
char peer_str[INET_ADDRSTRLEN];
|
|
char local_str[INET_ADDRSTRLEN];
|
|
char state_str[PIM_MSDP_STATE_STRLEN];
|
|
char timebuf[PIM_MSDP_UPTIME_STRLEN];
|
|
char katimer[PIM_MSDP_TIMER_STRLEN];
|
|
char crtimer[PIM_MSDP_TIMER_STRLEN];
|
|
char holdtimer[PIM_MSDP_TIMER_STRLEN];
|
|
int64_t now;
|
|
json_object *json = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
}
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
|
|
pim_inet4_dump("<peer?>", mp->peer, peer_str, sizeof(peer_str));
|
|
if (strcmp(peer, "detail") && strcmp(peer, peer_str))
|
|
continue;
|
|
|
|
if (mp->state == PIM_MSDP_ESTABLISHED) {
|
|
now = pim_time_monotonic_sec();
|
|
pim_time_uptime(timebuf, sizeof(timebuf),
|
|
now - mp->uptime);
|
|
} else {
|
|
strlcpy(timebuf, "-", sizeof(timebuf));
|
|
}
|
|
pim_inet4_dump("<local?>", mp->local, local_str,
|
|
sizeof(local_str));
|
|
pim_msdp_state_dump(mp->state, state_str, sizeof(state_str));
|
|
pim_time_timer_to_hhmmss(katimer, sizeof(katimer),
|
|
mp->ka_timer);
|
|
pim_time_timer_to_hhmmss(crtimer, sizeof(crtimer),
|
|
mp->cr_timer);
|
|
pim_time_timer_to_hhmmss(holdtimer, sizeof(holdtimer),
|
|
mp->hold_timer);
|
|
|
|
if (uj) {
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "peer", peer_str);
|
|
json_object_string_add(json_row, "local", local_str);
|
|
json_object_string_add(json_row, "meshGroupName",
|
|
mp->mesh_group_name);
|
|
json_object_string_add(json_row, "state", state_str);
|
|
json_object_string_add(json_row, "upTime", timebuf);
|
|
json_object_string_add(json_row, "keepAliveTimer",
|
|
katimer);
|
|
json_object_string_add(json_row, "connRetryTimer",
|
|
crtimer);
|
|
json_object_string_add(json_row, "holdTimer",
|
|
holdtimer);
|
|
json_object_string_add(json_row, "lastReset",
|
|
mp->last_reset);
|
|
json_object_int_add(json_row, "connAttempts",
|
|
mp->conn_attempts);
|
|
json_object_int_add(json_row, "establishedChanges",
|
|
mp->est_flaps);
|
|
json_object_int_add(json_row, "saCount", mp->sa_cnt);
|
|
json_object_int_add(json_row, "kaSent", mp->ka_tx_cnt);
|
|
json_object_int_add(json_row, "kaRcvd", mp->ka_rx_cnt);
|
|
json_object_int_add(json_row, "saSent", mp->sa_tx_cnt);
|
|
json_object_int_add(json_row, "saRcvd", mp->sa_rx_cnt);
|
|
json_object_object_add(json, peer_str, json_row);
|
|
} else {
|
|
vty_out(vty, "Peer : %s\n", peer_str);
|
|
vty_out(vty, " Local : %s\n", local_str);
|
|
vty_out(vty, " Mesh Group : %s\n",
|
|
mp->mesh_group_name);
|
|
vty_out(vty, " State : %s\n", state_str);
|
|
vty_out(vty, " Uptime : %s\n", timebuf);
|
|
|
|
vty_out(vty, " Keepalive Timer : %s\n", katimer);
|
|
vty_out(vty, " Conn Retry Timer : %s\n", crtimer);
|
|
vty_out(vty, " Hold Timer : %s\n", holdtimer);
|
|
vty_out(vty, " Last Reset : %s\n",
|
|
mp->last_reset);
|
|
vty_out(vty, " Conn Attempts : %d\n",
|
|
mp->conn_attempts);
|
|
vty_out(vty, " Established Changes : %d\n",
|
|
mp->est_flaps);
|
|
vty_out(vty, " SA Count : %d\n",
|
|
mp->sa_cnt);
|
|
vty_out(vty, " Statistics :\n");
|
|
vty_out(vty,
|
|
" Sent Rcvd\n");
|
|
vty_out(vty, " Keepalives : %10d %10d\n",
|
|
mp->ka_tx_cnt, mp->ka_rx_cnt);
|
|
vty_out(vty, " SAs : %10d %10d\n",
|
|
mp->sa_tx_cnt, mp->sa_rx_cnt);
|
|
vty_out(vty, "\n");
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
DEFUN (show_ip_msdp_peer_detail,
|
|
show_ip_msdp_peer_detail_cmd,
|
|
"show ip msdp [vrf NAME] peer [detail|A.B.C.D] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
MSDP_STR
|
|
VRF_CMD_HELP_STR
|
|
"MSDP peer information\n"
|
|
"Detailed output\n"
|
|
"peer ip address\n"
|
|
JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
char *arg = NULL;
|
|
|
|
if (argv_find(argv, argc, "detail", &idx))
|
|
arg = argv[idx]->text;
|
|
else if (argv_find(argv, argc, "A.B.C.D", &idx))
|
|
arg = argv[idx]->arg;
|
|
|
|
if (arg)
|
|
ip_msdp_show_peers_detail(vrf->info, vty, argv[idx]->arg, uj);
|
|
else
|
|
ip_msdp_show_peers(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_msdp_peer_detail_vrf_all,
|
|
show_ip_msdp_peer_detail_vrf_all_cmd,
|
|
"show ip msdp vrf all peer [detail|A.B.C.D] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
MSDP_STR
|
|
VRF_CMD_HELP_STR
|
|
"MSDP peer information\n"
|
|
"Detailed output\n"
|
|
"peer ip address\n"
|
|
JSON_STR)
|
|
{
|
|
int idx = 2;
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
if (argv_find(argv, argc, "detail", &idx)
|
|
|| argv_find(argv, argc, "A.B.C.D", &idx))
|
|
ip_msdp_show_peers_detail(vrf->info, vty,
|
|
argv[idx]->arg, uj);
|
|
else
|
|
ip_msdp_show_peers(vrf->info, vty, uj);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
static void ip_msdp_show_sa(struct pim_instance *pim, struct vty *vty, bool uj)
|
|
{
|
|
struct listnode *sanode;
|
|
struct pim_msdp_sa *sa;
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
char rp_str[INET_ADDRSTRLEN];
|
|
char timebuf[PIM_MSDP_UPTIME_STRLEN];
|
|
char spt_str[8];
|
|
char local_str[8];
|
|
int64_t now;
|
|
json_object *json = NULL;
|
|
json_object *json_group = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
} else {
|
|
vty_out(vty,
|
|
"Source Group RP Local SPT Uptime\n");
|
|
}
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
|
|
now = pim_time_monotonic_sec();
|
|
pim_time_uptime(timebuf, sizeof(timebuf), now - sa->uptime);
|
|
pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str));
|
|
pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str));
|
|
if (sa->flags & PIM_MSDP_SAF_PEER) {
|
|
pim_inet4_dump("<rp?>", sa->rp, rp_str, sizeof(rp_str));
|
|
if (sa->up) {
|
|
strlcpy(spt_str, "yes", sizeof(spt_str));
|
|
} else {
|
|
strlcpy(spt_str, "no", sizeof(spt_str));
|
|
}
|
|
} else {
|
|
strlcpy(rp_str, "-", sizeof(rp_str));
|
|
strlcpy(spt_str, "-", sizeof(spt_str));
|
|
}
|
|
if (sa->flags & PIM_MSDP_SAF_LOCAL) {
|
|
strlcpy(local_str, "yes", sizeof(local_str));
|
|
} else {
|
|
strlcpy(local_str, "no", sizeof(local_str));
|
|
}
|
|
if (uj) {
|
|
json_object_object_get_ex(json, grp_str, &json_group);
|
|
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_object_add(json, grp_str,
|
|
json_group);
|
|
}
|
|
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "source", src_str);
|
|
json_object_string_add(json_row, "group", grp_str);
|
|
json_object_string_add(json_row, "rp", rp_str);
|
|
json_object_string_add(json_row, "local", local_str);
|
|
json_object_string_add(json_row, "sptSetup", spt_str);
|
|
json_object_string_add(json_row, "upTime", timebuf);
|
|
json_object_object_add(json_group, src_str, json_row);
|
|
} else {
|
|
vty_out(vty, "%-15s %15s %15s %5c %3c %8s\n",
|
|
src_str, grp_str, rp_str, local_str[0],
|
|
spt_str[0], timebuf);
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void ip_msdp_show_sa_entry_detail(struct pim_msdp_sa *sa,
|
|
const char *src_str,
|
|
const char *grp_str, struct vty *vty,
|
|
bool uj, json_object *json)
|
|
{
|
|
char rp_str[INET_ADDRSTRLEN];
|
|
char peer_str[INET_ADDRSTRLEN];
|
|
char timebuf[PIM_MSDP_UPTIME_STRLEN];
|
|
char spt_str[8];
|
|
char local_str[8];
|
|
char statetimer[PIM_MSDP_TIMER_STRLEN];
|
|
int64_t now;
|
|
json_object *json_group = NULL;
|
|
json_object *json_row = NULL;
|
|
|
|
now = pim_time_monotonic_sec();
|
|
pim_time_uptime(timebuf, sizeof(timebuf), now - sa->uptime);
|
|
if (sa->flags & PIM_MSDP_SAF_PEER) {
|
|
pim_inet4_dump("<rp?>", sa->rp, rp_str, sizeof(rp_str));
|
|
pim_inet4_dump("<peer?>", sa->peer, peer_str, sizeof(peer_str));
|
|
if (sa->up) {
|
|
strlcpy(spt_str, "yes", sizeof(spt_str));
|
|
} else {
|
|
strlcpy(spt_str, "no", sizeof(spt_str));
|
|
}
|
|
} else {
|
|
strlcpy(rp_str, "-", sizeof(rp_str));
|
|
strlcpy(peer_str, "-", sizeof(peer_str));
|
|
strlcpy(spt_str, "-", sizeof(spt_str));
|
|
}
|
|
if (sa->flags & PIM_MSDP_SAF_LOCAL) {
|
|
strlcpy(local_str, "yes", sizeof(local_str));
|
|
} else {
|
|
strlcpy(local_str, "no", sizeof(local_str));
|
|
}
|
|
pim_time_timer_to_hhmmss(statetimer, sizeof(statetimer),
|
|
sa->sa_state_timer);
|
|
if (uj) {
|
|
json_object_object_get_ex(json, grp_str, &json_group);
|
|
|
|
if (!json_group) {
|
|
json_group = json_object_new_object();
|
|
json_object_object_add(json, grp_str, json_group);
|
|
}
|
|
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "source", src_str);
|
|
json_object_string_add(json_row, "group", grp_str);
|
|
json_object_string_add(json_row, "rp", rp_str);
|
|
json_object_string_add(json_row, "local", local_str);
|
|
json_object_string_add(json_row, "sptSetup", spt_str);
|
|
json_object_string_add(json_row, "upTime", timebuf);
|
|
json_object_string_add(json_row, "stateTimer", statetimer);
|
|
json_object_object_add(json_group, src_str, json_row);
|
|
} else {
|
|
vty_out(vty, "SA : %s\n", sa->sg_str);
|
|
vty_out(vty, " RP : %s\n", rp_str);
|
|
vty_out(vty, " Peer : %s\n", peer_str);
|
|
vty_out(vty, " Local : %s\n", local_str);
|
|
vty_out(vty, " SPT Setup : %s\n", spt_str);
|
|
vty_out(vty, " Uptime : %s\n", timebuf);
|
|
vty_out(vty, " State Timer : %s\n", statetimer);
|
|
vty_out(vty, "\n");
|
|
}
|
|
}
|
|
|
|
static void ip_msdp_show_sa_detail(struct pim_instance *pim, struct vty *vty,
|
|
bool uj)
|
|
{
|
|
struct listnode *sanode;
|
|
struct pim_msdp_sa *sa;
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
json_object *json = NULL;
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
}
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
|
|
pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str));
|
|
pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str));
|
|
ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty, uj,
|
|
json);
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
DEFUN (show_ip_msdp_sa_detail,
|
|
show_ip_msdp_sa_detail_cmd,
|
|
"show ip msdp [vrf NAME] sa detail [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
MSDP_STR
|
|
VRF_CMD_HELP_STR
|
|
"MSDP active-source information\n"
|
|
"Detailed output\n"
|
|
JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
int idx = 2;
|
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
ip_msdp_show_sa_detail(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_msdp_sa_detail_vrf_all,
|
|
show_ip_msdp_sa_detail_vrf_all_cmd,
|
|
"show ip msdp vrf all sa detail [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
MSDP_STR
|
|
VRF_CMD_HELP_STR
|
|
"MSDP active-source information\n"
|
|
"Detailed output\n"
|
|
JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
ip_msdp_show_sa_detail(vrf->info, vty, uj);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
static void ip_msdp_show_sa_addr(struct pim_instance *pim, struct vty *vty,
|
|
const char *addr, bool uj)
|
|
{
|
|
struct listnode *sanode;
|
|
struct pim_msdp_sa *sa;
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
json_object *json = NULL;
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
}
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
|
|
pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str));
|
|
pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str));
|
|
if (!strcmp(addr, src_str) || !strcmp(addr, grp_str)) {
|
|
ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty,
|
|
uj, json);
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void ip_msdp_show_sa_sg(struct pim_instance *pim, struct vty *vty,
|
|
const char *src, const char *grp, bool uj)
|
|
{
|
|
struct listnode *sanode;
|
|
struct pim_msdp_sa *sa;
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
json_object *json = NULL;
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
}
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
|
|
pim_inet4_dump("<src?>", sa->sg.src, src_str, sizeof(src_str));
|
|
pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str));
|
|
if (!strcmp(src, src_str) && !strcmp(grp, grp_str)) {
|
|
ip_msdp_show_sa_entry_detail(sa, src_str, grp_str, vty,
|
|
uj, json);
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
DEFUN (show_ip_msdp_sa_sg,
|
|
show_ip_msdp_sa_sg_cmd,
|
|
"show ip msdp [vrf NAME] sa [A.B.C.D [A.B.C.D]] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
MSDP_STR
|
|
VRF_CMD_HELP_STR
|
|
"MSDP active-source information\n"
|
|
"source or group ip\n"
|
|
"group ip\n"
|
|
JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
int idx = 2;
|
|
|
|
vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
char *src_ip = argv_find(argv, argc, "A.B.C.D", &idx) ? argv[idx++]->arg
|
|
: NULL;
|
|
char *grp_ip = idx < argc && argv_find(argv, argc, "A.B.C.D", &idx)
|
|
? argv[idx]->arg
|
|
: NULL;
|
|
|
|
if (src_ip && grp_ip)
|
|
ip_msdp_show_sa_sg(vrf->info, vty, src_ip, grp_ip, uj);
|
|
else if (src_ip)
|
|
ip_msdp_show_sa_addr(vrf->info, vty, src_ip, uj);
|
|
else
|
|
ip_msdp_show_sa(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN (show_ip_msdp_sa_sg_vrf_all,
|
|
show_ip_msdp_sa_sg_vrf_all_cmd,
|
|
"show ip msdp vrf all sa [A.B.C.D [A.B.C.D]] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
MSDP_STR
|
|
VRF_CMD_HELP_STR
|
|
"MSDP active-source information\n"
|
|
"source or group ip\n"
|
|
"group ip\n"
|
|
JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
bool first = true;
|
|
int idx = 2;
|
|
|
|
char *src_ip = argv_find(argv, argc, "A.B.C.D", &idx) ? argv[idx++]->arg
|
|
: NULL;
|
|
char *grp_ip = idx < argc && argv_find(argv, argc, "A.B.C.D", &idx)
|
|
? argv[idx]->arg
|
|
: NULL;
|
|
|
|
if (uj)
|
|
vty_out(vty, "{ ");
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
if (uj) {
|
|
if (!first)
|
|
vty_out(vty, ", ");
|
|
vty_out(vty, " \"%s\": ", vrf->name);
|
|
first = false;
|
|
} else
|
|
vty_out(vty, "VRF: %s\n", vrf->name);
|
|
|
|
if (src_ip && grp_ip)
|
|
ip_msdp_show_sa_sg(vrf->info, vty, src_ip, grp_ip, uj);
|
|
else if (src_ip)
|
|
ip_msdp_show_sa_addr(vrf->info, vty, src_ip, uj);
|
|
else
|
|
ip_msdp_show_sa(vrf->info, vty, uj);
|
|
}
|
|
if (uj)
|
|
vty_out(vty, "}\n");
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
struct pim_sg_cache_walk_data {
|
|
struct vty *vty;
|
|
json_object *json;
|
|
json_object *json_group;
|
|
struct in_addr addr;
|
|
bool addr_match;
|
|
};
|
|
|
|
static void pim_show_vxlan_sg_entry(struct pim_vxlan_sg *vxlan_sg,
|
|
struct pim_sg_cache_walk_data *cwd)
|
|
{
|
|
struct vty *vty = cwd->vty;
|
|
json_object *json = cwd->json;
|
|
char src_str[INET_ADDRSTRLEN];
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
json_object *json_row;
|
|
bool installed = (vxlan_sg->up) ? true : false;
|
|
const char *iif_name = vxlan_sg->iif?vxlan_sg->iif->name:"-";
|
|
const char *oif_name;
|
|
|
|
if (pim_vxlan_is_orig_mroute(vxlan_sg))
|
|
oif_name = vxlan_sg->orig_oif?vxlan_sg->orig_oif->name:"";
|
|
else
|
|
oif_name = vxlan_sg->term_oif?vxlan_sg->term_oif->name:"";
|
|
|
|
if (cwd->addr_match && (vxlan_sg->sg.src.s_addr != cwd->addr.s_addr) &&
|
|
(vxlan_sg->sg.grp.s_addr != cwd->addr.s_addr)) {
|
|
return;
|
|
}
|
|
pim_inet4_dump("<src?>", vxlan_sg->sg.src, src_str, sizeof(src_str));
|
|
pim_inet4_dump("<grp?>", vxlan_sg->sg.grp, grp_str, sizeof(grp_str));
|
|
if (json) {
|
|
json_object_object_get_ex(json, grp_str, &cwd->json_group);
|
|
|
|
if (!cwd->json_group) {
|
|
cwd->json_group = json_object_new_object();
|
|
json_object_object_add(json, grp_str,
|
|
cwd->json_group);
|
|
}
|
|
|
|
json_row = json_object_new_object();
|
|
json_object_string_add(json_row, "source", src_str);
|
|
json_object_string_add(json_row, "group", grp_str);
|
|
json_object_string_add(json_row, "input", iif_name);
|
|
json_object_string_add(json_row, "output", oif_name);
|
|
if (installed)
|
|
json_object_boolean_true_add(json_row, "installed");
|
|
else
|
|
json_object_boolean_false_add(json_row, "installed");
|
|
json_object_object_add(cwd->json_group, src_str, json_row);
|
|
} else {
|
|
vty_out(vty, "%-15s %-15s %-15s %-15s %-5s\n",
|
|
src_str, grp_str, iif_name, oif_name,
|
|
installed?"I":"");
|
|
}
|
|
}
|
|
|
|
static void pim_show_vxlan_sg_hash_entry(struct hash_bucket *bucket, void *arg)
|
|
{
|
|
pim_show_vxlan_sg_entry((struct pim_vxlan_sg *)bucket->data,
|
|
(struct pim_sg_cache_walk_data *)arg);
|
|
}
|
|
|
|
static void pim_show_vxlan_sg(struct pim_instance *pim,
|
|
struct vty *vty, bool uj)
|
|
{
|
|
json_object *json = NULL;
|
|
struct pim_sg_cache_walk_data cwd;
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
} else {
|
|
vty_out(vty, "Codes: I -> installed\n");
|
|
vty_out(vty,
|
|
"Source Group Input Output Flags\n");
|
|
}
|
|
|
|
memset(&cwd, 0, sizeof(cwd));
|
|
cwd.vty = vty;
|
|
cwd.json = json;
|
|
hash_iterate(pim->vxlan.sg_hash, pim_show_vxlan_sg_hash_entry, &cwd);
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void pim_show_vxlan_sg_match_addr(struct pim_instance *pim,
|
|
struct vty *vty, char *addr_str,
|
|
bool uj)
|
|
{
|
|
json_object *json = NULL;
|
|
struct pim_sg_cache_walk_data cwd;
|
|
int result = 0;
|
|
|
|
memset(&cwd, 0, sizeof(cwd));
|
|
result = inet_pton(AF_INET, addr_str, &cwd.addr);
|
|
if (result <= 0) {
|
|
vty_out(vty, "Bad address %s: errno=%d: %s\n", addr_str,
|
|
errno, safe_strerror(errno));
|
|
return;
|
|
}
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
} else {
|
|
vty_out(vty, "Codes: I -> installed\n");
|
|
vty_out(vty,
|
|
"Source Group Input Output Flags\n");
|
|
}
|
|
|
|
cwd.vty = vty;
|
|
cwd.json = json;
|
|
cwd.addr_match = true;
|
|
hash_iterate(pim->vxlan.sg_hash, pim_show_vxlan_sg_hash_entry, &cwd);
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
static void pim_show_vxlan_sg_one(struct pim_instance *pim,
|
|
struct vty *vty, char *src_str, char *grp_str,
|
|
bool uj)
|
|
{
|
|
json_object *json = NULL;
|
|
struct prefix_sg sg;
|
|
int result = 0;
|
|
struct pim_vxlan_sg *vxlan_sg;
|
|
const char *iif_name;
|
|
bool installed;
|
|
const char *oif_name;
|
|
|
|
result = inet_pton(AF_INET, src_str, &sg.src);
|
|
if (result <= 0) {
|
|
vty_out(vty, "Bad src address %s: errno=%d: %s\n", src_str,
|
|
errno, safe_strerror(errno));
|
|
return;
|
|
}
|
|
result = inet_pton(AF_INET, grp_str, &sg.grp);
|
|
if (result <= 0) {
|
|
vty_out(vty, "Bad grp address %s: errno=%d: %s\n", grp_str,
|
|
errno, safe_strerror(errno));
|
|
return;
|
|
}
|
|
|
|
sg.family = AF_INET;
|
|
sg.prefixlen = IPV4_MAX_BITLEN;
|
|
if (uj)
|
|
json = json_object_new_object();
|
|
|
|
vxlan_sg = pim_vxlan_sg_find(pim, &sg);
|
|
if (vxlan_sg) {
|
|
installed = (vxlan_sg->up) ? true : false;
|
|
iif_name = vxlan_sg->iif?vxlan_sg->iif->name:"-";
|
|
|
|
if (pim_vxlan_is_orig_mroute(vxlan_sg))
|
|
oif_name =
|
|
vxlan_sg->orig_oif?vxlan_sg->orig_oif->name:"";
|
|
else
|
|
oif_name =
|
|
vxlan_sg->term_oif?vxlan_sg->term_oif->name:"";
|
|
|
|
if (uj) {
|
|
json_object_string_add(json, "source", src_str);
|
|
json_object_string_add(json, "group", grp_str);
|
|
json_object_string_add(json, "input", iif_name);
|
|
json_object_string_add(json, "output", oif_name);
|
|
if (installed)
|
|
json_object_boolean_true_add(json, "installed");
|
|
else
|
|
json_object_boolean_false_add(json,
|
|
"installed");
|
|
} else {
|
|
vty_out(vty, "SG : %s\n", vxlan_sg->sg_str);
|
|
vty_out(vty, " Input : %s\n", iif_name);
|
|
vty_out(vty, " Output : %s\n", oif_name);
|
|
vty_out(vty, " installed : %s\n",
|
|
installed?"yes":"no");
|
|
}
|
|
}
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
DEFUN (show_ip_pim_vxlan_sg,
|
|
show_ip_pim_vxlan_sg_cmd,
|
|
"show ip pim [vrf NAME] vxlan-groups [A.B.C.D [A.B.C.D]] [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"VxLAN BUM groups\n"
|
|
"source or group ip\n"
|
|
"group ip\n"
|
|
JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
int idx = 2;
|
|
|
|
vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
char *src_ip = argv_find(argv, argc, "A.B.C.D", &idx) ?
|
|
argv[idx++]->arg:NULL;
|
|
char *grp_ip = idx < argc && argv_find(argv, argc, "A.B.C.D", &idx) ?
|
|
argv[idx]->arg:NULL;
|
|
|
|
if (src_ip && grp_ip)
|
|
pim_show_vxlan_sg_one(vrf->info, vty, src_ip, grp_ip, uj);
|
|
else if (src_ip)
|
|
pim_show_vxlan_sg_match_addr(vrf->info, vty, src_ip, uj);
|
|
else
|
|
pim_show_vxlan_sg(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
static void pim_show_vxlan_sg_work(struct pim_instance *pim,
|
|
struct vty *vty, bool uj)
|
|
{
|
|
json_object *json = NULL;
|
|
struct pim_sg_cache_walk_data cwd;
|
|
struct listnode *node;
|
|
struct pim_vxlan_sg *vxlan_sg;
|
|
|
|
if (uj) {
|
|
json = json_object_new_object();
|
|
} else {
|
|
vty_out(vty, "Codes: I -> installed\n");
|
|
vty_out(vty,
|
|
"Source Group Input Flags\n");
|
|
}
|
|
|
|
memset(&cwd, 0, sizeof(cwd));
|
|
cwd.vty = vty;
|
|
cwd.json = json;
|
|
for (ALL_LIST_ELEMENTS_RO(pim_vxlan_p->work_list, node, vxlan_sg))
|
|
pim_show_vxlan_sg_entry(vxlan_sg, &cwd);
|
|
|
|
if (uj) {
|
|
vty_out(vty, "%s\n", json_object_to_json_string_ext(
|
|
json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
}
|
|
|
|
DEFUN_HIDDEN (show_ip_pim_vxlan_sg_work,
|
|
show_ip_pim_vxlan_sg_work_cmd,
|
|
"show ip pim [vrf NAME] vxlan-work [json]",
|
|
SHOW_STR
|
|
IP_STR
|
|
PIM_STR
|
|
VRF_CMD_HELP_STR
|
|
"VxLAN work list\n"
|
|
JSON_STR)
|
|
{
|
|
bool uj = use_json(argc, argv);
|
|
struct vrf *vrf;
|
|
int idx = 2;
|
|
|
|
vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
|
|
|
|
if (!vrf)
|
|
return CMD_WARNING;
|
|
|
|
pim_show_vxlan_sg_work(vrf->info, vty, uj);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN_HIDDEN (no_ip_pim_mlag,
|
|
no_ip_pim_mlag_cmd,
|
|
"no ip pim mlag",
|
|
NO_STR
|
|
IP_STR
|
|
PIM_STR
|
|
"MLAG\n")
|
|
{
|
|
char mlag_xpath[XPATH_MAXLEN];
|
|
|
|
snprintf(mlag_xpath, sizeof(mlag_xpath), FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", "default", "frr-routing:ipv4");
|
|
strlcat(mlag_xpath, "/mlag", sizeof(mlag_xpath));
|
|
|
|
nb_cli_enqueue_change(vty, mlag_xpath, NB_OP_DESTROY, NULL);
|
|
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
DEFUN_HIDDEN (ip_pim_mlag,
|
|
ip_pim_mlag_cmd,
|
|
"ip pim mlag INTERFACE role [primary|secondary] state [up|down] addr A.B.C.D",
|
|
IP_STR
|
|
PIM_STR
|
|
"MLAG\n"
|
|
"peerlink sub interface\n"
|
|
"MLAG role\n"
|
|
"MLAG role primary\n"
|
|
"MLAG role secondary\n"
|
|
"peer session state\n"
|
|
"peer session state up\n"
|
|
"peer session state down\n"
|
|
"configure PIP\n"
|
|
"unique ip address\n")
|
|
{
|
|
int idx;
|
|
char mlag_peerlink_rif_xpath[XPATH_MAXLEN];
|
|
char mlag_my_role_xpath[XPATH_MAXLEN];
|
|
char mlag_peer_state_xpath[XPATH_MAXLEN];
|
|
char mlag_reg_address_xpath[XPATH_MAXLEN];
|
|
|
|
snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", "default", "frr-routing:ipv4");
|
|
strlcat(mlag_peerlink_rif_xpath, "/mlag/peerlink-rif",
|
|
sizeof(mlag_peerlink_rif_xpath));
|
|
|
|
idx = 3;
|
|
nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY,
|
|
argv[idx]->arg);
|
|
|
|
snprintf(mlag_my_role_xpath, sizeof(mlag_my_role_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", "default", "frr-routing:ipv4");
|
|
strlcat(mlag_my_role_xpath, "/mlag/my-role",
|
|
sizeof(mlag_my_role_xpath));
|
|
|
|
idx += 2;
|
|
if (!strcmp(argv[idx]->arg, "primary")) {
|
|
nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY,
|
|
"MLAG_ROLE_PRIMARY");
|
|
|
|
} else if (!strcmp(argv[idx]->arg, "secondary")) {
|
|
nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY,
|
|
"MLAG_ROLE_SECONDARY");
|
|
|
|
} else {
|
|
vty_out(vty, "unknown MLAG role %s\n", argv[idx]->arg);
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
snprintf(mlag_peer_state_xpath, sizeof(mlag_peer_state_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", "default", "frr-routing:ipv4");
|
|
strlcat(mlag_peer_state_xpath, "/mlag/peer-state",
|
|
sizeof(mlag_peer_state_xpath));
|
|
|
|
idx += 2;
|
|
if (!strcmp(argv[idx]->arg, "up")) {
|
|
nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY,
|
|
"true");
|
|
|
|
} else if (strcmp(argv[idx]->arg, "down")) {
|
|
nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY,
|
|
"false");
|
|
|
|
} else {
|
|
vty_out(vty, "unknown MLAG state %s\n", argv[idx]->arg);
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
snprintf(mlag_reg_address_xpath, sizeof(mlag_reg_address_xpath),
|
|
FRR_PIM_AF_XPATH,
|
|
"frr-pim:pimd", "pim", "default", "frr-routing:ipv4");
|
|
strlcat(mlag_reg_address_xpath, "/mlag/reg-address",
|
|
sizeof(mlag_reg_address_xpath));
|
|
|
|
idx += 2;
|
|
nb_cli_enqueue_change(vty, mlag_reg_address_xpath, NB_OP_MODIFY,
|
|
argv[idx]->arg);
|
|
|
|
return nb_cli_apply_changes(vty, NULL);
|
|
}
|
|
|
|
void pim_cmd_init(void)
|
|
{
|
|
install_node(&interface_node); /* INTERFACE_NODE */
|
|
if_cmd_init();
|
|
|
|
install_node(&debug_node);
|
|
|
|
install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd);
|
|
|
|
install_element(CONFIG_NODE, &ip_pim_rp_cmd);
|
|
install_element(VRF_NODE, &ip_pim_rp_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_pim_rp_cmd);
|
|
install_element(VRF_NODE, &no_ip_pim_rp_cmd);
|
|
install_element(CONFIG_NODE, &ip_pim_rp_prefix_list_cmd);
|
|
install_element(VRF_NODE, &ip_pim_rp_prefix_list_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_pim_rp_prefix_list_cmd);
|
|
install_element(VRF_NODE, &no_ip_pim_rp_prefix_list_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_pim_ssm_prefix_list_cmd);
|
|
install_element(VRF_NODE, &no_ip_pim_ssm_prefix_list_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_pim_ssm_prefix_list_name_cmd);
|
|
install_element(VRF_NODE, &no_ip_pim_ssm_prefix_list_name_cmd);
|
|
install_element(CONFIG_NODE, &ip_pim_ssm_prefix_list_cmd);
|
|
install_element(VRF_NODE, &ip_pim_ssm_prefix_list_cmd);
|
|
install_element(CONFIG_NODE, &ip_pim_register_suppress_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_pim_register_suppress_cmd);
|
|
install_element(CONFIG_NODE, &ip_pim_spt_switchover_infinity_cmd);
|
|
install_element(VRF_NODE, &ip_pim_spt_switchover_infinity_cmd);
|
|
install_element(CONFIG_NODE, &ip_pim_spt_switchover_infinity_plist_cmd);
|
|
install_element(VRF_NODE, &ip_pim_spt_switchover_infinity_plist_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_cmd);
|
|
install_element(VRF_NODE, &no_ip_pim_spt_switchover_infinity_cmd);
|
|
install_element(CONFIG_NODE,
|
|
&no_ip_pim_spt_switchover_infinity_plist_cmd);
|
|
install_element(VRF_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd);
|
|
install_element(CONFIG_NODE, &pim_register_accept_list_cmd);
|
|
install_element(VRF_NODE, &pim_register_accept_list_cmd);
|
|
install_element(CONFIG_NODE, &ip_pim_joinprune_time_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_pim_joinprune_time_cmd);
|
|
install_element(CONFIG_NODE, &ip_pim_keep_alive_cmd);
|
|
install_element(VRF_NODE, &ip_pim_keep_alive_cmd);
|
|
install_element(CONFIG_NODE, &ip_pim_rp_keep_alive_cmd);
|
|
install_element(VRF_NODE, &ip_pim_rp_keep_alive_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_pim_keep_alive_cmd);
|
|
install_element(VRF_NODE, &no_ip_pim_keep_alive_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_pim_rp_keep_alive_cmd);
|
|
install_element(VRF_NODE, &no_ip_pim_rp_keep_alive_cmd);
|
|
install_element(CONFIG_NODE, &ip_pim_packets_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_pim_packets_cmd);
|
|
install_element(CONFIG_NODE, &ip_pim_v6_secondary_cmd);
|
|
install_element(VRF_NODE, &ip_pim_v6_secondary_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_pim_v6_secondary_cmd);
|
|
install_element(VRF_NODE, &no_ip_pim_v6_secondary_cmd);
|
|
install_element(CONFIG_NODE, &ip_ssmpingd_cmd);
|
|
install_element(VRF_NODE, &ip_ssmpingd_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd);
|
|
install_element(VRF_NODE, &no_ip_ssmpingd_cmd);
|
|
install_element(CONFIG_NODE, &ip_msdp_peer_cmd);
|
|
install_element(VRF_NODE, &ip_msdp_peer_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd);
|
|
install_element(VRF_NODE, &no_ip_msdp_peer_cmd);
|
|
install_element(CONFIG_NODE, &ip_pim_ecmp_cmd);
|
|
install_element(VRF_NODE, &ip_pim_ecmp_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_pim_ecmp_cmd);
|
|
install_element(VRF_NODE, &no_ip_pim_ecmp_cmd);
|
|
install_element(CONFIG_NODE, &ip_pim_ecmp_rebalance_cmd);
|
|
install_element(VRF_NODE, &ip_pim_ecmp_rebalance_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_pim_ecmp_rebalance_cmd);
|
|
install_element(VRF_NODE, &no_ip_pim_ecmp_rebalance_cmd);
|
|
install_element(CONFIG_NODE, &ip_pim_mlag_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_pim_mlag_cmd);
|
|
install_element(CONFIG_NODE, &igmp_group_watermark_cmd);
|
|
install_element(VRF_NODE, &igmp_group_watermark_cmd);
|
|
install_element(CONFIG_NODE, &no_igmp_group_watermark_cmd);
|
|
install_element(VRF_NODE, &no_igmp_group_watermark_cmd);
|
|
|
|
install_element(INTERFACE_NODE, &interface_ip_igmp_cmd);
|
|
install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd);
|
|
install_element(INTERFACE_NODE, &interface_ip_igmp_join_cmd);
|
|
install_element(INTERFACE_NODE, &interface_no_ip_igmp_join_cmd);
|
|
install_element(INTERFACE_NODE, &interface_ip_igmp_version_cmd);
|
|
install_element(INTERFACE_NODE, &interface_no_ip_igmp_version_cmd);
|
|
install_element(INTERFACE_NODE, &interface_ip_igmp_query_interval_cmd);
|
|
install_element(INTERFACE_NODE,
|
|
&interface_no_ip_igmp_query_interval_cmd);
|
|
install_element(INTERFACE_NODE,
|
|
&interface_ip_igmp_query_max_response_time_cmd);
|
|
install_element(INTERFACE_NODE,
|
|
&interface_no_ip_igmp_query_max_response_time_cmd);
|
|
install_element(INTERFACE_NODE,
|
|
&interface_ip_igmp_query_max_response_time_dsec_cmd);
|
|
install_element(INTERFACE_NODE,
|
|
&interface_no_ip_igmp_query_max_response_time_dsec_cmd);
|
|
install_element(INTERFACE_NODE,
|
|
&interface_ip_igmp_last_member_query_count_cmd);
|
|
install_element(INTERFACE_NODE,
|
|
&interface_no_ip_igmp_last_member_query_count_cmd);
|
|
install_element(INTERFACE_NODE,
|
|
&interface_ip_igmp_last_member_query_interval_cmd);
|
|
install_element(INTERFACE_NODE,
|
|
&interface_no_ip_igmp_last_member_query_interval_cmd);
|
|
install_element(INTERFACE_NODE, &interface_ip_pim_activeactive_cmd);
|
|
install_element(INTERFACE_NODE, &interface_ip_pim_ssm_cmd);
|
|
install_element(INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd);
|
|
install_element(INTERFACE_NODE, &interface_ip_pim_sm_cmd);
|
|
install_element(INTERFACE_NODE, &interface_no_ip_pim_sm_cmd);
|
|
install_element(INTERFACE_NODE, &interface_ip_pim_cmd);
|
|
install_element(INTERFACE_NODE, &interface_no_ip_pim_cmd);
|
|
install_element(INTERFACE_NODE, &interface_ip_pim_drprio_cmd);
|
|
install_element(INTERFACE_NODE, &interface_no_ip_pim_drprio_cmd);
|
|
install_element(INTERFACE_NODE, &interface_ip_pim_hello_cmd);
|
|
install_element(INTERFACE_NODE, &interface_no_ip_pim_hello_cmd);
|
|
install_element(INTERFACE_NODE, &interface_ip_pim_boundary_oil_cmd);
|
|
install_element(INTERFACE_NODE, &interface_no_ip_pim_boundary_oil_cmd);
|
|
install_element(INTERFACE_NODE, &interface_ip_igmp_query_generate_cmd);
|
|
|
|
// Static mroutes NEB
|
|
install_element(INTERFACE_NODE, &interface_ip_mroute_cmd);
|
|
install_element(INTERFACE_NODE, &interface_no_ip_mroute_cmd);
|
|
|
|
install_element(VIEW_NODE, &show_ip_igmp_interface_cmd);
|
|
install_element(VIEW_NODE, &show_ip_igmp_interface_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_igmp_join_cmd);
|
|
install_element(VIEW_NODE, &show_ip_igmp_join_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_igmp_groups_cmd);
|
|
install_element(VIEW_NODE, &show_ip_igmp_groups_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd);
|
|
install_element(VIEW_NODE, &show_ip_igmp_sources_cmd);
|
|
install_element(VIEW_NODE, &show_ip_igmp_sources_retransmissions_cmd);
|
|
install_element(VIEW_NODE, &show_ip_igmp_statistics_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_assert_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_assert_internal_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_assert_metric_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_assert_winner_metric_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_interface_traffic_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_interface_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_interface_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_join_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_join_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_jp_agg_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_local_membership_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_mlag_summary_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_mlag_up_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_mlag_up_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_neighbor_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_neighbor_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_rpf_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_rpf_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_secondary_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_state_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_state_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_upstream_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_upstream_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_channel_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_upstream_join_desired_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_upstream_rpf_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_rp_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_rp_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_bsr_cmd);
|
|
install_element(VIEW_NODE, &show_ip_multicast_cmd);
|
|
install_element(VIEW_NODE, &show_ip_multicast_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_multicast_count_cmd);
|
|
install_element(VIEW_NODE, &show_ip_multicast_count_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_mroute_cmd);
|
|
install_element(VIEW_NODE, &show_ip_mroute_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_mroute_count_cmd);
|
|
install_element(VIEW_NODE, &show_ip_mroute_count_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_mroute_summary_cmd);
|
|
install_element(VIEW_NODE, &show_ip_mroute_summary_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_rib_cmd);
|
|
install_element(VIEW_NODE, &show_ip_ssmpingd_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_nexthop_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_nexthop_lookup_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_bsrp_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_bsm_db_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_statistics_cmd);
|
|
|
|
install_element(ENABLE_NODE, &clear_ip_mroute_count_cmd);
|
|
install_element(ENABLE_NODE, &clear_ip_interfaces_cmd);
|
|
install_element(ENABLE_NODE, &clear_ip_igmp_interfaces_cmd);
|
|
install_element(ENABLE_NODE, &clear_ip_mroute_cmd);
|
|
install_element(ENABLE_NODE, &clear_ip_pim_interfaces_cmd);
|
|
install_element(ENABLE_NODE, &clear_ip_pim_interface_traffic_cmd);
|
|
install_element(ENABLE_NODE, &clear_ip_pim_oil_cmd);
|
|
install_element(ENABLE_NODE, &clear_ip_pim_statistics_cmd);
|
|
install_element(ENABLE_NODE, &clear_ip_pim_bsr_db_cmd);
|
|
|
|
install_element(ENABLE_NODE, &show_debugging_pim_cmd);
|
|
|
|
install_element(ENABLE_NODE, &debug_igmp_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_igmp_cmd);
|
|
install_element(ENABLE_NODE, &debug_igmp_events_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_igmp_events_cmd);
|
|
install_element(ENABLE_NODE, &debug_igmp_packets_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_igmp_packets_cmd);
|
|
install_element(ENABLE_NODE, &debug_igmp_trace_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_igmp_trace_cmd);
|
|
install_element(ENABLE_NODE, &debug_mroute_cmd);
|
|
install_element(ENABLE_NODE, &debug_mroute_detail_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_mroute_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_mroute_detail_cmd);
|
|
install_element(ENABLE_NODE, &debug_pim_static_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_pim_static_cmd);
|
|
install_element(ENABLE_NODE, &debug_pim_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_pim_cmd);
|
|
install_element(ENABLE_NODE, &debug_pim_nht_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_pim_nht_cmd);
|
|
install_element(ENABLE_NODE, &debug_pim_nht_rp_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_pim_nht_rp_cmd);
|
|
install_element(ENABLE_NODE, &debug_pim_events_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_pim_events_cmd);
|
|
install_element(ENABLE_NODE, &debug_pim_packets_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_pim_packets_cmd);
|
|
install_element(ENABLE_NODE, &debug_pim_packetdump_send_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_pim_packetdump_send_cmd);
|
|
install_element(ENABLE_NODE, &debug_pim_packetdump_recv_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_pim_packetdump_recv_cmd);
|
|
install_element(ENABLE_NODE, &debug_pim_trace_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_pim_trace_cmd);
|
|
install_element(ENABLE_NODE, &debug_pim_trace_detail_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_pim_trace_detail_cmd);
|
|
install_element(ENABLE_NODE, &debug_ssmpingd_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd);
|
|
install_element(ENABLE_NODE, &debug_pim_zebra_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_pim_zebra_cmd);
|
|
install_element(ENABLE_NODE, &debug_pim_mlag_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd);
|
|
install_element(ENABLE_NODE, &debug_pim_vxlan_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd);
|
|
install_element(ENABLE_NODE, &debug_msdp_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_msdp_cmd);
|
|
install_element(ENABLE_NODE, &debug_msdp_events_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_msdp_events_cmd);
|
|
install_element(ENABLE_NODE, &debug_msdp_packets_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd);
|
|
install_element(ENABLE_NODE, &debug_mtrace_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_mtrace_cmd);
|
|
install_element(ENABLE_NODE, &debug_bsm_cmd);
|
|
install_element(ENABLE_NODE, &no_debug_bsm_cmd);
|
|
|
|
install_element(CONFIG_NODE, &debug_igmp_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_igmp_cmd);
|
|
install_element(CONFIG_NODE, &debug_igmp_events_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_igmp_events_cmd);
|
|
install_element(CONFIG_NODE, &debug_igmp_packets_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_igmp_packets_cmd);
|
|
install_element(CONFIG_NODE, &debug_igmp_trace_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_igmp_trace_cmd);
|
|
install_element(CONFIG_NODE, &debug_mroute_cmd);
|
|
install_element(CONFIG_NODE, &debug_mroute_detail_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_mroute_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_mroute_detail_cmd);
|
|
install_element(CONFIG_NODE, &debug_pim_static_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_pim_static_cmd);
|
|
install_element(CONFIG_NODE, &debug_pim_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_pim_cmd);
|
|
install_element(CONFIG_NODE, &debug_pim_nht_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_pim_nht_cmd);
|
|
install_element(CONFIG_NODE, &debug_pim_nht_rp_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_pim_nht_rp_cmd);
|
|
install_element(CONFIG_NODE, &debug_pim_events_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_pim_events_cmd);
|
|
install_element(CONFIG_NODE, &debug_pim_packets_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_pim_packets_cmd);
|
|
install_element(CONFIG_NODE, &debug_pim_trace_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_pim_trace_cmd);
|
|
install_element(CONFIG_NODE, &debug_pim_trace_detail_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_pim_trace_detail_cmd);
|
|
install_element(CONFIG_NODE, &debug_ssmpingd_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_ssmpingd_cmd);
|
|
install_element(CONFIG_NODE, &debug_pim_zebra_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_pim_zebra_cmd);
|
|
install_element(CONFIG_NODE, &debug_pim_mlag_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_pim_mlag_cmd);
|
|
install_element(CONFIG_NODE, &debug_pim_vxlan_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_pim_vxlan_cmd);
|
|
install_element(CONFIG_NODE, &debug_msdp_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_msdp_cmd);
|
|
install_element(CONFIG_NODE, &debug_msdp_events_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_msdp_events_cmd);
|
|
install_element(CONFIG_NODE, &debug_msdp_packets_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_msdp_packets_cmd);
|
|
install_element(CONFIG_NODE, &debug_mtrace_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_mtrace_cmd);
|
|
install_element(CONFIG_NODE, &debug_bsm_cmd);
|
|
install_element(CONFIG_NODE, &no_debug_bsm_cmd);
|
|
|
|
install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd);
|
|
install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd);
|
|
install_element(VRF_NODE, &no_ip_msdp_mesh_group_member_cmd);
|
|
install_element(CONFIG_NODE, &ip_msdp_mesh_group_source_cmd);
|
|
install_element(VRF_NODE, &ip_msdp_mesh_group_source_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_source_cmd);
|
|
install_element(VRF_NODE, &no_ip_msdp_mesh_group_source_cmd);
|
|
install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_cmd);
|
|
install_element(VRF_NODE, &no_ip_msdp_mesh_group_cmd);
|
|
install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd);
|
|
install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_msdp_sa_detail_cmd);
|
|
install_element(VIEW_NODE, &show_ip_msdp_sa_detail_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_msdp_sa_sg_cmd);
|
|
install_element(VIEW_NODE, &show_ip_msdp_sa_sg_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd);
|
|
install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_group_type_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd);
|
|
install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_work_cmd);
|
|
install_element(INTERFACE_NODE, &interface_pim_use_source_cmd);
|
|
install_element(INTERFACE_NODE, &interface_no_pim_use_source_cmd);
|
|
/* Install BSM command */
|
|
install_element(INTERFACE_NODE, &ip_pim_bsm_cmd);
|
|
install_element(INTERFACE_NODE, &no_ip_pim_bsm_cmd);
|
|
install_element(INTERFACE_NODE, &ip_pim_ucast_bsm_cmd);
|
|
install_element(INTERFACE_NODE, &no_ip_pim_ucast_bsm_cmd);
|
|
/* Install BFD command */
|
|
install_element(INTERFACE_NODE, &ip_pim_bfd_cmd);
|
|
install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd);
|
|
install_element(INTERFACE_NODE, &no_ip_pim_bfd_profile_cmd);
|
|
install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd);
|
|
#if HAVE_BFDD == 0
|
|
install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd);
|
|
#endif /* !HAVE_BFDD */
|
|
}
|