]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_cmd_common.c
pimd, pim6d: Using ttable for displaying "show ip/ipv6 pim neighbor" command output.
[mirror_frr.git] / pimd / pim_cmd_common.c
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"
33 #include "lib/srcdest_table.h"
34 #include "lib/linklist.h"
35 #include "termtable.h"
36
37 #include "pimd.h"
38 #include "pim_instance.h"
39 #include "pim_vty.h"
40 #include "lib/northbound_cli.h"
41 #include "pim_errors.h"
42 #include "pim_nb.h"
43 #include "pim_mroute.h"
44 #include "pim_cmd.h"
45 #include "pim6_cmd.h"
46 #include "pim_cmd_common.h"
47 #include "pim_time.h"
48 #include "pim_zebra.h"
49 #include "pim_zlookup.h"
50 #include "pim_iface.h"
51 #include "pim_macro.h"
52 #include "pim_neighbor.h"
53 #include "pim_nht.h"
54 #include "pim_sock.h"
55 #include "pim_ssm.h"
56 #include "pim_static.h"
57 #include "pim_addr.h"
58 #include "pim_static.h"
59 #include "pim_util.h"
60 #include "pim6_mld.h"
61
62 /**
63 * Get current node VRF name.
64 *
65 * NOTE:
66 * In case of failure it will print error message to user.
67 *
68 * \returns name or NULL if failed to get VRF.
69 */
70 const char *pim_cli_get_vrf_name(struct vty *vty)
71 {
72 const struct lyd_node *vrf_node;
73
74 /* Not inside any VRF context. */
75 if (vty->xpath_index == 0)
76 return VRF_DEFAULT_NAME;
77
78 vrf_node = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
79 if (vrf_node == NULL) {
80 vty_out(vty, "%% Failed to get vrf dnode in configuration\n");
81 return NULL;
82 }
83
84 return yang_dnode_get_string(vrf_node, "./name");
85 }
86
87 int pim_process_join_prune_cmd(struct vty *vty, const char *jpi_str)
88 {
89 char xpath[XPATH_MAXLEN];
90
91 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
92 FRR_PIM_AF_XPATH_VAL);
93 strlcat(xpath, "/join-prune-interval", sizeof(xpath));
94
95 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, jpi_str);
96
97 return nb_cli_apply_changes(vty, NULL);
98 }
99
100 int pim_process_no_join_prune_cmd(struct vty *vty)
101 {
102 char xpath[XPATH_MAXLEN];
103
104 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
105 FRR_PIM_AF_XPATH_VAL);
106 strlcat(xpath, "/join-prune-interval", sizeof(xpath));
107
108 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
109
110 return nb_cli_apply_changes(vty, NULL);
111 }
112
113 int pim_process_spt_switchover_infinity_cmd(struct vty *vty)
114 {
115 const char *vrfname;
116 char spt_plist_xpath[XPATH_MAXLEN];
117 char spt_action_xpath[XPATH_MAXLEN];
118
119 vrfname = pim_cli_get_vrf_name(vty);
120 if (vrfname == NULL)
121 return CMD_WARNING_CONFIG_FAILED;
122
123 snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
124 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
125 FRR_PIM_AF_XPATH_VAL);
126 strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
127 sizeof(spt_plist_xpath));
128
129 snprintf(spt_action_xpath, sizeof(spt_action_xpath),
130 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
131 FRR_PIM_AF_XPATH_VAL);
132 strlcat(spt_action_xpath, "/spt-switchover/spt-action",
133 sizeof(spt_action_xpath));
134
135 if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath))
136 nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY,
137 NULL);
138 nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
139 "PIM_SPT_INFINITY");
140
141 return nb_cli_apply_changes(vty, NULL);
142 }
143
144 int pim_process_spt_switchover_prefixlist_cmd(struct vty *vty,
145 const char *plist)
146 {
147 const char *vrfname;
148 char spt_plist_xpath[XPATH_MAXLEN];
149 char spt_action_xpath[XPATH_MAXLEN];
150
151 vrfname = pim_cli_get_vrf_name(vty);
152 if (vrfname == NULL)
153 return CMD_WARNING_CONFIG_FAILED;
154
155 snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
156 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
157 FRR_PIM_AF_XPATH_VAL);
158 strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
159 sizeof(spt_plist_xpath));
160
161 snprintf(spt_action_xpath, sizeof(spt_action_xpath),
162 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
163 FRR_PIM_AF_XPATH_VAL);
164 strlcat(spt_action_xpath, "/spt-switchover/spt-action",
165 sizeof(spt_action_xpath));
166
167 nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
168 "PIM_SPT_INFINITY");
169 nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY,
170 plist);
171
172 return nb_cli_apply_changes(vty, NULL);
173 }
174
175 int pim_process_no_spt_switchover_cmd(struct vty *vty)
176 {
177 const char *vrfname;
178 char spt_plist_xpath[XPATH_MAXLEN];
179 char spt_action_xpath[XPATH_MAXLEN];
180
181 vrfname = pim_cli_get_vrf_name(vty);
182 if (vrfname == NULL)
183 return CMD_WARNING_CONFIG_FAILED;
184
185 snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
186 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
187 FRR_PIM_AF_XPATH_VAL);
188 strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
189 sizeof(spt_plist_xpath));
190
191 snprintf(spt_action_xpath, sizeof(spt_action_xpath),
192 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
193 FRR_PIM_AF_XPATH_VAL);
194 strlcat(spt_action_xpath, "/spt-switchover/spt-action",
195 sizeof(spt_action_xpath));
196
197 nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL);
198 nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
199 "PIM_SPT_IMMEDIATE");
200
201 return nb_cli_apply_changes(vty, NULL);
202 }
203
204 int pim_process_pim_packet_cmd(struct vty *vty, const char *packet)
205 {
206 char xpath[XPATH_MAXLEN];
207
208 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
209 FRR_PIM_AF_XPATH_VAL);
210 strlcat(xpath, "/packets", sizeof(xpath));
211
212 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, packet);
213
214 return nb_cli_apply_changes(vty, NULL);
215 }
216
217 int pim_process_no_pim_packet_cmd(struct vty *vty)
218 {
219 char xpath[XPATH_MAXLEN];
220
221 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
222 FRR_PIM_AF_XPATH_VAL);
223 strlcat(xpath, "/packets", sizeof(xpath));
224
225 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
226
227 return nb_cli_apply_changes(vty, NULL);
228 }
229
230 int pim_process_keepalivetimer_cmd(struct vty *vty, const char *kat)
231 {
232 const char *vrfname;
233 char ka_timer_xpath[XPATH_MAXLEN];
234
235 vrfname = pim_cli_get_vrf_name(vty);
236 if (vrfname == NULL)
237 return CMD_WARNING_CONFIG_FAILED;
238
239 snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH,
240 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL);
241 strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
242
243 nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY,
244 kat);
245
246 return nb_cli_apply_changes(vty, NULL);
247 }
248
249 int pim_process_no_keepalivetimer_cmd(struct vty *vty)
250 {
251 const char *vrfname;
252 char ka_timer_xpath[XPATH_MAXLEN];
253
254 vrfname = pim_cli_get_vrf_name(vty);
255 if (vrfname == NULL)
256 return CMD_WARNING_CONFIG_FAILED;
257
258 snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH,
259 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL);
260 strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
261
262 nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_DESTROY, NULL);
263
264 return nb_cli_apply_changes(vty, NULL);
265 }
266
267 int pim_process_rp_kat_cmd(struct vty *vty, const char *rpkat)
268 {
269 const char *vrfname;
270 char rp_ka_timer_xpath[XPATH_MAXLEN];
271
272 vrfname = pim_cli_get_vrf_name(vty);
273 if (vrfname == NULL)
274 return CMD_WARNING_CONFIG_FAILED;
275
276 snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
277 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
278 FRR_PIM_AF_XPATH_VAL);
279 strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
280 sizeof(rp_ka_timer_xpath));
281
282 nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
283 rpkat);
284
285 return nb_cli_apply_changes(vty, NULL);
286 }
287
288 int pim_process_no_rp_kat_cmd(struct vty *vty)
289 {
290 const char *vrfname;
291 char rp_ka_timer[6];
292 char rp_ka_timer_xpath[XPATH_MAXLEN];
293 uint v;
294 char rs_timer_xpath[XPATH_MAXLEN];
295
296 snprintf(rs_timer_xpath, sizeof(rs_timer_xpath),
297 FRR_PIM_ROUTER_XPATH, FRR_PIM_AF_XPATH_VAL);
298 strlcat(rs_timer_xpath, "/register-suppress-time",
299 sizeof(rs_timer_xpath));
300
301 /* RFC4601 */
302 v = yang_dnode_get_uint16(vty->candidate_config->dnode,
303 rs_timer_xpath);
304 v = 3 * v + PIM_REGISTER_PROBE_TIME_DEFAULT;
305 if (v > UINT16_MAX)
306 v = UINT16_MAX;
307 snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%u", v);
308
309 vrfname = pim_cli_get_vrf_name(vty);
310 if (vrfname == NULL)
311 return CMD_WARNING_CONFIG_FAILED;
312
313 snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
314 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
315 FRR_PIM_AF_XPATH_VAL);
316 strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
317 sizeof(rp_ka_timer_xpath));
318
319 nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
320 rp_ka_timer);
321
322 return nb_cli_apply_changes(vty, NULL);
323 }
324
325 int pim_process_register_suppress_cmd(struct vty *vty, const char *rst)
326 {
327 char xpath[XPATH_MAXLEN];
328
329 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
330 FRR_PIM_AF_XPATH_VAL);
331 strlcat(xpath, "/register-suppress-time", sizeof(xpath));
332
333 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, rst);
334
335 return nb_cli_apply_changes(vty, NULL);
336 }
337
338 int pim_process_no_register_suppress_cmd(struct vty *vty)
339 {
340 char xpath[XPATH_MAXLEN];
341
342 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
343 FRR_PIM_AF_XPATH_VAL);
344 strlcat(xpath, "/register-suppress-time", sizeof(xpath));
345
346 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
347
348 return nb_cli_apply_changes(vty, NULL);
349 }
350
351 int pim_process_ip_pim_cmd(struct vty *vty)
352 {
353 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true");
354
355 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
356 FRR_PIM_AF_XPATH_VAL);
357 }
358
359 int pim_process_ip_pim_passive_cmd(struct vty *vty, bool enable)
360 {
361 if (enable)
362 nb_cli_enqueue_change(vty, "./pim-passive-enable", NB_OP_MODIFY,
363 "true");
364 else
365 nb_cli_enqueue_change(vty, "./pim-passive-enable", NB_OP_MODIFY,
366 "false");
367
368 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
369 FRR_PIM_AF_XPATH_VAL);
370 }
371
372 int pim_process_no_ip_pim_cmd(struct vty *vty)
373 {
374 const struct lyd_node *mld_enable_dnode;
375 char mld_if_xpath[XPATH_MAXLEN];
376
377 int printed =
378 snprintf(mld_if_xpath, sizeof(mld_if_xpath),
379 "%s/frr-gmp:gmp/address-family[address-family='%s']",
380 VTY_CURR_XPATH, FRR_PIM_AF_XPATH_VAL);
381
382 if (printed >= (int)(sizeof(mld_if_xpath))) {
383 vty_out(vty, "Xpath too long (%d > %u)", printed + 1,
384 XPATH_MAXLEN);
385 return CMD_WARNING_CONFIG_FAILED;
386 }
387
388 mld_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
389 FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
390 FRR_PIM_AF_XPATH_VAL);
391
392 if (!mld_enable_dnode) {
393 nb_cli_enqueue_change(vty, mld_if_xpath, NB_OP_DESTROY, NULL);
394 nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
395 } else {
396 if (!yang_dnode_get_bool(mld_enable_dnode, ".")) {
397 nb_cli_enqueue_change(vty, mld_if_xpath, NB_OP_DESTROY,
398 NULL);
399 nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
400 } else
401 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
402 "false");
403 }
404
405 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
406 FRR_PIM_AF_XPATH_VAL);
407 }
408
409 int pim_process_ip_pim_drprio_cmd(struct vty *vty, const char *drpriority_str)
410 {
411 nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY,
412 drpriority_str);
413
414 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
415 FRR_PIM_AF_XPATH_VAL);
416 }
417
418 int pim_process_no_ip_pim_drprio_cmd(struct vty *vty)
419 {
420 nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_DESTROY, NULL);
421
422 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
423 FRR_PIM_AF_XPATH_VAL);
424 }
425
426 int pim_process_ip_pim_hello_cmd(struct vty *vty, const char *hello_str,
427 const char *hold_str)
428 {
429 const struct lyd_node *mld_enable_dnode;
430
431 mld_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
432 FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
433 FRR_PIM_AF_XPATH_VAL);
434
435 if (!mld_enable_dnode) {
436 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
437 "true");
438 } else {
439 if (!yang_dnode_get_bool(mld_enable_dnode, "."))
440 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
441 "true");
442 }
443
444 nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_MODIFY, hello_str);
445
446 if (hold_str)
447 nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_MODIFY,
448 hold_str);
449
450 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
451 FRR_PIM_AF_XPATH_VAL);
452 }
453
454 int pim_process_no_ip_pim_hello_cmd(struct vty *vty)
455 {
456 nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_DESTROY, NULL);
457 nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_DESTROY, NULL);
458
459 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
460 FRR_PIM_AF_XPATH_VAL);
461 }
462
463 int pim_process_ip_pim_activeactive_cmd(struct vty *vty, const char *no)
464 {
465 if (no)
466 nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY,
467 "false");
468 else {
469 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
470 "true");
471
472 nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY,
473 "true");
474 }
475
476 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
477 FRR_PIM_AF_XPATH_VAL);
478 }
479
480 int pim_process_ip_pim_boundary_oil_cmd(struct vty *vty, const char *oil)
481 {
482 nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_MODIFY,
483 oil);
484
485 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
486 FRR_PIM_AF_XPATH_VAL);
487 }
488
489 int pim_process_no_ip_pim_boundary_oil_cmd(struct vty *vty)
490 {
491 nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_DESTROY,
492 NULL);
493
494 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
495 FRR_PIM_AF_XPATH_VAL);
496 }
497
498 int pim_process_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, "./oif", NB_OP_MODIFY, interface);
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 }
516
517 int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface,
518 const char *group_str, const char *source_str)
519 {
520 nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
521
522 if (!source_str) {
523 char buf[SRCDEST2STR_BUFFER];
524
525 inet_ntop(AF_INET6, &in6addr_any, buf, sizeof(buf));
526 return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH,
527 FRR_PIM_AF_XPATH_VAL, buf,
528 group_str);
529 }
530
531 return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH,
532 FRR_PIM_AF_XPATH_VAL, source_str,
533 group_str);
534 }
535
536 int pim_process_rp_cmd(struct vty *vty, const char *rp_str,
537 const char *group_str)
538 {
539 const char *vrfname;
540 char rp_group_xpath[XPATH_MAXLEN];
541 int result = 0;
542 struct prefix group;
543 pim_addr rp_addr;
544
545 result = str2prefix(group_str, &group);
546 if (result) {
547 struct prefix temp;
548
549 prefix_copy(&temp, &group);
550 apply_mask(&temp);
551 if (!prefix_same(&group, &temp)) {
552 vty_out(vty, "%% Inconsistent address and mask: %s\n",
553 group_str);
554 return CMD_WARNING_CONFIG_FAILED;
555 }
556 }
557
558 if (!result) {
559 vty_out(vty, "%% Bad group address specified: %s\n", group_str);
560 return CMD_WARNING_CONFIG_FAILED;
561 }
562
563 result = inet_pton(PIM_AF, rp_str, &rp_addr);
564 if (result <= 0) {
565 vty_out(vty, "%% Bad RP address specified: %s\n", rp_str);
566 return CMD_WARNING_CONFIG_FAILED;
567 }
568
569 vrfname = pim_cli_get_vrf_name(vty);
570 if (vrfname == NULL)
571 return CMD_WARNING_CONFIG_FAILED;
572
573 snprintf(rp_group_xpath, sizeof(rp_group_xpath),
574 FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname,
575 FRR_PIM_AF_XPATH_VAL, rp_str);
576 strlcat(rp_group_xpath, "/group-list", sizeof(rp_group_xpath));
577
578 nb_cli_enqueue_change(vty, rp_group_xpath, NB_OP_CREATE, group_str);
579
580 return nb_cli_apply_changes(vty, NULL);
581 }
582
583 int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str,
584 const char *group_str)
585 {
586 char group_list_xpath[XPATH_MAXLEN];
587 char group_xpath[XPATH_MAXLEN];
588 char rp_xpath[XPATH_MAXLEN];
589 int printed;
590 const char *vrfname;
591 const struct lyd_node *group_dnode;
592
593 vrfname = pim_cli_get_vrf_name(vty);
594 if (vrfname == NULL)
595 return CMD_WARNING_CONFIG_FAILED;
596
597 snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH,
598 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str);
599
600 printed = snprintf(group_list_xpath, sizeof(group_list_xpath),
601 "%s/group-list", rp_xpath);
602
603 if (printed >= (int)(sizeof(group_list_xpath))) {
604 vty_out(vty, "Xpath too long (%d > %u)", printed + 1,
605 XPATH_MAXLEN);
606 return CMD_WARNING_CONFIG_FAILED;
607 }
608
609 printed = snprintf(group_xpath, sizeof(group_xpath), "%s[.='%s']",
610 group_list_xpath, group_str);
611
612 if (printed >= (int)(sizeof(group_xpath))) {
613 vty_out(vty, "Xpath too long (%d > %u)", printed + 1,
614 XPATH_MAXLEN);
615 return CMD_WARNING_CONFIG_FAILED;
616 }
617
618 group_dnode = yang_dnode_get(vty->candidate_config->dnode, group_xpath);
619 if (!group_dnode) {
620 vty_out(vty, "%% Unable to find specified RP\n");
621 return NB_OK;
622 }
623
624 if (yang_is_last_list_dnode(group_dnode))
625 nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL);
626 else
627 nb_cli_enqueue_change(vty, group_list_xpath, NB_OP_DESTROY,
628 group_str);
629
630 return nb_cli_apply_changes(vty, NULL);
631 }
632
633 int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str,
634 const char *prefix_list)
635 {
636 const char *vrfname;
637 char rp_plist_xpath[XPATH_MAXLEN];
638
639 vrfname = pim_cli_get_vrf_name(vty);
640 if (vrfname == NULL)
641 return CMD_WARNING_CONFIG_FAILED;
642
643 snprintf(rp_plist_xpath, sizeof(rp_plist_xpath),
644 FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname,
645 FRR_PIM_AF_XPATH_VAL, rp_str);
646 strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath));
647
648 nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY, prefix_list);
649
650 return nb_cli_apply_changes(vty, NULL);
651 }
652
653 int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str,
654 const char *prefix_list)
655 {
656 char rp_xpath[XPATH_MAXLEN];
657 char plist_xpath[XPATH_MAXLEN];
658 const char *vrfname;
659 const struct lyd_node *plist_dnode;
660 const char *plist;
661
662 vrfname = pim_cli_get_vrf_name(vty);
663 if (vrfname == NULL)
664 return CMD_WARNING_CONFIG_FAILED;
665
666 snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH,
667 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str);
668
669 snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH,
670 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str);
671 strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath));
672
673 plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath);
674 if (!plist_dnode) {
675 vty_out(vty, "%% Unable to find specified RP\n");
676 return NB_OK;
677 }
678
679 plist = yang_dnode_get_string(plist_dnode, plist_xpath);
680 if (strcmp(prefix_list, plist)) {
681 vty_out(vty, "%% Unable to find specified RP\n");
682 return NB_OK;
683 }
684
685 nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL);
686
687 return nb_cli_apply_changes(vty, NULL);
688 }
689
690 bool pim_sgaddr_match(pim_sgaddr item, pim_sgaddr match)
691 {
692 return (pim_addr_is_any(match.grp) ||
693 !pim_addr_cmp(match.grp, item.grp)) &&
694 (pim_addr_is_any(match.src) ||
695 !pim_addr_cmp(match.src, item.src));
696 }
697
698 void json_object_pim_ifp_add(struct json_object *json, struct interface *ifp)
699 {
700 struct pim_interface *pim_ifp;
701
702 pim_ifp = ifp->info;
703 json_object_string_add(json, "name", ifp->name);
704 json_object_string_add(json, "state", if_is_up(ifp) ? "up" : "down");
705 json_object_string_addf(json, "address", "%pPA",
706 &pim_ifp->primary_address);
707 json_object_int_add(json, "index", ifp->ifindex);
708
709 if (if_is_multicast(ifp))
710 json_object_boolean_true_add(json, "flagMulticast");
711
712 if (if_is_broadcast(ifp))
713 json_object_boolean_true_add(json, "flagBroadcast");
714
715 if (ifp->flags & IFF_ALLMULTI)
716 json_object_boolean_true_add(json, "flagAllMulticast");
717
718 if (ifp->flags & IFF_PROMISC)
719 json_object_boolean_true_add(json, "flagPromiscuous");
720
721 if (PIM_IF_IS_DELETED(ifp))
722 json_object_boolean_true_add(json, "flagDeleted");
723
724 if (pim_if_lan_delay_enabled(ifp))
725 json_object_boolean_true_add(json, "lanDelayEnabled");
726 }
727
728 void pim_print_ifp_flags(struct vty *vty, struct interface *ifp)
729 {
730 vty_out(vty, "Flags\n");
731 vty_out(vty, "-----\n");
732 vty_out(vty, "All Multicast : %s\n",
733 (ifp->flags & IFF_ALLMULTI) ? "yes" : "no");
734 vty_out(vty, "Broadcast : %s\n",
735 if_is_broadcast(ifp) ? "yes" : "no");
736 vty_out(vty, "Deleted : %s\n",
737 PIM_IF_IS_DELETED(ifp) ? "yes" : "no");
738 vty_out(vty, "Interface Index : %d\n", ifp->ifindex);
739 vty_out(vty, "Multicast : %s\n",
740 if_is_multicast(ifp) ? "yes" : "no");
741 vty_out(vty, "Promiscuous : %s\n",
742 (ifp->flags & IFF_PROMISC) ? "yes" : "no");
743 vty_out(vty, "\n");
744 vty_out(vty, "\n");
745 }
746
747 void json_object_pim_upstream_add(json_object *json, struct pim_upstream *up)
748 {
749 json_object_boolean_add(
750 json, "drJoinDesired",
751 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED));
752 json_object_boolean_add(
753 json, "drJoinDesiredUpdated",
754 CHECK_FLAG(up->flags,
755 PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED));
756 json_object_boolean_add(
757 json, "firstHopRouter",
758 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_FHR));
759 json_object_boolean_add(
760 json, "sourceIgmp",
761 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP));
762 json_object_boolean_add(
763 json, "sourcePim",
764 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_PIM));
765 json_object_boolean_add(
766 json, "sourceStream",
767 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM));
768 /* XXX: need to print ths flag in the plain text display as well */
769 json_object_boolean_add(
770 json, "sourceMsdp",
771 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_MSDP));
772 json_object_boolean_add(
773 json, "sendSGRptPrune",
774 CHECK_FLAG(up->flags,
775 PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE));
776 json_object_boolean_add(
777 json, "lastHopRouter",
778 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_LHR));
779 json_object_boolean_add(
780 json, "disableKATExpiry",
781 CHECK_FLAG(up->flags,
782 PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY));
783 json_object_boolean_add(
784 json, "staticIncomingInterface",
785 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_STATIC_IIF));
786 json_object_boolean_add(
787 json, "allowIncomingInterfaceinOil",
788 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL));
789 json_object_boolean_add(
790 json, "noPimRegistrationData",
791 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA));
792 json_object_boolean_add(
793 json, "forcePimRegistration",
794 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG));
795 json_object_boolean_add(
796 json, "sourceVxlanOrigination",
797 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG));
798 json_object_boolean_add(
799 json, "sourceVxlanTermination",
800 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM));
801 json_object_boolean_add(
802 json, "mlagVxlan",
803 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN));
804 json_object_boolean_add(
805 json, "mlagNonDesignatedForwarder",
806 CHECK_FLAG(up->flags, PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF));
807 }
808
809 static const char *
810 pim_upstream_state2brief_str(enum pim_upstream_state join_state,
811 char *state_str, size_t state_str_len)
812 {
813 switch (join_state) {
814 case PIM_UPSTREAM_NOTJOINED:
815 strlcpy(state_str, "NotJ", state_str_len);
816 break;
817 case PIM_UPSTREAM_JOINED:
818 strlcpy(state_str, "J", state_str_len);
819 break;
820 default:
821 strlcpy(state_str, "Unk", state_str_len);
822 }
823 return state_str;
824 }
825
826 static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state,
827 char *state_str,
828 size_t state_str_len)
829 {
830 switch (reg_state) {
831 case PIM_REG_NOINFO:
832 strlcpy(state_str, "RegNI", state_str_len);
833 break;
834 case PIM_REG_JOIN:
835 strlcpy(state_str, "RegJ", state_str_len);
836 break;
837 case PIM_REG_JOIN_PENDING:
838 case PIM_REG_PRUNE:
839 strlcpy(state_str, "RegP", state_str_len);
840 break;
841 }
842 return state_str;
843 }
844
845 void pim_show_rpf_refresh_stats(struct vty *vty, struct pim_instance *pim,
846 time_t now, json_object *json)
847 {
848 char refresh_uptime[10];
849
850 pim_time_uptime_begin(refresh_uptime, sizeof(refresh_uptime), now,
851 pim->rpf_cache_refresh_last);
852
853 if (json) {
854 json_object_int_add(json, "rpfCacheRefreshDelayMsecs",
855 router->rpf_cache_refresh_delay_msec);
856 json_object_int_add(
857 json, "rpfCacheRefreshTimer",
858 pim_time_timer_remain_msec(pim->rpf_cache_refresher));
859 json_object_int_add(json, "rpfCacheRefreshRequests",
860 pim->rpf_cache_refresh_requests);
861 json_object_int_add(json, "rpfCacheRefreshEvents",
862 pim->rpf_cache_refresh_events);
863 json_object_string_add(json, "rpfCacheRefreshLast",
864 refresh_uptime);
865 json_object_int_add(json, "nexthopLookups",
866 pim->nexthop_lookups);
867 json_object_int_add(json, "nexthopLookupsAvoided",
868 pim->nexthop_lookups_avoided);
869 } else {
870 vty_out(vty,
871 "RPF Cache Refresh Delay: %ld msecs\n"
872 "RPF Cache Refresh Timer: %ld msecs\n"
873 "RPF Cache Refresh Requests: %lld\n"
874 "RPF Cache Refresh Events: %lld\n"
875 "RPF Cache Refresh Last: %s\n"
876 "Nexthop Lookups: %lld\n"
877 "Nexthop Lookups Avoided: %lld\n",
878 router->rpf_cache_refresh_delay_msec,
879 pim_time_timer_remain_msec(pim->rpf_cache_refresher),
880 (long long)pim->rpf_cache_refresh_requests,
881 (long long)pim->rpf_cache_refresh_events,
882 refresh_uptime, (long long)pim->nexthop_lookups,
883 (long long)pim->nexthop_lookups_avoided);
884 }
885 }
886
887 void pim_show_rpf(struct pim_instance *pim, struct vty *vty, json_object *json)
888 {
889 struct pim_upstream *up;
890 time_t now = pim_time_monotonic_sec();
891 struct ttable *tt = NULL;
892 char *table = NULL;
893 json_object *json_group = NULL;
894 json_object *json_row = NULL;
895
896 pim_show_rpf_refresh_stats(vty, pim, now, json);
897
898 if (!json) {
899 vty_out(vty, "\n");
900
901 /* Prepare table. */
902 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
903 ttable_add_row(
904 tt,
905 "Source|Group|RpfIface|RpfAddress|RibNextHop|Metric|Pref");
906 tt->style.cell.rpad = 2;
907 tt->style.corner = '+';
908 ttable_restyle(tt);
909 }
910
911 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
912 const char *rpf_ifname;
913 struct pim_rpf *rpf = &up->rpf;
914
915 rpf_ifname =
916 rpf->source_nexthop.interface ? rpf->source_nexthop
917 .interface->name
918 : "<ifname?>";
919
920 if (json) {
921 char grp_str[PIM_ADDRSTRLEN];
922 char src_str[PIM_ADDRSTRLEN];
923
924 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
925 &up->sg.grp);
926 snprintfrr(src_str, sizeof(src_str), "%pPAs",
927 &up->sg.src);
928
929 json_object_object_get_ex(json, grp_str, &json_group);
930
931 if (!json_group) {
932 json_group = json_object_new_object();
933 json_object_object_add(json, grp_str,
934 json_group);
935 }
936
937 json_row = json_object_new_object();
938 json_object_string_add(json_row, "source", src_str);
939 json_object_string_add(json_row, "group", grp_str);
940 json_object_string_add(json_row, "rpfInterface",
941 rpf_ifname);
942 json_object_string_addf(json_row, "rpfAddress", "%pPA",
943 &rpf->rpf_addr);
944 json_object_string_addf(
945 json_row, "ribNexthop", "%pPAs",
946 &rpf->source_nexthop.mrib_nexthop_addr);
947 json_object_int_add(
948 json_row, "routeMetric",
949 rpf->source_nexthop.mrib_route_metric);
950 json_object_int_add(
951 json_row, "routePreference",
952 rpf->source_nexthop.mrib_metric_preference);
953 json_object_object_add(json_group, src_str, json_row);
954
955 } else {
956 ttable_add_row(
957 tt, "%pPAs|%pPAs|%s|%pPA|%pPAs|%d|%d",
958 &up->sg.src, &up->sg.grp, rpf_ifname,
959 &rpf->rpf_addr,
960 &rpf->source_nexthop.mrib_nexthop_addr,
961 rpf->source_nexthop.mrib_route_metric,
962 rpf->source_nexthop.mrib_metric_preference);
963 }
964 }
965 /* Dump the generated table. */
966 if (!json) {
967 table = ttable_dump(tt, "\n");
968 vty_out(vty, "%s\n", table);
969 XFREE(MTYPE_TMP, table);
970 ttable_del(tt);
971 }
972 }
973
974 void pim_show_neighbors_secondary(struct pim_instance *pim, struct vty *vty)
975 {
976 struct interface *ifp;
977 struct ttable *tt = NULL;
978 char *table = NULL;
979
980 /* Prepare table. */
981 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
982 ttable_add_row(tt, "Interface|Address|Neighbor|Secondary");
983 tt->style.cell.rpad = 2;
984 tt->style.corner = '+';
985 ttable_restyle(tt);
986
987 FOR_ALL_INTERFACES (pim->vrf, ifp) {
988 struct pim_interface *pim_ifp;
989 pim_addr ifaddr;
990 struct listnode *neighnode;
991 struct pim_neighbor *neigh;
992
993 pim_ifp = ifp->info;
994
995 if (!pim_ifp)
996 continue;
997
998 if (pim_ifp->pim_sock_fd < 0)
999 continue;
1000
1001 ifaddr = pim_ifp->primary_address;
1002
1003 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
1004 neigh)) {
1005 struct listnode *prefix_node;
1006 struct prefix *p;
1007
1008 if (!neigh->prefix_list)
1009 continue;
1010
1011 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list,
1012 prefix_node, p))
1013 ttable_add_row(tt, "%s|%pPAs|%pPAs|%pFX",
1014 ifp->name, &ifaddr,
1015 &neigh->source_addr, p);
1016 }
1017 }
1018 /* Dump the generated table. */
1019 table = ttable_dump(tt, "\n");
1020 vty_out(vty, "%s\n", table);
1021 XFREE(MTYPE_TMP, table);
1022 ttable_del(tt);
1023 }
1024
1025 void pim_show_state(struct pim_instance *pim, struct vty *vty,
1026 const char *src_or_group, const char *group,
1027 json_object *json)
1028 {
1029 struct channel_oil *c_oil;
1030 json_object *json_group = NULL;
1031 json_object *json_ifp_in = NULL;
1032 json_object *json_ifp_out = NULL;
1033 json_object *json_source = NULL;
1034 time_t now;
1035 int first_oif;
1036
1037 now = pim_time_monotonic_sec();
1038
1039 if (!json) {
1040 vty_out(vty,
1041 "Codes: J -> Pim Join, I -> " GM " Report, S -> Source, * -> Inherited from (*,G), V -> VxLAN, M -> Muted");
1042 vty_out(vty,
1043 "\nActive Source Group RPT IIF OIL\n");
1044 }
1045
1046 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
1047 char src_str[PIM_ADDRSTRLEN];
1048 char grp_str[PIM_ADDRSTRLEN];
1049 char in_ifname[INTERFACE_NAMSIZ + 1];
1050 char out_ifname[INTERFACE_NAMSIZ + 1];
1051 int oif_vif_index;
1052 struct interface *ifp_in;
1053 bool isRpt;
1054
1055 first_oif = 1;
1056
1057 if ((c_oil->up &&
1058 PIM_UPSTREAM_FLAG_TEST_USE_RPT(c_oil->up->flags)) ||
1059 pim_addr_is_any(*oil_origin(c_oil)))
1060 isRpt = true;
1061 else
1062 isRpt = false;
1063
1064 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
1065 oil_mcastgrp(c_oil));
1066 snprintfrr(src_str, sizeof(src_str), "%pPAs",
1067 oil_origin(c_oil));
1068 ifp_in = pim_if_find_by_vif_index(pim, *oil_parent(c_oil));
1069
1070 if (ifp_in)
1071 strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
1072 else
1073 strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
1074
1075 if (src_or_group) {
1076 if (strcmp(src_or_group, src_str) &&
1077 strcmp(src_or_group, grp_str))
1078 continue;
1079
1080 if (group && strcmp(group, grp_str))
1081 continue;
1082 }
1083
1084 if (json) {
1085
1086 /* Find the group, create it if it doesn't exist */
1087 json_object_object_get_ex(json, grp_str, &json_group);
1088
1089 if (!json_group) {
1090 json_group = json_object_new_object();
1091 json_object_object_add(json, grp_str,
1092 json_group);
1093 }
1094
1095 /* Find the source nested under the group, create it if
1096 * it doesn't exist
1097 */
1098 json_object_object_get_ex(json_group, src_str,
1099 &json_source);
1100
1101 if (!json_source) {
1102 json_source = json_object_new_object();
1103 json_object_object_add(json_group, src_str,
1104 json_source);
1105 }
1106
1107 /* Find the inbound interface nested under the source,
1108 * create it if it doesn't exist
1109 */
1110 json_object_object_get_ex(json_source, in_ifname,
1111 &json_ifp_in);
1112
1113 if (!json_ifp_in) {
1114 json_ifp_in = json_object_new_object();
1115 json_object_object_add(json_source, in_ifname,
1116 json_ifp_in);
1117 json_object_int_add(json_source, "Installed",
1118 c_oil->installed);
1119 json_object_int_add(json_source, "installed",
1120 c_oil->installed);
1121 json_object_boolean_add(json_source, "isRpt",
1122 isRpt);
1123 json_object_int_add(json_source, "RefCount",
1124 c_oil->oil_ref_count);
1125 json_object_int_add(json_source, "refCount",
1126 c_oil->oil_ref_count);
1127 json_object_int_add(json_source, "OilListSize",
1128 c_oil->oil_size);
1129 json_object_int_add(json_source, "oilListSize",
1130 c_oil->oil_size);
1131 json_object_int_add(
1132 json_source, "OilRescan",
1133 c_oil->oil_inherited_rescan);
1134 json_object_int_add(
1135 json_source, "oilRescan",
1136 c_oil->oil_inherited_rescan);
1137 json_object_int_add(json_source, "LastUsed",
1138 c_oil->cc.lastused);
1139 json_object_int_add(json_source, "lastUsed",
1140 c_oil->cc.lastused);
1141 json_object_int_add(json_source, "PacketCount",
1142 c_oil->cc.pktcnt);
1143 json_object_int_add(json_source, "packetCount",
1144 c_oil->cc.pktcnt);
1145 json_object_int_add(json_source, "ByteCount",
1146 c_oil->cc.bytecnt);
1147 json_object_int_add(json_source, "byteCount",
1148 c_oil->cc.bytecnt);
1149 json_object_int_add(json_source,
1150 "WrongInterface",
1151 c_oil->cc.wrong_if);
1152 json_object_int_add(json_source,
1153 "wrongInterface",
1154 c_oil->cc.wrong_if);
1155 }
1156 } else
1157 vty_out(vty, "%-6d %-15pPAs %-15pPAs %-3s %-16s ",
1158 c_oil->installed, oil_origin(c_oil),
1159 oil_mcastgrp(c_oil), isRpt ? "y" : "n",
1160 in_ifname);
1161
1162 for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
1163 ++oif_vif_index) {
1164 struct interface *ifp_out;
1165 char oif_uptime[10];
1166 int ttl;
1167
1168 ttl = oil_if_has(c_oil, oif_vif_index);
1169 if (ttl < 1)
1170 continue;
1171
1172 ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
1173 pim_time_uptime(
1174 oif_uptime, sizeof(oif_uptime),
1175 now - c_oil->oif_creation[oif_vif_index]);
1176
1177 if (ifp_out)
1178 strlcpy(out_ifname, ifp_out->name,
1179 sizeof(out_ifname));
1180 else
1181 strlcpy(out_ifname, "<oif?>",
1182 sizeof(out_ifname));
1183
1184 if (json) {
1185 json_ifp_out = json_object_new_object();
1186 json_object_string_add(json_ifp_out, "source",
1187 src_str);
1188 json_object_string_add(json_ifp_out, "group",
1189 grp_str);
1190 json_object_string_add(json_ifp_out,
1191 "inboundInterface",
1192 in_ifname);
1193 json_object_string_add(json_ifp_out,
1194 "outboundInterface",
1195 out_ifname);
1196 json_object_int_add(json_ifp_out, "installed",
1197 c_oil->installed);
1198
1199 json_object_object_add(json_ifp_in, out_ifname,
1200 json_ifp_out);
1201 } else {
1202 if (first_oif) {
1203 first_oif = 0;
1204 vty_out(vty, "%s(%c%c%c%c%c)",
1205 out_ifname,
1206 (c_oil->oif_flags
1207 [oif_vif_index] &
1208 PIM_OIF_FLAG_PROTO_GM)
1209 ? 'I'
1210 : ' ',
1211 (c_oil->oif_flags
1212 [oif_vif_index] &
1213 PIM_OIF_FLAG_PROTO_PIM)
1214 ? 'J'
1215 : ' ',
1216 (c_oil->oif_flags
1217 [oif_vif_index] &
1218 PIM_OIF_FLAG_PROTO_VXLAN)
1219 ? 'V'
1220 : ' ',
1221 (c_oil->oif_flags
1222 [oif_vif_index] &
1223 PIM_OIF_FLAG_PROTO_STAR)
1224 ? '*'
1225 : ' ',
1226 (c_oil->oif_flags
1227 [oif_vif_index] &
1228 PIM_OIF_FLAG_MUTE)
1229 ? 'M'
1230 : ' ');
1231 } else
1232 vty_out(vty, ", %s(%c%c%c%c%c)",
1233 out_ifname,
1234 (c_oil->oif_flags
1235 [oif_vif_index] &
1236 PIM_OIF_FLAG_PROTO_GM)
1237 ? 'I'
1238 : ' ',
1239 (c_oil->oif_flags
1240 [oif_vif_index] &
1241 PIM_OIF_FLAG_PROTO_PIM)
1242 ? 'J'
1243 : ' ',
1244 (c_oil->oif_flags
1245 [oif_vif_index] &
1246 PIM_OIF_FLAG_PROTO_VXLAN)
1247 ? 'V'
1248 : ' ',
1249 (c_oil->oif_flags
1250 [oif_vif_index] &
1251 PIM_OIF_FLAG_PROTO_STAR)
1252 ? '*'
1253 : ' ',
1254 (c_oil->oif_flags
1255 [oif_vif_index] &
1256 PIM_OIF_FLAG_MUTE)
1257 ? 'M'
1258 : ' ');
1259 }
1260 }
1261
1262 if (!json)
1263 vty_out(vty, "\n");
1264 }
1265
1266 if (!json)
1267 vty_out(vty, "\n");
1268 }
1269
1270 /* pim statistics - just adding only bsm related now.
1271 * We can continue to add all pim related stats here.
1272 */
1273 void pim_show_statistics(struct pim_instance *pim, struct vty *vty,
1274 const char *ifname, bool uj)
1275 {
1276 json_object *json = NULL;
1277 struct interface *ifp;
1278
1279 if (uj) {
1280 json = json_object_new_object();
1281 json_object_int_add(json, "bsmRx", pim->bsm_rcvd);
1282 json_object_int_add(json, "bsmTx", pim->bsm_sent);
1283 json_object_int_add(json, "bsmDropped", pim->bsm_dropped);
1284 } else {
1285 vty_out(vty, "BSM Statistics :\n");
1286 vty_out(vty, "----------------\n");
1287 vty_out(vty, "Number of Received BSMs : %" PRIu64 "\n",
1288 pim->bsm_rcvd);
1289 vty_out(vty, "Number of Forwared BSMs : %" PRIu64 "\n",
1290 pim->bsm_sent);
1291 vty_out(vty, "Number of Dropped BSMs : %" PRIu64 "\n",
1292 pim->bsm_dropped);
1293 }
1294
1295 vty_out(vty, "\n");
1296
1297 /* scan interfaces */
1298 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1299 struct pim_interface *pim_ifp = ifp->info;
1300
1301 if (ifname && strcmp(ifname, ifp->name))
1302 continue;
1303
1304 if (!pim_ifp)
1305 continue;
1306
1307 if (!uj) {
1308 vty_out(vty, "Interface : %s\n", ifp->name);
1309 vty_out(vty, "-------------------\n");
1310 vty_out(vty,
1311 "Number of BSMs dropped due to config miss : %u\n",
1312 pim_ifp->pim_ifstat_bsm_cfg_miss);
1313 vty_out(vty, "Number of unicast BSMs dropped : %u\n",
1314 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss);
1315 vty_out(vty,
1316 "Number of BSMs dropped due to invalid scope zone : %u\n",
1317 pim_ifp->pim_ifstat_bsm_invalid_sz);
1318 } else {
1319
1320 json_object *json_row = NULL;
1321
1322 json_row = json_object_new_object();
1323
1324 json_object_string_add(json_row, "If Name", ifp->name);
1325 json_object_int_add(json_row, "bsmDroppedConfig",
1326 pim_ifp->pim_ifstat_bsm_cfg_miss);
1327 json_object_int_add(
1328 json_row, "bsmDroppedUnicast",
1329 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss);
1330 json_object_int_add(json_row,
1331 "bsmDroppedInvalidScopeZone",
1332 pim_ifp->pim_ifstat_bsm_invalid_sz);
1333 json_object_object_add(json, ifp->name, json_row);
1334 }
1335 vty_out(vty, "\n");
1336 }
1337
1338 if (uj)
1339 vty_json(vty, json);
1340 }
1341
1342 void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
1343 pim_sgaddr *sg, json_object *json)
1344 {
1345 struct pim_upstream *up;
1346 struct ttable *tt = NULL;
1347 char *table = NULL;
1348 time_t now;
1349 json_object *json_group = NULL;
1350 json_object *json_row = NULL;
1351
1352 now = pim_time_monotonic_sec();
1353
1354 if (!json) {
1355 /* Prepare table. */
1356 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
1357 ttable_add_row(
1358 tt,
1359 "Iif|Source|Group|State|Uptime|JoinTimer|RSTimer|KATimer|RefCnt");
1360 tt->style.cell.rpad = 2;
1361 tt->style.corner = '+';
1362 ttable_restyle(tt);
1363 }
1364
1365 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1366 char uptime[10];
1367 char join_timer[10];
1368 char rs_timer[10];
1369 char ka_timer[10];
1370 char msdp_reg_timer[10];
1371 char state_str[PIM_REG_STATE_STR_LEN];
1372
1373 if (!pim_sgaddr_match(up->sg, *sg))
1374 continue;
1375
1376 pim_time_uptime(uptime, sizeof(uptime),
1377 now - up->state_transition);
1378 pim_time_timer_to_hhmmss(join_timer, sizeof(join_timer),
1379 up->t_join_timer);
1380
1381 /*
1382 * If the upstream is not dummy and it has a J/P timer for the
1383 * neighbor display that
1384 */
1385 if (!up->t_join_timer && up->rpf.source_nexthop.interface) {
1386 struct pim_neighbor *nbr;
1387
1388 nbr = pim_neighbor_find(
1389 up->rpf.source_nexthop.interface,
1390 up->rpf.rpf_addr);
1391 if (nbr)
1392 pim_time_timer_to_hhmmss(join_timer,
1393 sizeof(join_timer),
1394 nbr->jp_timer);
1395 }
1396
1397 pim_time_timer_to_hhmmss(rs_timer, sizeof(rs_timer),
1398 up->t_rs_timer);
1399 pim_time_timer_to_hhmmss(ka_timer, sizeof(ka_timer),
1400 up->t_ka_timer);
1401 pim_time_timer_to_hhmmss(msdp_reg_timer, sizeof(msdp_reg_timer),
1402 up->t_msdp_reg_timer);
1403
1404 pim_upstream_state2brief_str(up->join_state, state_str,
1405 sizeof(state_str));
1406 if (up->reg_state != PIM_REG_NOINFO) {
1407 char tmp_str[PIM_REG_STATE_STR_LEN];
1408 char tmp[sizeof(state_str) + 1];
1409
1410 snprintf(tmp, sizeof(tmp), ",%s",
1411 pim_reg_state2brief_str(up->reg_state, tmp_str,
1412 sizeof(tmp_str)));
1413 strlcat(state_str, tmp, sizeof(state_str));
1414 }
1415
1416 if (json) {
1417 char grp_str[PIM_ADDRSTRLEN];
1418 char src_str[PIM_ADDRSTRLEN];
1419
1420 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
1421 &up->sg.grp);
1422 snprintfrr(src_str, sizeof(src_str), "%pPAs",
1423 &up->sg.src);
1424
1425 json_object_object_get_ex(json, grp_str, &json_group);
1426
1427 if (!json_group) {
1428 json_group = json_object_new_object();
1429 json_object_object_add(json, grp_str,
1430 json_group);
1431 }
1432
1433 json_row = json_object_new_object();
1434 json_object_pim_upstream_add(json_row, up);
1435 json_object_string_add(
1436 json_row, "inboundInterface",
1437 up->rpf.source_nexthop.interface
1438 ? up->rpf.source_nexthop.interface->name
1439 : "Unknown");
1440
1441 /*
1442 * The RPF address we use is slightly different
1443 * based upon what we are looking up.
1444 * If we have a S, list that unless
1445 * we are the FHR, else we just put
1446 * the RP as the rpfAddress
1447 */
1448 if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR ||
1449 pim_addr_is_any(up->sg.src)) {
1450 struct pim_rpf *rpg;
1451
1452 rpg = RP(pim, up->sg.grp);
1453 json_object_string_addf(json_row, "rpfAddress",
1454 "%pPA", &rpg->rpf_addr);
1455 } else {
1456 json_object_string_add(json_row, "rpfAddress",
1457 src_str);
1458 }
1459
1460 json_object_string_add(json_row, "source", src_str);
1461 json_object_string_add(json_row, "group", grp_str);
1462 json_object_string_add(json_row, "state", state_str);
1463 json_object_string_add(
1464 json_row, "joinState",
1465 pim_upstream_state2str(up->join_state));
1466 json_object_string_add(
1467 json_row, "regState",
1468 pim_reg_state2str(up->reg_state, state_str,
1469 sizeof(state_str)));
1470 json_object_string_add(json_row, "upTime", uptime);
1471 json_object_string_add(json_row, "joinTimer",
1472 join_timer);
1473 json_object_string_add(json_row, "resetTimer",
1474 rs_timer);
1475 json_object_string_add(json_row, "keepaliveTimer",
1476 ka_timer);
1477 json_object_string_add(json_row, "msdpRegTimer",
1478 msdp_reg_timer);
1479 json_object_int_add(json_row, "refCount",
1480 up->ref_count);
1481 json_object_int_add(json_row, "sptBit", up->sptbit);
1482 json_object_object_add(json_group, src_str, json_row);
1483 } else {
1484 ttable_add_row(tt,
1485 "%s|%pPAs|%pPAs|%s|%s|%s|%s|%s|%d",
1486 up->rpf.source_nexthop.interface
1487 ? up->rpf.source_nexthop.interface->name
1488 : "Unknown",
1489 &up->sg.src, &up->sg.grp, state_str, uptime,
1490 join_timer, rs_timer, ka_timer, up->ref_count);
1491 }
1492 }
1493 /* Dump the generated table. */
1494 if (!json) {
1495 table = ttable_dump(tt, "\n");
1496 vty_out(vty, "%s\n", table);
1497 XFREE(MTYPE_TMP, table);
1498 ttable_del(tt);
1499 }
1500 }
1501
1502 static void pim_show_join_desired_helper(struct pim_instance *pim,
1503 struct vty *vty,
1504 struct pim_upstream *up,
1505 json_object *json, bool uj,
1506 struct ttable *tt)
1507 {
1508 json_object *json_group = NULL;
1509 json_object *json_row = NULL;
1510
1511 if (uj) {
1512 char grp_str[PIM_ADDRSTRLEN];
1513 char src_str[PIM_ADDRSTRLEN];
1514
1515 snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &up->sg.grp);
1516 snprintfrr(src_str, sizeof(src_str), "%pPAs", &up->sg.src);
1517
1518 json_object_object_get_ex(json, grp_str, &json_group);
1519
1520 if (!json_group) {
1521 json_group = json_object_new_object();
1522 json_object_object_add(json, grp_str, json_group);
1523 }
1524
1525 json_row = json_object_new_object();
1526 json_object_pim_upstream_add(json_row, up);
1527 json_object_string_add(json_row, "source", src_str);
1528 json_object_string_add(json_row, "group", grp_str);
1529
1530 if (pim_upstream_evaluate_join_desired(pim, up))
1531 json_object_boolean_true_add(json_row,
1532 "evaluateJoinDesired");
1533
1534 json_object_object_add(json_group, src_str, json_row);
1535
1536 } else {
1537 ttable_add_row(tt, "%pPAs|%pPAs|%s", &up->sg.src, &up->sg.grp,
1538 pim_upstream_evaluate_join_desired(pim, up)
1539 ? "yes"
1540 : "no");
1541 }
1542 }
1543
1544 void pim_show_join_desired(struct pim_instance *pim, struct vty *vty, bool uj)
1545 {
1546 struct pim_upstream *up;
1547 struct ttable *tt = NULL;
1548 char *table = NULL;
1549
1550 json_object *json = NULL;
1551
1552 if (uj)
1553 json = json_object_new_object();
1554 else {
1555 /* Prepare table. */
1556 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
1557 ttable_add_row(tt, "Source|Group|EvalJD");
1558 tt->style.cell.rpad = 2;
1559 tt->style.corner = '+';
1560 ttable_restyle(tt);
1561 }
1562
1563 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1564 /* scan all interfaces */
1565 pim_show_join_desired_helper(pim, vty, up, json, uj, tt);
1566 }
1567
1568 if (uj)
1569 vty_json(vty, json);
1570 else {
1571 /* Dump the generated table. */
1572 table = ttable_dump(tt, "\n");
1573 vty_out(vty, "%s\n", table);
1574 XFREE(MTYPE_TMP, table);
1575 ttable_del(tt);
1576 }
1577 }
1578
1579 void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, bool uj)
1580 {
1581 struct pim_upstream *up;
1582 struct ttable *tt = NULL;
1583 char *table = NULL;
1584 json_object *json = NULL;
1585 json_object *json_group = NULL;
1586 json_object *json_row = NULL;
1587
1588 if (uj)
1589 json = json_object_new_object();
1590 else {
1591 /* Prepare table. */
1592 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
1593 ttable_add_row(tt,
1594 "Source|Group|RpfIface|RibNextHop|RpfAddress");
1595 tt->style.cell.rpad = 2;
1596 tt->style.corner = '+';
1597 ttable_restyle(tt);
1598 }
1599
1600 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1601 struct pim_rpf *rpf;
1602 const char *rpf_ifname;
1603
1604 rpf = &up->rpf;
1605
1606 rpf_ifname =
1607 rpf->source_nexthop.interface ? rpf->source_nexthop
1608 .interface->name
1609 : "<ifname?>";
1610
1611 if (uj) {
1612 char grp_str[PIM_ADDRSTRLEN];
1613 char src_str[PIM_ADDRSTRLEN];
1614
1615 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
1616 &up->sg.grp);
1617 snprintfrr(src_str, sizeof(src_str), "%pPAs",
1618 &up->sg.src);
1619 json_object_object_get_ex(json, grp_str, &json_group);
1620
1621 if (!json_group) {
1622 json_group = json_object_new_object();
1623 json_object_object_add(json, grp_str,
1624 json_group);
1625 }
1626
1627 json_row = json_object_new_object();
1628 json_object_pim_upstream_add(json_row, up);
1629 json_object_string_add(json_row, "source", src_str);
1630 json_object_string_add(json_row, "group", grp_str);
1631 json_object_string_add(json_row, "rpfInterface",
1632 rpf_ifname);
1633 json_object_string_addf(
1634 json_row, "ribNexthop", "%pPAs",
1635 &rpf->source_nexthop.mrib_nexthop_addr);
1636 json_object_string_addf(json_row, "rpfAddress", "%pPA",
1637 &rpf->rpf_addr);
1638 json_object_object_add(json_group, src_str, json_row);
1639 } else {
1640 ttable_add_row(tt, "%pPAs|%pPAs|%s|%pPA|%pPA",
1641 &up->sg.src, &up->sg.grp, rpf_ifname,
1642 &rpf->source_nexthop.mrib_nexthop_addr,
1643 &rpf->rpf_addr);
1644 }
1645 }
1646
1647 if (uj)
1648 vty_json(vty, json);
1649 else {
1650 /* Dump the generated table. */
1651 table = ttable_dump(tt, "\n");
1652 vty_out(vty, "%s\n", table);
1653 XFREE(MTYPE_TMP, table);
1654 ttable_del(tt);
1655 }
1656 }
1657
1658 static void pim_show_join_helper(struct pim_interface *pim_ifp,
1659 struct pim_ifchannel *ch, json_object *json,
1660 time_t now, struct ttable *tt)
1661 {
1662 json_object *json_iface = NULL;
1663 json_object *json_row = NULL;
1664 json_object *json_grp = NULL;
1665 pim_addr ifaddr;
1666 char uptime[10];
1667 char expire[10];
1668 char prune[10];
1669
1670 ifaddr = pim_ifp->primary_address;
1671
1672 pim_time_uptime_begin(uptime, sizeof(uptime), now, ch->ifjoin_creation);
1673 pim_time_timer_to_mmss(expire, sizeof(expire),
1674 ch->t_ifjoin_expiry_timer);
1675 pim_time_timer_to_mmss(prune, sizeof(prune),
1676 ch->t_ifjoin_prune_pending_timer);
1677
1678 if (json) {
1679 char ch_grp_str[PIM_ADDRSTRLEN];
1680
1681 json_object_object_get_ex(json, ch->interface->name,
1682 &json_iface);
1683
1684 if (!json_iface) {
1685 json_iface = json_object_new_object();
1686 json_object_pim_ifp_add(json_iface, ch->interface);
1687 json_object_object_add(json, ch->interface->name,
1688 json_iface);
1689 }
1690
1691 json_row = json_object_new_object();
1692 json_object_string_addf(json_row, "source", "%pPAs",
1693 &ch->sg.src);
1694 json_object_string_addf(json_row, "group", "%pPAs",
1695 &ch->sg.grp);
1696 json_object_string_add(json_row, "upTime", uptime);
1697 json_object_string_add(json_row, "expire", expire);
1698 json_object_string_add(json_row, "prune", prune);
1699 json_object_string_add(
1700 json_row, "channelJoinName",
1701 pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags));
1702 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) {
1703 #if CONFDATE > 20230131
1704 CPP_NOTICE(
1705 "Remove JSON object commands with keys starting with capital")
1706 #endif
1707 json_object_int_add(json_row, "SGRpt", 1);
1708 json_object_int_add(json_row, "sgRpt", 1);
1709 }
1710 if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
1711 json_object_int_add(json_row, "protocolPim", 1);
1712 if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
1713 json_object_int_add(json_row, "protocolIgmp", 1);
1714 snprintfrr(ch_grp_str, sizeof(ch_grp_str), "%pPAs",
1715 &ch->sg.grp);
1716 json_object_object_get_ex(json_iface, ch_grp_str, &json_grp);
1717 if (!json_grp) {
1718 json_grp = json_object_new_object();
1719 json_object_object_addf(json_grp, json_row, "%pPAs",
1720 &ch->sg.src);
1721 json_object_object_addf(json_iface, json_grp, "%pPAs",
1722 &ch->sg.grp);
1723 } else
1724 json_object_object_addf(json_grp, json_row, "%pPAs",
1725 &ch->sg.src);
1726 } else {
1727 ttable_add_row(
1728 tt, "%s|%pPAs|%pPAs|%pPAs|%s|%s|%s|%s",
1729 ch->interface->name, &ifaddr, &ch->sg.src, &ch->sg.grp,
1730 pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags),
1731 uptime, expire, prune);
1732 }
1733 }
1734
1735 int pim_show_join_cmd_helper(const char *vrf, struct vty *vty, pim_addr s_or_g,
1736 pim_addr g, const char *json)
1737 {
1738 pim_sgaddr sg = {};
1739 struct vrf *v;
1740 struct pim_instance *pim;
1741 json_object *json_parent = NULL;
1742
1743 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
1744
1745 if (!v) {
1746 vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
1747 return CMD_WARNING;
1748 }
1749 pim = v->info;
1750
1751 if (!pim) {
1752 vty_out(vty, "%% Unable to find pim instance\n");
1753 return CMD_WARNING;
1754 }
1755
1756 if (!pim_addr_is_any(s_or_g)) {
1757 if (!pim_addr_is_any(g)) {
1758 sg.src = s_or_g;
1759 sg.grp = g;
1760 } else
1761 sg.grp = s_or_g;
1762 }
1763
1764 if (json)
1765 json_parent = json_object_new_object();
1766
1767 pim_show_join(pim, vty, &sg, json_parent);
1768
1769 if (json)
1770 vty_json(vty, json_parent);
1771
1772 return CMD_SUCCESS;
1773 }
1774
1775 int pim_show_join_vrf_all_cmd_helper(struct vty *vty, const char *json)
1776 {
1777 pim_sgaddr sg = {0};
1778 struct vrf *vrf_struct;
1779 json_object *json_parent = NULL;
1780 json_object *json_vrf = NULL;
1781
1782 if (json)
1783 json_parent = json_object_new_object();
1784
1785 RB_FOREACH (vrf_struct, vrf_name_head, &vrfs_by_name) {
1786 if (!json_parent)
1787 vty_out(vty, "VRF: %s\n", vrf_struct->name);
1788 else
1789 json_vrf = json_object_new_object();
1790 pim_show_join(vrf_struct->info, vty, &sg, json_vrf);
1791
1792 if (json)
1793 json_object_object_add(json_parent, vrf_struct->name,
1794 json_vrf);
1795 }
1796 if (json)
1797 vty_json(vty, json_parent);
1798
1799 return CMD_WARNING;
1800 }
1801
1802 void pim_show_join(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg,
1803 json_object *json)
1804 {
1805 struct pim_interface *pim_ifp;
1806 struct pim_ifchannel *ch;
1807 struct interface *ifp;
1808 time_t now;
1809 struct ttable *tt = NULL;
1810 char *table = NULL;
1811
1812 now = pim_time_monotonic_sec();
1813
1814 if (!json) {
1815 /* Prepare table. */
1816 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
1817 ttable_add_row(
1818 tt,
1819 "Interface|Address|Source|Group|State|Uptime|Expire|Prune");
1820 tt->style.cell.rpad = 2;
1821 tt->style.corner = '+';
1822 ttable_restyle(tt);
1823 }
1824
1825 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1826 pim_ifp = ifp->info;
1827 if (!pim_ifp)
1828 continue;
1829
1830 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
1831 if (!pim_sgaddr_match(ch->sg, *sg))
1832 continue;
1833
1834 pim_show_join_helper(pim_ifp, ch, json, now, tt);
1835 } /* scan interface channels */
1836 }
1837 /* Dump the generated table. */
1838 if (!json) {
1839 table = ttable_dump(tt, "\n");
1840 vty_out(vty, "%s\n", table);
1841 XFREE(MTYPE_TMP, table);
1842 ttable_del(tt);
1843 }
1844 }
1845
1846 static void pim_show_jp_agg_helper(struct interface *ifp,
1847 struct pim_neighbor *neigh,
1848 struct pim_upstream *up, int is_join,
1849 struct ttable *tt)
1850 {
1851 ttable_add_row(tt, "%s|%pPAs|%pPAs|%pPAs|%s", ifp->name,
1852 &neigh->source_addr, &up->sg.src, &up->sg.grp,
1853 is_join ? "J" : "P");
1854 }
1855
1856 int pim_show_jp_agg_list_cmd_helper(const char *vrf, struct vty *vty)
1857 {
1858 struct vrf *v;
1859 struct pim_instance *pim;
1860
1861 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
1862
1863 if (!v) {
1864 vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
1865 return CMD_WARNING;
1866 }
1867 pim = v->info;
1868
1869 if (!pim) {
1870 vty_out(vty, "%% Unable to find pim instance\n");
1871 return CMD_WARNING;
1872 }
1873
1874 pim_show_jp_agg_list(pim, vty);
1875
1876 return CMD_SUCCESS;
1877 }
1878
1879 void pim_show_jp_agg_list(struct pim_instance *pim, struct vty *vty)
1880 {
1881 struct interface *ifp;
1882 struct pim_interface *pim_ifp;
1883 struct listnode *n_node;
1884 struct pim_neighbor *neigh;
1885 struct listnode *jag_node;
1886 struct pim_jp_agg_group *jag;
1887 struct listnode *js_node;
1888 struct pim_jp_sources *js;
1889 struct ttable *tt;
1890 char *table;
1891
1892 /* Prepare table. */
1893 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
1894 ttable_add_row(tt, "Interface|RPF Nbr|Source|Group|State");
1895 tt->style.cell.rpad = 2;
1896 tt->style.corner = '+';
1897 ttable_restyle(tt);
1898
1899 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1900 pim_ifp = ifp->info;
1901 if (!pim_ifp)
1902 continue;
1903
1904 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, n_node,
1905 neigh)) {
1906 for (ALL_LIST_ELEMENTS_RO(neigh->upstream_jp_agg,
1907 jag_node, jag)) {
1908 for (ALL_LIST_ELEMENTS_RO(jag->sources, js_node,
1909 js)) {
1910 pim_show_jp_agg_helper(ifp, neigh,
1911 js->up,
1912 js->is_join, tt);
1913 }
1914 }
1915 }
1916 }
1917
1918 /* Dump the generated table. */
1919 table = ttable_dump(tt, "\n");
1920 vty_out(vty, "%s\n", table);
1921 XFREE(MTYPE_TMP, table);
1922 ttable_del(tt);
1923 }
1924
1925 int pim_show_membership_cmd_helper(const char *vrf, struct vty *vty, bool uj)
1926 {
1927 struct vrf *v;
1928
1929 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
1930
1931 if (!v)
1932 return CMD_WARNING;
1933
1934 pim_show_membership(v->info, vty, uj);
1935
1936 return CMD_SUCCESS;
1937 }
1938
1939 static void pim_show_membership_helper(struct vty *vty,
1940 struct pim_interface *pim_ifp,
1941 struct pim_ifchannel *ch,
1942 struct json_object *json)
1943 {
1944 json_object *json_iface = NULL;
1945 json_object *json_row = NULL;
1946
1947 json_object_object_get_ex(json, ch->interface->name, &json_iface);
1948 if (!json_iface) {
1949 json_iface = json_object_new_object();
1950 json_object_pim_ifp_add(json_iface, ch->interface);
1951 json_object_object_add(json, ch->interface->name, json_iface);
1952 }
1953
1954 json_row = json_object_new_object();
1955 json_object_string_addf(json_row, "source", "%pPAs", &ch->sg.src);
1956 json_object_string_addf(json_row, "group", "%pPAs", &ch->sg.grp);
1957 json_object_string_add(json_row, "localMembership",
1958 ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO
1959 ? "NOINFO"
1960 : "INCLUDE");
1961 json_object_object_addf(json_iface, json_row, "%pPAs", &ch->sg.grp);
1962 }
1963
1964 void pim_show_membership(struct pim_instance *pim, struct vty *vty, bool uj)
1965 {
1966 struct pim_interface *pim_ifp;
1967 struct pim_ifchannel *ch;
1968 struct interface *ifp;
1969 enum json_type type;
1970 json_object *json = NULL;
1971 json_object *json_tmp = NULL;
1972
1973 json = json_object_new_object();
1974
1975 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1976 pim_ifp = ifp->info;
1977 if (!pim_ifp)
1978 continue;
1979
1980 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
1981 pim_show_membership_helper(vty, pim_ifp, ch, json);
1982 } /* scan interface channels */
1983 }
1984
1985 if (uj) {
1986 vty_json(vty, json);
1987 } else {
1988 vty_out(vty,
1989 "Interface Address Source Group Membership\n");
1990
1991 /*
1992 * Example of the json data we are traversing
1993 *
1994 * {
1995 * "swp3":{
1996 * "name":"swp3",
1997 * "state":"up",
1998 * "address":"10.1.20.1",
1999 * "index":5,
2000 * "flagMulticast":true,
2001 * "flagBroadcast":true,
2002 * "lanDelayEnabled":true,
2003 * "226.10.10.10":{
2004 * "source":"*",
2005 * "group":"226.10.10.10",
2006 * "localMembership":"INCLUDE"
2007 * }
2008 * }
2009 * }
2010 */
2011
2012 /* foreach interface */
2013 json_object_object_foreach(json, key, val)
2014 {
2015
2016 /* Find all of the keys where the val is an object. In
2017 * the example
2018 * above the only one is 226.10.10.10
2019 */
2020 json_object_object_foreach(val, if_field_key,
2021 if_field_val)
2022 {
2023 type = json_object_get_type(if_field_val);
2024
2025 if (type == json_type_object) {
2026 vty_out(vty, "%-16s ", key);
2027
2028 json_object_object_get_ex(
2029 val, "address", &json_tmp);
2030 vty_out(vty, "%-15s ",
2031 json_object_get_string(
2032 json_tmp));
2033
2034 json_object_object_get_ex(if_field_val,
2035 "source",
2036 &json_tmp);
2037 vty_out(vty, "%-15s ",
2038 json_object_get_string(
2039 json_tmp));
2040
2041 /* Group */
2042 vty_out(vty, "%-15s ", if_field_key);
2043
2044 json_object_object_get_ex(
2045 if_field_val, "localMembership",
2046 &json_tmp);
2047 vty_out(vty, "%-10s\n",
2048 json_object_get_string(
2049 json_tmp));
2050 }
2051 }
2052 }
2053 json_object_free(json);
2054 }
2055 }
2056
2057 static void pim_show_channel_helper(struct pim_instance *pim,
2058 struct pim_interface *pim_ifp,
2059 struct pim_ifchannel *ch, json_object *json,
2060 bool uj, struct ttable *tt)
2061 {
2062 struct pim_upstream *up = ch->upstream;
2063 json_object *json_group = NULL;
2064 json_object *json_row = NULL;
2065
2066 if (uj) {
2067 char grp_str[PIM_ADDRSTRLEN];
2068
2069 snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &up->sg.grp);
2070 json_object_object_get_ex(json, grp_str, &json_group);
2071
2072 if (!json_group) {
2073 json_group = json_object_new_object();
2074 json_object_object_add(json, grp_str, json_group);
2075 }
2076
2077 json_row = json_object_new_object();
2078 json_object_pim_upstream_add(json_row, up);
2079 json_object_string_add(json_row, "interface",
2080 ch->interface->name);
2081 json_object_string_addf(json_row, "source", "%pPAs",
2082 &up->sg.src);
2083 json_object_string_addf(json_row, "group", "%pPAs",
2084 &up->sg.grp);
2085
2086 if (pim_macro_ch_lost_assert(ch))
2087 json_object_boolean_true_add(json_row, "lostAssert");
2088
2089 if (pim_macro_chisin_joins(ch))
2090 json_object_boolean_true_add(json_row, "joins");
2091
2092 if (pim_macro_chisin_pim_include(ch))
2093 json_object_boolean_true_add(json_row, "pimInclude");
2094
2095 if (pim_upstream_evaluate_join_desired(pim, up))
2096 json_object_boolean_true_add(json_row,
2097 "evaluateJoinDesired");
2098
2099 json_object_object_addf(json_group, json_row, "%pPAs",
2100 &up->sg.src);
2101
2102 } else {
2103 ttable_add_row(tt, "%s|%pPAs|%pPAs|%s|%s|%s|%s|%s",
2104 ch->interface->name, &up->sg.src, &up->sg.grp,
2105 pim_macro_ch_lost_assert(ch) ? "yes" : "no",
2106 pim_macro_chisin_joins(ch) ? "yes" : "no",
2107 pim_macro_chisin_pim_include(ch) ? "yes" : "no",
2108 PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags)
2109 ? "yes"
2110 : "no",
2111 pim_upstream_evaluate_join_desired(pim, up)
2112 ? "yes"
2113 : "no");
2114 }
2115 }
2116
2117 void pim_show_channel(struct pim_instance *pim, struct vty *vty, bool uj)
2118 {
2119 struct pim_interface *pim_ifp;
2120 struct pim_ifchannel *ch;
2121 struct interface *ifp;
2122 struct ttable *tt = NULL;
2123 json_object *json = NULL;
2124 char *table = NULL;
2125
2126 if (uj)
2127 json = json_object_new_object();
2128 else {
2129 /* Prepare table. */
2130 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
2131 ttable_add_row(
2132 tt,
2133 "Interface|Source|Group|LostAssert|Joins|PimInclude|JoinDesired|EvalJD");
2134 tt->style.cell.rpad = 2;
2135 tt->style.corner = '+';
2136 ttable_restyle(tt);
2137 }
2138
2139 /* scan per-interface (S,G) state */
2140 FOR_ALL_INTERFACES (pim->vrf, ifp) {
2141 pim_ifp = ifp->info;
2142 if (!pim_ifp)
2143 continue;
2144
2145 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
2146 /* scan all interfaces */
2147 pim_show_channel_helper(pim, pim_ifp, ch, json, uj, tt);
2148 }
2149 }
2150
2151 if (uj)
2152 vty_json(vty, json);
2153 else {
2154 /* Dump the generated table. */
2155 table = ttable_dump(tt, "\n");
2156 vty_out(vty, "%s\n", table);
2157 XFREE(MTYPE_TMP, table);
2158 ttable_del(tt);
2159 }
2160 }
2161
2162 int pim_show_channel_cmd_helper(const char *vrf, struct vty *vty, bool uj)
2163 {
2164 struct vrf *v;
2165
2166 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
2167
2168 if (!v)
2169 return CMD_WARNING;
2170
2171 pim_show_channel(v->info, vty, uj);
2172
2173 return CMD_SUCCESS;
2174 }
2175
2176 int pim_show_interface_cmd_helper(const char *vrf, struct vty *vty, bool uj,
2177 bool mlag, const char *interface)
2178 {
2179 struct vrf *v;
2180 json_object *json_parent = NULL;
2181
2182 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
2183
2184 if (!v)
2185 return CMD_WARNING;
2186
2187 if (uj)
2188 json_parent = json_object_new_object();
2189
2190 if (interface)
2191 pim_show_interfaces_single(v->info, vty, interface, mlag,
2192 json_parent);
2193 else
2194 pim_show_interfaces(v->info, vty, mlag, json_parent);
2195
2196 if (uj)
2197 vty_json(vty, json_parent);
2198
2199 return CMD_SUCCESS;
2200 }
2201
2202 int pim_show_interface_vrf_all_cmd_helper(struct vty *vty, bool uj, bool mlag,
2203 const char *interface)
2204 {
2205 struct vrf *v;
2206 json_object *json_parent = NULL;
2207 json_object *json_vrf = NULL;
2208
2209 if (uj)
2210 json_parent = json_object_new_object();
2211
2212 RB_FOREACH (v, vrf_name_head, &vrfs_by_name) {
2213 if (!uj)
2214 vty_out(vty, "VRF: %s\n", v->name);
2215 else
2216 json_vrf = json_object_new_object();
2217
2218 if (interface)
2219 pim_show_interfaces_single(v->info, vty, interface,
2220 mlag, json_vrf);
2221 else
2222 pim_show_interfaces(v->info, vty, mlag, json_vrf);
2223
2224 if (uj)
2225 json_object_object_add(json_parent, v->name, json_vrf);
2226 }
2227 if (uj)
2228 vty_json(vty, json_parent);
2229
2230 return CMD_SUCCESS;
2231 }
2232
2233 void pim_show_interfaces(struct pim_instance *pim, struct vty *vty, bool mlag,
2234 json_object *json)
2235 {
2236 struct interface *ifp;
2237 struct pim_interface *pim_ifp;
2238 struct pim_upstream *up;
2239 int fhr = 0;
2240 int pim_nbrs = 0;
2241 int pim_ifchannels = 0;
2242 bool uj = true;
2243 struct ttable *tt = NULL;
2244 char *table = NULL;
2245 json_object *json_row = NULL;
2246 json_object *json_tmp;
2247
2248 if (!json) {
2249 uj = false;
2250 json = json_object_new_object();
2251 }
2252
2253 FOR_ALL_INTERFACES (pim->vrf, ifp) {
2254 pim_ifp = ifp->info;
2255
2256 if (!pim_ifp)
2257 continue;
2258
2259 if (mlag == true && pim_ifp->activeactive == false)
2260 continue;
2261
2262 pim_nbrs = pim_ifp->pim_neighbor_list->count;
2263 pim_ifchannels = pim_if_ifchannel_count(pim_ifp);
2264 fhr = 0;
2265
2266 frr_each (rb_pim_upstream, &pim->upstream_head, up)
2267 if (ifp == up->rpf.source_nexthop.interface)
2268 if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR)
2269 fhr++;
2270
2271 json_row = json_object_new_object();
2272 json_object_pim_ifp_add(json_row, ifp);
2273 json_object_int_add(json_row, "pimNeighbors", pim_nbrs);
2274 json_object_int_add(json_row, "pimIfChannels", pim_ifchannels);
2275 json_object_int_add(json_row, "firstHopRouterCount", fhr);
2276 json_object_string_addf(json_row, "pimDesignatedRouter",
2277 "%pPAs", &pim_ifp->pim_dr_addr);
2278
2279 if (!pim_addr_cmp(pim_ifp->pim_dr_addr,
2280 pim_ifp->primary_address))
2281 json_object_boolean_true_add(
2282 json_row, "pimDesignatedRouterLocal");
2283
2284 json_object_object_add(json, ifp->name, json_row);
2285 }
2286
2287 if (!uj) {
2288
2289 /* Prepare table. */
2290 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
2291 ttable_add_row(
2292 tt,
2293 "Interface|State|Address|PIM Nbrs|PIM DR|FHR|IfChannels");
2294 tt->style.cell.rpad = 2;
2295 tt->style.corner = '+';
2296 ttable_restyle(tt);
2297
2298 json_object_object_foreach(json, key, val)
2299 {
2300 const char *state, *address, *pimdr;
2301 int neighbors, firsthpr, pimifchnl;
2302
2303 json_object_object_get_ex(val, "state", &json_tmp);
2304 state = json_object_get_string(json_tmp);
2305
2306 json_object_object_get_ex(val, "address", &json_tmp);
2307 address = json_object_get_string(json_tmp);
2308
2309 json_object_object_get_ex(val, "pimNeighbors",
2310 &json_tmp);
2311 neighbors = json_object_get_int(json_tmp);
2312
2313 if (json_object_object_get_ex(
2314 val, "pimDesignatedRouterLocal",
2315 &json_tmp)) {
2316 pimdr = "local";
2317 } else {
2318 json_object_object_get_ex(
2319 val, "pimDesignatedRouter", &json_tmp);
2320 pimdr = json_object_get_string(json_tmp);
2321 }
2322
2323 json_object_object_get_ex(val, "firstHopRouter",
2324 &json_tmp);
2325 firsthpr = json_object_get_int(json_tmp);
2326
2327 json_object_object_get_ex(val, "pimIfChannels",
2328 &json_tmp);
2329 pimifchnl = json_object_get_int(json_tmp);
2330
2331 ttable_add_row(tt, "%s|%s|%s|%d|%s|%d|%d", key, state,
2332 address, neighbors, pimdr, firsthpr,
2333 pimifchnl);
2334 }
2335 json_object_free(json);
2336
2337 /* Dump the generated table. */
2338 table = ttable_dump(tt, "\n");
2339 vty_out(vty, "%s\n", table);
2340 XFREE(MTYPE_TMP, table);
2341
2342 ttable_del(tt);
2343 }
2344 }
2345
2346 void pim_show_interfaces_single(struct pim_instance *pim, struct vty *vty,
2347 const char *ifname, bool mlag,
2348 json_object *json)
2349 {
2350 pim_addr ifaddr;
2351 struct interface *ifp;
2352 struct listnode *neighnode;
2353 struct pim_interface *pim_ifp;
2354 struct pim_neighbor *neigh;
2355 struct pim_upstream *up;
2356 time_t now;
2357 char dr_str[PIM_ADDRSTRLEN];
2358 char dr_uptime[10];
2359 char expire[10];
2360 char grp_str[PIM_ADDRSTRLEN];
2361 char hello_period[10];
2362 char hello_timer[10];
2363 char neigh_src_str[PIM_ADDRSTRLEN];
2364 char src_str[PIM_ADDRSTRLEN];
2365 char stat_uptime[10];
2366 char uptime[10];
2367 int found_ifname = 0;
2368 int print_header;
2369 json_object *json_row = NULL;
2370 json_object *json_pim_neighbor = NULL;
2371 json_object *json_pim_neighbors = NULL;
2372 json_object *json_group = NULL;
2373 json_object *json_group_source = NULL;
2374 json_object *json_fhr_sources = NULL;
2375 struct pim_secondary_addr *sec_addr;
2376 struct listnode *sec_node;
2377
2378 now = pim_time_monotonic_sec();
2379
2380 FOR_ALL_INTERFACES (pim->vrf, ifp) {
2381 pim_ifp = ifp->info;
2382
2383 if (!pim_ifp)
2384 continue;
2385
2386 if (mlag == true && pim_ifp->activeactive == false)
2387 continue;
2388
2389 if (strcmp(ifname, "detail") && strcmp(ifname, ifp->name))
2390 continue;
2391
2392 found_ifname = 1;
2393 ifaddr = pim_ifp->primary_address;
2394 snprintfrr(dr_str, sizeof(dr_str), "%pPAs",
2395 &pim_ifp->pim_dr_addr);
2396 pim_time_uptime_begin(dr_uptime, sizeof(dr_uptime), now,
2397 pim_ifp->pim_dr_election_last);
2398 pim_time_timer_to_hhmmss(hello_timer, sizeof(hello_timer),
2399 pim_ifp->t_pim_hello_timer);
2400 pim_time_mmss(hello_period, sizeof(hello_period),
2401 pim_ifp->pim_hello_period);
2402 pim_time_uptime(stat_uptime, sizeof(stat_uptime),
2403 now - pim_ifp->pim_ifstat_start);
2404
2405 if (json) {
2406 json_row = json_object_new_object();
2407 json_object_pim_ifp_add(json_row, ifp);
2408
2409 if (!pim_addr_is_any(pim_ifp->update_source)) {
2410 json_object_string_addf(
2411 json_row, "useSource", "%pPAs",
2412 &pim_ifp->update_source);
2413 }
2414 if (pim_ifp->sec_addr_list) {
2415 json_object *sec_list = NULL;
2416
2417 sec_list = json_object_new_array();
2418 for (ALL_LIST_ELEMENTS_RO(
2419 pim_ifp->sec_addr_list, sec_node,
2420 sec_addr)) {
2421 json_object_array_add(
2422 sec_list,
2423 json_object_new_stringf(
2424 "%pFXh",
2425 &sec_addr->addr));
2426 }
2427 json_object_object_add(json_row,
2428 "secondaryAddressList",
2429 sec_list);
2430 }
2431
2432 if (pim_ifp->pim_passive_enable)
2433 json_object_boolean_true_add(json_row,
2434 "passive");
2435
2436 /* PIM neighbors */
2437 if (pim_ifp->pim_neighbor_list->count) {
2438 json_pim_neighbors = json_object_new_object();
2439
2440 for (ALL_LIST_ELEMENTS_RO(
2441 pim_ifp->pim_neighbor_list,
2442 neighnode, neigh)) {
2443 json_pim_neighbor =
2444 json_object_new_object();
2445 snprintfrr(neigh_src_str,
2446 sizeof(neigh_src_str),
2447 "%pPAs",
2448 &neigh->source_addr);
2449 pim_time_uptime(uptime, sizeof(uptime),
2450 now - neigh->creation);
2451 pim_time_timer_to_hhmmss(
2452 expire, sizeof(expire),
2453 neigh->t_expire_timer);
2454
2455 json_object_string_add(
2456 json_pim_neighbor, "address",
2457 neigh_src_str);
2458 json_object_string_add(
2459 json_pim_neighbor, "upTime",
2460 uptime);
2461 json_object_string_add(
2462 json_pim_neighbor, "holdtime",
2463 expire);
2464
2465 json_object_object_add(
2466 json_pim_neighbors,
2467 neigh_src_str,
2468 json_pim_neighbor);
2469 }
2470
2471 json_object_object_add(json_row, "neighbors",
2472 json_pim_neighbors);
2473 }
2474
2475 json_object_string_add(json_row, "drAddress", dr_str);
2476 json_object_int_add(json_row, "drPriority",
2477 pim_ifp->pim_dr_priority);
2478 json_object_string_add(json_row, "drUptime", dr_uptime);
2479 json_object_int_add(json_row, "drElections",
2480 pim_ifp->pim_dr_election_count);
2481 json_object_int_add(json_row, "drChanges",
2482 pim_ifp->pim_dr_election_changes);
2483
2484 /* FHR */
2485 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2486 if (ifp != up->rpf.source_nexthop.interface)
2487 continue;
2488
2489 if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_FHR))
2490 continue;
2491
2492 if (!json_fhr_sources)
2493 json_fhr_sources =
2494 json_object_new_object();
2495
2496 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
2497 &up->sg.grp);
2498 snprintfrr(src_str, sizeof(src_str), "%pPAs",
2499 &up->sg.src);
2500 pim_time_uptime(uptime, sizeof(uptime),
2501 now - up->state_transition);
2502
2503 /*
2504 * Does this group live in json_fhr_sources?
2505 * If not create it.
2506 */
2507 json_object_object_get_ex(json_fhr_sources,
2508 grp_str, &json_group);
2509
2510 if (!json_group) {
2511 json_group = json_object_new_object();
2512 json_object_object_add(json_fhr_sources,
2513 grp_str,
2514 json_group);
2515 }
2516
2517 json_group_source = json_object_new_object();
2518 json_object_string_add(json_group_source,
2519 "source", src_str);
2520 json_object_string_add(json_group_source,
2521 "group", grp_str);
2522 json_object_string_add(json_group_source,
2523 "upTime", uptime);
2524 json_object_object_add(json_group, src_str,
2525 json_group_source);
2526 }
2527
2528 if (json_fhr_sources) {
2529 json_object_object_add(json_row,
2530 "firstHopRouter",
2531 json_fhr_sources);
2532 }
2533
2534 json_object_int_add(json_row, "helloPeriod",
2535 pim_ifp->pim_hello_period);
2536 json_object_int_add(json_row, "holdTime",
2537 PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
2538 json_object_string_add(json_row, "helloTimer",
2539 hello_timer);
2540 json_object_string_add(json_row, "helloStatStart",
2541 stat_uptime);
2542 json_object_int_add(json_row, "helloReceived",
2543 pim_ifp->pim_ifstat_hello_recv);
2544 json_object_int_add(json_row, "helloReceivedFailed",
2545 pim_ifp->pim_ifstat_hello_recvfail);
2546 json_object_int_add(json_row, "helloSend",
2547 pim_ifp->pim_ifstat_hello_sent);
2548 json_object_int_add(json_row, "hellosendFailed",
2549 pim_ifp->pim_ifstat_hello_sendfail);
2550 json_object_int_add(json_row, "helloGenerationId",
2551 pim_ifp->pim_generation_id);
2552
2553 json_object_int_add(
2554 json_row, "effectivePropagationDelay",
2555 pim_if_effective_propagation_delay_msec(ifp));
2556 json_object_int_add(
2557 json_row, "effectiveOverrideInterval",
2558 pim_if_effective_override_interval_msec(ifp));
2559 json_object_int_add(
2560 json_row, "joinPruneOverrideInterval",
2561 pim_if_jp_override_interval_msec(ifp));
2562
2563 json_object_int_add(
2564 json_row, "propagationDelay",
2565 pim_ifp->pim_propagation_delay_msec);
2566 json_object_int_add(
2567 json_row, "propagationDelayHighest",
2568 pim_ifp->pim_neighbors_highest_propagation_delay_msec);
2569 json_object_int_add(
2570 json_row, "overrideInterval",
2571 pim_ifp->pim_override_interval_msec);
2572 json_object_int_add(
2573 json_row, "overrideIntervalHighest",
2574 pim_ifp->pim_neighbors_highest_override_interval_msec);
2575 if (pim_ifp->bsm_enable)
2576 json_object_boolean_true_add(json_row,
2577 "bsmEnabled");
2578 if (pim_ifp->ucast_bsm_accept)
2579 json_object_boolean_true_add(json_row,
2580 "ucastBsmEnabled");
2581 json_object_object_add(json, ifp->name, json_row);
2582
2583 } else {
2584 vty_out(vty, "Interface : %s\n", ifp->name);
2585 vty_out(vty, "State : %s\n",
2586 if_is_up(ifp) ? "up" : "down");
2587 if (!pim_addr_is_any(pim_ifp->update_source)) {
2588 vty_out(vty, "Use Source : %pPAs\n",
2589 &pim_ifp->update_source);
2590 }
2591 if (pim_ifp->sec_addr_list) {
2592 vty_out(vty, "Address : %pPAs (primary)\n",
2593 &ifaddr);
2594 for (ALL_LIST_ELEMENTS_RO(
2595 pim_ifp->sec_addr_list, sec_node,
2596 sec_addr))
2597 vty_out(vty, " %pFX\n",
2598 &sec_addr->addr);
2599 } else {
2600 vty_out(vty, "Address : %pPAs\n", &ifaddr);
2601 }
2602
2603 if (pim_ifp->pim_passive_enable)
2604 vty_out(vty, "Passive : %s\n",
2605 (pim_ifp->pim_passive_enable) ? "yes"
2606 : "no");
2607
2608 vty_out(vty, "\n");
2609
2610 /* PIM neighbors */
2611 print_header = 1;
2612
2613 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list,
2614 neighnode, neigh)) {
2615
2616 if (print_header) {
2617 vty_out(vty, "PIM Neighbors\n");
2618 vty_out(vty, "-------------\n");
2619 print_header = 0;
2620 }
2621
2622 snprintfrr(neigh_src_str, sizeof(neigh_src_str),
2623 "%pPAs", &neigh->source_addr);
2624 pim_time_uptime(uptime, sizeof(uptime),
2625 now - neigh->creation);
2626 pim_time_timer_to_hhmmss(expire, sizeof(expire),
2627 neigh->t_expire_timer);
2628 vty_out(vty,
2629 "%-15s : up for %s, holdtime expires in %s\n",
2630 neigh_src_str, uptime, expire);
2631 }
2632
2633 if (!print_header) {
2634 vty_out(vty, "\n");
2635 vty_out(vty, "\n");
2636 }
2637
2638 vty_out(vty, "Designated Router\n");
2639 vty_out(vty, "-----------------\n");
2640 vty_out(vty, "Address : %s\n", dr_str);
2641 vty_out(vty, "Priority : %u(%d)\n",
2642 pim_ifp->pim_dr_priority,
2643 pim_ifp->pim_dr_num_nondrpri_neighbors);
2644 vty_out(vty, "Uptime : %s\n", dr_uptime);
2645 vty_out(vty, "Elections : %d\n",
2646 pim_ifp->pim_dr_election_count);
2647 vty_out(vty, "Changes : %d\n",
2648 pim_ifp->pim_dr_election_changes);
2649 vty_out(vty, "\n");
2650 vty_out(vty, "\n");
2651
2652 /* FHR */
2653 print_header = 1;
2654 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2655 if (!up->rpf.source_nexthop.interface)
2656 continue;
2657
2658 if (strcmp(ifp->name,
2659 up->rpf.source_nexthop
2660 .interface->name) != 0)
2661 continue;
2662
2663 if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_FHR))
2664 continue;
2665
2666 if (print_header) {
2667 vty_out(vty,
2668 "FHR - First Hop Router\n");
2669 vty_out(vty,
2670 "----------------------\n");
2671 print_header = 0;
2672 }
2673
2674 pim_time_uptime(uptime, sizeof(uptime),
2675 now - up->state_transition);
2676 vty_out(vty,
2677 "%pPAs : %pPAs is a source, uptime is %s\n",
2678 &up->sg.grp, &up->sg.src, uptime);
2679 }
2680
2681 if (!print_header) {
2682 vty_out(vty, "\n");
2683 vty_out(vty, "\n");
2684 }
2685
2686 vty_out(vty, "Hellos\n");
2687 vty_out(vty, "------\n");
2688 vty_out(vty, "Period : %d\n",
2689 pim_ifp->pim_hello_period);
2690 vty_out(vty, "HoldTime : %d\n",
2691 PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
2692 vty_out(vty, "Timer : %s\n", hello_timer);
2693 vty_out(vty, "StatStart : %s\n", stat_uptime);
2694 vty_out(vty, "Receive : %d\n",
2695 pim_ifp->pim_ifstat_hello_recv);
2696 vty_out(vty, "Receive Failed : %d\n",
2697 pim_ifp->pim_ifstat_hello_recvfail);
2698 vty_out(vty, "Send : %d\n",
2699 pim_ifp->pim_ifstat_hello_sent);
2700 vty_out(vty, "Send Failed : %d\n",
2701 pim_ifp->pim_ifstat_hello_sendfail);
2702 vty_out(vty, "Generation ID : %08x\n",
2703 pim_ifp->pim_generation_id);
2704 vty_out(vty, "\n");
2705 vty_out(vty, "\n");
2706
2707 pim_print_ifp_flags(vty, ifp);
2708
2709 vty_out(vty, "Join Prune Interval\n");
2710 vty_out(vty, "-------------------\n");
2711 vty_out(vty, "LAN Delay : %s\n",
2712 pim_if_lan_delay_enabled(ifp) ? "yes" : "no");
2713 vty_out(vty, "Effective Propagation Delay : %d msec\n",
2714 pim_if_effective_propagation_delay_msec(ifp));
2715 vty_out(vty, "Effective Override Interval : %d msec\n",
2716 pim_if_effective_override_interval_msec(ifp));
2717 vty_out(vty, "Join Prune Override Interval : %d msec\n",
2718 pim_if_jp_override_interval_msec(ifp));
2719 vty_out(vty, "\n");
2720 vty_out(vty, "\n");
2721
2722 vty_out(vty, "LAN Prune Delay\n");
2723 vty_out(vty, "---------------\n");
2724 vty_out(vty, "Propagation Delay : %d msec\n",
2725 pim_ifp->pim_propagation_delay_msec);
2726 vty_out(vty, "Propagation Delay (Highest) : %d msec\n",
2727 pim_ifp->pim_neighbors_highest_propagation_delay_msec);
2728 vty_out(vty, "Override Interval : %d msec\n",
2729 pim_ifp->pim_override_interval_msec);
2730 vty_out(vty, "Override Interval (Highest) : %d msec\n",
2731 pim_ifp->pim_neighbors_highest_override_interval_msec);
2732 vty_out(vty, "\n");
2733 vty_out(vty, "\n");
2734
2735 vty_out(vty, "BSM Status\n");
2736 vty_out(vty, "----------\n");
2737 vty_out(vty, "Bsm Enabled : %s\n",
2738 pim_ifp->bsm_enable ? "yes" : "no");
2739 vty_out(vty, "Unicast Bsm Enabled : %s\n",
2740 pim_ifp->ucast_bsm_accept ? "yes" : "no");
2741 vty_out(vty, "\n");
2742 vty_out(vty, "\n");
2743 }
2744 }
2745
2746 if (!found_ifname)
2747 vty_out(vty, "%% No such interface\n");
2748 }
2749
2750 void ip_pim_ssm_show_group_range(struct pim_instance *pim, struct vty *vty,
2751 bool uj)
2752 {
2753 struct pim_ssm *ssm = pim->ssm_info;
2754 const char *range_str =
2755 ssm->plist_name ? ssm->plist_name : PIM_SSM_STANDARD_RANGE;
2756
2757 if (uj) {
2758 json_object *json;
2759
2760 json = json_object_new_object();
2761 json_object_string_add(json, "ssmGroups", range_str);
2762 vty_json(vty, json);
2763 } else
2764 vty_out(vty, "SSM group range : %s\n", range_str);
2765 }
2766
2767 struct vty_pnc_cache_walk_data {
2768 struct vty *vty;
2769 struct pim_instance *pim;
2770 };
2771
2772 struct json_pnc_cache_walk_data {
2773 json_object *json_obj;
2774 struct pim_instance *pim;
2775 };
2776
2777 static int pim_print_vty_pnc_cache_walkcb(struct hash_bucket *bucket, void *arg)
2778 {
2779 struct pim_nexthop_cache *pnc = bucket->data;
2780 struct vty_pnc_cache_walk_data *cwd = arg;
2781 struct vty *vty = cwd->vty;
2782 struct pim_instance *pim = cwd->pim;
2783 struct nexthop *nh_node = NULL;
2784 ifindex_t first_ifindex;
2785 struct interface *ifp = NULL;
2786
2787 for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
2788 first_ifindex = nh_node->ifindex;
2789
2790 ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
2791
2792 vty_out(vty, "%-15pPA ", &pnc->rpf.rpf_addr);
2793 vty_out(vty, "%-16s ", ifp ? ifp->name : "NULL");
2794 #if PIM_IPV == 4
2795 vty_out(vty, "%pI4 ", &nh_node->gate.ipv4);
2796 #else
2797 vty_out(vty, "%pI6 ", &nh_node->gate.ipv6);
2798 #endif
2799 vty_out(vty, "\n");
2800 }
2801 return CMD_SUCCESS;
2802 }
2803
2804 static int pim_print_json_pnc_cache_walkcb(struct hash_bucket *backet,
2805 void *arg)
2806 {
2807 struct pim_nexthop_cache *pnc = backet->data;
2808 struct json_pnc_cache_walk_data *cwd = arg;
2809 struct pim_instance *pim = cwd->pim;
2810 struct nexthop *nh_node = NULL;
2811 ifindex_t first_ifindex;
2812 struct interface *ifp = NULL;
2813 char addr_str[PIM_ADDRSTRLEN];
2814 json_object *json_row = NULL;
2815 json_object *json_ifp = NULL;
2816 json_object *json_arr = NULL;
2817
2818 for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
2819 first_ifindex = nh_node->ifindex;
2820 ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
2821 snprintfrr(addr_str, sizeof(addr_str), "%pPA",
2822 &pnc->rpf.rpf_addr);
2823 json_object_object_get_ex(cwd->json_obj, addr_str, &json_row);
2824 if (!json_row) {
2825 json_row = json_object_new_object();
2826 json_object_string_addf(json_row, "address", "%pPA",
2827 &pnc->rpf.rpf_addr);
2828 json_object_object_addf(cwd->json_obj, json_row, "%pPA",
2829 &pnc->rpf.rpf_addr);
2830 json_arr = json_object_new_array();
2831 json_object_object_add(json_row, "nexthops", json_arr);
2832 }
2833 json_ifp = json_object_new_object();
2834 json_object_string_add(json_ifp, "interface",
2835 ifp ? ifp->name : "NULL");
2836 #if PIM_IPV == 4
2837 json_object_string_addf(json_ifp, "nexthop", "%pI4",
2838 &nh_node->gate.ipv4);
2839 #else
2840 json_object_string_addf(json_ifp, "nexthop", "%pI6",
2841 &nh_node->gate.ipv6);
2842 #endif
2843 json_object_array_add(json_arr, json_ifp);
2844 }
2845 return CMD_SUCCESS;
2846 }
2847
2848 int pim_show_nexthop_lookup_cmd_helper(const char *vrf, struct vty *vty,
2849 pim_addr source, pim_addr group)
2850 {
2851 int result = 0;
2852 pim_addr vif_source;
2853 struct prefix grp;
2854 struct pim_nexthop nexthop;
2855 struct vrf *v;
2856 char grp_str[PREFIX_STRLEN];
2857
2858 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
2859
2860 if (!v)
2861 return CMD_WARNING;
2862
2863 #if PIM_IPV == 4
2864 if (pim_is_group_224_4(source)) {
2865 vty_out(vty,
2866 "Invalid argument. Expected Valid Source Address.\n");
2867 return CMD_WARNING;
2868 }
2869
2870 if (!pim_is_group_224_4(group)) {
2871 vty_out(vty,
2872 "Invalid argument. Expected Valid Multicast Group Address.\n");
2873 return CMD_WARNING;
2874 }
2875 #endif
2876
2877 if (!pim_rp_set_upstream_addr(v->info, &vif_source, source, group))
2878 return CMD_SUCCESS;
2879
2880 pim_addr_to_prefix(&grp, group);
2881 memset(&nexthop, 0, sizeof(nexthop));
2882
2883 result =
2884 pim_ecmp_nexthop_lookup(v->info, &nexthop, vif_source, &grp, 0);
2885
2886 if (!result) {
2887 vty_out(vty,
2888 "Nexthop Lookup failed, no usable routes returned.\n");
2889 return CMD_SUCCESS;
2890 }
2891
2892 pim_addr_dump("<grp?>", &grp, grp_str, sizeof(grp_str));
2893
2894 vty_out(vty, "Group %s --- Nexthop %pPAs Interface %s\n", grp_str,
2895 &nexthop.mrib_nexthop_addr, nexthop.interface->name);
2896
2897 return CMD_SUCCESS;
2898 }
2899
2900 int pim_show_nexthop_cmd_helper(const char *vrf, struct vty *vty, bool uj)
2901 {
2902 struct vrf *v;
2903
2904 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
2905
2906 if (!v)
2907 return CMD_WARNING;
2908
2909 pim_show_nexthop(v->info, vty, uj);
2910
2911 return CMD_SUCCESS;
2912 }
2913
2914 void pim_show_nexthop(struct pim_instance *pim, struct vty *vty, bool uj)
2915 {
2916 struct vty_pnc_cache_walk_data cwd;
2917 struct json_pnc_cache_walk_data jcwd;
2918
2919 cwd.vty = vty;
2920 cwd.pim = pim;
2921 jcwd.pim = pim;
2922
2923 if (uj) {
2924 jcwd.json_obj = json_object_new_object();
2925 } else {
2926 vty_out(vty, "Number of registered addresses: %lu\n",
2927 pim->rpf_hash->count);
2928 vty_out(vty, "Address Interface Nexthop\n");
2929 vty_out(vty, "---------------------------------------------\n");
2930 }
2931
2932 if (uj) {
2933 hash_walk(pim->rpf_hash, pim_print_json_pnc_cache_walkcb,
2934 &jcwd);
2935 vty_json(vty, jcwd.json_obj);
2936 } else
2937 hash_walk(pim->rpf_hash, pim_print_vty_pnc_cache_walkcb, &cwd);
2938 }
2939
2940 int pim_show_neighbors_cmd_helper(const char *vrf, struct vty *vty,
2941 const char *json, const char *interface)
2942 {
2943 struct vrf *v;
2944 json_object *json_parent = NULL;
2945
2946 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
2947
2948 if (!v)
2949 return CMD_WARNING;
2950
2951 if (json)
2952 json_parent = json_object_new_object();
2953
2954 if (interface)
2955 pim_show_neighbors_single(v->info, vty, interface, json_parent);
2956 else
2957 pim_show_neighbors(v->info, vty, json_parent);
2958
2959 if (json)
2960 vty_json(vty, json_parent);
2961
2962 return CMD_SUCCESS;
2963 }
2964
2965 int pim_show_neighbors_vrf_all_cmd_helper(struct vty *vty, const char *json,
2966 const char *interface)
2967 {
2968 struct vrf *v;
2969 json_object *json_parent = NULL;
2970 json_object *json_vrf = NULL;
2971
2972 if (json)
2973 json_parent = json_object_new_object();
2974 RB_FOREACH (v, vrf_name_head, &vrfs_by_name) {
2975 if (!json)
2976 vty_out(vty, "VRF: %s\n", v->name);
2977 else
2978 json_vrf = json_object_new_object();
2979
2980 if (interface)
2981 pim_show_neighbors_single(v->info, vty, interface,
2982 json_vrf);
2983 else
2984 pim_show_neighbors(v->info, vty, json_vrf);
2985
2986 if (json)
2987 json_object_object_add(json_parent, v->name, json_vrf);
2988 }
2989 if (json)
2990 vty_json(vty, json_parent);
2991
2992 return CMD_SUCCESS;
2993 }
2994
2995 void pim_show_neighbors_single(struct pim_instance *pim, struct vty *vty,
2996 const char *neighbor, json_object *json)
2997 {
2998 struct listnode *neighnode;
2999 struct interface *ifp;
3000 struct pim_interface *pim_ifp;
3001 struct pim_neighbor *neigh;
3002 time_t now;
3003 int found_neighbor = 0;
3004 int option_address_list;
3005 int option_dr_priority;
3006 int option_generation_id;
3007 int option_holdtime;
3008 int option_lan_prune_delay;
3009 int option_t_bit;
3010 char uptime[10];
3011 char expire[10];
3012 char neigh_src_str[PIM_ADDRSTRLEN];
3013
3014 json_object *json_ifp = NULL;
3015 json_object *json_row = NULL;
3016
3017 now = pim_time_monotonic_sec();
3018
3019 FOR_ALL_INTERFACES (pim->vrf, ifp) {
3020 pim_ifp = ifp->info;
3021
3022 if (!pim_ifp)
3023 continue;
3024
3025 if (pim_ifp->pim_sock_fd < 0)
3026 continue;
3027
3028 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
3029 neigh)) {
3030 snprintfrr(neigh_src_str, sizeof(neigh_src_str),
3031 "%pPAs", &neigh->source_addr);
3032
3033 /*
3034 * The user can specify either the interface name or the
3035 * PIM neighbor IP.
3036 * If this pim_ifp matches neither then skip.
3037 */
3038 if (strcmp(neighbor, "detail") &&
3039 strcmp(neighbor, ifp->name) &&
3040 strcmp(neighbor, neigh_src_str))
3041 continue;
3042
3043 found_neighbor = 1;
3044 pim_time_uptime(uptime, sizeof(uptime),
3045 now - neigh->creation);
3046 pim_time_timer_to_hhmmss(expire, sizeof(expire),
3047 neigh->t_expire_timer);
3048
3049 option_address_list = 0;
3050 option_dr_priority = 0;
3051 option_generation_id = 0;
3052 option_holdtime = 0;
3053 option_lan_prune_delay = 0;
3054 option_t_bit = 0;
3055
3056 if (PIM_OPTION_IS_SET(neigh->hello_options,
3057 PIM_OPTION_MASK_ADDRESS_LIST))
3058 option_address_list = 1;
3059
3060 if (PIM_OPTION_IS_SET(neigh->hello_options,
3061 PIM_OPTION_MASK_DR_PRIORITY))
3062 option_dr_priority = 1;
3063
3064 if (PIM_OPTION_IS_SET(neigh->hello_options,
3065 PIM_OPTION_MASK_GENERATION_ID))
3066 option_generation_id = 1;
3067
3068 if (PIM_OPTION_IS_SET(neigh->hello_options,
3069 PIM_OPTION_MASK_HOLDTIME))
3070 option_holdtime = 1;
3071
3072 if (PIM_OPTION_IS_SET(neigh->hello_options,
3073 PIM_OPTION_MASK_LAN_PRUNE_DELAY))
3074 option_lan_prune_delay = 1;
3075
3076 if (PIM_OPTION_IS_SET(
3077 neigh->hello_options,
3078 PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION))
3079 option_t_bit = 1;
3080
3081 if (json) {
3082
3083 /* Does this ifp live in json? If not create it
3084 */
3085 json_object_object_get_ex(json, ifp->name,
3086 &json_ifp);
3087
3088 if (!json_ifp) {
3089 json_ifp = json_object_new_object();
3090 json_object_pim_ifp_add(json_ifp, ifp);
3091 json_object_object_add(json, ifp->name,
3092 json_ifp);
3093 }
3094
3095 json_row = json_object_new_object();
3096 json_object_string_add(json_row, "interface",
3097 ifp->name);
3098 json_object_string_add(json_row, "address",
3099 neigh_src_str);
3100 json_object_string_add(json_row, "upTime",
3101 uptime);
3102 json_object_string_add(json_row, "holdtime",
3103 expire);
3104 json_object_int_add(json_row, "drPriority",
3105 neigh->dr_priority);
3106 json_object_int_add(json_row, "generationId",
3107 neigh->generation_id);
3108
3109 if (option_address_list)
3110 json_object_boolean_true_add(
3111 json_row,
3112 "helloOptionAddressList");
3113
3114 if (option_dr_priority)
3115 json_object_boolean_true_add(
3116 json_row,
3117 "helloOptionDrPriority");
3118
3119 if (option_generation_id)
3120 json_object_boolean_true_add(
3121 json_row,
3122 "helloOptionGenerationId");
3123
3124 if (option_holdtime)
3125 json_object_boolean_true_add(
3126 json_row,
3127 "helloOptionHoldtime");
3128
3129 if (option_lan_prune_delay)
3130 json_object_boolean_true_add(
3131 json_row,
3132 "helloOptionLanPruneDelay");
3133
3134 if (option_t_bit)
3135 json_object_boolean_true_add(
3136 json_row, "helloOptionTBit");
3137
3138 json_object_object_add(json_ifp, neigh_src_str,
3139 json_row);
3140
3141 } else {
3142 vty_out(vty, "Interface : %s\n", ifp->name);
3143 vty_out(vty, "Neighbor : %s\n", neigh_src_str);
3144 vty_out(vty,
3145 " Uptime : %s\n",
3146 uptime);
3147 vty_out(vty,
3148 " Holdtime : %s\n",
3149 expire);
3150 vty_out(vty,
3151 " DR Priority : %d\n",
3152 neigh->dr_priority);
3153 vty_out(vty,
3154 " Generation ID : %08x\n",
3155 neigh->generation_id);
3156 vty_out(vty,
3157 " Override Interval (msec) : %d\n",
3158 neigh->override_interval_msec);
3159 vty_out(vty,
3160 " Propagation Delay (msec) : %d\n",
3161 neigh->propagation_delay_msec);
3162 vty_out(vty,
3163 " Hello Option - Address List : %s\n",
3164 option_address_list ? "yes" : "no");
3165 vty_out(vty,
3166 " Hello Option - DR Priority : %s\n",
3167 option_dr_priority ? "yes" : "no");
3168 vty_out(vty,
3169 " Hello Option - Generation ID : %s\n",
3170 option_generation_id ? "yes" : "no");
3171 vty_out(vty,
3172 " Hello Option - Holdtime : %s\n",
3173 option_holdtime ? "yes" : "no");
3174 vty_out(vty,
3175 " Hello Option - LAN Prune Delay : %s\n",
3176 option_lan_prune_delay ? "yes" : "no");
3177 vty_out(vty,
3178 " Hello Option - T-bit : %s\n",
3179 option_t_bit ? "yes" : "no");
3180 bfd_sess_show(vty, json_ifp,
3181 neigh->bfd_session);
3182 vty_out(vty, "\n");
3183 }
3184 }
3185 }
3186
3187 if (!found_neighbor)
3188 vty_out(vty, "%% No such interface or neighbor\n");
3189 }
3190
3191 void pim_show_neighbors(struct pim_instance *pim, struct vty *vty,
3192 json_object *json)
3193 {
3194 struct listnode *neighnode;
3195 struct interface *ifp;
3196 struct pim_interface *pim_ifp;
3197 struct pim_neighbor *neigh;
3198 struct ttable *tt = NULL;
3199 char *table = NULL;
3200 time_t now;
3201 char uptime[10];
3202 char expire[10];
3203 char neigh_src_str[PIM_ADDRSTRLEN];
3204 json_object *json_ifp_rows = NULL;
3205 json_object *json_row = NULL;
3206
3207 now = pim_time_monotonic_sec();
3208
3209 if (!json) {
3210 /* Prepare table. */
3211 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
3212 ttable_add_row(tt, "Interface|Neighbor|Uptime|Holdtime|DR Pri");
3213 tt->style.cell.rpad = 2;
3214 tt->style.corner = '+';
3215 ttable_restyle(tt);
3216 }
3217
3218 FOR_ALL_INTERFACES (pim->vrf, ifp) {
3219 pim_ifp = ifp->info;
3220
3221 if (!pim_ifp)
3222 continue;
3223
3224 if (pim_ifp->pim_sock_fd < 0)
3225 continue;
3226
3227 if (json)
3228 json_ifp_rows = json_object_new_object();
3229
3230 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
3231 neigh)) {
3232 snprintfrr(neigh_src_str, sizeof(neigh_src_str),
3233 "%pPAs", &neigh->source_addr);
3234 pim_time_uptime(uptime, sizeof(uptime),
3235 now - neigh->creation);
3236 pim_time_timer_to_hhmmss(expire, sizeof(expire),
3237 neigh->t_expire_timer);
3238
3239 if (json) {
3240 json_row = json_object_new_object();
3241 json_object_string_add(json_row, "interface",
3242 ifp->name);
3243 json_object_string_add(json_row, "neighbor",
3244 neigh_src_str);
3245 json_object_string_add(json_row, "upTime",
3246 uptime);
3247 json_object_string_add(json_row, "holdTime",
3248 expire);
3249 json_object_int_add(json_row, "holdTimeMax",
3250 neigh->holdtime);
3251 json_object_int_add(json_row, "drPriority",
3252 neigh->dr_priority);
3253 json_object_object_add(json_ifp_rows,
3254 neigh_src_str, json_row);
3255
3256 } else {
3257 ttable_add_row(tt, "%s|%pPAs|%s|%s|%d",
3258 ifp->name, &neigh->source_addr,
3259 uptime, expire,
3260 neigh->dr_priority);
3261 }
3262 }
3263
3264 if (json) {
3265 json_object_object_add(json, ifp->name, json_ifp_rows);
3266 json_ifp_rows = NULL;
3267 }
3268 }
3269 /* Dump the generated table. */
3270 if (!json) {
3271 table = ttable_dump(tt, "\n");
3272 vty_out(vty, "%s\n", table);
3273 XFREE(MTYPE_TMP, table);
3274 ttable_del(tt);
3275 }
3276 }
3277
3278 int gm_process_query_max_response_time_cmd(struct vty *vty,
3279 const char *qmrt_str)
3280 {
3281 const struct lyd_node *pim_enable_dnode;
3282
3283 pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
3284 FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH,
3285 FRR_PIM_AF_XPATH_VAL);
3286
3287 if (!pim_enable_dnode) {
3288 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true");
3289 } else {
3290 if (!yang_dnode_get_bool(pim_enable_dnode, "."))
3291 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY,
3292 "true");
3293 }
3294
3295 nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
3296 qmrt_str);
3297 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3298 FRR_PIM_AF_XPATH_VAL);
3299 }
3300
3301 int gm_process_no_query_max_response_time_cmd(struct vty *vty)
3302 {
3303 nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_DESTROY,
3304 NULL);
3305 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3306 FRR_PIM_AF_XPATH_VAL);
3307 }
3308
3309 int gm_process_last_member_query_count_cmd(struct vty *vty,
3310 const char *lmqc_str)
3311 {
3312 const struct lyd_node *pim_enable_dnode;
3313
3314 pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
3315 FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH,
3316 FRR_PIM_AF_XPATH_VAL);
3317 if (!pim_enable_dnode) {
3318 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true");
3319 } else {
3320 if (!yang_dnode_get_bool(pim_enable_dnode, "."))
3321 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY,
3322 "true");
3323 }
3324
3325 nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_MODIFY,
3326 lmqc_str);
3327 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3328 FRR_PIM_AF_XPATH_VAL);
3329 }
3330
3331 int gm_process_no_last_member_query_count_cmd(struct vty *vty)
3332 {
3333 nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_DESTROY,
3334 NULL);
3335 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3336 FRR_PIM_AF_XPATH_VAL);
3337 }
3338
3339 int gm_process_last_member_query_interval_cmd(struct vty *vty,
3340 const char *lmqi_str)
3341 {
3342 const struct lyd_node *pim_enable_dnode;
3343
3344 pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
3345 FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH,
3346 FRR_PIM_AF_XPATH_VAL);
3347 if (!pim_enable_dnode) {
3348 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true");
3349 } else {
3350 if (!yang_dnode_get_bool(pim_enable_dnode, "."))
3351 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY,
3352 "true");
3353 }
3354
3355 nb_cli_enqueue_change(vty, "./last-member-query-interval", NB_OP_MODIFY,
3356 lmqi_str);
3357 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3358 FRR_PIM_AF_XPATH_VAL);
3359 }
3360
3361 int gm_process_no_last_member_query_interval_cmd(struct vty *vty)
3362 {
3363 nb_cli_enqueue_change(vty, "./last-member-query-interval",
3364 NB_OP_DESTROY, NULL);
3365 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3366 FRR_PIM_AF_XPATH_VAL);
3367 }
3368
3369 int pim_process_ssmpingd_cmd(struct vty *vty, enum nb_operation operation,
3370 const char *src_str)
3371 {
3372 const char *vrfname;
3373 char ssmpingd_ip_xpath[XPATH_MAXLEN];
3374
3375 vrfname = pim_cli_get_vrf_name(vty);
3376 if (vrfname == NULL)
3377 return CMD_WARNING_CONFIG_FAILED;
3378
3379 snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath),
3380 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
3381 FRR_PIM_AF_XPATH_VAL);
3382 strlcat(ssmpingd_ip_xpath, "/ssm-pingd-source-ip",
3383 sizeof(ssmpingd_ip_xpath));
3384
3385 nb_cli_enqueue_change(vty, ssmpingd_ip_xpath, operation, src_str);
3386
3387 return nb_cli_apply_changes(vty, NULL);
3388 }
3389
3390 static void show_scan_oil_stats(struct pim_instance *pim, struct vty *vty,
3391 time_t now)
3392 {
3393 char uptime_scan_oil[10];
3394 char uptime_mroute_add[10];
3395 char uptime_mroute_del[10];
3396
3397 pim_time_uptime_begin(uptime_scan_oil, sizeof(uptime_scan_oil), now,
3398 pim->scan_oil_last);
3399 pim_time_uptime_begin(uptime_mroute_add, sizeof(uptime_mroute_add), now,
3400 pim->mroute_add_last);
3401 pim_time_uptime_begin(uptime_mroute_del, sizeof(uptime_mroute_del), now,
3402 pim->mroute_del_last);
3403
3404 vty_out(vty,
3405 "Scan OIL - Last: %s Events: %lld\n"
3406 "MFC Add - Last: %s Events: %lld\n"
3407 "MFC Del - Last: %s Events: %lld\n",
3408 uptime_scan_oil, (long long)pim->scan_oil_events,
3409 uptime_mroute_add, (long long)pim->mroute_add_events,
3410 uptime_mroute_del, (long long)pim->mroute_del_events);
3411 }
3412
3413 void show_multicast_interfaces(struct pim_instance *pim, struct vty *vty,
3414 json_object *json)
3415 {
3416 struct interface *ifp;
3417 struct ttable *tt = NULL;
3418 char *table = NULL;
3419 json_object *json_row = NULL;
3420
3421 vty_out(vty, "\n");
3422
3423 if (!json) {
3424 /* Prepare table. */
3425 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
3426 ttable_add_row(
3427 tt,
3428 "Interface|Address|ifi|Vif|PktsIn|PktsOut|BytesIn|BytesOut");
3429 tt->style.cell.rpad = 2;
3430 tt->style.corner = '+';
3431 ttable_restyle(tt);
3432 }
3433
3434 FOR_ALL_INTERFACES (pim->vrf, ifp) {
3435 struct pim_interface *pim_ifp;
3436 #if PIM_IPV == 4
3437 struct sioc_vif_req vreq;
3438 #else
3439 struct sioc_mif_req6 vreq;
3440 #endif
3441
3442 pim_ifp = ifp->info;
3443
3444 if (!pim_ifp)
3445 continue;
3446
3447 memset(&vreq, 0, sizeof(vreq));
3448 #if PIM_IPV == 4
3449 vreq.vifi = pim_ifp->mroute_vif_index;
3450 if (ioctl(pim->mroute_socket, SIOCGETVIFCNT, &vreq)) {
3451 zlog_warn(
3452 "ioctl(SIOCGETVIFCNT=%lu) failure for interface %s vif_index=%d: errno=%d: %s",
3453 (unsigned long)SIOCGETVIFCNT, ifp->name,
3454 pim_ifp->mroute_vif_index, errno,
3455 safe_strerror(errno));
3456 }
3457 #else
3458 vreq.mifi = pim_ifp->mroute_vif_index;
3459 if (ioctl(pim->mroute_socket, SIOCGETMIFCNT_IN6, &vreq)) {
3460 zlog_warn(
3461 "ioctl(SIOCGETMIFCNT_IN6=%lu) failure for interface %s vif_index=%d: errno=%d: %s",
3462 (unsigned long)SIOCGETMIFCNT_IN6, ifp->name,
3463 pim_ifp->mroute_vif_index, errno,
3464 safe_strerror(errno));
3465 }
3466 #endif
3467
3468 if (json) {
3469 json_row = json_object_new_object();
3470 json_object_string_add(json_row, "name", ifp->name);
3471 json_object_string_add(json_row, "state",
3472 if_is_up(ifp) ? "up" : "down");
3473 json_object_string_addf(json_row, "address", "%pPA",
3474 &pim_ifp->primary_address);
3475 json_object_int_add(json_row, "ifIndex", ifp->ifindex);
3476 json_object_int_add(json_row, "vif",
3477 pim_ifp->mroute_vif_index);
3478 json_object_int_add(json_row, "pktsIn",
3479 (unsigned long)vreq.icount);
3480 json_object_int_add(json_row, "pktsOut",
3481 (unsigned long)vreq.ocount);
3482 json_object_int_add(json_row, "bytesIn",
3483 (unsigned long)vreq.ibytes);
3484 json_object_int_add(json_row, "bytesOut",
3485 (unsigned long)vreq.obytes);
3486 json_object_object_add(json, ifp->name, json_row);
3487 } else {
3488 ttable_add_row(tt, "%s|%pPAs|%d|%d|%lu|%lu|%lu|%lu",
3489 ifp->name, &pim_ifp->primary_address,
3490 ifp->ifindex, pim_ifp->mroute_vif_index,
3491 (unsigned long)vreq.icount,
3492 (unsigned long)vreq.ocount,
3493 (unsigned long)vreq.ibytes,
3494 (unsigned long)vreq.obytes);
3495 }
3496 }
3497 /* Dump the generated table. */
3498 if (!json) {
3499 table = ttable_dump(tt, "\n");
3500 vty_out(vty, "%s\n", table);
3501 XFREE(MTYPE_TMP, table);
3502 ttable_del(tt);
3503 }
3504 }
3505
3506 void pim_cmd_show_ip_multicast_helper(struct pim_instance *pim, struct vty *vty)
3507 {
3508 struct vrf *vrf = pim->vrf;
3509 time_t now = pim_time_monotonic_sec();
3510 char uptime[10];
3511 char mlag_role[80];
3512
3513 pim = vrf->info;
3514
3515 vty_out(vty, "Router MLAG Role: %s\n",
3516 mlag_role2str(router->mlag_role, mlag_role, sizeof(mlag_role)));
3517 vty_out(vty, "Mroute socket descriptor:");
3518
3519 vty_out(vty, " %d(%s)\n", pim->mroute_socket, vrf->name);
3520 vty_out(vty, "PIM Register socket descriptor:");
3521 vty_out(vty, " %d(%s)\n", pim->reg_sock, vrf->name);
3522
3523 pim_time_uptime(uptime, sizeof(uptime),
3524 now - pim->mroute_socket_creation);
3525 vty_out(vty, "Mroute socket uptime: %s\n", uptime);
3526
3527 vty_out(vty, "\n");
3528
3529 pim_zebra_zclient_update(vty);
3530 pim_zlookup_show_ip_multicast(vty);
3531
3532 vty_out(vty, "\n");
3533 vty_out(vty, "Maximum highest VifIndex: %d\n", PIM_MAX_USABLE_VIFS);
3534
3535 vty_out(vty, "\n");
3536 vty_out(vty, "Upstream Join Timer: %d secs\n", router->t_periodic);
3537 vty_out(vty, "Join/Prune Holdtime: %d secs\n", PIM_JP_HOLDTIME);
3538 vty_out(vty, "PIM ECMP: %s\n", pim->ecmp_enable ? "Enable" : "Disable");
3539 vty_out(vty, "PIM ECMP Rebalance: %s\n",
3540 pim->ecmp_rebalance_enable ? "Enable" : "Disable");
3541
3542 vty_out(vty, "\n");
3543
3544 pim_show_rpf_refresh_stats(vty, pim, now, NULL);
3545
3546 vty_out(vty, "\n");
3547
3548 show_scan_oil_stats(pim, vty, now);
3549
3550 show_multicast_interfaces(pim, vty, NULL);
3551 }
3552
3553 void show_mroute(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg,
3554 bool fill, json_object *json)
3555 {
3556 struct listnode *node;
3557 struct channel_oil *c_oil;
3558 struct static_route *s_route;
3559 struct ttable *tt = NULL;
3560 char *table = NULL;
3561 time_t now;
3562 json_object *json_group = NULL;
3563 json_object *json_source = NULL;
3564 json_object *json_oil = NULL;
3565 json_object *json_ifp_out = NULL;
3566 int found_oif;
3567 int first;
3568 char grp_str[PIM_ADDRSTRLEN];
3569 char src_str[PIM_ADDRSTRLEN];
3570 char in_ifname[INTERFACE_NAMSIZ + 1];
3571 char out_ifname[INTERFACE_NAMSIZ + 1];
3572 int oif_vif_index;
3573 struct interface *ifp_in;
3574 char proto[100];
3575 char state_str[PIM_REG_STATE_STR_LEN];
3576 char mroute_uptime[10];
3577
3578 if (!json) {
3579 vty_out(vty, "IP Multicast Routing Table\n");
3580 vty_out(vty, "Flags: S - Sparse, C - Connected, P - Pruned\n");
3581 vty_out(vty,
3582 " R - SGRpt Pruned, F - Register flag, T - SPT-bit set\n");
3583
3584 /* Prepare table. */
3585 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
3586 ttable_add_row(
3587 tt, "Source|Group|Flags|Proto|Input|Output|TTL|Uptime");
3588 tt->style.cell.rpad = 2;
3589 tt->style.corner = '+';
3590 ttable_restyle(tt);
3591 }
3592
3593 now = pim_time_monotonic_sec();
3594
3595 /* print list of PIM and IGMP routes */
3596 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
3597 found_oif = 0;
3598 first = 1;
3599 if (!c_oil->installed)
3600 continue;
3601
3602 if (!pim_addr_is_any(sg->grp) &&
3603 pim_addr_cmp(sg->grp, *oil_mcastgrp(c_oil)))
3604 continue;
3605 if (!pim_addr_is_any(sg->src) &&
3606 pim_addr_cmp(sg->src, *oil_origin(c_oil)))
3607 continue;
3608
3609 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
3610 oil_mcastgrp(c_oil));
3611 snprintfrr(src_str, sizeof(src_str), "%pPAs",
3612 oil_origin(c_oil));
3613
3614 strlcpy(state_str, "S", sizeof(state_str));
3615 /* When a non DR receives a igmp join, it creates a (*,G)
3616 * channel_oil without any upstream creation
3617 */
3618 if (c_oil->up) {
3619 if (PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(c_oil->up->flags))
3620 strlcat(state_str, "C", sizeof(state_str));
3621 if (pim_upstream_is_sg_rpt(c_oil->up))
3622 strlcat(state_str, "R", sizeof(state_str));
3623 if (PIM_UPSTREAM_FLAG_TEST_FHR(c_oil->up->flags))
3624 strlcat(state_str, "F", sizeof(state_str));
3625 if (c_oil->up->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
3626 strlcat(state_str, "T", sizeof(state_str));
3627 }
3628 if (pim_channel_oil_empty(c_oil))
3629 strlcat(state_str, "P", sizeof(state_str));
3630
3631 ifp_in = pim_if_find_by_vif_index(pim, *oil_parent(c_oil));
3632
3633 if (ifp_in)
3634 strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
3635 else
3636 strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
3637
3638
3639 pim_time_uptime(mroute_uptime, sizeof(mroute_uptime),
3640 now - c_oil->mroute_creation);
3641
3642 if (json) {
3643
3644 /* Find the group, create it if it doesn't exist */
3645 json_object_object_get_ex(json, grp_str, &json_group);
3646
3647 if (!json_group) {
3648 json_group = json_object_new_object();
3649 json_object_object_add(json, grp_str,
3650 json_group);
3651 }
3652
3653 /* Find the source nested under the group, create it if
3654 * it doesn't exist
3655 */
3656 json_object_object_get_ex(json_group, src_str,
3657 &json_source);
3658
3659 if (!json_source) {
3660 json_source = json_object_new_object();
3661 json_object_object_add(json_group, src_str,
3662 json_source);
3663 }
3664
3665 /* Find the inbound interface nested under the source,
3666 * create it if it doesn't exist
3667 */
3668 json_object_string_add(json_source, "source", src_str);
3669 json_object_string_add(json_source, "group", grp_str);
3670 json_object_int_add(json_source, "installed",
3671 c_oil->installed);
3672 json_object_int_add(json_source, "refCount",
3673 c_oil->oil_ref_count);
3674 json_object_int_add(json_source, "oilSize",
3675 c_oil->oil_size);
3676 json_object_int_add(json_source, "OilInheritedRescan",
3677 c_oil->oil_inherited_rescan);
3678 json_object_int_add(json_source, "oilInheritedRescan",
3679 c_oil->oil_inherited_rescan);
3680 json_object_string_add(json_source, "iif", in_ifname);
3681 json_object_string_add(json_source, "upTime",
3682 mroute_uptime);
3683 json_oil = NULL;
3684 }
3685
3686 for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
3687 ++oif_vif_index) {
3688 struct interface *ifp_out;
3689 int ttl;
3690
3691 ttl = oil_if_has(c_oil, oif_vif_index);
3692 if (ttl < 1)
3693 continue;
3694
3695 /* do not display muted OIFs */
3696 if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_MUTE)
3697 continue;
3698
3699 if (*oil_parent(c_oil) == oif_vif_index &&
3700 !pim_mroute_allow_iif_in_oil(c_oil, oif_vif_index))
3701 continue;
3702
3703 ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
3704 found_oif = 1;
3705
3706 if (ifp_out)
3707 strlcpy(out_ifname, ifp_out->name,
3708 sizeof(out_ifname));
3709 else
3710 strlcpy(out_ifname, "<oif?>",
3711 sizeof(out_ifname));
3712
3713 if (json) {
3714 json_ifp_out = json_object_new_object();
3715 json_object_string_add(json_ifp_out, "source",
3716 src_str);
3717 json_object_string_add(json_ifp_out, "group",
3718 grp_str);
3719
3720 if (c_oil->oif_flags[oif_vif_index] &
3721 PIM_OIF_FLAG_PROTO_PIM)
3722 json_object_boolean_true_add(
3723 json_ifp_out, "protocolPim");
3724
3725 if (c_oil->oif_flags[oif_vif_index] &
3726 PIM_OIF_FLAG_PROTO_GM)
3727 #if PIM_IPV == 4
3728 json_object_boolean_true_add(
3729 json_ifp_out, "protocolIgmp");
3730 #else
3731 json_object_boolean_true_add(
3732 json_ifp_out, "protocolMld");
3733 #endif
3734
3735 if (c_oil->oif_flags[oif_vif_index] &
3736 PIM_OIF_FLAG_PROTO_VXLAN)
3737 json_object_boolean_true_add(
3738 json_ifp_out, "protocolVxlan");
3739
3740 if (c_oil->oif_flags[oif_vif_index] &
3741 PIM_OIF_FLAG_PROTO_STAR)
3742 json_object_boolean_true_add(
3743 json_ifp_out,
3744 "protocolInherited");
3745
3746 json_object_string_add(json_ifp_out,
3747 "inboundInterface",
3748 in_ifname);
3749 json_object_int_add(json_ifp_out, "iVifI",
3750 *oil_parent(c_oil));
3751 json_object_string_add(json_ifp_out,
3752 "outboundInterface",
3753 out_ifname);
3754 json_object_int_add(json_ifp_out, "oVifI",
3755 oif_vif_index);
3756 json_object_int_add(json_ifp_out, "ttl", ttl);
3757 json_object_string_add(json_ifp_out, "upTime",
3758 mroute_uptime);
3759 json_object_string_add(json_source, "flags",
3760 state_str);
3761 if (!json_oil) {
3762 json_oil = json_object_new_object();
3763 json_object_object_add(json_source,
3764 "oil", json_oil);
3765 }
3766 json_object_object_add(json_oil, out_ifname,
3767 json_ifp_out);
3768 } else {
3769 proto[0] = '\0';
3770 if (c_oil->oif_flags[oif_vif_index] &
3771 PIM_OIF_FLAG_PROTO_PIM) {
3772 strlcpy(proto, "PIM", sizeof(proto));
3773 }
3774
3775 if (c_oil->oif_flags[oif_vif_index] &
3776 PIM_OIF_FLAG_PROTO_GM) {
3777 #if PIM_IPV == 4
3778 strlcpy(proto, "IGMP", sizeof(proto));
3779 #else
3780 strlcpy(proto, "MLD", sizeof(proto));
3781 #endif
3782 }
3783
3784 if (c_oil->oif_flags[oif_vif_index] &
3785 PIM_OIF_FLAG_PROTO_VXLAN) {
3786 strlcpy(proto, "VxLAN", sizeof(proto));
3787 }
3788
3789 if (c_oil->oif_flags[oif_vif_index] &
3790 PIM_OIF_FLAG_PROTO_STAR) {
3791 strlcpy(proto, "STAR", sizeof(proto));
3792 }
3793
3794 ttable_add_row(tt, "%s|%s|%s|%s|%s|%s|%d|%s",
3795 src_str, grp_str, state_str,
3796 proto, in_ifname, out_ifname,
3797 ttl, mroute_uptime);
3798
3799 if (first) {
3800 src_str[0] = '\0';
3801 grp_str[0] = '\0';
3802 in_ifname[0] = '\0';
3803 state_str[0] = '\0';
3804 mroute_uptime[0] = '\0';
3805 first = 0;
3806 }
3807 }
3808 }
3809
3810 if (!json && !found_oif) {
3811 ttable_add_row(tt, "%pPAs|%pPAs|%s|%s|%s|%s|%d|%s",
3812 oil_origin(c_oil), oil_mcastgrp(c_oil),
3813 state_str, "none", in_ifname, "none", 0,
3814 "--:--:--");
3815 }
3816 }
3817
3818 /* Print list of static routes */
3819 for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
3820 first = 1;
3821
3822 if (!s_route->c_oil.installed)
3823 continue;
3824
3825 snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &s_route->group);
3826 snprintfrr(src_str, sizeof(src_str), "%pPAs", &s_route->source);
3827 ifp_in = pim_if_find_by_vif_index(pim, s_route->iif);
3828 found_oif = 0;
3829
3830 if (ifp_in)
3831 strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
3832 else
3833 strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
3834
3835 if (json) {
3836
3837 /* Find the group, create it if it doesn't exist */
3838 json_object_object_get_ex(json, grp_str, &json_group);
3839
3840 if (!json_group) {
3841 json_group = json_object_new_object();
3842 json_object_object_add(json, grp_str,
3843 json_group);
3844 }
3845
3846 /* Find the source nested under the group, create it if
3847 * it doesn't exist
3848 */
3849 json_object_object_get_ex(json_group, src_str,
3850 &json_source);
3851
3852 if (!json_source) {
3853 json_source = json_object_new_object();
3854 json_object_object_add(json_group, src_str,
3855 json_source);
3856 }
3857
3858 json_object_string_add(json_source, "iif", in_ifname);
3859 json_oil = NULL;
3860 } else {
3861 strlcpy(proto, "STATIC", sizeof(proto));
3862 }
3863
3864 for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
3865 ++oif_vif_index) {
3866 struct interface *ifp_out;
3867 char oif_uptime[10];
3868 int ttl;
3869
3870 ttl = s_route->oif_ttls[oif_vif_index];
3871 if (ttl < 1)
3872 continue;
3873
3874 ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
3875 pim_time_uptime(
3876 oif_uptime, sizeof(oif_uptime),
3877 now - s_route->c_oil
3878 .oif_creation[oif_vif_index]);
3879 found_oif = 1;
3880
3881 if (ifp_out)
3882 strlcpy(out_ifname, ifp_out->name,
3883 sizeof(out_ifname));
3884 else
3885 strlcpy(out_ifname, "<oif?>",
3886 sizeof(out_ifname));
3887
3888 if (json) {
3889 json_ifp_out = json_object_new_object();
3890 json_object_string_add(json_ifp_out, "source",
3891 src_str);
3892 json_object_string_add(json_ifp_out, "group",
3893 grp_str);
3894 json_object_boolean_true_add(json_ifp_out,
3895 "protocolStatic");
3896 json_object_string_add(json_ifp_out,
3897 "inboundInterface",
3898 in_ifname);
3899 json_object_int_add(
3900 json_ifp_out, "iVifI",
3901 *oil_parent(&s_route->c_oil));
3902 json_object_string_add(json_ifp_out,
3903 "outboundInterface",
3904 out_ifname);
3905 json_object_int_add(json_ifp_out, "oVifI",
3906 oif_vif_index);
3907 json_object_int_add(json_ifp_out, "ttl", ttl);
3908 json_object_string_add(json_ifp_out, "upTime",
3909 oif_uptime);
3910 if (!json_oil) {
3911 json_oil = json_object_new_object();
3912 json_object_object_add(json_source,
3913 "oil", json_oil);
3914 }
3915 json_object_object_add(json_oil, out_ifname,
3916 json_ifp_out);
3917 } else {
3918 ttable_add_row(
3919 tt, "%pPAs|%pPAs|%s|%s|%s|%s|%d|%s",
3920 &s_route->source, &s_route->group, "-",
3921 proto, in_ifname, out_ifname, ttl,
3922 oif_uptime);
3923 if (first && !fill) {
3924 src_str[0] = '\0';
3925 grp_str[0] = '\0';
3926 in_ifname[0] = '\0';
3927 first = 0;
3928 }
3929 }
3930 }
3931
3932 if (!json && !found_oif) {
3933 ttable_add_row(tt, "%pPAs|%pPAs|%s|%s|%s|%s|%d|%s",
3934 &s_route->source, &s_route->group, "-",
3935 proto, in_ifname, "none", 0, "--:--:--");
3936 }
3937 }
3938 /* Dump the generated table. */
3939 if (!json) {
3940 table = ttable_dump(tt, "\n");
3941 vty_out(vty, "%s\n", table);
3942 XFREE(MTYPE_TMP, table);
3943 ttable_del(tt);
3944 }
3945 }
3946
3947 static void show_mroute_count_per_channel_oil(struct channel_oil *c_oil,
3948 json_object *json,
3949 struct ttable *tt)
3950 {
3951 json_object *json_group = NULL;
3952 json_object *json_source = NULL;
3953
3954 if (!c_oil->installed)
3955 return;
3956
3957 pim_mroute_update_counters(c_oil);
3958
3959 if (json) {
3960 char group_str[PIM_ADDRSTRLEN];
3961 char source_str[PIM_ADDRSTRLEN];
3962
3963 snprintfrr(group_str, sizeof(group_str), "%pPAs",
3964 oil_mcastgrp(c_oil));
3965 snprintfrr(source_str, sizeof(source_str), "%pPAs",
3966 oil_origin(c_oil));
3967
3968 json_object_object_get_ex(json, group_str, &json_group);
3969
3970 if (!json_group) {
3971 json_group = json_object_new_object();
3972 json_object_object_add(json, group_str, json_group);
3973 }
3974
3975 json_source = json_object_new_object();
3976 json_object_object_add(json_group, source_str, json_source);
3977 json_object_int_add(json_source, "lastUsed",
3978 c_oil->cc.lastused / 100);
3979 json_object_int_add(json_source, "packets", c_oil->cc.pktcnt);
3980 json_object_int_add(json_source, "bytes", c_oil->cc.bytecnt);
3981 json_object_int_add(json_source, "wrongIf", c_oil->cc.wrong_if);
3982
3983 } else {
3984 ttable_add_row(tt, "%pPAs|%pPAs|%llu|%ld|%ld|%ld",
3985 oil_origin(c_oil), oil_mcastgrp(c_oil),
3986 c_oil->cc.lastused / 100,
3987 c_oil->cc.pktcnt - c_oil->cc.origpktcnt,
3988 c_oil->cc.bytecnt - c_oil->cc.origbytecnt,
3989 c_oil->cc.wrong_if - c_oil->cc.origwrong_if);
3990 }
3991 }
3992
3993 void show_mroute_count(struct pim_instance *pim, struct vty *vty,
3994 json_object *json)
3995 {
3996 struct listnode *node;
3997 struct channel_oil *c_oil;
3998 struct static_route *sr;
3999 struct ttable *tt = NULL;
4000 char *table = NULL;
4001
4002 if (!json) {
4003 vty_out(vty, "\n");
4004
4005 /* Prepare table. */
4006 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
4007 ttable_add_row(tt,
4008 "Source|Group|LastUsed|Packets|Bytes|WrongIf");
4009 tt->style.cell.rpad = 2;
4010 tt->style.corner = '+';
4011 ttable_restyle(tt);
4012 }
4013
4014 /* Print PIM and IGMP route counts */
4015 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil)
4016 show_mroute_count_per_channel_oil(c_oil, json, tt);
4017
4018 for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sr))
4019 show_mroute_count_per_channel_oil(&sr->c_oil, json, tt);
4020
4021 /* Dump the generated table. */
4022 if (!json) {
4023 table = ttable_dump(tt, "\n");
4024 vty_out(vty, "%s\n", table);
4025 XFREE(MTYPE_TMP, table);
4026 ttable_del(tt);
4027 }
4028 }
4029
4030 void show_mroute_summary(struct pim_instance *pim, struct vty *vty,
4031 json_object *json)
4032 {
4033 struct listnode *node;
4034 struct channel_oil *c_oil;
4035 struct static_route *s_route;
4036 uint32_t starg_sw_mroute_cnt = 0;
4037 uint32_t sg_sw_mroute_cnt = 0;
4038 uint32_t starg_hw_mroute_cnt = 0;
4039 uint32_t sg_hw_mroute_cnt = 0;
4040 json_object *json_starg = NULL;
4041 json_object *json_sg = NULL;
4042
4043 if (!json)
4044 vty_out(vty, "Mroute Type Installed/Total\n");
4045
4046 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
4047 if (!c_oil->installed) {
4048 if (pim_addr_is_any(*oil_origin(c_oil)))
4049 starg_sw_mroute_cnt++;
4050 else
4051 sg_sw_mroute_cnt++;
4052 } else {
4053 if (pim_addr_is_any(*oil_origin(c_oil)))
4054 starg_hw_mroute_cnt++;
4055 else
4056 sg_hw_mroute_cnt++;
4057 }
4058 }
4059
4060 for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
4061 if (!s_route->c_oil.installed) {
4062 if (pim_addr_is_any(*oil_origin(&s_route->c_oil)))
4063 starg_sw_mroute_cnt++;
4064 else
4065 sg_sw_mroute_cnt++;
4066 } else {
4067 if (pim_addr_is_any(*oil_origin(&s_route->c_oil)))
4068 starg_hw_mroute_cnt++;
4069 else
4070 sg_hw_mroute_cnt++;
4071 }
4072 }
4073
4074 if (!json) {
4075 vty_out(vty, "%-20s %u/%u\n", "(*, G)", starg_hw_mroute_cnt,
4076 starg_sw_mroute_cnt + starg_hw_mroute_cnt);
4077 vty_out(vty, "%-20s %u/%u\n", "(S, G)", sg_hw_mroute_cnt,
4078 sg_sw_mroute_cnt + sg_hw_mroute_cnt);
4079 vty_out(vty, "------\n");
4080 vty_out(vty, "%-20s %u/%u\n", "Total",
4081 (starg_hw_mroute_cnt + sg_hw_mroute_cnt),
4082 (starg_sw_mroute_cnt + starg_hw_mroute_cnt +
4083 sg_sw_mroute_cnt + sg_hw_mroute_cnt));
4084 } else {
4085 /* (*,G) route details */
4086 json_starg = json_object_new_object();
4087 json_object_object_add(json, "wildcardGroup", json_starg);
4088
4089 json_object_int_add(json_starg, "installed",
4090 starg_hw_mroute_cnt);
4091 json_object_int_add(json_starg, "total",
4092 starg_sw_mroute_cnt + starg_hw_mroute_cnt);
4093
4094 /* (S, G) route details */
4095 json_sg = json_object_new_object();
4096 json_object_object_add(json, "sourceGroup", json_sg);
4097
4098 json_object_int_add(json_sg, "installed", sg_hw_mroute_cnt);
4099 json_object_int_add(json_sg, "total",
4100 sg_sw_mroute_cnt + sg_hw_mroute_cnt);
4101
4102 json_object_int_add(json, "totalNumOfInstalledMroutes",
4103 starg_hw_mroute_cnt + sg_hw_mroute_cnt);
4104 json_object_int_add(json, "totalNumOfMroutes",
4105 starg_sw_mroute_cnt + starg_hw_mroute_cnt +
4106 sg_sw_mroute_cnt +
4107 sg_hw_mroute_cnt);
4108 }
4109 }
4110
4111 int clear_ip_mroute_count_command(struct vty *vty, const char *name)
4112 {
4113 struct listnode *node;
4114 struct channel_oil *c_oil;
4115 struct static_route *sr;
4116 struct vrf *v = pim_cmd_lookup(vty, name);
4117 struct pim_instance *pim;
4118
4119 if (!v)
4120 return CMD_WARNING;
4121
4122 pim = v->info;
4123 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
4124 if (!c_oil->installed)
4125 continue;
4126
4127 pim_mroute_update_counters(c_oil);
4128 c_oil->cc.origpktcnt = c_oil->cc.pktcnt;
4129 c_oil->cc.origbytecnt = c_oil->cc.bytecnt;
4130 c_oil->cc.origwrong_if = c_oil->cc.wrong_if;
4131 }
4132
4133 for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sr)) {
4134 if (!sr->c_oil.installed)
4135 continue;
4136
4137 pim_mroute_update_counters(&sr->c_oil);
4138
4139 sr->c_oil.cc.origpktcnt = sr->c_oil.cc.pktcnt;
4140 sr->c_oil.cc.origbytecnt = sr->c_oil.cc.bytecnt;
4141 sr->c_oil.cc.origwrong_if = sr->c_oil.cc.wrong_if;
4142 }
4143 return CMD_SUCCESS;
4144 }
4145
4146 struct vrf *pim_cmd_lookup(struct vty *vty, const char *name)
4147 {
4148 struct vrf *vrf;
4149
4150 if (name)
4151 vrf = vrf_lookup_by_name(name);
4152 else
4153 vrf = vrf_lookup_by_id(VRF_DEFAULT);
4154
4155 if (!vrf)
4156 vty_out(vty, "Specified VRF: %s does not exist\n", name);
4157
4158 return vrf;
4159 }
4160
4161 void clear_mroute(struct pim_instance *pim)
4162 {
4163 struct pim_upstream *up;
4164 struct interface *ifp;
4165
4166 /* scan interfaces */
4167 FOR_ALL_INTERFACES (pim->vrf, ifp) {
4168 struct pim_interface *pim_ifp = ifp->info;
4169 struct pim_ifchannel *ch;
4170
4171 if (!pim_ifp)
4172 continue;
4173
4174 /* deleting all ifchannels */
4175 while (!RB_EMPTY(pim_ifchannel_rb, &pim_ifp->ifchannel_rb)) {
4176 ch = RB_ROOT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb);
4177
4178 pim_ifchannel_delete(ch);
4179 }
4180
4181 #if PIM_IPV == 4
4182 /* clean up all igmp groups */
4183 struct gm_group *grp;
4184
4185 if (pim_ifp->gm_group_list) {
4186 while (pim_ifp->gm_group_list->count) {
4187 grp = listnode_head(pim_ifp->gm_group_list);
4188 igmp_group_delete(grp);
4189 }
4190 }
4191 #else
4192 struct gm_if *gm_ifp;
4193
4194 gm_ifp = pim_ifp->mld;
4195 if (gm_ifp)
4196 gm_group_delete(gm_ifp);
4197 #endif
4198 }
4199
4200 /* clean up all upstreams*/
4201 while ((up = rb_pim_upstream_first(&pim->upstream_head)))
4202 pim_upstream_del(pim, up, __func__);
4203 }
4204
4205 void clear_pim_statistics(struct pim_instance *pim)
4206 {
4207 struct interface *ifp;
4208
4209 pim->bsm_rcvd = 0;
4210 pim->bsm_sent = 0;
4211 pim->bsm_dropped = 0;
4212
4213 /* scan interfaces */
4214 FOR_ALL_INTERFACES (pim->vrf, ifp) {
4215 struct pim_interface *pim_ifp = ifp->info;
4216
4217 if (!pim_ifp)
4218 continue;
4219
4220 pim_ifp->pim_ifstat_bsm_cfg_miss = 0;
4221 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss = 0;
4222 pim_ifp->pim_ifstat_bsm_invalid_sz = 0;
4223 }
4224 }
4225
4226 int clear_pim_interface_traffic(const char *vrf, struct vty *vty)
4227 {
4228 struct interface *ifp = NULL;
4229 struct pim_interface *pim_ifp = NULL;
4230
4231 struct vrf *v = pim_cmd_lookup(vty, vrf);
4232
4233 if (!v)
4234 return CMD_WARNING;
4235
4236 FOR_ALL_INTERFACES (v, ifp) {
4237 pim_ifp = ifp->info;
4238
4239 if (!pim_ifp)
4240 continue;
4241
4242 pim_ifp->pim_ifstat_hello_recv = 0;
4243 pim_ifp->pim_ifstat_hello_sent = 0;
4244 pim_ifp->pim_ifstat_join_recv = 0;
4245 pim_ifp->pim_ifstat_join_send = 0;
4246 pim_ifp->pim_ifstat_prune_recv = 0;
4247 pim_ifp->pim_ifstat_prune_send = 0;
4248 pim_ifp->pim_ifstat_reg_recv = 0;
4249 pim_ifp->pim_ifstat_reg_send = 0;
4250 pim_ifp->pim_ifstat_reg_stop_recv = 0;
4251 pim_ifp->pim_ifstat_reg_stop_send = 0;
4252 pim_ifp->pim_ifstat_assert_recv = 0;
4253 pim_ifp->pim_ifstat_assert_send = 0;
4254 pim_ifp->pim_ifstat_bsm_rx = 0;
4255 pim_ifp->pim_ifstat_bsm_tx = 0;
4256 #if PIM_IPV == 4
4257 pim_ifp->igmp_ifstat_joins_sent = 0;
4258 pim_ifp->igmp_ifstat_joins_failed = 0;
4259 pim_ifp->igmp_peak_group_count = 0;
4260 #endif
4261 }
4262
4263 return CMD_SUCCESS;
4264 }
4265
4266 int pim_debug_pim_cmd(void)
4267 {
4268 PIM_DO_DEBUG_PIM_EVENTS;
4269 PIM_DO_DEBUG_PIM_PACKETS;
4270 PIM_DO_DEBUG_PIM_TRACE;
4271 PIM_DO_DEBUG_MSDP_EVENTS;
4272 PIM_DO_DEBUG_MSDP_PACKETS;
4273 PIM_DO_DEBUG_BSM;
4274 PIM_DO_DEBUG_VXLAN;
4275 return CMD_SUCCESS;
4276 }
4277
4278 int pim_no_debug_pim_cmd(void)
4279 {
4280 PIM_DONT_DEBUG_PIM_EVENTS;
4281 PIM_DONT_DEBUG_PIM_PACKETS;
4282 PIM_DONT_DEBUG_PIM_TRACE;
4283 PIM_DONT_DEBUG_MSDP_EVENTS;
4284 PIM_DONT_DEBUG_MSDP_PACKETS;
4285
4286 PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND;
4287 PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV;
4288 PIM_DONT_DEBUG_BSM;
4289 PIM_DONT_DEBUG_VXLAN;
4290 return CMD_SUCCESS;
4291 }
4292
4293 int pim_debug_pim_packets_cmd(const char *hello, const char *joins,
4294 const char *registers, struct vty *vty)
4295 {
4296 if (hello) {
4297 PIM_DO_DEBUG_PIM_HELLO;
4298 vty_out(vty, "PIM Hello debugging is on\n");
4299 } else if (joins) {
4300 PIM_DO_DEBUG_PIM_J_P;
4301 vty_out(vty, "PIM Join/Prune debugging is on\n");
4302 } else if (registers) {
4303 PIM_DO_DEBUG_PIM_REG;
4304 vty_out(vty, "PIM Register debugging is on\n");
4305 } else {
4306 PIM_DO_DEBUG_PIM_PACKETS;
4307 vty_out(vty, "PIM Packet debugging is on\n");
4308 }
4309 return CMD_SUCCESS;
4310 }
4311
4312 int pim_no_debug_pim_packets_cmd(const char *hello, const char *joins,
4313 const char *registers, struct vty *vty)
4314 {
4315 if (hello) {
4316 PIM_DONT_DEBUG_PIM_HELLO;
4317 vty_out(vty, "PIM Hello debugging is off\n");
4318 } else if (joins) {
4319 PIM_DONT_DEBUG_PIM_J_P;
4320 vty_out(vty, "PIM Join/Prune debugging is off\n");
4321 } else if (registers) {
4322 PIM_DONT_DEBUG_PIM_REG;
4323 vty_out(vty, "PIM Register debugging is off\n");
4324 } else {
4325 PIM_DONT_DEBUG_PIM_PACKETS;
4326 vty_out(vty, "PIM Packet debugging is off\n");
4327 }
4328
4329 return CMD_SUCCESS;
4330 }
4331
4332 int pim_show_rpf_helper(const char *vrf, struct vty *vty, bool json)
4333 {
4334 struct pim_instance *pim;
4335 struct vrf *v;
4336 json_object *json_parent = NULL;
4337
4338 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4339
4340 if (!v)
4341 return CMD_WARNING;
4342
4343 pim = v->info;
4344
4345 if (!pim) {
4346 vty_out(vty, "%% Unable to find pim instance\n");
4347 return CMD_WARNING;
4348 }
4349
4350 if (json)
4351 json_parent = json_object_new_object();
4352
4353 pim_show_rpf(pim, vty, json_parent);
4354
4355 if (json)
4356 vty_json(vty, json_parent);
4357
4358 return CMD_SUCCESS;
4359 }
4360
4361 int pim_show_rpf_vrf_all_helper(struct vty *vty, bool json)
4362 {
4363 struct vrf *vrf;
4364 json_object *json_parent = NULL;
4365 json_object *json_vrf = NULL;
4366
4367 if (json)
4368 json_parent = json_object_new_object();
4369
4370 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4371 if (!json)
4372 vty_out(vty, "VRF: %s\n", vrf->name);
4373 else
4374 json_vrf = json_object_new_object();
4375 pim_show_rpf(vrf->info, vty, json_vrf);
4376 if (json)
4377 json_object_object_add(json_parent, vrf->name,
4378 json_vrf);
4379 }
4380 if (json)
4381 vty_json(vty, json_parent);
4382
4383 return CMD_SUCCESS;
4384 }
4385
4386 int pim_show_rp_helper(const char *vrf, struct vty *vty, const char *group_str,
4387 const struct prefix *group, bool json)
4388 {
4389 struct pim_instance *pim;
4390 struct vrf *v;
4391 json_object *json_parent = NULL;
4392 struct prefix *range = NULL;
4393
4394 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4395
4396 if (!v)
4397 return CMD_WARNING;
4398
4399 pim = v->info;
4400
4401 if (!pim) {
4402 vty_out(vty, "%% Unable to find pim instance\n");
4403 return CMD_WARNING;
4404 }
4405
4406 if (group_str) {
4407 range = prefix_new();
4408 prefix_copy(range, group);
4409 apply_mask(range);
4410 }
4411
4412 if (json)
4413 json_parent = json_object_new_object();
4414
4415 pim_rp_show_information(pim, range, vty, json_parent);
4416
4417 if (json)
4418 vty_json(vty, json_parent);
4419
4420 prefix_free(&range);
4421
4422 return CMD_SUCCESS;
4423 }
4424
4425 int pim_show_rp_vrf_all_helper(struct vty *vty, const char *group_str,
4426 const struct prefix *group, bool json)
4427 {
4428 struct vrf *vrf;
4429 json_object *json_parent = NULL;
4430 json_object *json_vrf = NULL;
4431 struct prefix *range = NULL;
4432
4433 if (group_str) {
4434 range = prefix_new();
4435 prefix_copy(range, group);
4436 apply_mask(range);
4437 }
4438
4439 if (json)
4440 json_parent = json_object_new_object();
4441
4442 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4443 if (!json)
4444 vty_out(vty, "VRF: %s\n", vrf->name);
4445 else
4446 json_vrf = json_object_new_object();
4447 pim_rp_show_information(vrf->info, range, vty, json_vrf);
4448 if (json)
4449 json_object_object_add(json_parent, vrf->name,
4450 json_vrf);
4451 }
4452 if (json)
4453 vty_json(vty, json_parent);
4454
4455 prefix_free(&range);
4456
4457 return CMD_SUCCESS;
4458 }
4459
4460 int pim_show_secondary_helper(const char *vrf, struct vty *vty)
4461 {
4462 struct pim_instance *pim;
4463 struct vrf *v;
4464
4465 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4466
4467 if (!v)
4468 return CMD_WARNING;
4469
4470 pim = v->info;
4471
4472 if (!pim) {
4473 vty_out(vty, "%% Unable to find pim instance\n");
4474 return CMD_WARNING;
4475 }
4476
4477 pim_show_neighbors_secondary(pim, vty);
4478
4479 return CMD_SUCCESS;
4480 }
4481
4482 int pim_show_statistics_helper(const char *vrf, struct vty *vty,
4483 const char *word, bool uj)
4484 {
4485 struct pim_instance *pim;
4486 struct vrf *v;
4487
4488 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4489
4490 if (!v)
4491 return CMD_WARNING;
4492
4493 pim = v->info;
4494
4495 if (!pim) {
4496 vty_out(vty, "%% Unable to find pim instance\n");
4497 return CMD_WARNING;
4498 }
4499
4500 if (word)
4501 pim_show_statistics(pim, vty, word, uj);
4502 else
4503 pim_show_statistics(pim, vty, NULL, uj);
4504
4505 return CMD_SUCCESS;
4506 }
4507
4508 int pim_show_upstream_helper(const char *vrf, struct vty *vty, pim_addr s_or_g,
4509 pim_addr g, bool json)
4510 {
4511 pim_sgaddr sg = {0};
4512 struct vrf *v;
4513 struct pim_instance *pim;
4514 json_object *json_parent = NULL;
4515
4516 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4517
4518 if (!v) {
4519 vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
4520 return CMD_WARNING;
4521 }
4522 pim = v->info;
4523
4524 if (!pim) {
4525 vty_out(vty, "%% Unable to find pim instance\n");
4526 return CMD_WARNING;
4527 }
4528
4529 if (json)
4530 json_parent = json_object_new_object();
4531
4532 if (!pim_addr_is_any(s_or_g)) {
4533 if (!pim_addr_is_any(g)) {
4534 sg.src = s_or_g;
4535 sg.grp = g;
4536 } else
4537 sg.grp = s_or_g;
4538 }
4539
4540 pim_show_upstream(pim, vty, &sg, json_parent);
4541
4542 if (json)
4543 vty_json(vty, json_parent);
4544
4545 return CMD_SUCCESS;
4546 }
4547
4548 int pim_show_upstream_vrf_all_helper(struct vty *vty, bool json)
4549 {
4550 pim_sgaddr sg = {0};
4551 struct vrf *vrf;
4552 json_object *json_parent = NULL;
4553 json_object *json_vrf = NULL;
4554
4555 if (json)
4556 json_parent = json_object_new_object();
4557
4558 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4559 if (!json)
4560 vty_out(vty, "VRF: %s\n", vrf->name);
4561 else
4562 json_vrf = json_object_new_object();
4563 pim_show_upstream(vrf->info, vty, &sg, json_vrf);
4564 if (json)
4565 json_object_object_add(json_parent, vrf->name,
4566 json_vrf);
4567 }
4568
4569 if (json)
4570 vty_json(vty, json_parent);
4571
4572 return CMD_SUCCESS;
4573 }
4574
4575 int pim_show_upstream_join_desired_helper(const char *vrf, struct vty *vty,
4576 bool uj)
4577 {
4578 struct pim_instance *pim;
4579 struct vrf *v;
4580
4581 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4582
4583 if (!v)
4584 return CMD_WARNING;
4585
4586 pim = v->info;
4587
4588 if (!pim) {
4589 vty_out(vty, "%% Unable to find pim instance\n");
4590 return CMD_WARNING;
4591 }
4592
4593 pim_show_join_desired(pim, vty, uj);
4594
4595 return CMD_SUCCESS;
4596 }
4597
4598 int pim_show_upstream_rpf_helper(const char *vrf, struct vty *vty, bool uj)
4599 {
4600 struct pim_instance *pim;
4601 struct vrf *v;
4602
4603 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4604
4605 if (!v)
4606 return CMD_WARNING;
4607
4608 pim = v->info;
4609
4610 if (!pim) {
4611 vty_out(vty, "%% Unable to find pim instance\n");
4612 return CMD_WARNING;
4613 }
4614
4615 pim_show_upstream_rpf(pim, vty, uj);
4616
4617 return CMD_SUCCESS;
4618 }
4619
4620 int pim_show_state_helper(const char *vrf, struct vty *vty,
4621 const char *s_or_g_str, const char *g_str, bool json)
4622 {
4623 struct pim_instance *pim;
4624 struct vrf *v;
4625 json_object *json_parent = NULL;
4626
4627 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4628
4629 if (!v)
4630 return CMD_WARNING;
4631
4632 pim = v->info;
4633
4634 if (!pim) {
4635 vty_out(vty, "%% Unable to find pim instance\n");
4636 return CMD_WARNING;
4637 }
4638
4639 if (json)
4640 json_parent = json_object_new_object();
4641
4642 pim_show_state(pim, vty, s_or_g_str, g_str, json_parent);
4643
4644 if (json)
4645 vty_json(vty, json_parent);
4646
4647 return CMD_SUCCESS;
4648 }
4649
4650 int pim_show_state_vrf_all_helper(struct vty *vty, const char *s_or_g_str,
4651 const char *g_str, bool json)
4652 {
4653 struct vrf *vrf;
4654 json_object *json_parent = NULL;
4655 json_object *json_vrf = NULL;
4656
4657 if (json)
4658 json_parent = json_object_new_object();
4659
4660 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4661 if (!json)
4662 vty_out(vty, "VRF: %s\n", vrf->name);
4663 else
4664 json_vrf = json_object_new_object();
4665 pim_show_state(vrf->info, vty, s_or_g_str, g_str, json_vrf);
4666 if (json)
4667 json_object_object_add(json_parent, vrf->name,
4668 json_vrf);
4669 }
4670 if (json)
4671 vty_json(vty, json_parent);
4672
4673 return CMD_SUCCESS;
4674 }
4675
4676 int pim_show_multicast_helper(const char *vrf, struct vty *vty)
4677 {
4678 struct vrf *v;
4679 struct pim_instance *pim;
4680
4681 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4682
4683 if (!v)
4684 return CMD_WARNING;
4685
4686 pim = v->info;
4687
4688 if (!pim) {
4689 vty_out(vty, "%% Unable to find pim instance\n");
4690 return CMD_WARNING;
4691 }
4692
4693 pim_cmd_show_ip_multicast_helper(pim, vty);
4694
4695 return CMD_SUCCESS;
4696 }
4697
4698 int pim_show_multicast_vrf_all_helper(struct vty *vty)
4699 {
4700 struct vrf *vrf;
4701
4702 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4703 vty_out(vty, "VRF: %s\n", vrf->name);
4704 pim_cmd_show_ip_multicast_helper(vrf->info, vty);
4705 }
4706
4707 return CMD_SUCCESS;
4708 }
4709
4710 int pim_show_multicast_count_helper(const char *vrf, struct vty *vty, bool json)
4711 {
4712 struct pim_instance *pim;
4713 struct vrf *v;
4714 json_object *json_parent = NULL;
4715
4716 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4717
4718 if (!v)
4719 return CMD_WARNING;
4720
4721 pim = v->info;
4722
4723 if (!pim) {
4724 vty_out(vty, "%% Unable to find pim instance\n");
4725 return CMD_WARNING;
4726 }
4727
4728 if (json)
4729 json_parent = json_object_new_object();
4730
4731 show_multicast_interfaces(pim, vty, json_parent);
4732
4733 if (json)
4734 vty_json(vty, json_parent);
4735
4736 return CMD_SUCCESS;
4737 }
4738
4739 int pim_show_multicast_count_vrf_all_helper(struct vty *vty, bool json)
4740 {
4741 struct vrf *vrf;
4742 json_object *json_parent = NULL;
4743 json_object *json_vrf = NULL;
4744
4745 if (json)
4746 json_parent = json_object_new_object();
4747
4748 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4749 if (!json)
4750 vty_out(vty, "VRF: %s\n", vrf->name);
4751 else
4752 json_vrf = json_object_new_object();
4753
4754 show_multicast_interfaces(vrf->info, vty, json_vrf);
4755 if (json)
4756 json_object_object_add(json_parent, vrf->name,
4757 json_vrf);
4758 }
4759 if (json)
4760 vty_json(vty, json_parent);
4761
4762 return CMD_SUCCESS;
4763 }
4764
4765 int pim_show_mroute_helper(const char *vrf, struct vty *vty, pim_addr s_or_g,
4766 pim_addr g, bool fill, bool json)
4767 {
4768 pim_sgaddr sg = {0};
4769 struct pim_instance *pim;
4770 struct vrf *v;
4771 json_object *json_parent = NULL;
4772
4773 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4774
4775 if (!v)
4776 return CMD_WARNING;
4777
4778 pim = v->info;
4779
4780 if (!pim) {
4781 vty_out(vty, "%% Unable to find pim instance\n");
4782 return CMD_WARNING;
4783 }
4784
4785 if (json)
4786 json_parent = json_object_new_object();
4787
4788 if (!pim_addr_is_any(s_or_g)) {
4789 if (!pim_addr_is_any(g)) {
4790 sg.src = s_or_g;
4791 sg.grp = g;
4792 } else
4793 sg.grp = s_or_g;
4794 }
4795
4796 show_mroute(pim, vty, &sg, fill, json_parent);
4797
4798 if (json)
4799 vty_json(vty, json_parent);
4800
4801 return CMD_SUCCESS;
4802 }
4803
4804 int pim_show_mroute_vrf_all_helper(struct vty *vty, bool fill, bool json)
4805 {
4806 pim_sgaddr sg = {0};
4807 struct vrf *vrf;
4808 json_object *json_parent = NULL;
4809 json_object *json_vrf = NULL;
4810
4811 if (json)
4812 json_parent = json_object_new_object();
4813
4814 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4815 if (!json)
4816 vty_out(vty, "VRF: %s\n", vrf->name);
4817 else
4818 json_vrf = json_object_new_object();
4819 show_mroute(vrf->info, vty, &sg, fill, json_vrf);
4820 if (json)
4821 json_object_object_add(json_parent, vrf->name,
4822 json_vrf);
4823 }
4824 if (json)
4825 vty_json(vty, json_parent);
4826
4827 return CMD_SUCCESS;
4828 }
4829
4830 int pim_show_mroute_count_helper(const char *vrf, struct vty *vty, bool json)
4831 {
4832 struct pim_instance *pim;
4833 struct vrf *v;
4834 json_object *json_parent = NULL;
4835
4836 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4837
4838 if (!v)
4839 return CMD_WARNING;
4840
4841 pim = v->info;
4842
4843 if (!pim) {
4844 vty_out(vty, "%% Unable to find pim instance\n");
4845 return CMD_WARNING;
4846 }
4847
4848 if (json)
4849 json_parent = json_object_new_object();
4850
4851 show_mroute_count(pim, vty, json_parent);
4852
4853 if (json)
4854 vty_json(vty, json_parent);
4855
4856 return CMD_SUCCESS;
4857 }
4858
4859 int pim_show_mroute_count_vrf_all_helper(struct vty *vty, bool json)
4860 {
4861 struct vrf *vrf;
4862 json_object *json_parent = NULL;
4863 json_object *json_vrf = NULL;
4864
4865 if (json)
4866 json_parent = json_object_new_object();
4867
4868 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4869 if (!json)
4870 vty_out(vty, "VRF: %s\n", vrf->name);
4871 else
4872 json_vrf = json_object_new_object();
4873
4874 show_mroute_count(vrf->info, vty, json_vrf);
4875
4876 if (json)
4877 json_object_object_add(json_parent, vrf->name,
4878 json_vrf);
4879 }
4880 if (json)
4881 vty_json(vty, json_parent);
4882
4883 return CMD_SUCCESS;
4884 }
4885
4886 int pim_show_mroute_summary_helper(const char *vrf, struct vty *vty, bool json)
4887 {
4888 struct pim_instance *pim;
4889 struct vrf *v;
4890 json_object *json_parent = NULL;
4891
4892 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4893
4894 if (!v)
4895 return CMD_WARNING;
4896
4897 pim = v->info;
4898
4899 if (!pim) {
4900 vty_out(vty, "%% Unable to find pim instance\n");
4901 return CMD_WARNING;
4902 }
4903
4904 if (json)
4905 json_parent = json_object_new_object();
4906
4907 show_mroute_summary(pim, vty, json_parent);
4908
4909 if (json)
4910 vty_json(vty, json_parent);
4911
4912 return CMD_SUCCESS;
4913 }
4914
4915 int pim_show_mroute_summary_vrf_all_helper(struct vty *vty, bool json)
4916 {
4917 struct vrf *vrf;
4918 json_object *json_parent = NULL;
4919 json_object *json_vrf = NULL;
4920
4921 if (json)
4922 json_parent = json_object_new_object();
4923
4924 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4925 if (!json)
4926 vty_out(vty, "VRF: %s\n", vrf->name);
4927 else
4928 json_vrf = json_object_new_object();
4929
4930 show_mroute_summary(vrf->info, vty, json_vrf);
4931
4932 if (json)
4933 json_object_object_add(json_parent, vrf->name,
4934 json_vrf);
4935 }
4936
4937 if (json)
4938 vty_json(vty, json_parent);
4939
4940 return CMD_SUCCESS;
4941 }
4942
4943 void pim_show_interface_traffic(struct pim_instance *pim, struct vty *vty,
4944 bool uj)
4945 {
4946 struct interface *ifp = NULL;
4947 struct pim_interface *pim_ifp = NULL;
4948 json_object *json = NULL;
4949 json_object *json_row = NULL;
4950
4951 if (uj)
4952 json = json_object_new_object();
4953 else {
4954 vty_out(vty, "\n");
4955 vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n",
4956 "Interface", " HELLO", " JOIN",
4957 " PRUNE", " REGISTER", "REGISTER-STOP",
4958 " ASSERT", " BSM");
4959 vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n", "",
4960 " Rx/Tx", " Rx/Tx", " Rx/Tx",
4961 " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx");
4962 vty_out(vty,
4963 "---------------------------------------------------------------------------------------------------------------\n");
4964 }
4965
4966 FOR_ALL_INTERFACES (pim->vrf, ifp) {
4967 pim_ifp = ifp->info;
4968
4969 if (!pim_ifp)
4970 continue;
4971
4972 if (uj) {
4973 json_row = json_object_new_object();
4974 json_object_pim_ifp_add(json_row, ifp);
4975 json_object_int_add(json_row, "helloRx",
4976 pim_ifp->pim_ifstat_hello_recv);
4977 json_object_int_add(json_row, "helloTx",
4978 pim_ifp->pim_ifstat_hello_sent);
4979 json_object_int_add(json_row, "joinRx",
4980 pim_ifp->pim_ifstat_join_recv);
4981 json_object_int_add(json_row, "joinTx",
4982 pim_ifp->pim_ifstat_join_send);
4983 json_object_int_add(json_row, "pruneRx",
4984 pim_ifp->pim_ifstat_prune_recv);
4985 json_object_int_add(json_row, "pruneTx",
4986 pim_ifp->pim_ifstat_prune_send);
4987 json_object_int_add(json_row, "registerRx",
4988 pim_ifp->pim_ifstat_reg_recv);
4989 json_object_int_add(json_row, "registerTx",
4990 pim_ifp->pim_ifstat_reg_send);
4991 json_object_int_add(json_row, "registerStopRx",
4992 pim_ifp->pim_ifstat_reg_stop_recv);
4993 json_object_int_add(json_row, "registerStopTx",
4994 pim_ifp->pim_ifstat_reg_stop_send);
4995 json_object_int_add(json_row, "assertRx",
4996 pim_ifp->pim_ifstat_assert_recv);
4997 json_object_int_add(json_row, "assertTx",
4998 pim_ifp->pim_ifstat_assert_send);
4999 json_object_int_add(json_row, "bsmRx",
5000 pim_ifp->pim_ifstat_bsm_rx);
5001 json_object_int_add(json_row, "bsmTx",
5002 pim_ifp->pim_ifstat_bsm_tx);
5003 json_object_object_add(json, ifp->name, json_row);
5004 } else {
5005 vty_out(vty,
5006 "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7" PRIu64
5007 "/%-7" PRIu64 "\n",
5008 ifp->name, pim_ifp->pim_ifstat_hello_recv,
5009 pim_ifp->pim_ifstat_hello_sent,
5010 pim_ifp->pim_ifstat_join_recv,
5011 pim_ifp->pim_ifstat_join_send,
5012 pim_ifp->pim_ifstat_prune_recv,
5013 pim_ifp->pim_ifstat_prune_send,
5014 pim_ifp->pim_ifstat_reg_recv,
5015 pim_ifp->pim_ifstat_reg_send,
5016 pim_ifp->pim_ifstat_reg_stop_recv,
5017 pim_ifp->pim_ifstat_reg_stop_send,
5018 pim_ifp->pim_ifstat_assert_recv,
5019 pim_ifp->pim_ifstat_assert_send,
5020 pim_ifp->pim_ifstat_bsm_rx,
5021 pim_ifp->pim_ifstat_bsm_tx);
5022 }
5023 }
5024 if (uj)
5025 vty_json(vty, json);
5026 }
5027
5028 void pim_show_interface_traffic_single(struct pim_instance *pim,
5029 struct vty *vty, const char *ifname,
5030 bool uj)
5031 {
5032 struct interface *ifp = NULL;
5033 struct pim_interface *pim_ifp = NULL;
5034 json_object *json = NULL;
5035 json_object *json_row = NULL;
5036 uint8_t found_ifname = 0;
5037
5038 if (uj)
5039 json = json_object_new_object();
5040 else {
5041 vty_out(vty, "\n");
5042 vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n",
5043 "Interface", " HELLO", " JOIN", " PRUNE",
5044 " REGISTER", " REGISTER-STOP", " ASSERT",
5045 " BSM");
5046 vty_out(vty, "%-14s%-18s%-17s%-17s%-17s%-17s%-17s%-17s\n", "",
5047 " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx",
5048 " Rx/Tx", " Rx/Tx", " Rx/Tx");
5049 vty_out(vty,
5050 "-------------------------------------------------------------------------------------------------------------------------------\n");
5051 }
5052
5053 FOR_ALL_INTERFACES (pim->vrf, ifp) {
5054 if (strcmp(ifname, ifp->name))
5055 continue;
5056
5057 pim_ifp = ifp->info;
5058
5059 if (!pim_ifp)
5060 continue;
5061
5062 found_ifname = 1;
5063 if (uj) {
5064 json_row = json_object_new_object();
5065 json_object_pim_ifp_add(json_row, ifp);
5066 json_object_int_add(json_row, "helloRx",
5067 pim_ifp->pim_ifstat_hello_recv);
5068 json_object_int_add(json_row, "helloTx",
5069 pim_ifp->pim_ifstat_hello_sent);
5070 json_object_int_add(json_row, "joinRx",
5071 pim_ifp->pim_ifstat_join_recv);
5072 json_object_int_add(json_row, "joinTx",
5073 pim_ifp->pim_ifstat_join_send);
5074 json_object_int_add(json_row, "pruneRx",
5075 pim_ifp->pim_ifstat_prune_recv);
5076 json_object_int_add(json_row, "pruneTx",
5077 pim_ifp->pim_ifstat_prune_send);
5078 json_object_int_add(json_row, "registerRx",
5079 pim_ifp->pim_ifstat_reg_recv);
5080 json_object_int_add(json_row, "registerTx",
5081 pim_ifp->pim_ifstat_reg_send);
5082 json_object_int_add(json_row, "registerStopRx",
5083 pim_ifp->pim_ifstat_reg_stop_recv);
5084 json_object_int_add(json_row, "registerStopTx",
5085 pim_ifp->pim_ifstat_reg_stop_send);
5086 json_object_int_add(json_row, "assertRx",
5087 pim_ifp->pim_ifstat_assert_recv);
5088 json_object_int_add(json_row, "assertTx",
5089 pim_ifp->pim_ifstat_assert_send);
5090 json_object_int_add(json_row, "bsmRx",
5091 pim_ifp->pim_ifstat_bsm_rx);
5092 json_object_int_add(json_row, "bsmTx",
5093 pim_ifp->pim_ifstat_bsm_tx);
5094
5095 json_object_object_add(json, ifp->name, json_row);
5096 } else {
5097 vty_out(vty,
5098 "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7" PRIu64
5099 "/%-7" PRIu64 "\n",
5100 ifp->name, pim_ifp->pim_ifstat_hello_recv,
5101 pim_ifp->pim_ifstat_hello_sent,
5102 pim_ifp->pim_ifstat_join_recv,
5103 pim_ifp->pim_ifstat_join_send,
5104 pim_ifp->pim_ifstat_prune_recv,
5105 pim_ifp->pim_ifstat_prune_send,
5106 pim_ifp->pim_ifstat_reg_recv,
5107 pim_ifp->pim_ifstat_reg_send,
5108 pim_ifp->pim_ifstat_reg_stop_recv,
5109 pim_ifp->pim_ifstat_reg_stop_send,
5110 pim_ifp->pim_ifstat_assert_recv,
5111 pim_ifp->pim_ifstat_assert_send,
5112 pim_ifp->pim_ifstat_bsm_rx,
5113 pim_ifp->pim_ifstat_bsm_tx);
5114 }
5115 }
5116 if (uj)
5117 vty_json(vty, json);
5118 else if (!found_ifname)
5119 vty_out(vty, "%% No such interface\n");
5120 }
5121
5122 int pim_show_interface_traffic_helper(const char *vrf, const char *if_name,
5123 struct vty *vty, bool uj)
5124 {
5125 struct pim_instance *pim;
5126 struct vrf *v;
5127
5128 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
5129
5130 if (!v)
5131 return CMD_WARNING;
5132
5133 pim = v->info;
5134
5135 if (!pim) {
5136 vty_out(vty, "%% Unable to find pim instance\n");
5137 return CMD_WARNING;
5138 }
5139
5140 if (if_name)
5141 pim_show_interface_traffic_single(v->info, vty, if_name, uj);
5142 else
5143 pim_show_interface_traffic(v->info, vty, uj);
5144
5145 return CMD_SUCCESS;
5146 }
5147
5148 void clear_pim_interfaces(struct pim_instance *pim)
5149 {
5150 struct interface *ifp;
5151
5152 FOR_ALL_INTERFACES (pim->vrf, ifp) {
5153 if (ifp->info)
5154 pim_neighbor_delete_all(ifp, "interface cleared");
5155 }
5156 }