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