]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_cmd_common.c
pim6d: Adding "ipv6 mld query-max-response-time" CLI
[mirror_frr.git] / pimd / pim_cmd_common.c
CommitLineData
26cd3d66
MR
1/*
2 * PIM for IPv6 FRR
3 * Copyright (C) 2022 Vmware, Inc.
4 * Mobashshera Rasool <mrasool@vmware.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <zebra.h>
22
23#include "lib/json.h"
24#include "command.h"
25#include "if.h"
26#include "prefix.h"
27#include "zclient.h"
28#include "plist.h"
29#include "hash.h"
30#include "nexthop.h"
31#include "vrf.h"
32#include "ferr.h"
63ee25c0 33#include "lib/srcdest_table.h"
e2b601e8 34#include "lib/linklist.h"
26cd3d66
MR
35
36#include "pimd.h"
37#include "pim_vty.h"
38#include "lib/northbound_cli.h"
39#include "pim_errors.h"
40#include "pim_nb.h"
45e26aa0
A
41#include "pim_mroute.h"
42#include "pim_cmd.h"
43#include "pim6_cmd.h"
44#include "pim_cmd_common.h"
45#include "pim_time.h"
46#include "pim_zebra.h"
47#include "pim_zlookup.h"
48#include "pim_iface.h"
e2b601e8 49#include "pim_macro.h"
45e26aa0 50#include "pim_neighbor.h"
e2b601e8
SG
51#include "pim_nht.h"
52#include "pim_sock.h"
53#include "pim_ssm.h"
24de75a2 54#include "pim_addr.h"
26cd3d66 55
2328b7ef
MR
56/**
57 * Get current node VRF name.
58 *
59 * NOTE:
60 * In case of failure it will print error message to user.
61 *
62 * \returns name or NULL if failed to get VRF.
63 */
64const char *pim_cli_get_vrf_name(struct vty *vty)
65{
66 const struct lyd_node *vrf_node;
67
68 /* Not inside any VRF context. */
69 if (vty->xpath_index == 0)
70 return VRF_DEFAULT_NAME;
71
72 vrf_node = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
73 if (vrf_node == NULL) {
74 vty_out(vty, "%% Failed to get vrf dnode in configuration\n");
75 return NULL;
76 }
77
78 return yang_dnode_get_string(vrf_node, "./name");
79}
26cd3d66 80
c73113ea
MR
81int pim_process_join_prune_cmd(struct vty *vty, const char *jpi_str)
82{
83 char xpath[XPATH_MAXLEN];
84
85 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
86 FRR_PIM_AF_XPATH_VAL);
87 strlcat(xpath, "/join-prune-interval", sizeof(xpath));
88
89 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, jpi_str);
90
91 return nb_cli_apply_changes(vty, NULL);
92}
93
94int pim_process_no_join_prune_cmd(struct vty *vty)
95{
96 char xpath[XPATH_MAXLEN];
97
98 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
99 FRR_PIM_AF_XPATH_VAL);
100 strlcat(xpath, "/join-prune-interval", sizeof(xpath));
101
102 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
103
104 return nb_cli_apply_changes(vty, NULL);
105}
fb991ce9
MR
106
107int pim_process_spt_switchover_infinity_cmd(struct vty *vty)
108{
109 const char *vrfname;
110 char spt_plist_xpath[XPATH_MAXLEN];
111 char spt_action_xpath[XPATH_MAXLEN];
112
113 vrfname = pim_cli_get_vrf_name(vty);
114 if (vrfname == NULL)
115 return CMD_WARNING_CONFIG_FAILED;
116
117 snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
118 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
119 FRR_PIM_AF_XPATH_VAL);
120 strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
121 sizeof(spt_plist_xpath));
122
123 snprintf(spt_action_xpath, sizeof(spt_action_xpath),
124 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
125 FRR_PIM_AF_XPATH_VAL);
126 strlcat(spt_action_xpath, "/spt-switchover/spt-action",
127 sizeof(spt_action_xpath));
128
129 if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath))
130 nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY,
131 NULL);
132 nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
133 "PIM_SPT_INFINITY");
134
135 return nb_cli_apply_changes(vty, NULL);
136}
137
138int pim_process_spt_switchover_prefixlist_cmd(struct vty *vty,
139 const char *plist)
140{
141 const char *vrfname;
142 char spt_plist_xpath[XPATH_MAXLEN];
143 char spt_action_xpath[XPATH_MAXLEN];
144
145 vrfname = pim_cli_get_vrf_name(vty);
146 if (vrfname == NULL)
147 return CMD_WARNING_CONFIG_FAILED;
148
149 snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
150 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
151 FRR_PIM_AF_XPATH_VAL);
152 strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
153 sizeof(spt_plist_xpath));
154
155 snprintf(spt_action_xpath, sizeof(spt_action_xpath),
156 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
157 FRR_PIM_AF_XPATH_VAL);
158 strlcat(spt_action_xpath, "/spt-switchover/spt-action",
159 sizeof(spt_action_xpath));
160
161 nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
162 "PIM_SPT_INFINITY");
163 nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY,
164 plist);
165
166 return nb_cli_apply_changes(vty, NULL);
167}
168
169int pim_process_no_spt_switchover_cmd(struct vty *vty)
170{
171 const char *vrfname;
172 char spt_plist_xpath[XPATH_MAXLEN];
173 char spt_action_xpath[XPATH_MAXLEN];
174
175 vrfname = pim_cli_get_vrf_name(vty);
176 if (vrfname == NULL)
177 return CMD_WARNING_CONFIG_FAILED;
178
179 snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
180 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
181 FRR_PIM_AF_XPATH_VAL);
182 strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
183 sizeof(spt_plist_xpath));
184
185 snprintf(spt_action_xpath, sizeof(spt_action_xpath),
186 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
187 FRR_PIM_AF_XPATH_VAL);
188 strlcat(spt_action_xpath, "/spt-switchover/spt-action",
189 sizeof(spt_action_xpath));
190
191 nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL);
192 nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
193 "PIM_SPT_IMMEDIATE");
194
195 return nb_cli_apply_changes(vty, NULL);
196}
0da72f1f
MR
197
198int pim_process_pim_packet_cmd(struct vty *vty, const char *packet)
199{
200 char xpath[XPATH_MAXLEN];
201
202 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
203 FRR_PIM_AF_XPATH_VAL);
204 strlcat(xpath, "/packets", sizeof(xpath));
205
206 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, packet);
207
208 return nb_cli_apply_changes(vty, NULL);
209}
210
211int pim_process_no_pim_packet_cmd(struct vty *vty)
212{
213 char xpath[XPATH_MAXLEN];
214
215 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
216 FRR_PIM_AF_XPATH_VAL);
217 strlcat(xpath, "/packets", sizeof(xpath));
218
219 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
220
221 return nb_cli_apply_changes(vty, NULL);
222}
28e32366
MR
223
224int pim_process_keepalivetimer_cmd(struct vty *vty, const char *kat)
225{
226 const char *vrfname;
227 char ka_timer_xpath[XPATH_MAXLEN];
228
229 vrfname = pim_cli_get_vrf_name(vty);
230 if (vrfname == NULL)
231 return CMD_WARNING_CONFIG_FAILED;
232
233 snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH,
234 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL);
235 strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
236
237 nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY,
238 kat);
239
240 return nb_cli_apply_changes(vty, NULL);
241}
242
243int pim_process_no_keepalivetimer_cmd(struct vty *vty)
244{
245 const char *vrfname;
246 char ka_timer_xpath[XPATH_MAXLEN];
247
248 vrfname = pim_cli_get_vrf_name(vty);
249 if (vrfname == NULL)
250 return CMD_WARNING_CONFIG_FAILED;
251
252 snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH,
253 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL);
254 strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
255
256 nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_DESTROY, NULL);
257
258 return nb_cli_apply_changes(vty, NULL);
259}
2322b991
MR
260
261int pim_process_rp_kat_cmd(struct vty *vty, const char *rpkat)
262{
263 const char *vrfname;
264 char rp_ka_timer_xpath[XPATH_MAXLEN];
265
266 vrfname = pim_cli_get_vrf_name(vty);
267 if (vrfname == NULL)
268 return CMD_WARNING_CONFIG_FAILED;
269
270 snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
271 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
272 FRR_PIM_AF_XPATH_VAL);
273 strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
274 sizeof(rp_ka_timer_xpath));
275
276 nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
277 rpkat);
278
279 return nb_cli_apply_changes(vty, NULL);
280}
281
282int pim_process_no_rp_kat_cmd(struct vty *vty)
283{
284 const char *vrfname;
285 char rp_ka_timer[6];
286 char rp_ka_timer_xpath[XPATH_MAXLEN];
287 uint v;
288 char rs_timer_xpath[XPATH_MAXLEN];
289
290 snprintf(rs_timer_xpath, sizeof(rs_timer_xpath),
291 FRR_PIM_ROUTER_XPATH, FRR_PIM_AF_XPATH_VAL);
292 strlcat(rs_timer_xpath, "/register-suppress-time",
293 sizeof(rs_timer_xpath));
294
295 /* RFC4601 */
296 v = yang_dnode_get_uint16(vty->candidate_config->dnode,
297 rs_timer_xpath);
298 v = 3 * v + PIM_REGISTER_PROBE_TIME_DEFAULT;
299 if (v > UINT16_MAX)
300 v = UINT16_MAX;
301 snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%u", v);
302
303 vrfname = pim_cli_get_vrf_name(vty);
304 if (vrfname == NULL)
305 return CMD_WARNING_CONFIG_FAILED;
306
307 snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
308 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
309 FRR_PIM_AF_XPATH_VAL);
310 strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
311 sizeof(rp_ka_timer_xpath));
312
313 nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
314 rp_ka_timer);
315
316 return nb_cli_apply_changes(vty, NULL);
317}
18ca7de5
MR
318
319int pim_process_register_suppress_cmd(struct vty *vty, const char *rst)
320{
321 char xpath[XPATH_MAXLEN];
322
323 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
324 FRR_PIM_AF_XPATH_VAL);
325 strlcat(xpath, "/register-suppress-time", sizeof(xpath));
326
327 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, rst);
328
329 return nb_cli_apply_changes(vty, NULL);
330}
331
332int pim_process_no_register_suppress_cmd(struct vty *vty)
333{
334 char xpath[XPATH_MAXLEN];
335
336 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
337 FRR_PIM_AF_XPATH_VAL);
338 strlcat(xpath, "/register-suppress-time", sizeof(xpath));
339
340 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
341
342 return nb_cli_apply_changes(vty, NULL);
343}
a1caf7a8 344
345int pim_process_ip_pim_cmd(struct vty *vty)
346{
347 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true");
348
349 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
350 FRR_PIM_AF_XPATH_VAL);
351}
352
353int pim_process_no_ip_pim_cmd(struct vty *vty)
354{
355 const struct lyd_node *mld_enable_dnode;
356 char mld_if_xpath[XPATH_MAXLEN];
357
358 int printed =
359 snprintf(mld_if_xpath, sizeof(mld_if_xpath),
360 "%s/frr-gmp:gmp/address-family[address-family='%s']",
361 VTY_CURR_XPATH, FRR_PIM_AF_XPATH_VAL);
362
363 if (printed >= (int)(sizeof(mld_if_xpath))) {
364 vty_out(vty, "Xpath too long (%d > %u)", printed + 1,
365 XPATH_MAXLEN);
366 return CMD_WARNING_CONFIG_FAILED;
367 }
368
369 mld_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
370 FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
371 FRR_PIM_AF_XPATH_VAL);
372
373 if (!mld_enable_dnode) {
374 nb_cli_enqueue_change(vty, mld_if_xpath, NB_OP_DESTROY, NULL);
375 nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
376 } else {
377 if (!yang_dnode_get_bool(mld_enable_dnode, ".")) {
378 nb_cli_enqueue_change(vty, mld_if_xpath, NB_OP_DESTROY,
379 NULL);
380 nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
381 } else
382 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
383 "false");
384 }
385
386 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
387 FRR_PIM_AF_XPATH_VAL);
388}
bb387611 389
390int pim_process_ip_pim_drprio_cmd(struct vty *vty, const char *drpriority_str)
391{
392 nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY,
393 drpriority_str);
394
395 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
396 FRR_PIM_AF_XPATH_VAL);
397}
398
399int pim_process_no_ip_pim_drprio_cmd(struct vty *vty)
400{
401 nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_DESTROY, NULL);
402
403 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
404 FRR_PIM_AF_XPATH_VAL);
405}
e6aab613 406
407int pim_process_ip_pim_hello_cmd(struct vty *vty, const char *hello_str,
408 const char *hold_str)
409{
410 const struct lyd_node *mld_enable_dnode;
411
412 mld_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
413 FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
414 FRR_PIM_AF_XPATH_VAL);
415
416 if (!mld_enable_dnode) {
417 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
418 "true");
419 } else {
420 if (!yang_dnode_get_bool(mld_enable_dnode, "."))
421 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
422 "true");
423 }
424
425 nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_MODIFY, hello_str);
426
427 if (hold_str)
428 nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_MODIFY,
429 hold_str);
430
431 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
432 FRR_PIM_AF_XPATH_VAL);
433}
434
435int pim_process_no_ip_pim_hello_cmd(struct vty *vty)
436{
437 nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_DESTROY, NULL);
438 nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_DESTROY, NULL);
439
440 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
441 FRR_PIM_AF_XPATH_VAL);
442}
7e01b641 443
444int pim_process_ip_pim_activeactive_cmd(struct vty *vty, const char *no)
445{
446 if (no)
447 nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY,
448 "false");
449 else {
450 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
451 "true");
452
453 nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY,
454 "true");
455 }
456
457 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
458 FRR_PIM_AF_XPATH_VAL);
459}
52c52d78 460
461int pim_process_ip_pim_boundary_oil_cmd(struct vty *vty, const char *oil)
462{
463 nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_MODIFY,
464 oil);
465
466 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
467 FRR_PIM_AF_XPATH_VAL);
468}
469
470int pim_process_no_ip_pim_boundary_oil_cmd(struct vty *vty)
471{
472 nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_DESTROY,
473 NULL);
474
475 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
476 FRR_PIM_AF_XPATH_VAL);
477}
63ee25c0 478
479int pim_process_ip_mroute_cmd(struct vty *vty, const char *interface,
480 const char *group_str, const char *source_str)
481{
482 nb_cli_enqueue_change(vty, "./oif", NB_OP_MODIFY, interface);
483
484 if (!source_str) {
485 char buf[SRCDEST2STR_BUFFER];
486
487 inet_ntop(AF_INET6, &in6addr_any, buf, sizeof(buf));
488 return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH,
489 FRR_PIM_AF_XPATH_VAL, buf,
490 group_str);
491 }
492
493 return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH,
494 FRR_PIM_AF_XPATH_VAL, source_str,
495 group_str);
496}
497
498int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface,
499 const char *group_str, const char *source_str)
500{
501 nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
502
503 if (!source_str) {
504 char buf[SRCDEST2STR_BUFFER];
505
506 inet_ntop(AF_INET6, &in6addr_any, buf, sizeof(buf));
507 return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH,
508 FRR_PIM_AF_XPATH_VAL, buf,
509 group_str);
510 }
511
512 return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH,
513 FRR_PIM_AF_XPATH_VAL, source_str,
514 group_str);
515}
13ddf7cf
MR
516
517int pim_process_rp_cmd(struct vty *vty, const char *rp_str,
518 const char *group_str)
519{
520 const char *vrfname;
521 char rp_group_xpath[XPATH_MAXLEN];
522 int result = 0;
523 struct prefix group;
a96942ca 524 pim_addr rp_addr;
13ddf7cf
MR
525
526 result = str2prefix(group_str, &group);
527 if (result) {
528 struct prefix temp;
529
530 prefix_copy(&temp, &group);
531 apply_mask(&temp);
532 if (!prefix_same(&group, &temp)) {
533 vty_out(vty, "%% Inconsistent address and mask: %s\n",
534 group_str);
535 return CMD_WARNING_CONFIG_FAILED;
536 }
537 }
538
539 if (!result) {
540 vty_out(vty, "%% Bad group address specified: %s\n", group_str);
541 return CMD_WARNING_CONFIG_FAILED;
542 }
543
a96942ca 544 result = inet_pton(PIM_AF, rp_str, &rp_addr);
13ddf7cf
MR
545 if (result <= 0) {
546 vty_out(vty, "%% Bad RP address specified: %s\n", rp_str);
547 return CMD_WARNING_CONFIG_FAILED;
548 }
549
550 vrfname = pim_cli_get_vrf_name(vty);
551 if (vrfname == NULL)
552 return CMD_WARNING_CONFIG_FAILED;
553
554 snprintf(rp_group_xpath, sizeof(rp_group_xpath),
a96942ca
MR
555 FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname,
556 FRR_PIM_AF_XPATH_VAL, rp_str);
13ddf7cf
MR
557 strlcat(rp_group_xpath, "/group-list", sizeof(rp_group_xpath));
558
559 nb_cli_enqueue_change(vty, rp_group_xpath, NB_OP_CREATE, group_str);
560
561 return nb_cli_apply_changes(vty, NULL);
562}
563
564int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str,
565 const char *group_str)
566{
567 char group_list_xpath[XPATH_MAXLEN];
568 char group_xpath[XPATH_MAXLEN];
569 char rp_xpath[XPATH_MAXLEN];
570 int printed;
571 const char *vrfname;
572 const struct lyd_node *group_dnode;
573
574 vrfname = pim_cli_get_vrf_name(vty);
575 if (vrfname == NULL)
576 return CMD_WARNING_CONFIG_FAILED;
577
578 snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH,
a96942ca 579 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str);
13ddf7cf
MR
580
581 printed = snprintf(group_list_xpath, sizeof(group_list_xpath),
582 "%s/group-list", rp_xpath);
583
584 if (printed >= (int)(sizeof(group_list_xpath))) {
585 vty_out(vty, "Xpath too long (%d > %u)", printed + 1,
586 XPATH_MAXLEN);
587 return CMD_WARNING_CONFIG_FAILED;
588 }
589
590 printed = snprintf(group_xpath, sizeof(group_xpath), "%s[.='%s']",
591 group_list_xpath, group_str);
592
593 if (printed >= (int)(sizeof(group_xpath))) {
594 vty_out(vty, "Xpath too long (%d > %u)", printed + 1,
595 XPATH_MAXLEN);
596 return CMD_WARNING_CONFIG_FAILED;
597 }
598
ea5f4c4c
MR
599 group_dnode = yang_dnode_get(vty->candidate_config->dnode, group_xpath);
600 if (!group_dnode) {
13ddf7cf
MR
601 vty_out(vty, "%% Unable to find specified RP\n");
602 return NB_OK;
603 }
604
13ddf7cf
MR
605 if (yang_is_last_list_dnode(group_dnode))
606 nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL);
607 else
608 nb_cli_enqueue_change(vty, group_list_xpath, NB_OP_DESTROY,
609 group_str);
610
611 return nb_cli_apply_changes(vty, NULL);
612}
f39f3497
MR
613
614int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str,
615 const char *prefix_list)
616{
617 const char *vrfname;
618 char rp_plist_xpath[XPATH_MAXLEN];
619
620 vrfname = pim_cli_get_vrf_name(vty);
621 if (vrfname == NULL)
622 return CMD_WARNING_CONFIG_FAILED;
623
624 snprintf(rp_plist_xpath, sizeof(rp_plist_xpath),
625 FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname,
626 FRR_PIM_AF_XPATH_VAL, rp_str);
627 strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath));
628
629 nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY, prefix_list);
630
631 return nb_cli_apply_changes(vty, NULL);
632}
633
634int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str,
635 const char *prefix_list)
636{
637 char rp_xpath[XPATH_MAXLEN];
638 char plist_xpath[XPATH_MAXLEN];
639 const char *vrfname;
640 const struct lyd_node *plist_dnode;
641 const char *plist;
642
643 vrfname = pim_cli_get_vrf_name(vty);
644 if (vrfname == NULL)
645 return CMD_WARNING_CONFIG_FAILED;
646
647 snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH,
648 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str);
649
650 snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH,
651 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str);
652 strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath));
653
654 plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath);
655 if (!plist_dnode) {
656 vty_out(vty, "%% Unable to find specified RP\n");
657 return NB_OK;
658 }
659
660 plist = yang_dnode_get_string(plist_dnode, plist_xpath);
661 if (strcmp(prefix_list, plist)) {
662 vty_out(vty, "%% Unable to find specified RP\n");
663 return NB_OK;
664 }
665
666 nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL);
667
668 return nb_cli_apply_changes(vty, NULL);
669}
45e26aa0 670
95023bd7
A
671bool pim_sgaddr_match(pim_sgaddr item, pim_sgaddr match)
672{
673 return (pim_addr_is_any(match.grp) ||
674 !pim_addr_cmp(match.grp, item.grp)) &&
675 (pim_addr_is_any(match.src) ||
676 !pim_addr_cmp(match.src, item.src));
677}
678
e2b601e8
SG
679void json_object_pim_ifp_add(struct json_object *json, struct interface *ifp)
680{
681 struct pim_interface *pim_ifp;
682
683 pim_ifp = ifp->info;
684 json_object_string_add(json, "name", ifp->name);
685 json_object_string_add(json, "state", if_is_up(ifp) ? "up" : "down");
686 json_object_string_addf(json, "address", "%pPA",
687 &pim_ifp->primary_address);
688 json_object_int_add(json, "index", ifp->ifindex);
689
690 if (if_is_multicast(ifp))
691 json_object_boolean_true_add(json, "flagMulticast");
692
693 if (if_is_broadcast(ifp))
694 json_object_boolean_true_add(json, "flagBroadcast");
695
696 if (ifp->flags & IFF_ALLMULTI)
697 json_object_boolean_true_add(json, "flagAllMulticast");
698
699 if (ifp->flags & IFF_PROMISC)
700 json_object_boolean_true_add(json, "flagPromiscuous");
701
702 if (PIM_IF_IS_DELETED(ifp))
703 json_object_boolean_true_add(json, "flagDeleted");
704
705 if (pim_if_lan_delay_enabled(ifp))
706 json_object_boolean_true_add(json, "lanDelayEnabled");
707}
708
709void pim_print_ifp_flags(struct vty *vty, struct interface *ifp)
710{
711 vty_out(vty, "Flags\n");
712 vty_out(vty, "-----\n");
713 vty_out(vty, "All Multicast : %s\n",
714 (ifp->flags & IFF_ALLMULTI) ? "yes" : "no");
715 vty_out(vty, "Broadcast : %s\n",
716 if_is_broadcast(ifp) ? "yes" : "no");
717 vty_out(vty, "Deleted : %s\n",
718 PIM_IF_IS_DELETED(ifp) ? "yes" : "no");
719 vty_out(vty, "Interface Index : %d\n", ifp->ifindex);
720 vty_out(vty, "Multicast : %s\n",
721 if_is_multicast(ifp) ? "yes" : "no");
722 vty_out(vty, "Promiscuous : %s\n",
723 (ifp->flags & IFF_PROMISC) ? "yes" : "no");
724 vty_out(vty, "\n");
725 vty_out(vty, "\n");
726}
727
45e26aa0
A
728void json_object_pim_upstream_add(json_object *json, struct pim_upstream *up)
729{
b1a419ba
A
730 json_object_boolean_add(
731 json, "drJoinDesired",
732 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED));
733 json_object_boolean_add(
734 json, "drJoinDesiredUpdated",
735 CHECK_FLAG(up->flags,
736 PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED));
737 json_object_boolean_add(
738 json, "firstHopRouter",
739 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_FHR));
740 json_object_boolean_add(
741 json, "sourceIgmp",
742 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP));
743 json_object_boolean_add(
744 json, "sourcePim",
745 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_PIM));
746 json_object_boolean_add(
747 json, "sourceStream",
748 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM));
45e26aa0 749 /* XXX: need to print ths flag in the plain text display as well */
b1a419ba
A
750 json_object_boolean_add(
751 json, "sourceMsdp",
752 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_MSDP));
753 json_object_boolean_add(
754 json, "sendSGRptPrune",
755 CHECK_FLAG(up->flags,
756 PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE));
757 json_object_boolean_add(
758 json, "lastHopRouter",
759 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_LHR));
760 json_object_boolean_add(
761 json, "disableKATExpiry",
762 CHECK_FLAG(up->flags,
763 PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY));
764 json_object_boolean_add(
765 json, "staticIncomingInterface",
766 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_STATIC_IIF));
767 json_object_boolean_add(
768 json, "allowIncomingInterfaceinOil",
769 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL));
770 json_object_boolean_add(
771 json, "noPimRegistrationData",
772 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA));
773 json_object_boolean_add(
774 json, "forcePimRegistration",
775 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG));
776 json_object_boolean_add(
777 json, "sourceVxlanOrigination",
778 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG));
779 json_object_boolean_add(
780 json, "sourceVxlanTermination",
781 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM));
782 json_object_boolean_add(
783 json, "mlagVxlan",
784 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN));
785 json_object_boolean_add(
786 json, "mlagNonDesignatedForwarder",
787 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF));
45e26aa0
A
788}
789
790static const char *
791pim_upstream_state2brief_str(enum pim_upstream_state join_state,
792 char *state_str, size_t state_str_len)
793{
794 switch (join_state) {
795 case PIM_UPSTREAM_NOTJOINED:
796 strlcpy(state_str, "NotJ", state_str_len);
797 break;
798 case PIM_UPSTREAM_JOINED:
799 strlcpy(state_str, "J", state_str_len);
800 break;
801 default:
802 strlcpy(state_str, "Unk", state_str_len);
803 }
804 return state_str;
805}
806
807static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state,
808 char *state_str,
809 size_t state_str_len)
810{
811 switch (reg_state) {
812 case PIM_REG_NOINFO:
813 strlcpy(state_str, "RegNI", state_str_len);
814 break;
815 case PIM_REG_JOIN:
816 strlcpy(state_str, "RegJ", state_str_len);
817 break;
818 case PIM_REG_JOIN_PENDING:
819 case PIM_REG_PRUNE:
820 strlcpy(state_str, "RegP", state_str_len);
821 break;
822 }
823 return state_str;
824}
825
1aa8de46
A
826void pim_show_rpf_refresh_stats(struct vty *vty, struct pim_instance *pim,
827 time_t now, json_object *json)
45e26aa0
A
828{
829 char refresh_uptime[10];
830
831 pim_time_uptime_begin(refresh_uptime, sizeof(refresh_uptime), now,
832 pim->rpf_cache_refresh_last);
833
834 if (json) {
835 json_object_int_add(json, "rpfCacheRefreshDelayMsecs",
836 router->rpf_cache_refresh_delay_msec);
837 json_object_int_add(
838 json, "rpfCacheRefreshTimer",
839 pim_time_timer_remain_msec(pim->rpf_cache_refresher));
840 json_object_int_add(json, "rpfCacheRefreshRequests",
841 pim->rpf_cache_refresh_requests);
842 json_object_int_add(json, "rpfCacheRefreshEvents",
843 pim->rpf_cache_refresh_events);
844 json_object_string_add(json, "rpfCacheRefreshLast",
845 refresh_uptime);
846 json_object_int_add(json, "nexthopLookups",
847 pim->nexthop_lookups);
848 json_object_int_add(json, "nexthopLookupsAvoided",
849 pim->nexthop_lookups_avoided);
850 } else {
851 vty_out(vty,
852 "RPF Cache Refresh Delay: %ld msecs\n"
853 "RPF Cache Refresh Timer: %ld msecs\n"
854 "RPF Cache Refresh Requests: %lld\n"
855 "RPF Cache Refresh Events: %lld\n"
856 "RPF Cache Refresh Last: %s\n"
857 "Nexthop Lookups: %lld\n"
858 "Nexthop Lookups Avoided: %lld\n",
859 router->rpf_cache_refresh_delay_msec,
860 pim_time_timer_remain_msec(pim->rpf_cache_refresher),
861 (long long)pim->rpf_cache_refresh_requests,
862 (long long)pim->rpf_cache_refresh_events,
863 refresh_uptime, (long long)pim->nexthop_lookups,
864 (long long)pim->nexthop_lookups_avoided);
865 }
866}
867
1aa8de46 868void pim_show_rpf(struct pim_instance *pim, struct vty *vty, json_object *json)
45e26aa0
A
869{
870 struct pim_upstream *up;
871 time_t now = pim_time_monotonic_sec();
45e26aa0
A
872 json_object *json_group = NULL;
873 json_object *json_row = NULL;
874
1aa8de46
A
875 pim_show_rpf_refresh_stats(vty, pim, now, json);
876
877 if (!json) {
45e26aa0
A
878 vty_out(vty, "\n");
879 vty_out(vty,
880 "Source Group RpfIface RpfAddress RibNextHop Metric Pref\n");
881 }
882
883 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
884 char rpf_addr_str[PREFIX_STRLEN];
885 char rib_nexthop_str[PREFIX_STRLEN];
886 const char *rpf_ifname;
887 struct pim_rpf *rpf = &up->rpf;
888
889 pim_addr_dump("<rpf?>", &rpf->rpf_addr, rpf_addr_str,
890 sizeof(rpf_addr_str));
891 pim_addr_dump("<nexthop?>",
892 &rpf->source_nexthop.mrib_nexthop_addr,
893 rib_nexthop_str, sizeof(rib_nexthop_str));
894
1aa8de46
A
895 rpf_ifname =
896 rpf->source_nexthop.interface ? rpf->source_nexthop
897 .interface->name
898 : "<ifname?>";
45e26aa0 899
1aa8de46 900 if (json) {
45e26aa0
A
901 char grp_str[PIM_ADDRSTRLEN];
902 char src_str[PIM_ADDRSTRLEN];
903
904 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
905 &up->sg.grp);
906 snprintfrr(src_str, sizeof(src_str), "%pPAs",
907 &up->sg.src);
908
909 json_object_object_get_ex(json, grp_str, &json_group);
910
911 if (!json_group) {
912 json_group = json_object_new_object();
913 json_object_object_add(json, grp_str,
914 json_group);
915 }
916
917 json_row = json_object_new_object();
918 json_object_string_add(json_row, "source", src_str);
919 json_object_string_add(json_row, "group", grp_str);
920 json_object_string_add(json_row, "rpfInterface",
921 rpf_ifname);
922 json_object_string_add(json_row, "rpfAddress",
923 rpf_addr_str);
924 json_object_string_add(json_row, "ribNexthop",
925 rib_nexthop_str);
926 json_object_int_add(
927 json_row, "routeMetric",
928 rpf->source_nexthop.mrib_route_metric);
929 json_object_int_add(
930 json_row, "routePreference",
931 rpf->source_nexthop.mrib_metric_preference);
932 json_object_object_add(json_group, src_str, json_row);
933
934 } else {
1aa8de46
A
935 vty_out(vty,
936 "%-15pPAs %-15pPAs %-16s %-15s %-15s %6d %4d\n",
45e26aa0
A
937 &up->sg.src, &up->sg.grp, rpf_ifname,
938 rpf_addr_str, rib_nexthop_str,
939 rpf->source_nexthop.mrib_route_metric,
940 rpf->source_nexthop.mrib_metric_preference);
941 }
942 }
45e26aa0
A
943}
944
945void pim_show_neighbors_secondary(struct pim_instance *pim, struct vty *vty)
946{
947 struct interface *ifp;
948
949 vty_out(vty,
950 "Interface Address Neighbor Secondary \n");
951
952 FOR_ALL_INTERFACES (pim->vrf, ifp) {
953 struct pim_interface *pim_ifp;
626dab7f 954 pim_addr ifaddr;
45e26aa0
A
955 struct listnode *neighnode;
956 struct pim_neighbor *neigh;
45e26aa0
A
957
958 pim_ifp = ifp->info;
959
960 if (!pim_ifp)
961 continue;
962
963 if (pim_ifp->pim_sock_fd < 0)
964 continue;
965
966 ifaddr = pim_ifp->primary_address;
967
968 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
969 neigh)) {
45e26aa0
A
970 struct listnode *prefix_node;
971 struct prefix *p;
972
973 if (!neigh->prefix_list)
974 continue;
975
45e26aa0
A
976 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list,
977 prefix_node, p))
626dab7f
A
978 vty_out(vty,
979 "%-16s %-15pPAs %-15pPAs %-15pFX\n",
980 ifp->name, &ifaddr, &neigh->source_addr,
981 p);
45e26aa0
A
982 }
983 }
984}
985
986void pim_show_state(struct pim_instance *pim, struct vty *vty,
2d85c671
A
987 const char *src_or_group, const char *group,
988 json_object *json)
45e26aa0
A
989{
990 struct channel_oil *c_oil;
45e26aa0
A
991 json_object *json_group = NULL;
992 json_object *json_ifp_in = NULL;
993 json_object *json_ifp_out = NULL;
994 json_object *json_source = NULL;
995 time_t now;
996 int first_oif;
997
998 now = pim_time_monotonic_sec();
999
2d85c671 1000 if (!json) {
45e26aa0
A
1001 vty_out(vty,
1002 "Codes: J -> Pim Join, I -> IGMP Report, S -> Source, * -> Inherited from (*,G), V -> VxLAN, M -> Muted");
1003 vty_out(vty,
1004 "\nActive Source Group RPT IIF OIL\n");
1005 }
1006
1007 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
2d85c671
A
1008 char src_str[PIM_ADDRSTRLEN];
1009 char grp_str[PIM_ADDRSTRLEN];
45e26aa0
A
1010 char in_ifname[INTERFACE_NAMSIZ + 1];
1011 char out_ifname[INTERFACE_NAMSIZ + 1];
1012 int oif_vif_index;
1013 struct interface *ifp_in;
1014 bool isRpt;
1015
1016 first_oif = 1;
1017
1018 if ((c_oil->up &&
1019 PIM_UPSTREAM_FLAG_TEST_USE_RPT(c_oil->up->flags)) ||
2d85c671 1020 pim_addr_is_any(*oil_origin(c_oil)))
45e26aa0
A
1021 isRpt = true;
1022 else
1023 isRpt = false;
1024
2d85c671
A
1025 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
1026 oil_mcastgrp(c_oil));
1027 snprintfrr(src_str, sizeof(src_str), "%pPAs",
1028 oil_origin(c_oil));
1029 ifp_in = pim_if_find_by_vif_index(pim, *oil_parent(c_oil));
45e26aa0
A
1030
1031 if (ifp_in)
1032 strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
1033 else
1034 strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
1035
1036 if (src_or_group) {
1037 if (strcmp(src_or_group, src_str) &&
1038 strcmp(src_or_group, grp_str))
1039 continue;
1040
1041 if (group && strcmp(group, grp_str))
1042 continue;
1043 }
1044
2d85c671 1045 if (json) {
45e26aa0
A
1046
1047 /* Find the group, create it if it doesn't exist */
1048 json_object_object_get_ex(json, grp_str, &json_group);
1049
1050 if (!json_group) {
1051 json_group = json_object_new_object();
1052 json_object_object_add(json, grp_str,
1053 json_group);
1054 }
1055
1056 /* Find the source nested under the group, create it if
1057 * it doesn't exist
1058 */
1059 json_object_object_get_ex(json_group, src_str,
1060 &json_source);
1061
1062 if (!json_source) {
1063 json_source = json_object_new_object();
1064 json_object_object_add(json_group, src_str,
1065 json_source);
1066 }
1067
1068 /* Find the inbound interface nested under the source,
1069 * create it if it doesn't exist
1070 */
1071 json_object_object_get_ex(json_source, in_ifname,
1072 &json_ifp_in);
1073
1074 if (!json_ifp_in) {
1075 json_ifp_in = json_object_new_object();
1076 json_object_object_add(json_source, in_ifname,
1077 json_ifp_in);
1078 json_object_int_add(json_source, "Installed",
1079 c_oil->installed);
1080 json_object_int_add(json_source, "installed",
1081 c_oil->installed);
2d85c671
A
1082 json_object_boolean_add(json_source, "isRpt",
1083 isRpt);
45e26aa0
A
1084 json_object_int_add(json_source, "RefCount",
1085 c_oil->oil_ref_count);
1086 json_object_int_add(json_source, "refCount",
1087 c_oil->oil_ref_count);
1088 json_object_int_add(json_source, "OilListSize",
1089 c_oil->oil_size);
1090 json_object_int_add(json_source, "oilListSize",
1091 c_oil->oil_size);
1092 json_object_int_add(
1093 json_source, "OilRescan",
1094 c_oil->oil_inherited_rescan);
1095 json_object_int_add(
1096 json_source, "oilRescan",
1097 c_oil->oil_inherited_rescan);
1098 json_object_int_add(json_source, "LastUsed",
1099 c_oil->cc.lastused);
1100 json_object_int_add(json_source, "lastUsed",
1101 c_oil->cc.lastused);
1102 json_object_int_add(json_source, "PacketCount",
1103 c_oil->cc.pktcnt);
1104 json_object_int_add(json_source, "packetCount",
1105 c_oil->cc.pktcnt);
1106 json_object_int_add(json_source, "ByteCount",
1107 c_oil->cc.bytecnt);
1108 json_object_int_add(json_source, "byteCount",
1109 c_oil->cc.bytecnt);
1110 json_object_int_add(json_source,
1111 "WrongInterface",
1112 c_oil->cc.wrong_if);
1113 json_object_int_add(json_source,
1114 "wrongInterface",
1115 c_oil->cc.wrong_if);
1116 }
2d85c671
A
1117 } else
1118 vty_out(vty, "%-6d %-15pPAs %-15pPAs %-3s %-16s ",
1119 c_oil->installed, oil_origin(c_oil),
1120 oil_mcastgrp(c_oil), isRpt ? "y" : "n",
1121 in_ifname);
45e26aa0
A
1122
1123 for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
1124 ++oif_vif_index) {
1125 struct interface *ifp_out;
1126 char oif_uptime[10];
1127 int ttl;
1128
2d85c671 1129 ttl = oil_if_has(c_oil, oif_vif_index);
45e26aa0
A
1130 if (ttl < 1)
1131 continue;
1132
1133 ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
1134 pim_time_uptime(
1135 oif_uptime, sizeof(oif_uptime),
1136 now - c_oil->oif_creation[oif_vif_index]);
1137
1138 if (ifp_out)
1139 strlcpy(out_ifname, ifp_out->name,
1140 sizeof(out_ifname));
1141 else
1142 strlcpy(out_ifname, "<oif?>",
1143 sizeof(out_ifname));
1144
2d85c671 1145 if (json) {
45e26aa0
A
1146 json_ifp_out = json_object_new_object();
1147 json_object_string_add(json_ifp_out, "source",
1148 src_str);
1149 json_object_string_add(json_ifp_out, "group",
1150 grp_str);
1151 json_object_string_add(json_ifp_out,
1152 "inboundInterface",
1153 in_ifname);
1154 json_object_string_add(json_ifp_out,
1155 "outboundInterface",
1156 out_ifname);
1157 json_object_int_add(json_ifp_out, "installed",
1158 c_oil->installed);
1159
1160 json_object_object_add(json_ifp_in, out_ifname,
1161 json_ifp_out);
1162 } else {
1163 if (first_oif) {
1164 first_oif = 0;
1165 vty_out(vty, "%s(%c%c%c%c%c)",
1166 out_ifname,
1167 (c_oil->oif_flags
1168 [oif_vif_index] &
1169 PIM_OIF_FLAG_PROTO_IGMP)
1170 ? 'I'
1171 : ' ',
1172 (c_oil->oif_flags
1173 [oif_vif_index] &
1174 PIM_OIF_FLAG_PROTO_PIM)
1175 ? 'J'
1176 : ' ',
1177 (c_oil->oif_flags
1178 [oif_vif_index] &
1179 PIM_OIF_FLAG_PROTO_VXLAN)
1180 ? 'V'
1181 : ' ',
1182 (c_oil->oif_flags
1183 [oif_vif_index] &
1184 PIM_OIF_FLAG_PROTO_STAR)
1185 ? '*'
1186 : ' ',
1187 (c_oil->oif_flags
1188 [oif_vif_index] &
1189 PIM_OIF_FLAG_MUTE)
1190 ? 'M'
1191 : ' ');
1192 } else
1193 vty_out(vty, ", %s(%c%c%c%c%c)",
1194 out_ifname,
1195 (c_oil->oif_flags
1196 [oif_vif_index] &
1197 PIM_OIF_FLAG_PROTO_IGMP)
1198 ? 'I'
1199 : ' ',
1200 (c_oil->oif_flags
1201 [oif_vif_index] &
1202 PIM_OIF_FLAG_PROTO_PIM)
1203 ? 'J'
1204 : ' ',
1205 (c_oil->oif_flags
1206 [oif_vif_index] &
1207 PIM_OIF_FLAG_PROTO_VXLAN)
1208 ? 'V'
1209 : ' ',
1210 (c_oil->oif_flags
1211 [oif_vif_index] &
1212 PIM_OIF_FLAG_PROTO_STAR)
1213 ? '*'
1214 : ' ',
1215 (c_oil->oif_flags
1216 [oif_vif_index] &
1217 PIM_OIF_FLAG_MUTE)
1218 ? 'M'
1219 : ' ');
1220 }
1221 }
1222
2d85c671 1223 if (!json)
45e26aa0
A
1224 vty_out(vty, "\n");
1225 }
1226
2d85c671 1227 if (!json)
45e26aa0
A
1228 vty_out(vty, "\n");
1229}
1230
1231/* pim statistics - just adding only bsm related now.
1232 * We can continue to add all pim related stats here.
1233 */
1234void pim_show_statistics(struct pim_instance *pim, struct vty *vty,
1235 const char *ifname, bool uj)
1236{
1237 json_object *json = NULL;
1238 struct interface *ifp;
1239
1240 if (uj) {
1241 json = json_object_new_object();
1242 json_object_int_add(json, "bsmRx", pim->bsm_rcvd);
1243 json_object_int_add(json, "bsmTx", pim->bsm_sent);
1244 json_object_int_add(json, "bsmDropped", pim->bsm_dropped);
1245 } else {
1246 vty_out(vty, "BSM Statistics :\n");
1247 vty_out(vty, "----------------\n");
1248 vty_out(vty, "Number of Received BSMs : %" PRIu64 "\n",
1249 pim->bsm_rcvd);
1250 vty_out(vty, "Number of Forwared BSMs : %" PRIu64 "\n",
1251 pim->bsm_sent);
1252 vty_out(vty, "Number of Dropped BSMs : %" PRIu64 "\n",
1253 pim->bsm_dropped);
1254 }
1255
1256 vty_out(vty, "\n");
1257
1258 /* scan interfaces */
1259 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1260 struct pim_interface *pim_ifp = ifp->info;
1261
1262 if (ifname && strcmp(ifname, ifp->name))
1263 continue;
1264
1265 if (!pim_ifp)
1266 continue;
1267
1268 if (!uj) {
1269 vty_out(vty, "Interface : %s\n", ifp->name);
1270 vty_out(vty, "-------------------\n");
1271 vty_out(vty,
1272 "Number of BSMs dropped due to config miss : %u\n",
1273 pim_ifp->pim_ifstat_bsm_cfg_miss);
1274 vty_out(vty, "Number of unicast BSMs dropped : %u\n",
1275 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss);
1276 vty_out(vty,
1277 "Number of BSMs dropped due to invalid scope zone : %u\n",
1278 pim_ifp->pim_ifstat_bsm_invalid_sz);
1279 } else {
1280
1281 json_object *json_row = NULL;
1282
1283 json_row = json_object_new_object();
1284
1285 json_object_string_add(json_row, "If Name", ifp->name);
1286 json_object_int_add(json_row, "bsmDroppedConfig",
1287 pim_ifp->pim_ifstat_bsm_cfg_miss);
1288 json_object_int_add(
1289 json_row, "bsmDroppedUnicast",
1290 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss);
1291 json_object_int_add(json_row,
1292 "bsmDroppedInvalidScopeZone",
1293 pim_ifp->pim_ifstat_bsm_invalid_sz);
1294 json_object_object_add(json, ifp->name, json_row);
1295 }
1296 vty_out(vty, "\n");
1297 }
1298
1299 if (uj)
1300 vty_json(vty, json);
1301}
1302
1303void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
95023bd7 1304 pim_sgaddr *sg, json_object *json)
45e26aa0
A
1305{
1306 struct pim_upstream *up;
1307 time_t now;
45e26aa0
A
1308 json_object *json_group = NULL;
1309 json_object *json_row = NULL;
1310
1311 now = pim_time_monotonic_sec();
1312
95023bd7 1313 if (!json)
45e26aa0
A
1314 vty_out(vty,
1315 "Iif Source Group State Uptime JoinTimer RSTimer KATimer RefCnt\n");
1316
1317 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
45e26aa0
A
1318 char uptime[10];
1319 char join_timer[10];
1320 char rs_timer[10];
1321 char ka_timer[10];
1322 char msdp_reg_timer[10];
1323 char state_str[PIM_REG_STATE_STR_LEN];
1324
95023bd7 1325 if (!pim_sgaddr_match(up->sg, *sg))
45e26aa0
A
1326 continue;
1327
45e26aa0
A
1328 pim_time_uptime(uptime, sizeof(uptime),
1329 now - up->state_transition);
1330 pim_time_timer_to_hhmmss(join_timer, sizeof(join_timer),
1331 up->t_join_timer);
1332
1333 /*
1334 * If the upstream is not dummy and it has a J/P timer for the
1335 * neighbor display that
1336 */
1337 if (!up->t_join_timer && up->rpf.source_nexthop.interface) {
1338 struct pim_neighbor *nbr;
1339
95023bd7 1340 nbr = pim_neighbor_find_prefix(
45e26aa0 1341 up->rpf.source_nexthop.interface,
95023bd7 1342 &up->rpf.rpf_addr);
45e26aa0
A
1343 if (nbr)
1344 pim_time_timer_to_hhmmss(join_timer,
1345 sizeof(join_timer),
1346 nbr->jp_timer);
1347 }
1348
1349 pim_time_timer_to_hhmmss(rs_timer, sizeof(rs_timer),
1350 up->t_rs_timer);
1351 pim_time_timer_to_hhmmss(ka_timer, sizeof(ka_timer),
1352 up->t_ka_timer);
1353 pim_time_timer_to_hhmmss(msdp_reg_timer, sizeof(msdp_reg_timer),
1354 up->t_msdp_reg_timer);
1355
1356 pim_upstream_state2brief_str(up->join_state, state_str,
1357 sizeof(state_str));
1358 if (up->reg_state != PIM_REG_NOINFO) {
1359 char tmp_str[PIM_REG_STATE_STR_LEN];
1360 char tmp[sizeof(state_str) + 1];
1361
1362 snprintf(tmp, sizeof(tmp), ",%s",
1363 pim_reg_state2brief_str(up->reg_state, tmp_str,
1364 sizeof(tmp_str)));
1365 strlcat(state_str, tmp, sizeof(state_str));
1366 }
1367
95023bd7
A
1368 if (json) {
1369 char grp_str[PIM_ADDRSTRLEN];
1370 char src_str[PIM_ADDRSTRLEN];
1371
1372 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
1373 &up->sg.grp);
1374 snprintfrr(src_str, sizeof(src_str), "%pPAs",
1375 &up->sg.src);
1376
45e26aa0
A
1377 json_object_object_get_ex(json, grp_str, &json_group);
1378
1379 if (!json_group) {
1380 json_group = json_object_new_object();
1381 json_object_object_add(json, grp_str,
1382 json_group);
1383 }
1384
1385 json_row = json_object_new_object();
1386 json_object_pim_upstream_add(json_row, up);
1387 json_object_string_add(
1388 json_row, "inboundInterface",
1389 up->rpf.source_nexthop.interface
1390 ? up->rpf.source_nexthop.interface->name
1391 : "Unknown");
1392
1393 /*
1394 * The RPF address we use is slightly different
1395 * based upon what we are looking up.
1396 * If we have a S, list that unless
1397 * we are the FHR, else we just put
1398 * the RP as the rpfAddress
1399 */
1400 if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR ||
95023bd7 1401 pim_addr_is_any(up->sg.src)) {
45e26aa0
A
1402 struct pim_rpf *rpg;
1403
1404 rpg = RP(pim, up->sg.grp);
95023bd7
A
1405 json_object_string_addf(json_row, "rpfAddress",
1406 "%pFX", &rpg->rpf_addr);
45e26aa0
A
1407 } else {
1408 json_object_string_add(json_row, "rpfAddress",
1409 src_str);
1410 }
1411
1412 json_object_string_add(json_row, "source", src_str);
1413 json_object_string_add(json_row, "group", grp_str);
1414 json_object_string_add(json_row, "state", state_str);
1415 json_object_string_add(
1416 json_row, "joinState",
1417 pim_upstream_state2str(up->join_state));
1418 json_object_string_add(
1419 json_row, "regState",
1420 pim_reg_state2str(up->reg_state, state_str,
1421 sizeof(state_str)));
1422 json_object_string_add(json_row, "upTime", uptime);
1423 json_object_string_add(json_row, "joinTimer",
1424 join_timer);
1425 json_object_string_add(json_row, "resetTimer",
1426 rs_timer);
1427 json_object_string_add(json_row, "keepaliveTimer",
1428 ka_timer);
1429 json_object_string_add(json_row, "msdpRegTimer",
1430 msdp_reg_timer);
1431 json_object_int_add(json_row, "refCount",
1432 up->ref_count);
1433 json_object_int_add(json_row, "sptBit", up->sptbit);
1434 json_object_object_add(json_group, src_str, json_row);
1435 } else {
1436 vty_out(vty,
95023bd7 1437 "%-16s%-15pPAs %-15pPAs %-11s %-8s %-9s %-9s %-9s %6d\n",
45e26aa0
A
1438 up->rpf.source_nexthop.interface
1439 ? up->rpf.source_nexthop.interface->name
1440 : "Unknown",
95023bd7
A
1441 &up->sg.src, &up->sg.grp, state_str, uptime,
1442 join_timer, rs_timer, ka_timer, up->ref_count);
45e26aa0
A
1443 }
1444 }
45e26aa0
A
1445}
1446
1447static void pim_show_join_desired_helper(struct pim_instance *pim,
1448 struct vty *vty,
1449 struct pim_upstream *up,
1450 json_object *json, bool uj)
1451{
1452 json_object *json_group = NULL;
45e26aa0
A
1453 json_object *json_row = NULL;
1454
45e26aa0 1455 if (uj) {
e577f6e7
A
1456 char grp_str[PIM_ADDRSTRLEN];
1457 char src_str[PIM_ADDRSTRLEN];
1458
1459 snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &up->sg.grp);
1460 snprintfrr(src_str, sizeof(src_str), "%pPAs", &up->sg.src);
1461
45e26aa0
A
1462 json_object_object_get_ex(json, grp_str, &json_group);
1463
1464 if (!json_group) {
1465 json_group = json_object_new_object();
1466 json_object_object_add(json, grp_str, json_group);
1467 }
1468
1469 json_row = json_object_new_object();
1470 json_object_pim_upstream_add(json_row, up);
1471 json_object_string_add(json_row, "source", src_str);
1472 json_object_string_add(json_row, "group", grp_str);
1473
1474 if (pim_upstream_evaluate_join_desired(pim, up))
1475 json_object_boolean_true_add(json_row,
1476 "evaluateJoinDesired");
1477
1478 json_object_object_add(json_group, src_str, json_row);
1479
1480 } else {
e577f6e7
A
1481 vty_out(vty, "%-15pPAs %-15pPAs %-6s\n", &up->sg.src,
1482 &up->sg.grp,
45e26aa0
A
1483 pim_upstream_evaluate_join_desired(pim, up) ? "yes"
1484 : "no");
1485 }
1486}
1487
1488void pim_show_join_desired(struct pim_instance *pim, struct vty *vty, bool uj)
1489{
1490 struct pim_upstream *up;
1491
1492 json_object *json = NULL;
1493
1494 if (uj)
1495 json = json_object_new_object();
1496 else
1497 vty_out(vty, "Source Group EvalJD\n");
1498
1499 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1500 /* scan all interfaces */
1501 pim_show_join_desired_helper(pim, vty, up, json, uj);
1502 }
1503
1504 if (uj)
1505 vty_json(vty, json);
1506}
1507
1508void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, bool uj)
1509{
1510 struct pim_upstream *up;
1511 json_object *json = NULL;
1512 json_object *json_group = NULL;
1513 json_object *json_row = NULL;
1514
1515 if (uj)
1516 json = json_object_new_object();
1517 else
1518 vty_out(vty,
1519 "Source Group RpfIface RibNextHop RpfAddress \n");
1520
1521 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
45e26aa0
A
1522 char rpf_nexthop_str[PREFIX_STRLEN];
1523 char rpf_addr_str[PREFIX_STRLEN];
1524 struct pim_rpf *rpf;
1525 const char *rpf_ifname;
1526
1527 rpf = &up->rpf;
1528
45e26aa0
A
1529 pim_addr_dump("<nexthop?>",
1530 &rpf->source_nexthop.mrib_nexthop_addr,
1531 rpf_nexthop_str, sizeof(rpf_nexthop_str));
1532 pim_addr_dump("<rpf?>", &rpf->rpf_addr, rpf_addr_str,
1533 sizeof(rpf_addr_str));
1534
1535 rpf_ifname =
1536 rpf->source_nexthop.interface ? rpf->source_nexthop
1537 .interface->name
1538 : "<ifname?>";
1539
1540 if (uj) {
b1a419ba
A
1541 char grp_str[PIM_ADDRSTRLEN];
1542 char src_str[PIM_ADDRSTRLEN];
1543
1544 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
1545 &up->sg.grp);
1546 snprintfrr(src_str, sizeof(src_str), "%pPAs",
1547 &up->sg.src);
45e26aa0
A
1548 json_object_object_get_ex(json, grp_str, &json_group);
1549
1550 if (!json_group) {
1551 json_group = json_object_new_object();
1552 json_object_object_add(json, grp_str,
1553 json_group);
1554 }
1555
1556 json_row = json_object_new_object();
1557 json_object_pim_upstream_add(json_row, up);
1558 json_object_string_add(json_row, "source", src_str);
1559 json_object_string_add(json_row, "group", grp_str);
1560 json_object_string_add(json_row, "rpfInterface",
1561 rpf_ifname);
1562 json_object_string_add(json_row, "ribNexthop",
1563 rpf_nexthop_str);
1564 json_object_string_add(json_row, "rpfAddress",
1565 rpf_addr_str);
1566 json_object_object_add(json_group, src_str, json_row);
1567 } else {
b1a419ba
A
1568 vty_out(vty, "%-15pPAs %-15pPAs %-16s %-15s %-15s\n",
1569 &up->sg.src, &up->sg.grp, rpf_ifname,
1570 rpf_nexthop_str, rpf_addr_str);
45e26aa0
A
1571 }
1572 }
1573
1574 if (uj)
1575 vty_json(vty, json);
1576}
e2b601e8
SG
1577
1578static void pim_show_join_helper(struct vty *vty, struct pim_interface *pim_ifp,
1579 struct pim_ifchannel *ch, json_object *json,
24de75a2 1580 time_t now)
e2b601e8
SG
1581{
1582 json_object *json_iface = NULL;
1583 json_object *json_row = NULL;
1584 json_object *json_grp = NULL;
1585 pim_addr ifaddr;
1586 char uptime[10];
1587 char expire[10];
1588 char prune[10];
e2b601e8
SG
1589
1590 ifaddr = pim_ifp->primary_address;
1591
1592 pim_time_uptime_begin(uptime, sizeof(uptime), now, ch->ifjoin_creation);
1593 pim_time_timer_to_mmss(expire, sizeof(expire),
1594 ch->t_ifjoin_expiry_timer);
1595 pim_time_timer_to_mmss(prune, sizeof(prune),
1596 ch->t_ifjoin_prune_pending_timer);
1597
24de75a2 1598 if (json) {
e2b601e8 1599 char ch_grp_str[PIM_ADDRSTRLEN];
e2b601e8
SG
1600
1601 json_object_object_get_ex(json, ch->interface->name,
1602 &json_iface);
1603
1604 if (!json_iface) {
1605 json_iface = json_object_new_object();
1606 json_object_pim_ifp_add(json_iface, ch->interface);
1607 json_object_object_add(json, ch->interface->name,
1608 json_iface);
1609 }
1610
1611 json_row = json_object_new_object();
24de75a2
SG
1612 json_object_string_addf(json_row, "source", "%pPAs",
1613 &ch->sg.src);
1614 json_object_string_addf(json_row, "group", "%pPAs",
1615 &ch->sg.grp);
e2b601e8
SG
1616 json_object_string_add(json_row, "upTime", uptime);
1617 json_object_string_add(json_row, "expire", expire);
1618 json_object_string_add(json_row, "prune", prune);
1619 json_object_string_add(
1620 json_row, "channelJoinName",
1621 pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags));
1622 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) {
1623#if CONFDATE > 20230131
1624 CPP_NOTICE(
1625 "Remove JSON object commands with keys starting with capital")
1626#endif
1627 json_object_int_add(json_row, "SGRpt", 1);
1628 json_object_int_add(json_row, "sgRpt", 1);
1629 }
1630 if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
1631 json_object_int_add(json_row, "protocolPim", 1);
1632 if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
1633 json_object_int_add(json_row, "protocolIgmp", 1);
24de75a2
SG
1634 snprintfrr(ch_grp_str, sizeof(ch_grp_str), "%pPAs",
1635 &ch->sg.grp);
e2b601e8
SG
1636 json_object_object_get_ex(json_iface, ch_grp_str, &json_grp);
1637 if (!json_grp) {
1638 json_grp = json_object_new_object();
24de75a2
SG
1639 json_object_object_addf(json_grp, json_row, "%pPAs",
1640 &ch->sg.src);
1641 json_object_object_addf(json_iface, json_grp, "%pPAs",
1642 &ch->sg.grp);
e2b601e8 1643 } else
24de75a2
SG
1644 json_object_object_addf(json_grp, json_row, "%pPAs",
1645 &ch->sg.src);
e2b601e8 1646 } else {
24de75a2
SG
1647 vty_out(vty,
1648 "%-16s %-15pPAs %-15pPAs %-15pPAs %-10s %8s %-6s %5s\n",
1649 ch->interface->name, &ifaddr, &ch->sg.src, &ch->sg.grp,
e2b601e8
SG
1650 pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags),
1651 uptime, expire, prune);
1652 }
1653}
1654
24de75a2
SG
1655void pim_show_join(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg,
1656 json_object *json)
e2b601e8
SG
1657{
1658 struct pim_interface *pim_ifp;
1659 struct pim_ifchannel *ch;
1660 struct interface *ifp;
1661 time_t now;
e2b601e8
SG
1662
1663 now = pim_time_monotonic_sec();
1664
24de75a2 1665 if (!json)
e2b601e8
SG
1666 vty_out(vty,
1667 "Interface Address Source Group State Uptime Expire Prune\n");
1668
1669 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1670 pim_ifp = ifp->info;
1671 if (!pim_ifp)
1672 continue;
1673
1674 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
1675 if (!pim_sgaddr_match(ch->sg, *sg))
1676 continue;
24de75a2
SG
1677
1678 pim_show_join_helper(vty, pim_ifp, ch, json, now);
e2b601e8
SG
1679 } /* scan interface channels */
1680 }
e2b601e8
SG
1681}
1682
1683static void pim_show_jp_agg_helper(struct vty *vty, struct interface *ifp,
1684 struct pim_neighbor *neigh,
1685 struct pim_upstream *up, int is_join)
1686{
be223239
SG
1687 vty_out(vty, "%-16s %-15pPAs %-15pPAs %-15pPAs %5s\n", ifp->name,
1688 &neigh->source_addr, &up->sg.src, &up->sg.grp,
1689 is_join ? "J" : "P");
e2b601e8
SG
1690}
1691
1692void pim_show_jp_agg_list(struct pim_instance *pim, struct vty *vty)
1693{
1694 struct interface *ifp;
1695 struct pim_interface *pim_ifp;
1696 struct listnode *n_node;
1697 struct pim_neighbor *neigh;
1698 struct listnode *jag_node;
1699 struct pim_jp_agg_group *jag;
1700 struct listnode *js_node;
1701 struct pim_jp_sources *js;
1702
1703 vty_out(vty,
1704 "Interface RPF Nbr Source Group State\n");
1705
1706 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1707 pim_ifp = ifp->info;
1708 if (!pim_ifp)
1709 continue;
1710
1711 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, n_node,
1712 neigh)) {
1713 for (ALL_LIST_ELEMENTS_RO(neigh->upstream_jp_agg,
1714 jag_node, jag)) {
1715 for (ALL_LIST_ELEMENTS_RO(jag->sources, js_node,
1716 js)) {
1717 pim_show_jp_agg_helper(vty, ifp, neigh,
1718 js->up,
1719 js->is_join);
1720 }
1721 }
1722 }
1723 }
1724}
1725
1726static void pim_show_membership_helper(struct vty *vty,
1727 struct pim_interface *pim_ifp,
1728 struct pim_ifchannel *ch,
1729 struct json_object *json)
1730{
e2b601e8
SG
1731 json_object *json_iface = NULL;
1732 json_object *json_row = NULL;
1733
1734 json_object_object_get_ex(json, ch->interface->name, &json_iface);
1735 if (!json_iface) {
1736 json_iface = json_object_new_object();
1737 json_object_pim_ifp_add(json_iface, ch->interface);
1738 json_object_object_add(json, ch->interface->name, json_iface);
1739 }
1740
e2b601e8
SG
1741 json_row = json_object_new_object();
1742 json_object_string_addf(json_row, "source", "%pPAs", &ch->sg.src);
de11054e 1743 json_object_string_addf(json_row, "group", "%pPAs", &ch->sg.grp);
e2b601e8
SG
1744 json_object_string_add(json_row, "localMembership",
1745 ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO
de11054e
SG
1746 ? "NOINFO"
1747 : "INCLUDE");
1748 json_object_object_addf(json_iface, json_row, "%pPAs", &ch->sg.grp);
e2b601e8
SG
1749}
1750
1751void pim_show_membership(struct pim_instance *pim, struct vty *vty, bool uj)
1752{
1753 struct pim_interface *pim_ifp;
1754 struct pim_ifchannel *ch;
1755 struct interface *ifp;
1756 enum json_type type;
1757 json_object *json = NULL;
1758 json_object *json_tmp = NULL;
1759
1760 json = json_object_new_object();
1761
1762 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1763 pim_ifp = ifp->info;
1764 if (!pim_ifp)
1765 continue;
1766
1767 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
1768 pim_show_membership_helper(vty, pim_ifp, ch, json);
1769 } /* scan interface channels */
1770 }
1771
1772 if (uj) {
de11054e 1773 vty_json(vty, json);
e2b601e8
SG
1774 } else {
1775 vty_out(vty,
1776 "Interface Address Source Group Membership\n");
1777
1778 /*
1779 * Example of the json data we are traversing
1780 *
1781 * {
1782 * "swp3":{
1783 * "name":"swp3",
1784 * "state":"up",
1785 * "address":"10.1.20.1",
1786 * "index":5,
1787 * "flagMulticast":true,
1788 * "flagBroadcast":true,
1789 * "lanDelayEnabled":true,
1790 * "226.10.10.10":{
1791 * "source":"*",
1792 * "group":"226.10.10.10",
1793 * "localMembership":"INCLUDE"
1794 * }
1795 * }
1796 * }
1797 */
1798
1799 /* foreach interface */
1800 json_object_object_foreach(json, key, val)
1801 {
1802
1803 /* Find all of the keys where the val is an object. In
1804 * the example
1805 * above the only one is 226.10.10.10
1806 */
1807 json_object_object_foreach(val, if_field_key,
1808 if_field_val)
1809 {
1810 type = json_object_get_type(if_field_val);
1811
1812 if (type == json_type_object) {
1813 vty_out(vty, "%-16s ", key);
1814
1815 json_object_object_get_ex(
1816 val, "address", &json_tmp);
1817 vty_out(vty, "%-15s ",
1818 json_object_get_string(
1819 json_tmp));
1820
1821 json_object_object_get_ex(if_field_val,
1822 "source",
1823 &json_tmp);
1824 vty_out(vty, "%-15s ",
1825 json_object_get_string(
1826 json_tmp));
1827
1828 /* Group */
1829 vty_out(vty, "%-15s ", if_field_key);
1830
1831 json_object_object_get_ex(
1832 if_field_val, "localMembership",
1833 &json_tmp);
1834 vty_out(vty, "%-10s\n",
1835 json_object_get_string(
1836 json_tmp));
1837 }
1838 }
1839 }
de11054e 1840 json_object_free(json);
e2b601e8 1841 }
e2b601e8
SG
1842}
1843
1844static void pim_show_channel_helper(struct pim_instance *pim, struct vty *vty,
1845 struct pim_interface *pim_ifp,
1846 struct pim_ifchannel *ch, json_object *json,
1847 bool uj)
1848{
1849 struct pim_upstream *up = ch->upstream;
1850 json_object *json_group = NULL;
e2b601e8
SG
1851 json_object *json_row = NULL;
1852
e2b601e8 1853 if (uj) {
bf083b3a
SG
1854 char grp_str[PIM_ADDRSTRLEN];
1855
1856 snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &up->sg.grp);
e2b601e8
SG
1857 json_object_object_get_ex(json, grp_str, &json_group);
1858
1859 if (!json_group) {
1860 json_group = json_object_new_object();
1861 json_object_object_add(json, grp_str, json_group);
1862 }
1863
1864 json_row = json_object_new_object();
1865 json_object_pim_upstream_add(json_row, up);
1866 json_object_string_add(json_row, "interface",
1867 ch->interface->name);
bf083b3a
SG
1868 json_object_string_addf(json_row, "source", "%pPAs",
1869 &up->sg.src);
1870 json_object_string_addf(json_row, "group", "%pPAs",
1871 &up->sg.grp);
e2b601e8
SG
1872
1873 if (pim_macro_ch_lost_assert(ch))
1874 json_object_boolean_true_add(json_row, "lostAssert");
1875
1876 if (pim_macro_chisin_joins(ch))
1877 json_object_boolean_true_add(json_row, "joins");
1878
1879 if (pim_macro_chisin_pim_include(ch))
1880 json_object_boolean_true_add(json_row, "pimInclude");
1881
1882 if (pim_upstream_evaluate_join_desired(pim, up))
1883 json_object_boolean_true_add(json_row,
1884 "evaluateJoinDesired");
1885
bf083b3a
SG
1886 json_object_object_addf(json_group, json_row, "%pPAs",
1887 &up->sg.src);
e2b601e8
SG
1888
1889 } else {
bf083b3a
SG
1890 vty_out(vty,
1891 "%-16s %-15pPAs %-15pPAs %-10s %-5s %-10s %-11s %-6s\n",
1892 ch->interface->name, &up->sg.src, &up->sg.grp,
e2b601e8
SG
1893 pim_macro_ch_lost_assert(ch) ? "yes" : "no",
1894 pim_macro_chisin_joins(ch) ? "yes" : "no",
1895 pim_macro_chisin_pim_include(ch) ? "yes" : "no",
1896 PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags)
1897 ? "yes"
1898 : "no",
1899 pim_upstream_evaluate_join_desired(pim, up) ? "yes"
1900 : "no");
1901 }
1902}
1903
1904void pim_show_channel(struct pim_instance *pim, struct vty *vty, bool uj)
1905{
1906 struct pim_interface *pim_ifp;
1907 struct pim_ifchannel *ch;
1908 struct interface *ifp;
1909
1910 json_object *json = NULL;
1911
1912 if (uj)
1913 json = json_object_new_object();
1914 else
1915 vty_out(vty,
1916 "Interface Source Group LostAssert Joins PimInclude JoinDesired EvalJD\n");
1917
1918 /* scan per-interface (S,G) state */
1919 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1920 pim_ifp = ifp->info;
1921 if (!pim_ifp)
1922 continue;
1923
1924
1925 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
1926 /* scan all interfaces */
1927 pim_show_channel_helper(pim, vty, pim_ifp, ch, json,
1928 uj);
1929 }
1930 }
1931
1932 if (uj)
1933 vty_json(vty, json);
1934}
1935
1936void pim_show_interfaces(struct pim_instance *pim, struct vty *vty, bool mlag,
44f99d22 1937 json_object *json)
e2b601e8
SG
1938{
1939 struct interface *ifp;
1940 struct pim_interface *pim_ifp;
1941 struct pim_upstream *up;
1942 int fhr = 0;
1943 int pim_nbrs = 0;
1944 int pim_ifchannels = 0;
44f99d22 1945 bool uj = true;
e2b601e8
SG
1946 json_object *json_row = NULL;
1947 json_object *json_tmp;
1948
44f99d22
SG
1949 if (!json) {
1950 uj = false;
1951 json = json_object_new_object();
1952 }
e2b601e8
SG
1953
1954 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1955 pim_ifp = ifp->info;
1956
1957 if (!pim_ifp)
1958 continue;
1959
1960 if (mlag == true && pim_ifp->activeactive == false)
1961 continue;
1962
1963 pim_nbrs = pim_ifp->pim_neighbor_list->count;
1964 pim_ifchannels = pim_if_ifchannel_count(pim_ifp);
1965 fhr = 0;
1966
1967 frr_each (rb_pim_upstream, &pim->upstream_head, up)
1968 if (ifp == up->rpf.source_nexthop.interface)
1969 if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR)
1970 fhr++;
1971
1972 json_row = json_object_new_object();
1973 json_object_pim_ifp_add(json_row, ifp);
1974 json_object_int_add(json_row, "pimNeighbors", pim_nbrs);
1975 json_object_int_add(json_row, "pimIfChannels", pim_ifchannels);
1976 json_object_int_add(json_row, "firstHopRouterCount", fhr);
44f99d22
SG
1977 json_object_string_addf(json_row, "pimDesignatedRouter",
1978 "%pPAs", &pim_ifp->pim_dr_addr);
e2b601e8
SG
1979
1980 if (pim_addr_cmp(pim_ifp->pim_dr_addr,
44f99d22 1981 pim_ifp->primary_address))
e2b601e8
SG
1982 json_object_boolean_true_add(
1983 json_row, "pimDesignatedRouterLocal");
1984
1985 json_object_object_add(json, ifp->name, json_row);
1986 }
1987
44f99d22 1988 if (!uj) {
e2b601e8
SG
1989 vty_out(vty,
1990 "Interface State Address PIM Nbrs PIM DR FHR IfChannels\n");
1991
1992 json_object_object_foreach(json, key, val)
1993 {
1994 vty_out(vty, "%-16s ", key);
1995
1996 json_object_object_get_ex(val, "state", &json_tmp);
1997 vty_out(vty, "%5s ", json_object_get_string(json_tmp));
1998
1999 json_object_object_get_ex(val, "address", &json_tmp);
2000 vty_out(vty, "%15s ",
2001 json_object_get_string(json_tmp));
2002
2003 json_object_object_get_ex(val, "pimNeighbors",
2004 &json_tmp);
2005 vty_out(vty, "%8d ", json_object_get_int(json_tmp));
2006
2007 if (json_object_object_get_ex(
2008 val, "pimDesignatedRouterLocal",
2009 &json_tmp)) {
2010 vty_out(vty, "%15s ", "local");
2011 } else {
2012 json_object_object_get_ex(
2013 val, "pimDesignatedRouter", &json_tmp);
2014 vty_out(vty, "%15s ",
2015 json_object_get_string(json_tmp));
2016 }
2017
2018 json_object_object_get_ex(val, "firstHopRouter",
2019 &json_tmp);
2020 vty_out(vty, "%3d ", json_object_get_int(json_tmp));
2021
2022 json_object_object_get_ex(val, "pimIfChannels",
2023 &json_tmp);
2024 vty_out(vty, "%9d\n", json_object_get_int(json_tmp));
2025 }
2026 }
e2b601e8
SG
2027}
2028
44f99d22
SG
2029void pim_show_interfaces_single(struct pim_instance *pim, struct vty *vty,
2030 const char *ifname, bool mlag,
2031 json_object *json)
e2b601e8
SG
2032{
2033 pim_addr ifaddr;
2034 struct interface *ifp;
2035 struct listnode *neighnode;
2036 struct pim_interface *pim_ifp;
2037 struct pim_neighbor *neigh;
2038 struct pim_upstream *up;
2039 time_t now;
44f99d22 2040 char dr_str[PIM_ADDRSTRLEN];
e2b601e8
SG
2041 char dr_uptime[10];
2042 char expire[10];
44f99d22 2043 char grp_str[PIM_ADDRSTRLEN];
e2b601e8
SG
2044 char hello_period[10];
2045 char hello_timer[10];
44f99d22
SG
2046 char neigh_src_str[PIM_ADDRSTRLEN];
2047 char src_str[PIM_ADDRSTRLEN];
e2b601e8
SG
2048 char stat_uptime[10];
2049 char uptime[10];
2050 int found_ifname = 0;
2051 int print_header;
e2b601e8
SG
2052 json_object *json_row = NULL;
2053 json_object *json_pim_neighbor = NULL;
2054 json_object *json_pim_neighbors = NULL;
2055 json_object *json_group = NULL;
2056 json_object *json_group_source = NULL;
2057 json_object *json_fhr_sources = NULL;
2058 struct pim_secondary_addr *sec_addr;
2059 struct listnode *sec_node;
2060
2061 now = pim_time_monotonic_sec();
2062
e2b601e8
SG
2063 FOR_ALL_INTERFACES (pim->vrf, ifp) {
2064 pim_ifp = ifp->info;
2065
2066 if (!pim_ifp)
2067 continue;
2068
2069 if (mlag == true && pim_ifp->activeactive == false)
2070 continue;
2071
2072 if (strcmp(ifname, "detail") && strcmp(ifname, ifp->name))
2073 continue;
2074
2075 found_ifname = 1;
2076 ifaddr = pim_ifp->primary_address;
44f99d22
SG
2077 snprintfrr(dr_str, sizeof(dr_str), "%pPAs",
2078 &pim_ifp->pim_dr_addr);
e2b601e8
SG
2079 pim_time_uptime_begin(dr_uptime, sizeof(dr_uptime), now,
2080 pim_ifp->pim_dr_election_last);
2081 pim_time_timer_to_hhmmss(hello_timer, sizeof(hello_timer),
2082 pim_ifp->t_pim_hello_timer);
2083 pim_time_mmss(hello_period, sizeof(hello_period),
2084 pim_ifp->pim_hello_period);
2085 pim_time_uptime(stat_uptime, sizeof(stat_uptime),
2086 now - pim_ifp->pim_ifstat_start);
2087
44f99d22 2088 if (json) {
e2b601e8
SG
2089 json_row = json_object_new_object();
2090 json_object_pim_ifp_add(json_row, ifp);
2091
44f99d22 2092 if (!pim_addr_is_any(pim_ifp->update_source)) {
e2b601e8 2093 json_object_string_addf(
44f99d22 2094 json_row, "useSource", "%pPAs",
e2b601e8
SG
2095 &pim_ifp->update_source);
2096 }
2097 if (pim_ifp->sec_addr_list) {
2098 json_object *sec_list = NULL;
2099
2100 sec_list = json_object_new_array();
2101 for (ALL_LIST_ELEMENTS_RO(
2102 pim_ifp->sec_addr_list, sec_node,
2103 sec_addr)) {
2104 json_object_array_add(
2105 sec_list,
44f99d22
SG
2106 json_object_new_stringf(
2107 "%pFXh",
2108 &sec_addr->addr));
e2b601e8
SG
2109 }
2110 json_object_object_add(json_row,
2111 "secondaryAddressList",
2112 sec_list);
2113 }
2114
2115 /* PIM neighbors */
2116 if (pim_ifp->pim_neighbor_list->count) {
2117 json_pim_neighbors = json_object_new_object();
2118
2119 for (ALL_LIST_ELEMENTS_RO(
2120 pim_ifp->pim_neighbor_list,
2121 neighnode, neigh)) {
2122 json_pim_neighbor =
2123 json_object_new_object();
44f99d22
SG
2124 snprintfrr(neigh_src_str,
2125 sizeof(neigh_src_str),
2126 "%pPAs",
2127 &neigh->source_addr);
e2b601e8
SG
2128 pim_time_uptime(uptime, sizeof(uptime),
2129 now - neigh->creation);
2130 pim_time_timer_to_hhmmss(
2131 expire, sizeof(expire),
2132 neigh->t_expire_timer);
2133
2134 json_object_string_add(
2135 json_pim_neighbor, "address",
2136 neigh_src_str);
2137 json_object_string_add(
2138 json_pim_neighbor, "upTime",
2139 uptime);
2140 json_object_string_add(
2141 json_pim_neighbor, "holdtime",
2142 expire);
2143
2144 json_object_object_add(
2145 json_pim_neighbors,
2146 neigh_src_str,
2147 json_pim_neighbor);
2148 }
2149
2150 json_object_object_add(json_row, "neighbors",
2151 json_pim_neighbors);
2152 }
2153
2154 json_object_string_add(json_row, "drAddress", dr_str);
2155 json_object_int_add(json_row, "drPriority",
2156 pim_ifp->pim_dr_priority);
2157 json_object_string_add(json_row, "drUptime", dr_uptime);
2158 json_object_int_add(json_row, "drElections",
2159 pim_ifp->pim_dr_election_count);
2160 json_object_int_add(json_row, "drChanges",
2161 pim_ifp->pim_dr_election_changes);
2162
2163 /* FHR */
2164 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2165 if (ifp != up->rpf.source_nexthop.interface)
2166 continue;
2167
2168 if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_FHR))
2169 continue;
2170
2171 if (!json_fhr_sources)
2172 json_fhr_sources =
2173 json_object_new_object();
2174
2175 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
2176 &up->sg.grp);
2177 snprintfrr(src_str, sizeof(src_str), "%pPAs",
2178 &up->sg.src);
2179 pim_time_uptime(uptime, sizeof(uptime),
2180 now - up->state_transition);
2181
2182 /*
2183 * Does this group live in json_fhr_sources?
2184 * If not create it.
2185 */
2186 json_object_object_get_ex(json_fhr_sources,
2187 grp_str, &json_group);
2188
2189 if (!json_group) {
2190 json_group = json_object_new_object();
2191 json_object_object_add(json_fhr_sources,
2192 grp_str,
2193 json_group);
2194 }
2195
2196 json_group_source = json_object_new_object();
2197 json_object_string_add(json_group_source,
2198 "source", src_str);
2199 json_object_string_add(json_group_source,
2200 "group", grp_str);
2201 json_object_string_add(json_group_source,
2202 "upTime", uptime);
2203 json_object_object_add(json_group, src_str,
2204 json_group_source);
2205 }
2206
2207 if (json_fhr_sources) {
2208 json_object_object_add(json_row,
2209 "firstHopRouter",
2210 json_fhr_sources);
2211 }
2212
2213 json_object_int_add(json_row, "helloPeriod",
2214 pim_ifp->pim_hello_period);
2215 json_object_int_add(json_row, "holdTime",
2216 PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
2217 json_object_string_add(json_row, "helloTimer",
2218 hello_timer);
2219 json_object_string_add(json_row, "helloStatStart",
2220 stat_uptime);
2221 json_object_int_add(json_row, "helloReceived",
2222 pim_ifp->pim_ifstat_hello_recv);
2223 json_object_int_add(json_row, "helloReceivedFailed",
2224 pim_ifp->pim_ifstat_hello_recvfail);
2225 json_object_int_add(json_row, "helloSend",
2226 pim_ifp->pim_ifstat_hello_sent);
2227 json_object_int_add(json_row, "hellosendFailed",
2228 pim_ifp->pim_ifstat_hello_sendfail);
2229 json_object_int_add(json_row, "helloGenerationId",
2230 pim_ifp->pim_generation_id);
2231
2232 json_object_int_add(
2233 json_row, "effectivePropagationDelay",
2234 pim_if_effective_propagation_delay_msec(ifp));
2235 json_object_int_add(
2236 json_row, "effectiveOverrideInterval",
2237 pim_if_effective_override_interval_msec(ifp));
2238 json_object_int_add(
2239 json_row, "joinPruneOverrideInterval",
2240 pim_if_jp_override_interval_msec(ifp));
2241
2242 json_object_int_add(
2243 json_row, "propagationDelay",
2244 pim_ifp->pim_propagation_delay_msec);
2245 json_object_int_add(
2246 json_row, "propagationDelayHighest",
2247 pim_ifp->pim_neighbors_highest_propagation_delay_msec);
2248 json_object_int_add(
2249 json_row, "overrideInterval",
2250 pim_ifp->pim_override_interval_msec);
2251 json_object_int_add(
2252 json_row, "overrideIntervalHighest",
2253 pim_ifp->pim_neighbors_highest_override_interval_msec);
2254 if (pim_ifp->bsm_enable)
2255 json_object_boolean_true_add(json_row,
2256 "bsmEnabled");
2257 if (pim_ifp->ucast_bsm_accept)
2258 json_object_boolean_true_add(json_row,
2259 "ucastBsmEnabled");
2260 json_object_object_add(json, ifp->name, json_row);
2261
2262 } else {
2263 vty_out(vty, "Interface : %s\n", ifp->name);
2264 vty_out(vty, "State : %s\n",
2265 if_is_up(ifp) ? "up" : "down");
44f99d22
SG
2266 if (!pim_addr_is_any(pim_ifp->update_source)) {
2267 vty_out(vty, "Use Source : %pPAs\n",
e2b601e8
SG
2268 &pim_ifp->update_source);
2269 }
2270 if (pim_ifp->sec_addr_list) {
44f99d22 2271 vty_out(vty, "Address : %pPAs (primary)\n",
e2b601e8
SG
2272 &ifaddr);
2273 for (ALL_LIST_ELEMENTS_RO(
2274 pim_ifp->sec_addr_list, sec_node,
2275 sec_addr))
2276 vty_out(vty, " %pFX\n",
2277 &sec_addr->addr);
2278 } else {
44f99d22 2279 vty_out(vty, "Address : %pPAs\n", &ifaddr);
e2b601e8
SG
2280 }
2281 vty_out(vty, "\n");
2282
2283 /* PIM neighbors */
2284 print_header = 1;
2285
2286 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list,
2287 neighnode, neigh)) {
2288
2289 if (print_header) {
2290 vty_out(vty, "PIM Neighbors\n");
2291 vty_out(vty, "-------------\n");
2292 print_header = 0;
2293 }
2294
44f99d22
SG
2295 snprintfrr(neigh_src_str, sizeof(neigh_src_str),
2296 "%pPAs", &neigh->source_addr);
e2b601e8
SG
2297 pim_time_uptime(uptime, sizeof(uptime),
2298 now - neigh->creation);
2299 pim_time_timer_to_hhmmss(expire, sizeof(expire),
2300 neigh->t_expire_timer);
2301 vty_out(vty,
2302 "%-15s : up for %s, holdtime expires in %s\n",
2303 neigh_src_str, uptime, expire);
2304 }
2305
2306 if (!print_header) {
2307 vty_out(vty, "\n");
2308 vty_out(vty, "\n");
2309 }
2310
2311 vty_out(vty, "Designated Router\n");
2312 vty_out(vty, "-----------------\n");
2313 vty_out(vty, "Address : %s\n", dr_str);
2314 vty_out(vty, "Priority : %u(%d)\n",
2315 pim_ifp->pim_dr_priority,
2316 pim_ifp->pim_dr_num_nondrpri_neighbors);
2317 vty_out(vty, "Uptime : %s\n", dr_uptime);
2318 vty_out(vty, "Elections : %d\n",
2319 pim_ifp->pim_dr_election_count);
2320 vty_out(vty, "Changes : %d\n",
2321 pim_ifp->pim_dr_election_changes);
2322 vty_out(vty, "\n");
2323 vty_out(vty, "\n");
2324
2325 /* FHR */
2326 print_header = 1;
2327 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2328 if (!up->rpf.source_nexthop.interface)
2329 continue;
2330
2331 if (strcmp(ifp->name,
2332 up->rpf.source_nexthop
44f99d22 2333 .interface->name) != 0)
e2b601e8
SG
2334 continue;
2335
2336 if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_FHR))
2337 continue;
2338
2339 if (print_header) {
2340 vty_out(vty,
2341 "FHR - First Hop Router\n");
2342 vty_out(vty,
2343 "----------------------\n");
2344 print_header = 0;
2345 }
2346
2347 pim_time_uptime(uptime, sizeof(uptime),
2348 now - up->state_transition);
2349 vty_out(vty,
2350 "%pPAs : %pPAs is a source, uptime is %s\n",
2351 &up->sg.grp, &up->sg.src, uptime);
2352 }
2353
2354 if (!print_header) {
2355 vty_out(vty, "\n");
2356 vty_out(vty, "\n");
2357 }
2358
2359 vty_out(vty, "Hellos\n");
2360 vty_out(vty, "------\n");
2361 vty_out(vty, "Period : %d\n",
2362 pim_ifp->pim_hello_period);
2363 vty_out(vty, "HoldTime : %d\n",
2364 PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
2365 vty_out(vty, "Timer : %s\n", hello_timer);
2366 vty_out(vty, "StatStart : %s\n", stat_uptime);
2367 vty_out(vty, "Receive : %d\n",
2368 pim_ifp->pim_ifstat_hello_recv);
2369 vty_out(vty, "Receive Failed : %d\n",
2370 pim_ifp->pim_ifstat_hello_recvfail);
2371 vty_out(vty, "Send : %d\n",
2372 pim_ifp->pim_ifstat_hello_sent);
2373 vty_out(vty, "Send Failed : %d\n",
2374 pim_ifp->pim_ifstat_hello_sendfail);
2375 vty_out(vty, "Generation ID : %08x\n",
2376 pim_ifp->pim_generation_id);
2377 vty_out(vty, "\n");
2378 vty_out(vty, "\n");
2379
2380 pim_print_ifp_flags(vty, ifp);
2381
2382 vty_out(vty, "Join Prune Interval\n");
2383 vty_out(vty, "-------------------\n");
2384 vty_out(vty, "LAN Delay : %s\n",
2385 pim_if_lan_delay_enabled(ifp) ? "yes" : "no");
2386 vty_out(vty, "Effective Propagation Delay : %d msec\n",
2387 pim_if_effective_propagation_delay_msec(ifp));
2388 vty_out(vty, "Effective Override Interval : %d msec\n",
2389 pim_if_effective_override_interval_msec(ifp));
2390 vty_out(vty, "Join Prune Override Interval : %d msec\n",
2391 pim_if_jp_override_interval_msec(ifp));
2392 vty_out(vty, "\n");
2393 vty_out(vty, "\n");
2394
2395 vty_out(vty, "LAN Prune Delay\n");
2396 vty_out(vty, "---------------\n");
2397 vty_out(vty, "Propagation Delay : %d msec\n",
2398 pim_ifp->pim_propagation_delay_msec);
2399 vty_out(vty, "Propagation Delay (Highest) : %d msec\n",
2400 pim_ifp->pim_neighbors_highest_propagation_delay_msec);
2401 vty_out(vty, "Override Interval : %d msec\n",
2402 pim_ifp->pim_override_interval_msec);
2403 vty_out(vty, "Override Interval (Highest) : %d msec\n",
2404 pim_ifp->pim_neighbors_highest_override_interval_msec);
2405 vty_out(vty, "\n");
2406 vty_out(vty, "\n");
2407
2408 vty_out(vty, "BSM Status\n");
2409 vty_out(vty, "----------\n");
2410 vty_out(vty, "Bsm Enabled : %s\n",
2411 pim_ifp->bsm_enable ? "yes" : "no");
2412 vty_out(vty, "Unicast Bsm Enabled : %s\n",
2413 pim_ifp->ucast_bsm_accept ? "yes" : "no");
2414 vty_out(vty, "\n");
2415 vty_out(vty, "\n");
2416 }
2417 }
2418
44f99d22 2419 if (!found_ifname)
e2b601e8
SG
2420 vty_out(vty, "%% No such interface\n");
2421}
2422
2423void ip_pim_ssm_show_group_range(struct pim_instance *pim, struct vty *vty,
2424 bool uj)
2425{
2426 struct pim_ssm *ssm = pim->ssm_info;
2427 const char *range_str =
2428 ssm->plist_name ? ssm->plist_name : PIM_SSM_STANDARD_RANGE;
2429
2430 if (uj) {
2431 json_object *json;
2432
2433 json = json_object_new_object();
2434 json_object_string_add(json, "ssmGroups", range_str);
2435 vty_json(vty, json);
2436 } else
2437 vty_out(vty, "SSM group range : %s\n", range_str);
2438}
2439
2440struct pnc_cache_walk_data {
2441 struct vty *vty;
2442 struct pim_instance *pim;
2443};
2444
2445static int pim_print_pnc_cache_walkcb(struct hash_bucket *bucket, void *arg)
2446{
2447 struct pim_nexthop_cache *pnc = bucket->data;
2448 struct pnc_cache_walk_data *cwd = arg;
2449 struct vty *vty = cwd->vty;
2450 struct pim_instance *pim = cwd->pim;
2451 struct nexthop *nh_node = NULL;
2452 ifindex_t first_ifindex;
2453 struct interface *ifp = NULL;
2454 char buf[PREFIX_STRLEN];
2455
2456 for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
2457 first_ifindex = nh_node->ifindex;
2458 ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
2459
2460 vty_out(vty, "%-15s ",
2461 inet_ntop(AF_INET, &pnc->rpf.rpf_addr.u.prefix4, buf,
2462 sizeof(buf)));
2463 vty_out(vty, "%-16s ", ifp ? ifp->name : "NULL");
2464 vty_out(vty, "%pI4 ", &nh_node->gate.ipv4);
2465 vty_out(vty, "\n");
2466 }
2467 return CMD_SUCCESS;
2468}
2469
2470void pim_show_nexthop(struct pim_instance *pim, struct vty *vty)
2471{
2472 struct pnc_cache_walk_data cwd;
2473
2474 cwd.vty = vty;
2475 cwd.pim = pim;
2476 vty_out(vty, "Number of registered addresses: %lu\n",
2477 pim->rpf_hash->count);
2478 vty_out(vty, "Address Interface Nexthop\n");
2479 vty_out(vty, "---------------------------------------------\n");
2480
2481 hash_walk(pim->rpf_hash, pim_print_pnc_cache_walkcb, &cwd);
2482}
2483
2484void pim_show_neighbors_single(struct pim_instance *pim, struct vty *vty,
2485 const char *neighbor, json_object *json)
2486{
2487 struct listnode *neighnode;
2488 struct interface *ifp;
2489 struct pim_interface *pim_ifp;
2490 struct pim_neighbor *neigh;
2491 time_t now;
2492 int found_neighbor = 0;
2493 int option_address_list;
2494 int option_dr_priority;
2495 int option_generation_id;
2496 int option_holdtime;
2497 int option_lan_prune_delay;
2498 int option_t_bit;
2499 char uptime[10];
2500 char expire[10];
2501 char neigh_src_str[PIM_ADDRSTRLEN];
2502
2503 json_object *json_ifp = NULL;
2504 json_object *json_row = NULL;
2505
2506 now = pim_time_monotonic_sec();
2507
2508 FOR_ALL_INTERFACES (pim->vrf, ifp) {
2509 pim_ifp = ifp->info;
2510
2511 if (!pim_ifp)
2512 continue;
2513
2514 if (pim_ifp->pim_sock_fd < 0)
2515 continue;
2516
2517 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
2518 neigh)) {
2519 snprintfrr(neigh_src_str, sizeof(neigh_src_str),
2520 "%pPAs", &neigh->source_addr);
2521
2522 /*
2523 * The user can specify either the interface name or the
2524 * PIM neighbor IP.
2525 * If this pim_ifp matches neither then skip.
2526 */
2527 if (strcmp(neighbor, "detail") &&
2528 strcmp(neighbor, ifp->name) &&
2529 strcmp(neighbor, neigh_src_str))
2530 continue;
2531
2532 found_neighbor = 1;
2533 pim_time_uptime(uptime, sizeof(uptime),
2534 now - neigh->creation);
2535 pim_time_timer_to_hhmmss(expire, sizeof(expire),
2536 neigh->t_expire_timer);
2537
2538 option_address_list = 0;
2539 option_dr_priority = 0;
2540 option_generation_id = 0;
2541 option_holdtime = 0;
2542 option_lan_prune_delay = 0;
2543 option_t_bit = 0;
2544
2545 if (PIM_OPTION_IS_SET(neigh->hello_options,
2546 PIM_OPTION_MASK_ADDRESS_LIST))
2547 option_address_list = 1;
2548
2549 if (PIM_OPTION_IS_SET(neigh->hello_options,
2550 PIM_OPTION_MASK_DR_PRIORITY))
2551 option_dr_priority = 1;
2552
2553 if (PIM_OPTION_IS_SET(neigh->hello_options,
2554 PIM_OPTION_MASK_GENERATION_ID))
2555 option_generation_id = 1;
2556
2557 if (PIM_OPTION_IS_SET(neigh->hello_options,
2558 PIM_OPTION_MASK_HOLDTIME))
2559 option_holdtime = 1;
2560
2561 if (PIM_OPTION_IS_SET(neigh->hello_options,
2562 PIM_OPTION_MASK_LAN_PRUNE_DELAY))
2563 option_lan_prune_delay = 1;
2564
2565 if (PIM_OPTION_IS_SET(
2566 neigh->hello_options,
2567 PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION))
2568 option_t_bit = 1;
2569
2570 if (json) {
2571
2572 /* Does this ifp live in json? If not create it
2573 */
2574 json_object_object_get_ex(json, ifp->name,
2575 &json_ifp);
2576
2577 if (!json_ifp) {
2578 json_ifp = json_object_new_object();
2579 json_object_pim_ifp_add(json_ifp, ifp);
2580 json_object_object_add(json, ifp->name,
2581 json_ifp);
2582 }
2583
2584 json_row = json_object_new_object();
2585 json_object_string_add(json_row, "interface",
2586 ifp->name);
2587 json_object_string_add(json_row, "address",
2588 neigh_src_str);
2589 json_object_string_add(json_row, "upTime",
2590 uptime);
2591 json_object_string_add(json_row, "holdtime",
2592 expire);
2593 json_object_int_add(json_row, "drPriority",
2594 neigh->dr_priority);
2595 json_object_int_add(json_row, "generationId",
2596 neigh->generation_id);
2597
2598 if (option_address_list)
2599 json_object_boolean_true_add(
2600 json_row,
2601 "helloOptionAddressList");
2602
2603 if (option_dr_priority)
2604 json_object_boolean_true_add(
2605 json_row,
2606 "helloOptionDrPriority");
2607
2608 if (option_generation_id)
2609 json_object_boolean_true_add(
2610 json_row,
2611 "helloOptionGenerationId");
2612
2613 if (option_holdtime)
2614 json_object_boolean_true_add(
2615 json_row,
2616 "helloOptionHoldtime");
2617
2618 if (option_lan_prune_delay)
2619 json_object_boolean_true_add(
2620 json_row,
2621 "helloOptionLanPruneDelay");
2622
2623 if (option_t_bit)
2624 json_object_boolean_true_add(
2625 json_row, "helloOptionTBit");
2626
2627 json_object_object_add(json_ifp, neigh_src_str,
2628 json_row);
2629
2630 } else {
2631 vty_out(vty, "Interface : %s\n", ifp->name);
2632 vty_out(vty, "Neighbor : %s\n", neigh_src_str);
2633 vty_out(vty,
2634 " Uptime : %s\n",
2635 uptime);
2636 vty_out(vty,
2637 " Holdtime : %s\n",
2638 expire);
2639 vty_out(vty,
2640 " DR Priority : %d\n",
2641 neigh->dr_priority);
2642 vty_out(vty,
2643 " Generation ID : %08x\n",
2644 neigh->generation_id);
2645 vty_out(vty,
2646 " Override Interval (msec) : %d\n",
2647 neigh->override_interval_msec);
2648 vty_out(vty,
2649 " Propagation Delay (msec) : %d\n",
2650 neigh->propagation_delay_msec);
2651 vty_out(vty,
2652 " Hello Option - Address List : %s\n",
2653 option_address_list ? "yes" : "no");
2654 vty_out(vty,
2655 " Hello Option - DR Priority : %s\n",
2656 option_dr_priority ? "yes" : "no");
2657 vty_out(vty,
2658 " Hello Option - Generation ID : %s\n",
2659 option_generation_id ? "yes" : "no");
2660 vty_out(vty,
2661 " Hello Option - Holdtime : %s\n",
2662 option_holdtime ? "yes" : "no");
2663 vty_out(vty,
2664 " Hello Option - LAN Prune Delay : %s\n",
2665 option_lan_prune_delay ? "yes" : "no");
2666 vty_out(vty,
2667 " Hello Option - T-bit : %s\n",
2668 option_t_bit ? "yes" : "no");
2669 bfd_sess_show(vty, json_ifp,
2670 neigh->bfd_session);
2671 vty_out(vty, "\n");
2672 }
2673 }
2674 }
2675
2676 if (!found_neighbor)
2677 vty_out(vty, "%% No such interface or neighbor\n");
2678}
2679
1295dbeb
SG
2680void pim_show_neighbors(struct pim_instance *pim, struct vty *vty,
2681 json_object *json)
e2b601e8
SG
2682{
2683 struct listnode *neighnode;
2684 struct interface *ifp;
2685 struct pim_interface *pim_ifp;
2686 struct pim_neighbor *neigh;
2687 time_t now;
2688 char uptime[10];
2689 char expire[10];
1295dbeb 2690 char neigh_src_str[PIM_ADDRSTRLEN];
e2b601e8
SG
2691 json_object *json_ifp_rows = NULL;
2692 json_object *json_row = NULL;
2693
2694 now = pim_time_monotonic_sec();
2695
1295dbeb 2696 if (!json) {
e2b601e8
SG
2697 vty_out(vty,
2698 "Interface Neighbor Uptime Holdtime DR Pri\n");
2699 }
2700
2701 FOR_ALL_INTERFACES (pim->vrf, ifp) {
2702 pim_ifp = ifp->info;
2703
2704 if (!pim_ifp)
2705 continue;
2706
2707 if (pim_ifp->pim_sock_fd < 0)
2708 continue;
2709
1295dbeb 2710 if (json)
e2b601e8
SG
2711 json_ifp_rows = json_object_new_object();
2712
2713 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
2714 neigh)) {
1295dbeb
SG
2715 snprintfrr(neigh_src_str, sizeof(neigh_src_str),
2716 "%pPAs", &neigh->source_addr);
e2b601e8
SG
2717 pim_time_uptime(uptime, sizeof(uptime),
2718 now - neigh->creation);
2719 pim_time_timer_to_hhmmss(expire, sizeof(expire),
2720 neigh->t_expire_timer);
2721
1295dbeb 2722 if (json) {
e2b601e8
SG
2723 json_row = json_object_new_object();
2724 json_object_string_add(json_row, "interface",
2725 ifp->name);
2726 json_object_string_add(json_row, "neighbor",
2727 neigh_src_str);
2728 json_object_string_add(json_row, "upTime",
2729 uptime);
2730 json_object_string_add(json_row, "holdTime",
2731 expire);
2732 json_object_int_add(json_row, "holdTimeMax",
2733 neigh->holdtime);
2734 json_object_int_add(json_row, "drPriority",
2735 neigh->dr_priority);
2736 json_object_object_add(json_ifp_rows,
2737 neigh_src_str, json_row);
2738
2739 } else {
2740 vty_out(vty, "%-16s %15s %8s %8s %6d\n",
2741 ifp->name, neigh_src_str, uptime,
2742 expire, neigh->dr_priority);
2743 }
2744 }
2745
1295dbeb 2746 if (json) {
e2b601e8
SG
2747 json_object_object_add(json, ifp->name, json_ifp_rows);
2748 json_ifp_rows = NULL;
2749 }
2750 }
e2b601e8 2751}
c8b3d45d
SG
2752
2753int gm_process_query_max_response_time_cmd(struct vty *vty,
2754 const char *qmrt_str)
2755{
2756 const struct lyd_node *pim_enable_dnode;
2757
2758 pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
2759 FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH,
2760 FRR_PIM_AF_XPATH_VAL);
2761
2762 if (!pim_enable_dnode) {
2763 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true");
2764 } else {
2765 if (!yang_dnode_get_bool(pim_enable_dnode, "."))
2766 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY,
2767 "true");
2768 }
2769
2770 nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
2771 qmrt_str);
2772 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
2773 FRR_PIM_AF_XPATH_VAL);
2774}
2775
2776int gm_process_no_query_max_response_time_cmd(struct vty *vty)
2777{
2778 nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_DESTROY,
2779 NULL);
2780 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
2781 FRR_PIM_AF_XPATH_VAL);
2782}