]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_cmd_common.c
pim6d: Add [no] ipv6 pim unicast-bsm" command
[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 #if PIM_IPV != 4
1031 struct ttable *tt = NULL;
1032 char *table = NULL;
1033 #endif
1034 char flag[50];
1035 json_object *json_group = NULL;
1036 json_object *json_ifp_in = NULL;
1037 json_object *json_ifp_out = NULL;
1038 json_object *json_source = NULL;
1039 time_t now;
1040 int first_oif;
1041
1042 now = pim_time_monotonic_sec();
1043
1044 if (!json) {
1045 vty_out(vty,
1046 "Codes: J -> Pim Join, I -> " GM " Report, S -> Source, * -> Inherited from (*,G), V -> VxLAN, M -> Muted\n");
1047 #if PIM_IPV == 4
1048 vty_out(vty,
1049 "Active Source Group RPT IIF OIL\n");
1050 #else
1051 /* Prepare table. */
1052 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
1053 ttable_add_row(tt, "Active|Source|Group|RPT|IIF|OIL");
1054 tt->style.cell.rpad = 2;
1055 tt->style.corner = '+';
1056 ttable_restyle(tt);
1057 #endif
1058 }
1059
1060 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
1061 char src_str[PIM_ADDRSTRLEN];
1062 char grp_str[PIM_ADDRSTRLEN];
1063 char in_ifname[INTERFACE_NAMSIZ + 1];
1064 char out_ifname[INTERFACE_NAMSIZ + 1];
1065 int oif_vif_index;
1066 struct interface *ifp_in;
1067 bool isRpt;
1068
1069 first_oif = 1;
1070
1071 if ((c_oil->up &&
1072 PIM_UPSTREAM_FLAG_TEST_USE_RPT(c_oil->up->flags)) ||
1073 pim_addr_is_any(*oil_origin(c_oil)))
1074 isRpt = true;
1075 else
1076 isRpt = false;
1077
1078 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
1079 oil_mcastgrp(c_oil));
1080 snprintfrr(src_str, sizeof(src_str), "%pPAs",
1081 oil_origin(c_oil));
1082 ifp_in = pim_if_find_by_vif_index(pim, *oil_parent(c_oil));
1083
1084 if (ifp_in)
1085 strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
1086 else
1087 strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
1088
1089 if (src_or_group) {
1090 if (strcmp(src_or_group, src_str) &&
1091 strcmp(src_or_group, grp_str))
1092 continue;
1093
1094 if (group && strcmp(group, grp_str))
1095 continue;
1096 }
1097
1098 if (json) {
1099
1100 /* Find the group, create it if it doesn't exist */
1101 json_object_object_get_ex(json, grp_str, &json_group);
1102
1103 if (!json_group) {
1104 json_group = json_object_new_object();
1105 json_object_object_add(json, grp_str,
1106 json_group);
1107 }
1108
1109 /* Find the source nested under the group, create it if
1110 * it doesn't exist
1111 */
1112 json_object_object_get_ex(json_group, src_str,
1113 &json_source);
1114
1115 if (!json_source) {
1116 json_source = json_object_new_object();
1117 json_object_object_add(json_group, src_str,
1118 json_source);
1119 }
1120
1121 /* Find the inbound interface nested under the source,
1122 * create it if it doesn't exist
1123 */
1124 json_object_object_get_ex(json_source, in_ifname,
1125 &json_ifp_in);
1126
1127 if (!json_ifp_in) {
1128 json_ifp_in = json_object_new_object();
1129 json_object_object_add(json_source, in_ifname,
1130 json_ifp_in);
1131 json_object_int_add(json_source, "Installed",
1132 c_oil->installed);
1133 json_object_int_add(json_source, "installed",
1134 c_oil->installed);
1135 json_object_boolean_add(json_source, "isRpt",
1136 isRpt);
1137 json_object_int_add(json_source, "RefCount",
1138 c_oil->oil_ref_count);
1139 json_object_int_add(json_source, "refCount",
1140 c_oil->oil_ref_count);
1141 json_object_int_add(json_source, "OilListSize",
1142 c_oil->oil_size);
1143 json_object_int_add(json_source, "oilListSize",
1144 c_oil->oil_size);
1145 json_object_int_add(
1146 json_source, "OilRescan",
1147 c_oil->oil_inherited_rescan);
1148 json_object_int_add(
1149 json_source, "oilRescan",
1150 c_oil->oil_inherited_rescan);
1151 json_object_int_add(json_source, "LastUsed",
1152 c_oil->cc.lastused);
1153 json_object_int_add(json_source, "lastUsed",
1154 c_oil->cc.lastused);
1155 json_object_int_add(json_source, "PacketCount",
1156 c_oil->cc.pktcnt);
1157 json_object_int_add(json_source, "packetCount",
1158 c_oil->cc.pktcnt);
1159 json_object_int_add(json_source, "ByteCount",
1160 c_oil->cc.bytecnt);
1161 json_object_int_add(json_source, "byteCount",
1162 c_oil->cc.bytecnt);
1163 json_object_int_add(json_source,
1164 "WrongInterface",
1165 c_oil->cc.wrong_if);
1166 json_object_int_add(json_source,
1167 "wrongInterface",
1168 c_oil->cc.wrong_if);
1169 }
1170 }
1171 #if PIM_IPV == 4
1172 else
1173 vty_out(vty, "%-6d %-15pPAs %-15pPAs %-3s %-16s ",
1174 c_oil->installed, oil_origin(c_oil),
1175 oil_mcastgrp(c_oil), isRpt ? "y" : "n",
1176 in_ifname);
1177 #endif
1178
1179 for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
1180 ++oif_vif_index) {
1181 struct interface *ifp_out;
1182 char oif_uptime[10];
1183 int ttl;
1184
1185 ttl = oil_if_has(c_oil, oif_vif_index);
1186 if (ttl < 1)
1187 continue;
1188
1189 ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
1190 pim_time_uptime(
1191 oif_uptime, sizeof(oif_uptime),
1192 now - c_oil->oif_creation[oif_vif_index]);
1193
1194 if (ifp_out)
1195 strlcpy(out_ifname, ifp_out->name,
1196 sizeof(out_ifname));
1197 else
1198 strlcpy(out_ifname, "<oif?>",
1199 sizeof(out_ifname));
1200
1201 if (json) {
1202 json_ifp_out = json_object_new_object();
1203 json_object_string_add(json_ifp_out, "source",
1204 src_str);
1205 json_object_string_add(json_ifp_out, "group",
1206 grp_str);
1207 json_object_string_add(json_ifp_out,
1208 "inboundInterface",
1209 in_ifname);
1210 json_object_string_add(json_ifp_out,
1211 "outboundInterface",
1212 out_ifname);
1213 json_object_int_add(json_ifp_out, "installed",
1214 c_oil->installed);
1215
1216 json_object_object_add(json_ifp_in, out_ifname,
1217 json_ifp_out);
1218 } else {
1219 flag[0] = '\0';
1220 snprintf(flag, sizeof(flag), "(%c%c%c%c%c)",
1221 (c_oil->oif_flags[oif_vif_index] &
1222 PIM_OIF_FLAG_PROTO_GM)
1223 ? 'I'
1224 : ' ',
1225 (c_oil->oif_flags[oif_vif_index] &
1226 PIM_OIF_FLAG_PROTO_PIM)
1227 ? 'J'
1228 : ' ',
1229 (c_oil->oif_flags[oif_vif_index] &
1230 PIM_OIF_FLAG_PROTO_VXLAN)
1231 ? 'V'
1232 : ' ',
1233 (c_oil->oif_flags[oif_vif_index] &
1234 PIM_OIF_FLAG_PROTO_STAR)
1235 ? '*'
1236 : ' ',
1237 (c_oil->oif_flags[oif_vif_index] &
1238 PIM_OIF_FLAG_MUTE)
1239 ? 'M'
1240 : ' ');
1241
1242 if (first_oif) {
1243 first_oif = 0;
1244 #if PIM_IPV == 4
1245 vty_out(vty, "%s%s", out_ifname, flag);
1246 #else
1247 ttable_add_row(
1248 tt, "%d|%pPAs|%pPAs|%s|%s|%s%s",
1249 c_oil->installed,
1250 oil_origin(c_oil),
1251 oil_mcastgrp(c_oil),
1252 isRpt ? "y" : "n", in_ifname,
1253 out_ifname, flag);
1254 #endif
1255 } else {
1256 #if PIM_IPV == 4
1257 vty_out(vty, ", %s%s", out_ifname,
1258 flag);
1259 #else
1260 ttable_add_row(tt,
1261 "%c|%c|%c|%c|%c|%s%s",
1262 ' ', ' ', ' ', ' ', ' ',
1263 out_ifname, flag);
1264 #endif
1265 }
1266 }
1267 }
1268 #if PIM_IPV == 4
1269 if (!json)
1270 vty_out(vty, "\n");
1271 #endif
1272 }
1273
1274 /* Dump the generated table. */
1275 if (!json) {
1276 #if PIM_IPV == 4
1277 vty_out(vty, "\n");
1278 #else
1279 table = ttable_dump(tt, "\n");
1280 vty_out(vty, "%s\n", table);
1281 XFREE(MTYPE_TMP, table);
1282 ttable_del(tt);
1283 #endif
1284 }
1285 }
1286
1287 /* pim statistics - just adding only bsm related now.
1288 * We can continue to add all pim related stats here.
1289 */
1290 void pim_show_statistics(struct pim_instance *pim, struct vty *vty,
1291 const char *ifname, bool uj)
1292 {
1293 json_object *json = NULL;
1294 struct interface *ifp;
1295
1296 if (uj) {
1297 json = json_object_new_object();
1298 json_object_int_add(json, "bsmRx", pim->bsm_rcvd);
1299 json_object_int_add(json, "bsmTx", pim->bsm_sent);
1300 json_object_int_add(json, "bsmDropped", pim->bsm_dropped);
1301 } else {
1302 vty_out(vty, "BSM Statistics :\n");
1303 vty_out(vty, "----------------\n");
1304 vty_out(vty, "Number of Received BSMs : %" PRIu64 "\n",
1305 pim->bsm_rcvd);
1306 vty_out(vty, "Number of Forwared BSMs : %" PRIu64 "\n",
1307 pim->bsm_sent);
1308 vty_out(vty, "Number of Dropped BSMs : %" PRIu64 "\n",
1309 pim->bsm_dropped);
1310 }
1311
1312 vty_out(vty, "\n");
1313
1314 /* scan interfaces */
1315 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1316 struct pim_interface *pim_ifp = ifp->info;
1317
1318 if (ifname && strcmp(ifname, ifp->name))
1319 continue;
1320
1321 if (!pim_ifp)
1322 continue;
1323
1324 if (!uj) {
1325 vty_out(vty, "Interface : %s\n", ifp->name);
1326 vty_out(vty, "-------------------\n");
1327 vty_out(vty,
1328 "Number of BSMs dropped due to config miss : %u\n",
1329 pim_ifp->pim_ifstat_bsm_cfg_miss);
1330 vty_out(vty, "Number of unicast BSMs dropped : %u\n",
1331 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss);
1332 vty_out(vty,
1333 "Number of BSMs dropped due to invalid scope zone : %u\n",
1334 pim_ifp->pim_ifstat_bsm_invalid_sz);
1335 } else {
1336
1337 json_object *json_row = NULL;
1338
1339 json_row = json_object_new_object();
1340
1341 json_object_string_add(json_row, "If Name", ifp->name);
1342 json_object_int_add(json_row, "bsmDroppedConfig",
1343 pim_ifp->pim_ifstat_bsm_cfg_miss);
1344 json_object_int_add(
1345 json_row, "bsmDroppedUnicast",
1346 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss);
1347 json_object_int_add(json_row,
1348 "bsmDroppedInvalidScopeZone",
1349 pim_ifp->pim_ifstat_bsm_invalid_sz);
1350 json_object_object_add(json, ifp->name, json_row);
1351 }
1352 vty_out(vty, "\n");
1353 }
1354
1355 if (uj)
1356 vty_json(vty, json);
1357 }
1358
1359 void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
1360 pim_sgaddr *sg, json_object *json)
1361 {
1362 struct pim_upstream *up;
1363 struct ttable *tt = NULL;
1364 char *table = NULL;
1365 time_t now;
1366 json_object *json_group = NULL;
1367 json_object *json_row = NULL;
1368
1369 now = pim_time_monotonic_sec();
1370
1371 if (!json) {
1372 /* Prepare table. */
1373 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
1374 ttable_add_row(
1375 tt,
1376 "Iif|Source|Group|State|Uptime|JoinTimer|RSTimer|KATimer|RefCnt");
1377 tt->style.cell.rpad = 2;
1378 tt->style.corner = '+';
1379 ttable_restyle(tt);
1380 }
1381
1382 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1383 char uptime[10];
1384 char join_timer[10];
1385 char rs_timer[10];
1386 char ka_timer[10];
1387 char msdp_reg_timer[10];
1388 char state_str[PIM_REG_STATE_STR_LEN];
1389
1390 if (!pim_sgaddr_match(up->sg, *sg))
1391 continue;
1392
1393 pim_time_uptime(uptime, sizeof(uptime),
1394 now - up->state_transition);
1395 pim_time_timer_to_hhmmss(join_timer, sizeof(join_timer),
1396 up->t_join_timer);
1397
1398 /*
1399 * If the upstream is not dummy and it has a J/P timer for the
1400 * neighbor display that
1401 */
1402 if (!up->t_join_timer && up->rpf.source_nexthop.interface) {
1403 struct pim_neighbor *nbr;
1404
1405 nbr = pim_neighbor_find(
1406 up->rpf.source_nexthop.interface,
1407 up->rpf.rpf_addr);
1408 if (nbr)
1409 pim_time_timer_to_hhmmss(join_timer,
1410 sizeof(join_timer),
1411 nbr->jp_timer);
1412 }
1413
1414 pim_time_timer_to_hhmmss(rs_timer, sizeof(rs_timer),
1415 up->t_rs_timer);
1416 pim_time_timer_to_hhmmss(ka_timer, sizeof(ka_timer),
1417 up->t_ka_timer);
1418 pim_time_timer_to_hhmmss(msdp_reg_timer, sizeof(msdp_reg_timer),
1419 up->t_msdp_reg_timer);
1420
1421 pim_upstream_state2brief_str(up->join_state, state_str,
1422 sizeof(state_str));
1423 if (up->reg_state != PIM_REG_NOINFO) {
1424 char tmp_str[PIM_REG_STATE_STR_LEN];
1425 char tmp[sizeof(state_str) + 1];
1426
1427 snprintf(tmp, sizeof(tmp), ",%s",
1428 pim_reg_state2brief_str(up->reg_state, tmp_str,
1429 sizeof(tmp_str)));
1430 strlcat(state_str, tmp, sizeof(state_str));
1431 }
1432
1433 if (json) {
1434 char grp_str[PIM_ADDRSTRLEN];
1435 char src_str[PIM_ADDRSTRLEN];
1436
1437 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
1438 &up->sg.grp);
1439 snprintfrr(src_str, sizeof(src_str), "%pPAs",
1440 &up->sg.src);
1441
1442 json_object_object_get_ex(json, grp_str, &json_group);
1443
1444 if (!json_group) {
1445 json_group = json_object_new_object();
1446 json_object_object_add(json, grp_str,
1447 json_group);
1448 }
1449
1450 json_row = json_object_new_object();
1451 json_object_pim_upstream_add(json_row, up);
1452 json_object_string_add(
1453 json_row, "inboundInterface",
1454 up->rpf.source_nexthop.interface
1455 ? up->rpf.source_nexthop.interface->name
1456 : "Unknown");
1457
1458 /*
1459 * The RPF address we use is slightly different
1460 * based upon what we are looking up.
1461 * If we have a S, list that unless
1462 * we are the FHR, else we just put
1463 * the RP as the rpfAddress
1464 */
1465 if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR ||
1466 pim_addr_is_any(up->sg.src)) {
1467 struct pim_rpf *rpg;
1468
1469 rpg = RP(pim, up->sg.grp);
1470 json_object_string_addf(json_row, "rpfAddress",
1471 "%pPA", &rpg->rpf_addr);
1472 } else {
1473 json_object_string_add(json_row, "rpfAddress",
1474 src_str);
1475 }
1476
1477 json_object_string_add(json_row, "source", src_str);
1478 json_object_string_add(json_row, "group", grp_str);
1479 json_object_string_add(json_row, "state", state_str);
1480 json_object_string_add(
1481 json_row, "joinState",
1482 pim_upstream_state2str(up->join_state));
1483 json_object_string_add(
1484 json_row, "regState",
1485 pim_reg_state2str(up->reg_state, state_str,
1486 sizeof(state_str)));
1487 json_object_string_add(json_row, "upTime", uptime);
1488 json_object_string_add(json_row, "joinTimer",
1489 join_timer);
1490 json_object_string_add(json_row, "resetTimer",
1491 rs_timer);
1492 json_object_string_add(json_row, "keepaliveTimer",
1493 ka_timer);
1494 json_object_string_add(json_row, "msdpRegTimer",
1495 msdp_reg_timer);
1496 json_object_int_add(json_row, "refCount",
1497 up->ref_count);
1498 json_object_int_add(json_row, "sptBit", up->sptbit);
1499 json_object_object_add(json_group, src_str, json_row);
1500 } else {
1501 ttable_add_row(tt,
1502 "%s|%pPAs|%pPAs|%s|%s|%s|%s|%s|%d",
1503 up->rpf.source_nexthop.interface
1504 ? up->rpf.source_nexthop.interface->name
1505 : "Unknown",
1506 &up->sg.src, &up->sg.grp, state_str, uptime,
1507 join_timer, rs_timer, ka_timer, up->ref_count);
1508 }
1509 }
1510 /* Dump the generated table. */
1511 if (!json) {
1512 table = ttable_dump(tt, "\n");
1513 vty_out(vty, "%s\n", table);
1514 XFREE(MTYPE_TMP, table);
1515 ttable_del(tt);
1516 }
1517 }
1518
1519 static void pim_show_join_desired_helper(struct pim_instance *pim,
1520 struct vty *vty,
1521 struct pim_upstream *up,
1522 json_object *json, bool uj,
1523 struct ttable *tt)
1524 {
1525 json_object *json_group = NULL;
1526 json_object *json_row = NULL;
1527
1528 if (uj) {
1529 char grp_str[PIM_ADDRSTRLEN];
1530 char src_str[PIM_ADDRSTRLEN];
1531
1532 snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &up->sg.grp);
1533 snprintfrr(src_str, sizeof(src_str), "%pPAs", &up->sg.src);
1534
1535 json_object_object_get_ex(json, grp_str, &json_group);
1536
1537 if (!json_group) {
1538 json_group = json_object_new_object();
1539 json_object_object_add(json, grp_str, json_group);
1540 }
1541
1542 json_row = json_object_new_object();
1543 json_object_pim_upstream_add(json_row, up);
1544 json_object_string_add(json_row, "source", src_str);
1545 json_object_string_add(json_row, "group", grp_str);
1546
1547 if (pim_upstream_evaluate_join_desired(pim, up))
1548 json_object_boolean_true_add(json_row,
1549 "evaluateJoinDesired");
1550
1551 json_object_object_add(json_group, src_str, json_row);
1552
1553 } else {
1554 ttable_add_row(tt, "%pPAs|%pPAs|%s", &up->sg.src, &up->sg.grp,
1555 pim_upstream_evaluate_join_desired(pim, up)
1556 ? "yes"
1557 : "no");
1558 }
1559 }
1560
1561 void pim_show_join_desired(struct pim_instance *pim, struct vty *vty, bool uj)
1562 {
1563 struct pim_upstream *up;
1564 struct ttable *tt = NULL;
1565 char *table = NULL;
1566
1567 json_object *json = NULL;
1568
1569 if (uj)
1570 json = json_object_new_object();
1571 else {
1572 /* Prepare table. */
1573 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
1574 ttable_add_row(tt, "Source|Group|EvalJD");
1575 tt->style.cell.rpad = 2;
1576 tt->style.corner = '+';
1577 ttable_restyle(tt);
1578 }
1579
1580 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1581 /* scan all interfaces */
1582 pim_show_join_desired_helper(pim, vty, up, json, uj, tt);
1583 }
1584
1585 if (uj)
1586 vty_json(vty, json);
1587 else {
1588 /* Dump the generated table. */
1589 table = ttable_dump(tt, "\n");
1590 vty_out(vty, "%s\n", table);
1591 XFREE(MTYPE_TMP, table);
1592 ttable_del(tt);
1593 }
1594 }
1595
1596 void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, bool uj)
1597 {
1598 struct pim_upstream *up;
1599 struct ttable *tt = NULL;
1600 char *table = NULL;
1601 json_object *json = NULL;
1602 json_object *json_group = NULL;
1603 json_object *json_row = NULL;
1604
1605 if (uj)
1606 json = json_object_new_object();
1607 else {
1608 /* Prepare table. */
1609 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
1610 ttable_add_row(tt,
1611 "Source|Group|RpfIface|RibNextHop|RpfAddress");
1612 tt->style.cell.rpad = 2;
1613 tt->style.corner = '+';
1614 ttable_restyle(tt);
1615 }
1616
1617 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1618 struct pim_rpf *rpf;
1619 const char *rpf_ifname;
1620
1621 rpf = &up->rpf;
1622
1623 rpf_ifname =
1624 rpf->source_nexthop.interface ? rpf->source_nexthop
1625 .interface->name
1626 : "<ifname?>";
1627
1628 if (uj) {
1629 char grp_str[PIM_ADDRSTRLEN];
1630 char src_str[PIM_ADDRSTRLEN];
1631
1632 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
1633 &up->sg.grp);
1634 snprintfrr(src_str, sizeof(src_str), "%pPAs",
1635 &up->sg.src);
1636 json_object_object_get_ex(json, grp_str, &json_group);
1637
1638 if (!json_group) {
1639 json_group = json_object_new_object();
1640 json_object_object_add(json, grp_str,
1641 json_group);
1642 }
1643
1644 json_row = json_object_new_object();
1645 json_object_pim_upstream_add(json_row, up);
1646 json_object_string_add(json_row, "source", src_str);
1647 json_object_string_add(json_row, "group", grp_str);
1648 json_object_string_add(json_row, "rpfInterface",
1649 rpf_ifname);
1650 json_object_string_addf(
1651 json_row, "ribNexthop", "%pPAs",
1652 &rpf->source_nexthop.mrib_nexthop_addr);
1653 json_object_string_addf(json_row, "rpfAddress", "%pPA",
1654 &rpf->rpf_addr);
1655 json_object_object_add(json_group, src_str, json_row);
1656 } else {
1657 ttable_add_row(tt, "%pPAs|%pPAs|%s|%pPA|%pPA",
1658 &up->sg.src, &up->sg.grp, rpf_ifname,
1659 &rpf->source_nexthop.mrib_nexthop_addr,
1660 &rpf->rpf_addr);
1661 }
1662 }
1663
1664 if (uj)
1665 vty_json(vty, json);
1666 else {
1667 /* Dump the generated table. */
1668 table = ttable_dump(tt, "\n");
1669 vty_out(vty, "%s\n", table);
1670 XFREE(MTYPE_TMP, table);
1671 ttable_del(tt);
1672 }
1673 }
1674
1675 static void pim_show_join_helper(struct pim_interface *pim_ifp,
1676 struct pim_ifchannel *ch, json_object *json,
1677 time_t now, struct ttable *tt)
1678 {
1679 json_object *json_iface = NULL;
1680 json_object *json_row = NULL;
1681 json_object *json_grp = NULL;
1682 pim_addr ifaddr;
1683 char uptime[10];
1684 char expire[10];
1685 char prune[10];
1686
1687 ifaddr = pim_ifp->primary_address;
1688
1689 pim_time_uptime_begin(uptime, sizeof(uptime), now, ch->ifjoin_creation);
1690 pim_time_timer_to_mmss(expire, sizeof(expire),
1691 ch->t_ifjoin_expiry_timer);
1692 pim_time_timer_to_mmss(prune, sizeof(prune),
1693 ch->t_ifjoin_prune_pending_timer);
1694
1695 if (json) {
1696 char ch_grp_str[PIM_ADDRSTRLEN];
1697
1698 json_object_object_get_ex(json, ch->interface->name,
1699 &json_iface);
1700
1701 if (!json_iface) {
1702 json_iface = json_object_new_object();
1703 json_object_pim_ifp_add(json_iface, ch->interface);
1704 json_object_object_add(json, ch->interface->name,
1705 json_iface);
1706 }
1707
1708 json_row = json_object_new_object();
1709 json_object_string_addf(json_row, "source", "%pPAs",
1710 &ch->sg.src);
1711 json_object_string_addf(json_row, "group", "%pPAs",
1712 &ch->sg.grp);
1713 json_object_string_add(json_row, "upTime", uptime);
1714 json_object_string_add(json_row, "expire", expire);
1715 json_object_string_add(json_row, "prune", prune);
1716 json_object_string_add(
1717 json_row, "channelJoinName",
1718 pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags));
1719 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) {
1720 #if CONFDATE > 20230131
1721 CPP_NOTICE(
1722 "Remove JSON object commands with keys starting with capital")
1723 #endif
1724 json_object_int_add(json_row, "SGRpt", 1);
1725 json_object_int_add(json_row, "sgRpt", 1);
1726 }
1727 if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
1728 json_object_int_add(json_row, "protocolPim", 1);
1729 if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
1730 json_object_int_add(json_row, "protocolIgmp", 1);
1731 snprintfrr(ch_grp_str, sizeof(ch_grp_str), "%pPAs",
1732 &ch->sg.grp);
1733 json_object_object_get_ex(json_iface, ch_grp_str, &json_grp);
1734 if (!json_grp) {
1735 json_grp = json_object_new_object();
1736 json_object_object_addf(json_grp, json_row, "%pPAs",
1737 &ch->sg.src);
1738 json_object_object_addf(json_iface, json_grp, "%pPAs",
1739 &ch->sg.grp);
1740 } else
1741 json_object_object_addf(json_grp, json_row, "%pPAs",
1742 &ch->sg.src);
1743 } else {
1744 ttable_add_row(
1745 tt, "%s|%pPAs|%pPAs|%pPAs|%s|%s|%s|%s",
1746 ch->interface->name, &ifaddr, &ch->sg.src, &ch->sg.grp,
1747 pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags),
1748 uptime, expire, prune);
1749 }
1750 }
1751
1752 int pim_show_join_cmd_helper(const char *vrf, struct vty *vty, pim_addr s_or_g,
1753 pim_addr g, const char *json)
1754 {
1755 pim_sgaddr sg = {};
1756 struct vrf *v;
1757 struct pim_instance *pim;
1758 json_object *json_parent = NULL;
1759
1760 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
1761
1762 if (!v) {
1763 vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
1764 return CMD_WARNING;
1765 }
1766 pim = v->info;
1767
1768 if (!pim) {
1769 vty_out(vty, "%% Unable to find pim instance\n");
1770 return CMD_WARNING;
1771 }
1772
1773 if (!pim_addr_is_any(s_or_g)) {
1774 if (!pim_addr_is_any(g)) {
1775 sg.src = s_or_g;
1776 sg.grp = g;
1777 } else
1778 sg.grp = s_or_g;
1779 }
1780
1781 if (json)
1782 json_parent = json_object_new_object();
1783
1784 pim_show_join(pim, vty, &sg, json_parent);
1785
1786 if (json)
1787 vty_json(vty, json_parent);
1788
1789 return CMD_SUCCESS;
1790 }
1791
1792 int pim_show_join_vrf_all_cmd_helper(struct vty *vty, const char *json)
1793 {
1794 pim_sgaddr sg = {0};
1795 struct vrf *vrf_struct;
1796 json_object *json_parent = NULL;
1797 json_object *json_vrf = NULL;
1798
1799 if (json)
1800 json_parent = json_object_new_object();
1801
1802 RB_FOREACH (vrf_struct, vrf_name_head, &vrfs_by_name) {
1803 if (!json_parent)
1804 vty_out(vty, "VRF: %s\n", vrf_struct->name);
1805 else
1806 json_vrf = json_object_new_object();
1807 pim_show_join(vrf_struct->info, vty, &sg, json_vrf);
1808
1809 if (json)
1810 json_object_object_add(json_parent, vrf_struct->name,
1811 json_vrf);
1812 }
1813 if (json)
1814 vty_json(vty, json_parent);
1815
1816 return CMD_WARNING;
1817 }
1818
1819 void pim_show_join(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg,
1820 json_object *json)
1821 {
1822 struct pim_interface *pim_ifp;
1823 struct pim_ifchannel *ch;
1824 struct interface *ifp;
1825 time_t now;
1826 struct ttable *tt = NULL;
1827 char *table = NULL;
1828
1829 now = pim_time_monotonic_sec();
1830
1831 if (!json) {
1832 /* Prepare table. */
1833 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
1834 ttable_add_row(
1835 tt,
1836 "Interface|Address|Source|Group|State|Uptime|Expire|Prune");
1837 tt->style.cell.rpad = 2;
1838 tt->style.corner = '+';
1839 ttable_restyle(tt);
1840 }
1841
1842 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1843 pim_ifp = ifp->info;
1844 if (!pim_ifp)
1845 continue;
1846
1847 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
1848 if (!pim_sgaddr_match(ch->sg, *sg))
1849 continue;
1850
1851 pim_show_join_helper(pim_ifp, ch, json, now, tt);
1852 } /* scan interface channels */
1853 }
1854 /* Dump the generated table. */
1855 if (!json) {
1856 table = ttable_dump(tt, "\n");
1857 vty_out(vty, "%s\n", table);
1858 XFREE(MTYPE_TMP, table);
1859 ttable_del(tt);
1860 }
1861 }
1862
1863 static void pim_show_jp_agg_helper(struct interface *ifp,
1864 struct pim_neighbor *neigh,
1865 struct pim_upstream *up, int is_join,
1866 struct ttable *tt)
1867 {
1868 ttable_add_row(tt, "%s|%pPAs|%pPAs|%pPAs|%s", ifp->name,
1869 &neigh->source_addr, &up->sg.src, &up->sg.grp,
1870 is_join ? "J" : "P");
1871 }
1872
1873 int pim_show_jp_agg_list_cmd_helper(const char *vrf, struct vty *vty)
1874 {
1875 struct vrf *v;
1876 struct pim_instance *pim;
1877
1878 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
1879
1880 if (!v) {
1881 vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
1882 return CMD_WARNING;
1883 }
1884 pim = v->info;
1885
1886 if (!pim) {
1887 vty_out(vty, "%% Unable to find pim instance\n");
1888 return CMD_WARNING;
1889 }
1890
1891 pim_show_jp_agg_list(pim, vty);
1892
1893 return CMD_SUCCESS;
1894 }
1895
1896 void pim_show_jp_agg_list(struct pim_instance *pim, struct vty *vty)
1897 {
1898 struct interface *ifp;
1899 struct pim_interface *pim_ifp;
1900 struct listnode *n_node;
1901 struct pim_neighbor *neigh;
1902 struct listnode *jag_node;
1903 struct pim_jp_agg_group *jag;
1904 struct listnode *js_node;
1905 struct pim_jp_sources *js;
1906 struct ttable *tt;
1907 char *table;
1908
1909 /* Prepare table. */
1910 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
1911 ttable_add_row(tt, "Interface|RPF Nbr|Source|Group|State");
1912 tt->style.cell.rpad = 2;
1913 tt->style.corner = '+';
1914 ttable_restyle(tt);
1915
1916 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1917 pim_ifp = ifp->info;
1918 if (!pim_ifp)
1919 continue;
1920
1921 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, n_node,
1922 neigh)) {
1923 for (ALL_LIST_ELEMENTS_RO(neigh->upstream_jp_agg,
1924 jag_node, jag)) {
1925 for (ALL_LIST_ELEMENTS_RO(jag->sources, js_node,
1926 js)) {
1927 pim_show_jp_agg_helper(ifp, neigh,
1928 js->up,
1929 js->is_join, tt);
1930 }
1931 }
1932 }
1933 }
1934
1935 /* Dump the generated table. */
1936 table = ttable_dump(tt, "\n");
1937 vty_out(vty, "%s\n", table);
1938 XFREE(MTYPE_TMP, table);
1939 ttable_del(tt);
1940 }
1941
1942 int pim_show_membership_cmd_helper(const char *vrf, struct vty *vty, bool uj)
1943 {
1944 struct vrf *v;
1945
1946 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
1947
1948 if (!v)
1949 return CMD_WARNING;
1950
1951 pim_show_membership(v->info, vty, uj);
1952
1953 return CMD_SUCCESS;
1954 }
1955
1956 static void pim_show_membership_helper(struct vty *vty,
1957 struct pim_interface *pim_ifp,
1958 struct pim_ifchannel *ch,
1959 struct json_object *json)
1960 {
1961 json_object *json_iface = NULL;
1962 json_object *json_row = NULL;
1963
1964 json_object_object_get_ex(json, ch->interface->name, &json_iface);
1965 if (!json_iface) {
1966 json_iface = json_object_new_object();
1967 json_object_pim_ifp_add(json_iface, ch->interface);
1968 json_object_object_add(json, ch->interface->name, json_iface);
1969 }
1970
1971 json_row = json_object_new_object();
1972 json_object_string_addf(json_row, "source", "%pPAs", &ch->sg.src);
1973 json_object_string_addf(json_row, "group", "%pPAs", &ch->sg.grp);
1974 json_object_string_add(json_row, "localMembership",
1975 ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO
1976 ? "NOINFO"
1977 : "INCLUDE");
1978 json_object_object_addf(json_iface, json_row, "%pPAs", &ch->sg.grp);
1979 }
1980
1981 void pim_show_membership(struct pim_instance *pim, struct vty *vty, bool uj)
1982 {
1983 struct pim_interface *pim_ifp;
1984 struct pim_ifchannel *ch;
1985 struct interface *ifp;
1986 enum json_type type;
1987 json_object *json = NULL;
1988 json_object *json_tmp = NULL;
1989 struct ttable *tt = NULL;
1990 char *table = NULL;
1991
1992 json = json_object_new_object();
1993
1994 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1995 pim_ifp = ifp->info;
1996 if (!pim_ifp)
1997 continue;
1998
1999 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
2000 pim_show_membership_helper(vty, pim_ifp, ch, json);
2001 } /* scan interface channels */
2002 }
2003
2004 if (uj) {
2005 vty_json(vty, json);
2006 } else {
2007 /* Prepare table. */
2008 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
2009 ttable_add_row(tt, "Interface|Address|Source|Group|Membership");
2010 tt->style.cell.rpad = 2;
2011 tt->style.corner = '+';
2012 ttable_restyle(tt);
2013
2014 /*
2015 * Example of the json data we are traversing
2016 *
2017 * {
2018 * "swp3":{
2019 * "name":"swp3",
2020 * "state":"up",
2021 * "address":"10.1.20.1",
2022 * "index":5,
2023 * "flagMulticast":true,
2024 * "flagBroadcast":true,
2025 * "lanDelayEnabled":true,
2026 * "226.10.10.10":{
2027 * "source":"*",
2028 * "group":"226.10.10.10",
2029 * "localMembership":"INCLUDE"
2030 * }
2031 * }
2032 * }
2033 */
2034
2035 /* foreach interface */
2036 json_object_object_foreach(json, key, val)
2037 {
2038
2039 /* Find all of the keys where the val is an object. In
2040 * the example
2041 * above the only one is 226.10.10.10
2042 */
2043 json_object_object_foreach(val, if_field_key,
2044 if_field_val)
2045 {
2046 type = json_object_get_type(if_field_val);
2047
2048 if (type == json_type_object) {
2049 const char *address, *source,
2050 *localMembership;
2051
2052 json_object_object_get_ex(
2053 val, "address", &json_tmp);
2054 address = json_object_get_string(
2055 json_tmp);
2056
2057 json_object_object_get_ex(if_field_val,
2058 "source",
2059 &json_tmp);
2060 source = json_object_get_string(
2061 json_tmp);
2062
2063 json_object_object_get_ex(
2064 if_field_val, "localMembership",
2065 &json_tmp);
2066 localMembership =
2067 json_object_get_string(
2068 json_tmp);
2069
2070 ttable_add_row(tt, "%s|%s|%s|%s|%s",
2071 key, address, source,
2072 if_field_key,
2073 localMembership);
2074 }
2075 }
2076 }
2077 json_object_free(json);
2078 /* Dump the generated table. */
2079 table = ttable_dump(tt, "\n");
2080 vty_out(vty, "%s\n", table);
2081 XFREE(MTYPE_TMP, table);
2082 ttable_del(tt);
2083 }
2084 }
2085
2086 static void pim_show_channel_helper(struct pim_instance *pim,
2087 struct pim_interface *pim_ifp,
2088 struct pim_ifchannel *ch, json_object *json,
2089 bool uj, struct ttable *tt)
2090 {
2091 struct pim_upstream *up = ch->upstream;
2092 json_object *json_group = NULL;
2093 json_object *json_row = NULL;
2094
2095 if (uj) {
2096 char grp_str[PIM_ADDRSTRLEN];
2097
2098 snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &up->sg.grp);
2099 json_object_object_get_ex(json, grp_str, &json_group);
2100
2101 if (!json_group) {
2102 json_group = json_object_new_object();
2103 json_object_object_add(json, grp_str, json_group);
2104 }
2105
2106 json_row = json_object_new_object();
2107 json_object_pim_upstream_add(json_row, up);
2108 json_object_string_add(json_row, "interface",
2109 ch->interface->name);
2110 json_object_string_addf(json_row, "source", "%pPAs",
2111 &up->sg.src);
2112 json_object_string_addf(json_row, "group", "%pPAs",
2113 &up->sg.grp);
2114
2115 if (pim_macro_ch_lost_assert(ch))
2116 json_object_boolean_true_add(json_row, "lostAssert");
2117
2118 if (pim_macro_chisin_joins(ch))
2119 json_object_boolean_true_add(json_row, "joins");
2120
2121 if (pim_macro_chisin_pim_include(ch))
2122 json_object_boolean_true_add(json_row, "pimInclude");
2123
2124 if (pim_upstream_evaluate_join_desired(pim, up))
2125 json_object_boolean_true_add(json_row,
2126 "evaluateJoinDesired");
2127
2128 json_object_object_addf(json_group, json_row, "%pPAs",
2129 &up->sg.src);
2130
2131 } else {
2132 ttable_add_row(tt, "%s|%pPAs|%pPAs|%s|%s|%s|%s|%s",
2133 ch->interface->name, &up->sg.src, &up->sg.grp,
2134 pim_macro_ch_lost_assert(ch) ? "yes" : "no",
2135 pim_macro_chisin_joins(ch) ? "yes" : "no",
2136 pim_macro_chisin_pim_include(ch) ? "yes" : "no",
2137 PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags)
2138 ? "yes"
2139 : "no",
2140 pim_upstream_evaluate_join_desired(pim, up)
2141 ? "yes"
2142 : "no");
2143 }
2144 }
2145
2146 void pim_show_channel(struct pim_instance *pim, struct vty *vty, bool uj)
2147 {
2148 struct pim_interface *pim_ifp;
2149 struct pim_ifchannel *ch;
2150 struct interface *ifp;
2151 struct ttable *tt = NULL;
2152 json_object *json = NULL;
2153 char *table = NULL;
2154
2155 if (uj)
2156 json = json_object_new_object();
2157 else {
2158 /* Prepare table. */
2159 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
2160 ttable_add_row(
2161 tt,
2162 "Interface|Source|Group|LostAssert|Joins|PimInclude|JoinDesired|EvalJD");
2163 tt->style.cell.rpad = 2;
2164 tt->style.corner = '+';
2165 ttable_restyle(tt);
2166 }
2167
2168 /* scan per-interface (S,G) state */
2169 FOR_ALL_INTERFACES (pim->vrf, ifp) {
2170 pim_ifp = ifp->info;
2171 if (!pim_ifp)
2172 continue;
2173
2174 RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
2175 /* scan all interfaces */
2176 pim_show_channel_helper(pim, pim_ifp, ch, json, uj, tt);
2177 }
2178 }
2179
2180 if (uj)
2181 vty_json(vty, json);
2182 else {
2183 /* Dump the generated table. */
2184 table = ttable_dump(tt, "\n");
2185 vty_out(vty, "%s\n", table);
2186 XFREE(MTYPE_TMP, table);
2187 ttable_del(tt);
2188 }
2189 }
2190
2191 int pim_show_channel_cmd_helper(const char *vrf, struct vty *vty, bool uj)
2192 {
2193 struct vrf *v;
2194
2195 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
2196
2197 if (!v)
2198 return CMD_WARNING;
2199
2200 pim_show_channel(v->info, vty, uj);
2201
2202 return CMD_SUCCESS;
2203 }
2204
2205 int pim_show_interface_cmd_helper(const char *vrf, struct vty *vty, bool uj,
2206 bool mlag, const char *interface)
2207 {
2208 struct vrf *v;
2209 json_object *json_parent = NULL;
2210
2211 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
2212
2213 if (!v)
2214 return CMD_WARNING;
2215
2216 if (uj)
2217 json_parent = json_object_new_object();
2218
2219 if (interface)
2220 pim_show_interfaces_single(v->info, vty, interface, mlag,
2221 json_parent);
2222 else
2223 pim_show_interfaces(v->info, vty, mlag, json_parent);
2224
2225 if (uj)
2226 vty_json(vty, json_parent);
2227
2228 return CMD_SUCCESS;
2229 }
2230
2231 int pim_show_interface_vrf_all_cmd_helper(struct vty *vty, bool uj, bool mlag,
2232 const char *interface)
2233 {
2234 struct vrf *v;
2235 json_object *json_parent = NULL;
2236 json_object *json_vrf = NULL;
2237
2238 if (uj)
2239 json_parent = json_object_new_object();
2240
2241 RB_FOREACH (v, vrf_name_head, &vrfs_by_name) {
2242 if (!uj)
2243 vty_out(vty, "VRF: %s\n", v->name);
2244 else
2245 json_vrf = json_object_new_object();
2246
2247 if (interface)
2248 pim_show_interfaces_single(v->info, vty, interface,
2249 mlag, json_vrf);
2250 else
2251 pim_show_interfaces(v->info, vty, mlag, json_vrf);
2252
2253 if (uj)
2254 json_object_object_add(json_parent, v->name, json_vrf);
2255 }
2256 if (uj)
2257 vty_json(vty, json_parent);
2258
2259 return CMD_SUCCESS;
2260 }
2261
2262 void pim_show_interfaces(struct pim_instance *pim, struct vty *vty, bool mlag,
2263 json_object *json)
2264 {
2265 struct interface *ifp;
2266 struct pim_interface *pim_ifp;
2267 struct pim_upstream *up;
2268 int fhr = 0;
2269 int pim_nbrs = 0;
2270 int pim_ifchannels = 0;
2271 bool uj = true;
2272 struct ttable *tt = NULL;
2273 char *table = NULL;
2274 json_object *json_row = NULL;
2275 json_object *json_tmp;
2276
2277 if (!json) {
2278 uj = false;
2279 json = json_object_new_object();
2280 }
2281
2282 FOR_ALL_INTERFACES (pim->vrf, ifp) {
2283 pim_ifp = ifp->info;
2284
2285 if (!pim_ifp)
2286 continue;
2287
2288 if (mlag == true && pim_ifp->activeactive == false)
2289 continue;
2290
2291 pim_nbrs = pim_ifp->pim_neighbor_list->count;
2292 pim_ifchannels = pim_if_ifchannel_count(pim_ifp);
2293 fhr = 0;
2294
2295 frr_each (rb_pim_upstream, &pim->upstream_head, up)
2296 if (ifp == up->rpf.source_nexthop.interface)
2297 if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR)
2298 fhr++;
2299
2300 json_row = json_object_new_object();
2301 json_object_pim_ifp_add(json_row, ifp);
2302 json_object_int_add(json_row, "pimNeighbors", pim_nbrs);
2303 json_object_int_add(json_row, "pimIfChannels", pim_ifchannels);
2304 json_object_int_add(json_row, "firstHopRouterCount", fhr);
2305 json_object_string_addf(json_row, "pimDesignatedRouter",
2306 "%pPAs", &pim_ifp->pim_dr_addr);
2307
2308 if (!pim_addr_cmp(pim_ifp->pim_dr_addr,
2309 pim_ifp->primary_address))
2310 json_object_boolean_true_add(
2311 json_row, "pimDesignatedRouterLocal");
2312
2313 json_object_object_add(json, ifp->name, json_row);
2314 }
2315
2316 if (!uj) {
2317
2318 /* Prepare table. */
2319 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
2320 ttable_add_row(
2321 tt,
2322 "Interface|State|Address|PIM Nbrs|PIM DR|FHR|IfChannels");
2323 tt->style.cell.rpad = 2;
2324 tt->style.corner = '+';
2325 ttable_restyle(tt);
2326
2327 json_object_object_foreach(json, key, val)
2328 {
2329 const char *state, *address, *pimdr;
2330 int neighbors, firsthpr, pimifchnl;
2331
2332 json_object_object_get_ex(val, "state", &json_tmp);
2333 state = json_object_get_string(json_tmp);
2334
2335 json_object_object_get_ex(val, "address", &json_tmp);
2336 address = json_object_get_string(json_tmp);
2337
2338 json_object_object_get_ex(val, "pimNeighbors",
2339 &json_tmp);
2340 neighbors = json_object_get_int(json_tmp);
2341
2342 if (json_object_object_get_ex(
2343 val, "pimDesignatedRouterLocal",
2344 &json_tmp)) {
2345 pimdr = "local";
2346 } else {
2347 json_object_object_get_ex(
2348 val, "pimDesignatedRouter", &json_tmp);
2349 pimdr = json_object_get_string(json_tmp);
2350 }
2351
2352 json_object_object_get_ex(val, "firstHopRouter",
2353 &json_tmp);
2354 firsthpr = json_object_get_int(json_tmp);
2355
2356 json_object_object_get_ex(val, "pimIfChannels",
2357 &json_tmp);
2358 pimifchnl = json_object_get_int(json_tmp);
2359
2360 ttable_add_row(tt, "%s|%s|%s|%d|%s|%d|%d", key, state,
2361 address, neighbors, pimdr, firsthpr,
2362 pimifchnl);
2363 }
2364 json_object_free(json);
2365
2366 /* Dump the generated table. */
2367 table = ttable_dump(tt, "\n");
2368 vty_out(vty, "%s\n", table);
2369 XFREE(MTYPE_TMP, table);
2370
2371 ttable_del(tt);
2372 }
2373 }
2374
2375 void pim_show_interfaces_single(struct pim_instance *pim, struct vty *vty,
2376 const char *ifname, bool mlag,
2377 json_object *json)
2378 {
2379 pim_addr ifaddr;
2380 struct interface *ifp;
2381 struct listnode *neighnode;
2382 struct pim_interface *pim_ifp;
2383 struct pim_neighbor *neigh;
2384 struct pim_upstream *up;
2385 time_t now;
2386 char dr_str[PIM_ADDRSTRLEN];
2387 char dr_uptime[10];
2388 char expire[10];
2389 char grp_str[PIM_ADDRSTRLEN];
2390 char hello_period[10];
2391 char hello_timer[10];
2392 char neigh_src_str[PIM_ADDRSTRLEN];
2393 char src_str[PIM_ADDRSTRLEN];
2394 char stat_uptime[10];
2395 char uptime[10];
2396 int found_ifname = 0;
2397 int print_header;
2398 json_object *json_row = NULL;
2399 json_object *json_pim_neighbor = NULL;
2400 json_object *json_pim_neighbors = NULL;
2401 json_object *json_group = NULL;
2402 json_object *json_group_source = NULL;
2403 json_object *json_fhr_sources = NULL;
2404 struct pim_secondary_addr *sec_addr;
2405 struct listnode *sec_node;
2406
2407 now = pim_time_monotonic_sec();
2408
2409 FOR_ALL_INTERFACES (pim->vrf, ifp) {
2410 pim_ifp = ifp->info;
2411
2412 if (!pim_ifp)
2413 continue;
2414
2415 if (mlag == true && pim_ifp->activeactive == false)
2416 continue;
2417
2418 if (strcmp(ifname, "detail") && strcmp(ifname, ifp->name))
2419 continue;
2420
2421 found_ifname = 1;
2422 ifaddr = pim_ifp->primary_address;
2423 snprintfrr(dr_str, sizeof(dr_str), "%pPAs",
2424 &pim_ifp->pim_dr_addr);
2425 pim_time_uptime_begin(dr_uptime, sizeof(dr_uptime), now,
2426 pim_ifp->pim_dr_election_last);
2427 pim_time_timer_to_hhmmss(hello_timer, sizeof(hello_timer),
2428 pim_ifp->t_pim_hello_timer);
2429 pim_time_mmss(hello_period, sizeof(hello_period),
2430 pim_ifp->pim_hello_period);
2431 pim_time_uptime(stat_uptime, sizeof(stat_uptime),
2432 now - pim_ifp->pim_ifstat_start);
2433
2434 if (json) {
2435 json_row = json_object_new_object();
2436 json_object_pim_ifp_add(json_row, ifp);
2437
2438 if (!pim_addr_is_any(pim_ifp->update_source)) {
2439 json_object_string_addf(
2440 json_row, "useSource", "%pPAs",
2441 &pim_ifp->update_source);
2442 }
2443 if (pim_ifp->sec_addr_list) {
2444 json_object *sec_list = NULL;
2445
2446 sec_list = json_object_new_array();
2447 for (ALL_LIST_ELEMENTS_RO(
2448 pim_ifp->sec_addr_list, sec_node,
2449 sec_addr)) {
2450 json_object_array_add(
2451 sec_list,
2452 json_object_new_stringf(
2453 "%pFXh",
2454 &sec_addr->addr));
2455 }
2456 json_object_object_add(json_row,
2457 "secondaryAddressList",
2458 sec_list);
2459 }
2460
2461 if (pim_ifp->pim_passive_enable)
2462 json_object_boolean_true_add(json_row,
2463 "passive");
2464
2465 /* PIM neighbors */
2466 if (pim_ifp->pim_neighbor_list->count) {
2467 json_pim_neighbors = json_object_new_object();
2468
2469 for (ALL_LIST_ELEMENTS_RO(
2470 pim_ifp->pim_neighbor_list,
2471 neighnode, neigh)) {
2472 json_pim_neighbor =
2473 json_object_new_object();
2474 snprintfrr(neigh_src_str,
2475 sizeof(neigh_src_str),
2476 "%pPAs",
2477 &neigh->source_addr);
2478 pim_time_uptime(uptime, sizeof(uptime),
2479 now - neigh->creation);
2480 pim_time_timer_to_hhmmss(
2481 expire, sizeof(expire),
2482 neigh->t_expire_timer);
2483
2484 json_object_string_add(
2485 json_pim_neighbor, "address",
2486 neigh_src_str);
2487 json_object_string_add(
2488 json_pim_neighbor, "upTime",
2489 uptime);
2490 json_object_string_add(
2491 json_pim_neighbor, "holdtime",
2492 expire);
2493
2494 json_object_object_add(
2495 json_pim_neighbors,
2496 neigh_src_str,
2497 json_pim_neighbor);
2498 }
2499
2500 json_object_object_add(json_row, "neighbors",
2501 json_pim_neighbors);
2502 }
2503
2504 json_object_string_add(json_row, "drAddress", dr_str);
2505 json_object_int_add(json_row, "drPriority",
2506 pim_ifp->pim_dr_priority);
2507 json_object_string_add(json_row, "drUptime", dr_uptime);
2508 json_object_int_add(json_row, "drElections",
2509 pim_ifp->pim_dr_election_count);
2510 json_object_int_add(json_row, "drChanges",
2511 pim_ifp->pim_dr_election_changes);
2512
2513 /* FHR */
2514 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2515 if (ifp != up->rpf.source_nexthop.interface)
2516 continue;
2517
2518 if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_FHR))
2519 continue;
2520
2521 if (!json_fhr_sources)
2522 json_fhr_sources =
2523 json_object_new_object();
2524
2525 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
2526 &up->sg.grp);
2527 snprintfrr(src_str, sizeof(src_str), "%pPAs",
2528 &up->sg.src);
2529 pim_time_uptime(uptime, sizeof(uptime),
2530 now - up->state_transition);
2531
2532 /*
2533 * Does this group live in json_fhr_sources?
2534 * If not create it.
2535 */
2536 json_object_object_get_ex(json_fhr_sources,
2537 grp_str, &json_group);
2538
2539 if (!json_group) {
2540 json_group = json_object_new_object();
2541 json_object_object_add(json_fhr_sources,
2542 grp_str,
2543 json_group);
2544 }
2545
2546 json_group_source = json_object_new_object();
2547 json_object_string_add(json_group_source,
2548 "source", src_str);
2549 json_object_string_add(json_group_source,
2550 "group", grp_str);
2551 json_object_string_add(json_group_source,
2552 "upTime", uptime);
2553 json_object_object_add(json_group, src_str,
2554 json_group_source);
2555 }
2556
2557 if (json_fhr_sources) {
2558 json_object_object_add(json_row,
2559 "firstHopRouter",
2560 json_fhr_sources);
2561 }
2562
2563 json_object_int_add(json_row, "helloPeriod",
2564 pim_ifp->pim_hello_period);
2565 json_object_int_add(json_row, "holdTime",
2566 PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
2567 json_object_string_add(json_row, "helloTimer",
2568 hello_timer);
2569 json_object_string_add(json_row, "helloStatStart",
2570 stat_uptime);
2571 json_object_int_add(json_row, "helloReceived",
2572 pim_ifp->pim_ifstat_hello_recv);
2573 json_object_int_add(json_row, "helloReceivedFailed",
2574 pim_ifp->pim_ifstat_hello_recvfail);
2575 json_object_int_add(json_row, "helloSend",
2576 pim_ifp->pim_ifstat_hello_sent);
2577 json_object_int_add(json_row, "hellosendFailed",
2578 pim_ifp->pim_ifstat_hello_sendfail);
2579 json_object_int_add(json_row, "helloGenerationId",
2580 pim_ifp->pim_generation_id);
2581
2582 json_object_int_add(
2583 json_row, "effectivePropagationDelay",
2584 pim_if_effective_propagation_delay_msec(ifp));
2585 json_object_int_add(
2586 json_row, "effectiveOverrideInterval",
2587 pim_if_effective_override_interval_msec(ifp));
2588 json_object_int_add(
2589 json_row, "joinPruneOverrideInterval",
2590 pim_if_jp_override_interval_msec(ifp));
2591
2592 json_object_int_add(
2593 json_row, "propagationDelay",
2594 pim_ifp->pim_propagation_delay_msec);
2595 json_object_int_add(
2596 json_row, "propagationDelayHighest",
2597 pim_ifp->pim_neighbors_highest_propagation_delay_msec);
2598 json_object_int_add(
2599 json_row, "overrideInterval",
2600 pim_ifp->pim_override_interval_msec);
2601 json_object_int_add(
2602 json_row, "overrideIntervalHighest",
2603 pim_ifp->pim_neighbors_highest_override_interval_msec);
2604 if (pim_ifp->bsm_enable)
2605 json_object_boolean_true_add(json_row,
2606 "bsmEnabled");
2607 if (pim_ifp->ucast_bsm_accept)
2608 json_object_boolean_true_add(json_row,
2609 "ucastBsmEnabled");
2610 json_object_object_add(json, ifp->name, json_row);
2611
2612 } else {
2613 vty_out(vty, "Interface : %s\n", ifp->name);
2614 vty_out(vty, "State : %s\n",
2615 if_is_up(ifp) ? "up" : "down");
2616 if (!pim_addr_is_any(pim_ifp->update_source)) {
2617 vty_out(vty, "Use Source : %pPAs\n",
2618 &pim_ifp->update_source);
2619 }
2620 if (pim_ifp->sec_addr_list) {
2621 vty_out(vty, "Address : %pPAs (primary)\n",
2622 &ifaddr);
2623 for (ALL_LIST_ELEMENTS_RO(
2624 pim_ifp->sec_addr_list, sec_node,
2625 sec_addr))
2626 vty_out(vty, " %pFX\n",
2627 &sec_addr->addr);
2628 } else {
2629 vty_out(vty, "Address : %pPAs\n", &ifaddr);
2630 }
2631
2632 if (pim_ifp->pim_passive_enable)
2633 vty_out(vty, "Passive : %s\n",
2634 (pim_ifp->pim_passive_enable) ? "yes"
2635 : "no");
2636
2637 vty_out(vty, "\n");
2638
2639 /* PIM neighbors */
2640 print_header = 1;
2641
2642 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list,
2643 neighnode, neigh)) {
2644
2645 if (print_header) {
2646 vty_out(vty, "PIM Neighbors\n");
2647 vty_out(vty, "-------------\n");
2648 print_header = 0;
2649 }
2650
2651 snprintfrr(neigh_src_str, sizeof(neigh_src_str),
2652 "%pPAs", &neigh->source_addr);
2653 pim_time_uptime(uptime, sizeof(uptime),
2654 now - neigh->creation);
2655 pim_time_timer_to_hhmmss(expire, sizeof(expire),
2656 neigh->t_expire_timer);
2657 vty_out(vty,
2658 "%-15s : up for %s, holdtime expires in %s\n",
2659 neigh_src_str, uptime, expire);
2660 }
2661
2662 if (!print_header) {
2663 vty_out(vty, "\n");
2664 vty_out(vty, "\n");
2665 }
2666
2667 vty_out(vty, "Designated Router\n");
2668 vty_out(vty, "-----------------\n");
2669 vty_out(vty, "Address : %s\n", dr_str);
2670 vty_out(vty, "Priority : %u(%d)\n",
2671 pim_ifp->pim_dr_priority,
2672 pim_ifp->pim_dr_num_nondrpri_neighbors);
2673 vty_out(vty, "Uptime : %s\n", dr_uptime);
2674 vty_out(vty, "Elections : %d\n",
2675 pim_ifp->pim_dr_election_count);
2676 vty_out(vty, "Changes : %d\n",
2677 pim_ifp->pim_dr_election_changes);
2678 vty_out(vty, "\n");
2679 vty_out(vty, "\n");
2680
2681 /* FHR */
2682 print_header = 1;
2683 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2684 if (!up->rpf.source_nexthop.interface)
2685 continue;
2686
2687 if (strcmp(ifp->name,
2688 up->rpf.source_nexthop
2689 .interface->name) != 0)
2690 continue;
2691
2692 if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_FHR))
2693 continue;
2694
2695 if (print_header) {
2696 vty_out(vty,
2697 "FHR - First Hop Router\n");
2698 vty_out(vty,
2699 "----------------------\n");
2700 print_header = 0;
2701 }
2702
2703 pim_time_uptime(uptime, sizeof(uptime),
2704 now - up->state_transition);
2705 vty_out(vty,
2706 "%pPAs : %pPAs is a source, uptime is %s\n",
2707 &up->sg.grp, &up->sg.src, uptime);
2708 }
2709
2710 if (!print_header) {
2711 vty_out(vty, "\n");
2712 vty_out(vty, "\n");
2713 }
2714
2715 vty_out(vty, "Hellos\n");
2716 vty_out(vty, "------\n");
2717 vty_out(vty, "Period : %d\n",
2718 pim_ifp->pim_hello_period);
2719 vty_out(vty, "HoldTime : %d\n",
2720 PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
2721 vty_out(vty, "Timer : %s\n", hello_timer);
2722 vty_out(vty, "StatStart : %s\n", stat_uptime);
2723 vty_out(vty, "Receive : %d\n",
2724 pim_ifp->pim_ifstat_hello_recv);
2725 vty_out(vty, "Receive Failed : %d\n",
2726 pim_ifp->pim_ifstat_hello_recvfail);
2727 vty_out(vty, "Send : %d\n",
2728 pim_ifp->pim_ifstat_hello_sent);
2729 vty_out(vty, "Send Failed : %d\n",
2730 pim_ifp->pim_ifstat_hello_sendfail);
2731 vty_out(vty, "Generation ID : %08x\n",
2732 pim_ifp->pim_generation_id);
2733 vty_out(vty, "\n");
2734 vty_out(vty, "\n");
2735
2736 pim_print_ifp_flags(vty, ifp);
2737
2738 vty_out(vty, "Join Prune Interval\n");
2739 vty_out(vty, "-------------------\n");
2740 vty_out(vty, "LAN Delay : %s\n",
2741 pim_if_lan_delay_enabled(ifp) ? "yes" : "no");
2742 vty_out(vty, "Effective Propagation Delay : %d msec\n",
2743 pim_if_effective_propagation_delay_msec(ifp));
2744 vty_out(vty, "Effective Override Interval : %d msec\n",
2745 pim_if_effective_override_interval_msec(ifp));
2746 vty_out(vty, "Join Prune Override Interval : %d msec\n",
2747 pim_if_jp_override_interval_msec(ifp));
2748 vty_out(vty, "\n");
2749 vty_out(vty, "\n");
2750
2751 vty_out(vty, "LAN Prune Delay\n");
2752 vty_out(vty, "---------------\n");
2753 vty_out(vty, "Propagation Delay : %d msec\n",
2754 pim_ifp->pim_propagation_delay_msec);
2755 vty_out(vty, "Propagation Delay (Highest) : %d msec\n",
2756 pim_ifp->pim_neighbors_highest_propagation_delay_msec);
2757 vty_out(vty, "Override Interval : %d msec\n",
2758 pim_ifp->pim_override_interval_msec);
2759 vty_out(vty, "Override Interval (Highest) : %d msec\n",
2760 pim_ifp->pim_neighbors_highest_override_interval_msec);
2761 vty_out(vty, "\n");
2762 vty_out(vty, "\n");
2763
2764 vty_out(vty, "BSM Status\n");
2765 vty_out(vty, "----------\n");
2766 vty_out(vty, "Bsm Enabled : %s\n",
2767 pim_ifp->bsm_enable ? "yes" : "no");
2768 vty_out(vty, "Unicast Bsm Enabled : %s\n",
2769 pim_ifp->ucast_bsm_accept ? "yes" : "no");
2770 vty_out(vty, "\n");
2771 vty_out(vty, "\n");
2772 }
2773 }
2774
2775 if (!found_ifname)
2776 vty_out(vty, "%% No such interface\n");
2777 }
2778
2779 void ip_pim_ssm_show_group_range(struct pim_instance *pim, struct vty *vty,
2780 bool uj)
2781 {
2782 struct pim_ssm *ssm = pim->ssm_info;
2783 const char *range_str =
2784 ssm->plist_name ? ssm->plist_name : PIM_SSM_STANDARD_RANGE;
2785
2786 if (uj) {
2787 json_object *json;
2788
2789 json = json_object_new_object();
2790 json_object_string_add(json, "ssmGroups", range_str);
2791 vty_json(vty, json);
2792 } else
2793 vty_out(vty, "SSM group range : %s\n", range_str);
2794 }
2795
2796 struct vty_pnc_cache_walk_data {
2797 struct vty *vty;
2798 struct pim_instance *pim;
2799 };
2800
2801 struct json_pnc_cache_walk_data {
2802 json_object *json_obj;
2803 struct pim_instance *pim;
2804 };
2805
2806 static int pim_print_vty_pnc_cache_walkcb(struct hash_bucket *bucket, void *arg)
2807 {
2808 struct pim_nexthop_cache *pnc = bucket->data;
2809 struct vty_pnc_cache_walk_data *cwd = arg;
2810 struct vty *vty = cwd->vty;
2811 struct pim_instance *pim = cwd->pim;
2812 struct nexthop *nh_node = NULL;
2813 ifindex_t first_ifindex;
2814 struct interface *ifp = NULL;
2815
2816 for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
2817 first_ifindex = nh_node->ifindex;
2818
2819 ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
2820
2821 vty_out(vty, "%-15pPA ", &pnc->rpf.rpf_addr);
2822 vty_out(vty, "%-16s ", ifp ? ifp->name : "NULL");
2823 #if PIM_IPV == 4
2824 vty_out(vty, "%pI4 ", &nh_node->gate.ipv4);
2825 #else
2826 vty_out(vty, "%pI6 ", &nh_node->gate.ipv6);
2827 #endif
2828 vty_out(vty, "\n");
2829 }
2830 return CMD_SUCCESS;
2831 }
2832
2833 static int pim_print_json_pnc_cache_walkcb(struct hash_bucket *backet,
2834 void *arg)
2835 {
2836 struct pim_nexthop_cache *pnc = backet->data;
2837 struct json_pnc_cache_walk_data *cwd = arg;
2838 struct pim_instance *pim = cwd->pim;
2839 struct nexthop *nh_node = NULL;
2840 ifindex_t first_ifindex;
2841 struct interface *ifp = NULL;
2842 char addr_str[PIM_ADDRSTRLEN];
2843 json_object *json_row = NULL;
2844 json_object *json_ifp = NULL;
2845 json_object *json_arr = NULL;
2846
2847 for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
2848 first_ifindex = nh_node->ifindex;
2849 ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
2850 snprintfrr(addr_str, sizeof(addr_str), "%pPA",
2851 &pnc->rpf.rpf_addr);
2852 json_object_object_get_ex(cwd->json_obj, addr_str, &json_row);
2853 if (!json_row) {
2854 json_row = json_object_new_object();
2855 json_object_string_addf(json_row, "address", "%pPA",
2856 &pnc->rpf.rpf_addr);
2857 json_object_object_addf(cwd->json_obj, json_row, "%pPA",
2858 &pnc->rpf.rpf_addr);
2859 json_arr = json_object_new_array();
2860 json_object_object_add(json_row, "nexthops", json_arr);
2861 }
2862 json_ifp = json_object_new_object();
2863 json_object_string_add(json_ifp, "interface",
2864 ifp ? ifp->name : "NULL");
2865 #if PIM_IPV == 4
2866 json_object_string_addf(json_ifp, "nexthop", "%pI4",
2867 &nh_node->gate.ipv4);
2868 #else
2869 json_object_string_addf(json_ifp, "nexthop", "%pI6",
2870 &nh_node->gate.ipv6);
2871 #endif
2872 json_object_array_add(json_arr, json_ifp);
2873 }
2874 return CMD_SUCCESS;
2875 }
2876
2877 int pim_show_nexthop_lookup_cmd_helper(const char *vrf, struct vty *vty,
2878 pim_addr source, pim_addr group)
2879 {
2880 int result = 0;
2881 pim_addr vif_source;
2882 struct prefix grp;
2883 struct pim_nexthop nexthop;
2884 struct vrf *v;
2885 char grp_str[PREFIX_STRLEN];
2886
2887 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
2888
2889 if (!v)
2890 return CMD_WARNING;
2891
2892 #if PIM_IPV == 4
2893 if (pim_is_group_224_4(source)) {
2894 vty_out(vty,
2895 "Invalid argument. Expected Valid Source Address.\n");
2896 return CMD_WARNING;
2897 }
2898
2899 if (!pim_is_group_224_4(group)) {
2900 vty_out(vty,
2901 "Invalid argument. Expected Valid Multicast Group Address.\n");
2902 return CMD_WARNING;
2903 }
2904 #endif
2905
2906 if (!pim_rp_set_upstream_addr(v->info, &vif_source, source, group))
2907 return CMD_SUCCESS;
2908
2909 pim_addr_to_prefix(&grp, group);
2910 memset(&nexthop, 0, sizeof(nexthop));
2911
2912 result =
2913 pim_ecmp_nexthop_lookup(v->info, &nexthop, vif_source, &grp, 0);
2914
2915 if (!result) {
2916 vty_out(vty,
2917 "Nexthop Lookup failed, no usable routes returned.\n");
2918 return CMD_SUCCESS;
2919 }
2920
2921 pim_addr_dump("<grp?>", &grp, grp_str, sizeof(grp_str));
2922
2923 vty_out(vty, "Group %s --- Nexthop %pPAs Interface %s\n", grp_str,
2924 &nexthop.mrib_nexthop_addr, nexthop.interface->name);
2925
2926 return CMD_SUCCESS;
2927 }
2928
2929 int pim_show_nexthop_cmd_helper(const char *vrf, struct vty *vty, bool uj)
2930 {
2931 struct vrf *v;
2932
2933 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
2934
2935 if (!v)
2936 return CMD_WARNING;
2937
2938 pim_show_nexthop(v->info, vty, uj);
2939
2940 return CMD_SUCCESS;
2941 }
2942
2943 void pim_show_nexthop(struct pim_instance *pim, struct vty *vty, bool uj)
2944 {
2945 struct vty_pnc_cache_walk_data cwd;
2946 struct json_pnc_cache_walk_data jcwd;
2947
2948 cwd.vty = vty;
2949 cwd.pim = pim;
2950 jcwd.pim = pim;
2951
2952 if (uj) {
2953 jcwd.json_obj = json_object_new_object();
2954 } else {
2955 vty_out(vty, "Number of registered addresses: %lu\n",
2956 pim->rpf_hash->count);
2957 vty_out(vty, "Address Interface Nexthop\n");
2958 vty_out(vty, "---------------------------------------------\n");
2959 }
2960
2961 if (uj) {
2962 hash_walk(pim->rpf_hash, pim_print_json_pnc_cache_walkcb,
2963 &jcwd);
2964 vty_json(vty, jcwd.json_obj);
2965 } else
2966 hash_walk(pim->rpf_hash, pim_print_vty_pnc_cache_walkcb, &cwd);
2967 }
2968
2969 int pim_show_neighbors_cmd_helper(const char *vrf, struct vty *vty,
2970 const char *json, const char *interface)
2971 {
2972 struct vrf *v;
2973 json_object *json_parent = NULL;
2974
2975 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
2976
2977 if (!v)
2978 return CMD_WARNING;
2979
2980 if (json)
2981 json_parent = json_object_new_object();
2982
2983 if (interface)
2984 pim_show_neighbors_single(v->info, vty, interface, json_parent);
2985 else
2986 pim_show_neighbors(v->info, vty, json_parent);
2987
2988 if (json)
2989 vty_json(vty, json_parent);
2990
2991 return CMD_SUCCESS;
2992 }
2993
2994 int pim_show_neighbors_vrf_all_cmd_helper(struct vty *vty, const char *json,
2995 const char *interface)
2996 {
2997 struct vrf *v;
2998 json_object *json_parent = NULL;
2999 json_object *json_vrf = NULL;
3000
3001 if (json)
3002 json_parent = json_object_new_object();
3003 RB_FOREACH (v, vrf_name_head, &vrfs_by_name) {
3004 if (!json)
3005 vty_out(vty, "VRF: %s\n", v->name);
3006 else
3007 json_vrf = json_object_new_object();
3008
3009 if (interface)
3010 pim_show_neighbors_single(v->info, vty, interface,
3011 json_vrf);
3012 else
3013 pim_show_neighbors(v->info, vty, json_vrf);
3014
3015 if (json)
3016 json_object_object_add(json_parent, v->name, json_vrf);
3017 }
3018 if (json)
3019 vty_json(vty, json_parent);
3020
3021 return CMD_SUCCESS;
3022 }
3023
3024 void pim_show_neighbors_single(struct pim_instance *pim, struct vty *vty,
3025 const char *neighbor, json_object *json)
3026 {
3027 struct listnode *neighnode;
3028 struct interface *ifp;
3029 struct pim_interface *pim_ifp;
3030 struct pim_neighbor *neigh;
3031 time_t now;
3032 int found_neighbor = 0;
3033 int option_address_list;
3034 int option_dr_priority;
3035 int option_generation_id;
3036 int option_holdtime;
3037 int option_lan_prune_delay;
3038 int option_t_bit;
3039 char uptime[10];
3040 char expire[10];
3041 char neigh_src_str[PIM_ADDRSTRLEN];
3042
3043 json_object *json_ifp = NULL;
3044 json_object *json_row = NULL;
3045
3046 now = pim_time_monotonic_sec();
3047
3048 FOR_ALL_INTERFACES (pim->vrf, ifp) {
3049 pim_ifp = ifp->info;
3050
3051 if (!pim_ifp)
3052 continue;
3053
3054 if (pim_ifp->pim_sock_fd < 0)
3055 continue;
3056
3057 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
3058 neigh)) {
3059 snprintfrr(neigh_src_str, sizeof(neigh_src_str),
3060 "%pPAs", &neigh->source_addr);
3061
3062 /*
3063 * The user can specify either the interface name or the
3064 * PIM neighbor IP.
3065 * If this pim_ifp matches neither then skip.
3066 */
3067 if (strcmp(neighbor, "detail") &&
3068 strcmp(neighbor, ifp->name) &&
3069 strcmp(neighbor, neigh_src_str))
3070 continue;
3071
3072 found_neighbor = 1;
3073 pim_time_uptime(uptime, sizeof(uptime),
3074 now - neigh->creation);
3075 pim_time_timer_to_hhmmss(expire, sizeof(expire),
3076 neigh->t_expire_timer);
3077
3078 option_address_list = 0;
3079 option_dr_priority = 0;
3080 option_generation_id = 0;
3081 option_holdtime = 0;
3082 option_lan_prune_delay = 0;
3083 option_t_bit = 0;
3084
3085 if (PIM_OPTION_IS_SET(neigh->hello_options,
3086 PIM_OPTION_MASK_ADDRESS_LIST))
3087 option_address_list = 1;
3088
3089 if (PIM_OPTION_IS_SET(neigh->hello_options,
3090 PIM_OPTION_MASK_DR_PRIORITY))
3091 option_dr_priority = 1;
3092
3093 if (PIM_OPTION_IS_SET(neigh->hello_options,
3094 PIM_OPTION_MASK_GENERATION_ID))
3095 option_generation_id = 1;
3096
3097 if (PIM_OPTION_IS_SET(neigh->hello_options,
3098 PIM_OPTION_MASK_HOLDTIME))
3099 option_holdtime = 1;
3100
3101 if (PIM_OPTION_IS_SET(neigh->hello_options,
3102 PIM_OPTION_MASK_LAN_PRUNE_DELAY))
3103 option_lan_prune_delay = 1;
3104
3105 if (PIM_OPTION_IS_SET(
3106 neigh->hello_options,
3107 PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION))
3108 option_t_bit = 1;
3109
3110 if (json) {
3111
3112 /* Does this ifp live in json? If not create it
3113 */
3114 json_object_object_get_ex(json, ifp->name,
3115 &json_ifp);
3116
3117 if (!json_ifp) {
3118 json_ifp = json_object_new_object();
3119 json_object_pim_ifp_add(json_ifp, ifp);
3120 json_object_object_add(json, ifp->name,
3121 json_ifp);
3122 }
3123
3124 json_row = json_object_new_object();
3125 json_object_string_add(json_row, "interface",
3126 ifp->name);
3127 json_object_string_add(json_row, "address",
3128 neigh_src_str);
3129 json_object_string_add(json_row, "upTime",
3130 uptime);
3131 json_object_string_add(json_row, "holdtime",
3132 expire);
3133 json_object_int_add(json_row, "drPriority",
3134 neigh->dr_priority);
3135 json_object_int_add(json_row, "generationId",
3136 neigh->generation_id);
3137
3138 if (option_address_list)
3139 json_object_boolean_true_add(
3140 json_row,
3141 "helloOptionAddressList");
3142
3143 if (option_dr_priority)
3144 json_object_boolean_true_add(
3145 json_row,
3146 "helloOptionDrPriority");
3147
3148 if (option_generation_id)
3149 json_object_boolean_true_add(
3150 json_row,
3151 "helloOptionGenerationId");
3152
3153 if (option_holdtime)
3154 json_object_boolean_true_add(
3155 json_row,
3156 "helloOptionHoldtime");
3157
3158 if (option_lan_prune_delay)
3159 json_object_boolean_true_add(
3160 json_row,
3161 "helloOptionLanPruneDelay");
3162
3163 if (option_t_bit)
3164 json_object_boolean_true_add(
3165 json_row, "helloOptionTBit");
3166
3167 json_object_object_add(json_ifp, neigh_src_str,
3168 json_row);
3169
3170 } else {
3171 vty_out(vty, "Interface : %s\n", ifp->name);
3172 vty_out(vty, "Neighbor : %s\n", neigh_src_str);
3173 vty_out(vty,
3174 " Uptime : %s\n",
3175 uptime);
3176 vty_out(vty,
3177 " Holdtime : %s\n",
3178 expire);
3179 vty_out(vty,
3180 " DR Priority : %d\n",
3181 neigh->dr_priority);
3182 vty_out(vty,
3183 " Generation ID : %08x\n",
3184 neigh->generation_id);
3185 vty_out(vty,
3186 " Override Interval (msec) : %d\n",
3187 neigh->override_interval_msec);
3188 vty_out(vty,
3189 " Propagation Delay (msec) : %d\n",
3190 neigh->propagation_delay_msec);
3191 vty_out(vty,
3192 " Hello Option - Address List : %s\n",
3193 option_address_list ? "yes" : "no");
3194 vty_out(vty,
3195 " Hello Option - DR Priority : %s\n",
3196 option_dr_priority ? "yes" : "no");
3197 vty_out(vty,
3198 " Hello Option - Generation ID : %s\n",
3199 option_generation_id ? "yes" : "no");
3200 vty_out(vty,
3201 " Hello Option - Holdtime : %s\n",
3202 option_holdtime ? "yes" : "no");
3203 vty_out(vty,
3204 " Hello Option - LAN Prune Delay : %s\n",
3205 option_lan_prune_delay ? "yes" : "no");
3206 vty_out(vty,
3207 " Hello Option - T-bit : %s\n",
3208 option_t_bit ? "yes" : "no");
3209 bfd_sess_show(vty, json_ifp,
3210 neigh->bfd_session);
3211 vty_out(vty, "\n");
3212 }
3213 }
3214 }
3215
3216 if (!found_neighbor)
3217 vty_out(vty, "%% No such interface or neighbor\n");
3218 }
3219
3220 void pim_show_neighbors(struct pim_instance *pim, struct vty *vty,
3221 json_object *json)
3222 {
3223 struct listnode *neighnode;
3224 struct interface *ifp;
3225 struct pim_interface *pim_ifp;
3226 struct pim_neighbor *neigh;
3227 struct ttable *tt = NULL;
3228 char *table = NULL;
3229 time_t now;
3230 char uptime[10];
3231 char expire[10];
3232 char neigh_src_str[PIM_ADDRSTRLEN];
3233 json_object *json_ifp_rows = NULL;
3234 json_object *json_row = NULL;
3235
3236 now = pim_time_monotonic_sec();
3237
3238 if (!json) {
3239 /* Prepare table. */
3240 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
3241 ttable_add_row(tt, "Interface|Neighbor|Uptime|Holdtime|DR Pri");
3242 tt->style.cell.rpad = 2;
3243 tt->style.corner = '+';
3244 ttable_restyle(tt);
3245 }
3246
3247 FOR_ALL_INTERFACES (pim->vrf, ifp) {
3248 pim_ifp = ifp->info;
3249
3250 if (!pim_ifp)
3251 continue;
3252
3253 if (pim_ifp->pim_sock_fd < 0)
3254 continue;
3255
3256 if (json)
3257 json_ifp_rows = json_object_new_object();
3258
3259 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
3260 neigh)) {
3261 snprintfrr(neigh_src_str, sizeof(neigh_src_str),
3262 "%pPAs", &neigh->source_addr);
3263 pim_time_uptime(uptime, sizeof(uptime),
3264 now - neigh->creation);
3265 pim_time_timer_to_hhmmss(expire, sizeof(expire),
3266 neigh->t_expire_timer);
3267
3268 if (json) {
3269 json_row = json_object_new_object();
3270 json_object_string_add(json_row, "interface",
3271 ifp->name);
3272 json_object_string_add(json_row, "neighbor",
3273 neigh_src_str);
3274 json_object_string_add(json_row, "upTime",
3275 uptime);
3276 json_object_string_add(json_row, "holdTime",
3277 expire);
3278 json_object_int_add(json_row, "holdTimeMax",
3279 neigh->holdtime);
3280 json_object_int_add(json_row, "drPriority",
3281 neigh->dr_priority);
3282 json_object_object_add(json_ifp_rows,
3283 neigh_src_str, json_row);
3284
3285 } else {
3286 ttable_add_row(tt, "%s|%pPAs|%s|%s|%d",
3287 ifp->name, &neigh->source_addr,
3288 uptime, expire,
3289 neigh->dr_priority);
3290 }
3291 }
3292
3293 if (json) {
3294 json_object_object_add(json, ifp->name, json_ifp_rows);
3295 json_ifp_rows = NULL;
3296 }
3297 }
3298 /* Dump the generated table. */
3299 if (!json) {
3300 table = ttable_dump(tt, "\n");
3301 vty_out(vty, "%s\n", table);
3302 XFREE(MTYPE_TMP, table);
3303 ttable_del(tt);
3304 }
3305 }
3306
3307 int gm_process_query_max_response_time_cmd(struct vty *vty,
3308 const char *qmrt_str)
3309 {
3310 const struct lyd_node *pim_enable_dnode;
3311
3312 pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
3313 FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH,
3314 FRR_PIM_AF_XPATH_VAL);
3315
3316 if (!pim_enable_dnode) {
3317 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true");
3318 } else {
3319 if (!yang_dnode_get_bool(pim_enable_dnode, "."))
3320 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY,
3321 "true");
3322 }
3323
3324 nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
3325 qmrt_str);
3326 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3327 FRR_PIM_AF_XPATH_VAL);
3328 }
3329
3330 int gm_process_no_query_max_response_time_cmd(struct vty *vty)
3331 {
3332 nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_DESTROY,
3333 NULL);
3334 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3335 FRR_PIM_AF_XPATH_VAL);
3336 }
3337
3338 int gm_process_last_member_query_count_cmd(struct vty *vty,
3339 const char *lmqc_str)
3340 {
3341 const struct lyd_node *pim_enable_dnode;
3342
3343 pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
3344 FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH,
3345 FRR_PIM_AF_XPATH_VAL);
3346 if (!pim_enable_dnode) {
3347 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true");
3348 } else {
3349 if (!yang_dnode_get_bool(pim_enable_dnode, "."))
3350 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY,
3351 "true");
3352 }
3353
3354 nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_MODIFY,
3355 lmqc_str);
3356 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3357 FRR_PIM_AF_XPATH_VAL);
3358 }
3359
3360 int gm_process_no_last_member_query_count_cmd(struct vty *vty)
3361 {
3362 nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_DESTROY,
3363 NULL);
3364 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3365 FRR_PIM_AF_XPATH_VAL);
3366 }
3367
3368 int gm_process_last_member_query_interval_cmd(struct vty *vty,
3369 const char *lmqi_str)
3370 {
3371 const struct lyd_node *pim_enable_dnode;
3372
3373 pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
3374 FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH,
3375 FRR_PIM_AF_XPATH_VAL);
3376 if (!pim_enable_dnode) {
3377 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true");
3378 } else {
3379 if (!yang_dnode_get_bool(pim_enable_dnode, "."))
3380 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY,
3381 "true");
3382 }
3383
3384 nb_cli_enqueue_change(vty, "./last-member-query-interval", NB_OP_MODIFY,
3385 lmqi_str);
3386 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3387 FRR_PIM_AF_XPATH_VAL);
3388 }
3389
3390 int gm_process_no_last_member_query_interval_cmd(struct vty *vty)
3391 {
3392 nb_cli_enqueue_change(vty, "./last-member-query-interval",
3393 NB_OP_DESTROY, NULL);
3394 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3395 FRR_PIM_AF_XPATH_VAL);
3396 }
3397
3398 int pim_process_ssmpingd_cmd(struct vty *vty, enum nb_operation operation,
3399 const char *src_str)
3400 {
3401 const char *vrfname;
3402 char ssmpingd_ip_xpath[XPATH_MAXLEN];
3403
3404 vrfname = pim_cli_get_vrf_name(vty);
3405 if (vrfname == NULL)
3406 return CMD_WARNING_CONFIG_FAILED;
3407
3408 snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath),
3409 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
3410 FRR_PIM_AF_XPATH_VAL);
3411 strlcat(ssmpingd_ip_xpath, "/ssm-pingd-source-ip",
3412 sizeof(ssmpingd_ip_xpath));
3413
3414 nb_cli_enqueue_change(vty, ssmpingd_ip_xpath, operation, src_str);
3415
3416 return nb_cli_apply_changes(vty, NULL);
3417 }
3418
3419 int pim_process_bsm_cmd(struct vty *vty)
3420 {
3421 const struct lyd_node *gm_enable_dnode;
3422
3423 gm_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
3424 FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
3425 FRR_PIM_AF_XPATH_VAL);
3426 if (!gm_enable_dnode)
3427 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
3428 "true");
3429 else {
3430 if (!yang_dnode_get_bool(gm_enable_dnode, "."))
3431 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
3432 "true");
3433 }
3434
3435 nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "true");
3436
3437 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
3438 FRR_PIM_AF_XPATH_VAL);
3439 }
3440
3441 int pim_process_no_bsm_cmd(struct vty *vty)
3442 {
3443 nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "false");
3444
3445 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
3446 FRR_PIM_AF_XPATH_VAL);
3447 }
3448
3449 int pim_process_unicast_bsm_cmd(struct vty *vty)
3450 {
3451 const struct lyd_node *gm_enable_dnode;
3452
3453 gm_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
3454 FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
3455 FRR_PIM_AF_XPATH_VAL);
3456 if (!gm_enable_dnode)
3457 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
3458 "true");
3459 else {
3460 if (!yang_dnode_get_bool(gm_enable_dnode, "."))
3461 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
3462 "true");
3463 }
3464
3465 nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "true");
3466
3467 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
3468 FRR_PIM_AF_XPATH_VAL);
3469 }
3470
3471 int pim_process_no_unicast_bsm_cmd(struct vty *vty)
3472 {
3473 nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "false");
3474
3475 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
3476 FRR_PIM_AF_XPATH_VAL);
3477 }
3478
3479 static void show_scan_oil_stats(struct pim_instance *pim, struct vty *vty,
3480 time_t now)
3481 {
3482 char uptime_scan_oil[10];
3483 char uptime_mroute_add[10];
3484 char uptime_mroute_del[10];
3485
3486 pim_time_uptime_begin(uptime_scan_oil, sizeof(uptime_scan_oil), now,
3487 pim->scan_oil_last);
3488 pim_time_uptime_begin(uptime_mroute_add, sizeof(uptime_mroute_add), now,
3489 pim->mroute_add_last);
3490 pim_time_uptime_begin(uptime_mroute_del, sizeof(uptime_mroute_del), now,
3491 pim->mroute_del_last);
3492
3493 vty_out(vty,
3494 "Scan OIL - Last: %s Events: %lld\n"
3495 "MFC Add - Last: %s Events: %lld\n"
3496 "MFC Del - Last: %s Events: %lld\n",
3497 uptime_scan_oil, (long long)pim->scan_oil_events,
3498 uptime_mroute_add, (long long)pim->mroute_add_events,
3499 uptime_mroute_del, (long long)pim->mroute_del_events);
3500 }
3501
3502 void show_multicast_interfaces(struct pim_instance *pim, struct vty *vty,
3503 json_object *json)
3504 {
3505 struct interface *ifp;
3506 struct ttable *tt = NULL;
3507 char *table = NULL;
3508 json_object *json_row = NULL;
3509
3510 vty_out(vty, "\n");
3511
3512 if (!json) {
3513 /* Prepare table. */
3514 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
3515 ttable_add_row(
3516 tt,
3517 "Interface|Address|ifi|Vif|PktsIn|PktsOut|BytesIn|BytesOut");
3518 tt->style.cell.rpad = 2;
3519 tt->style.corner = '+';
3520 ttable_restyle(tt);
3521 }
3522
3523 FOR_ALL_INTERFACES (pim->vrf, ifp) {
3524 struct pim_interface *pim_ifp;
3525 #if PIM_IPV == 4
3526 struct sioc_vif_req vreq;
3527 #else
3528 struct sioc_mif_req6 vreq;
3529 #endif
3530
3531 pim_ifp = ifp->info;
3532
3533 if (!pim_ifp)
3534 continue;
3535
3536 memset(&vreq, 0, sizeof(vreq));
3537 #if PIM_IPV == 4
3538 vreq.vifi = pim_ifp->mroute_vif_index;
3539 if (ioctl(pim->mroute_socket, SIOCGETVIFCNT, &vreq)) {
3540 zlog_warn(
3541 "ioctl(SIOCGETVIFCNT=%lu) failure for interface %s vif_index=%d: errno=%d: %s",
3542 (unsigned long)SIOCGETVIFCNT, ifp->name,
3543 pim_ifp->mroute_vif_index, errno,
3544 safe_strerror(errno));
3545 }
3546 #else
3547 vreq.mifi = pim_ifp->mroute_vif_index;
3548 if (ioctl(pim->mroute_socket, SIOCGETMIFCNT_IN6, &vreq)) {
3549 zlog_warn(
3550 "ioctl(SIOCGETMIFCNT_IN6=%lu) failure for interface %s vif_index=%d: errno=%d: %s",
3551 (unsigned long)SIOCGETMIFCNT_IN6, ifp->name,
3552 pim_ifp->mroute_vif_index, errno,
3553 safe_strerror(errno));
3554 }
3555 #endif
3556
3557 if (json) {
3558 json_row = json_object_new_object();
3559 json_object_string_add(json_row, "name", ifp->name);
3560 json_object_string_add(json_row, "state",
3561 if_is_up(ifp) ? "up" : "down");
3562 json_object_string_addf(json_row, "address", "%pPA",
3563 &pim_ifp->primary_address);
3564 json_object_int_add(json_row, "ifIndex", ifp->ifindex);
3565 json_object_int_add(json_row, "vif",
3566 pim_ifp->mroute_vif_index);
3567 json_object_int_add(json_row, "pktsIn",
3568 (unsigned long)vreq.icount);
3569 json_object_int_add(json_row, "pktsOut",
3570 (unsigned long)vreq.ocount);
3571 json_object_int_add(json_row, "bytesIn",
3572 (unsigned long)vreq.ibytes);
3573 json_object_int_add(json_row, "bytesOut",
3574 (unsigned long)vreq.obytes);
3575 json_object_object_add(json, ifp->name, json_row);
3576 } else {
3577 ttable_add_row(tt, "%s|%pPAs|%d|%d|%lu|%lu|%lu|%lu",
3578 ifp->name, &pim_ifp->primary_address,
3579 ifp->ifindex, pim_ifp->mroute_vif_index,
3580 (unsigned long)vreq.icount,
3581 (unsigned long)vreq.ocount,
3582 (unsigned long)vreq.ibytes,
3583 (unsigned long)vreq.obytes);
3584 }
3585 }
3586 /* Dump the generated table. */
3587 if (!json) {
3588 table = ttable_dump(tt, "\n");
3589 vty_out(vty, "%s\n", table);
3590 XFREE(MTYPE_TMP, table);
3591 ttable_del(tt);
3592 }
3593 }
3594
3595 void pim_cmd_show_ip_multicast_helper(struct pim_instance *pim, struct vty *vty)
3596 {
3597 struct vrf *vrf = pim->vrf;
3598 time_t now = pim_time_monotonic_sec();
3599 char uptime[10];
3600 char mlag_role[80];
3601
3602 pim = vrf->info;
3603
3604 vty_out(vty, "Router MLAG Role: %s\n",
3605 mlag_role2str(router->mlag_role, mlag_role, sizeof(mlag_role)));
3606 vty_out(vty, "Mroute socket descriptor:");
3607
3608 vty_out(vty, " %d(%s)\n", pim->mroute_socket, vrf->name);
3609 vty_out(vty, "PIM Register socket descriptor:");
3610 vty_out(vty, " %d(%s)\n", pim->reg_sock, vrf->name);
3611
3612 pim_time_uptime(uptime, sizeof(uptime),
3613 now - pim->mroute_socket_creation);
3614 vty_out(vty, "Mroute socket uptime: %s\n", uptime);
3615
3616 vty_out(vty, "\n");
3617
3618 pim_zebra_zclient_update(vty);
3619 pim_zlookup_show_ip_multicast(vty);
3620
3621 vty_out(vty, "\n");
3622 vty_out(vty, "Maximum highest VifIndex: %d\n", PIM_MAX_USABLE_VIFS);
3623
3624 vty_out(vty, "\n");
3625 vty_out(vty, "Upstream Join Timer: %d secs\n", router->t_periodic);
3626 vty_out(vty, "Join/Prune Holdtime: %d secs\n", PIM_JP_HOLDTIME);
3627 vty_out(vty, "PIM ECMP: %s\n", pim->ecmp_enable ? "Enable" : "Disable");
3628 vty_out(vty, "PIM ECMP Rebalance: %s\n",
3629 pim->ecmp_rebalance_enable ? "Enable" : "Disable");
3630
3631 vty_out(vty, "\n");
3632
3633 pim_show_rpf_refresh_stats(vty, pim, now, NULL);
3634
3635 vty_out(vty, "\n");
3636
3637 show_scan_oil_stats(pim, vty, now);
3638
3639 show_multicast_interfaces(pim, vty, NULL);
3640 }
3641
3642 void show_mroute(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg,
3643 bool fill, json_object *json)
3644 {
3645 struct listnode *node;
3646 struct channel_oil *c_oil;
3647 struct static_route *s_route;
3648 struct ttable *tt = NULL;
3649 char *table = NULL;
3650 time_t now;
3651 json_object *json_group = NULL;
3652 json_object *json_source = NULL;
3653 json_object *json_oil = NULL;
3654 json_object *json_ifp_out = NULL;
3655 int found_oif;
3656 int first;
3657 char grp_str[PIM_ADDRSTRLEN];
3658 char src_str[PIM_ADDRSTRLEN];
3659 char in_ifname[INTERFACE_NAMSIZ + 1];
3660 char out_ifname[INTERFACE_NAMSIZ + 1];
3661 int oif_vif_index;
3662 struct interface *ifp_in;
3663 char proto[100];
3664 char state_str[PIM_REG_STATE_STR_LEN];
3665 char mroute_uptime[10];
3666
3667 if (!json) {
3668 vty_out(vty, "IP Multicast Routing Table\n");
3669 vty_out(vty, "Flags: S - Sparse, C - Connected, P - Pruned\n");
3670 vty_out(vty,
3671 " R - SGRpt Pruned, F - Register flag, T - SPT-bit set\n");
3672
3673 /* Prepare table. */
3674 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
3675 ttable_add_row(
3676 tt, "Source|Group|Flags|Proto|Input|Output|TTL|Uptime");
3677 tt->style.cell.rpad = 2;
3678 tt->style.corner = '+';
3679 ttable_restyle(tt);
3680 }
3681
3682 now = pim_time_monotonic_sec();
3683
3684 /* print list of PIM and IGMP routes */
3685 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
3686 found_oif = 0;
3687 first = 1;
3688 if (!c_oil->installed)
3689 continue;
3690
3691 if (!pim_addr_is_any(sg->grp) &&
3692 pim_addr_cmp(sg->grp, *oil_mcastgrp(c_oil)))
3693 continue;
3694 if (!pim_addr_is_any(sg->src) &&
3695 pim_addr_cmp(sg->src, *oil_origin(c_oil)))
3696 continue;
3697
3698 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
3699 oil_mcastgrp(c_oil));
3700 snprintfrr(src_str, sizeof(src_str), "%pPAs",
3701 oil_origin(c_oil));
3702
3703 strlcpy(state_str, "S", sizeof(state_str));
3704 /* When a non DR receives a igmp join, it creates a (*,G)
3705 * channel_oil without any upstream creation
3706 */
3707 if (c_oil->up) {
3708 if (PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(c_oil->up->flags))
3709 strlcat(state_str, "C", sizeof(state_str));
3710 if (pim_upstream_is_sg_rpt(c_oil->up))
3711 strlcat(state_str, "R", sizeof(state_str));
3712 if (PIM_UPSTREAM_FLAG_TEST_FHR(c_oil->up->flags))
3713 strlcat(state_str, "F", sizeof(state_str));
3714 if (c_oil->up->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
3715 strlcat(state_str, "T", sizeof(state_str));
3716 }
3717 if (pim_channel_oil_empty(c_oil))
3718 strlcat(state_str, "P", sizeof(state_str));
3719
3720 ifp_in = pim_if_find_by_vif_index(pim, *oil_parent(c_oil));
3721
3722 if (ifp_in)
3723 strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
3724 else
3725 strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
3726
3727
3728 pim_time_uptime(mroute_uptime, sizeof(mroute_uptime),
3729 now - c_oil->mroute_creation);
3730
3731 if (json) {
3732
3733 /* Find the group, create it if it doesn't exist */
3734 json_object_object_get_ex(json, grp_str, &json_group);
3735
3736 if (!json_group) {
3737 json_group = json_object_new_object();
3738 json_object_object_add(json, grp_str,
3739 json_group);
3740 }
3741
3742 /* Find the source nested under the group, create it if
3743 * it doesn't exist
3744 */
3745 json_object_object_get_ex(json_group, src_str,
3746 &json_source);
3747
3748 if (!json_source) {
3749 json_source = json_object_new_object();
3750 json_object_object_add(json_group, src_str,
3751 json_source);
3752 }
3753
3754 /* Find the inbound interface nested under the source,
3755 * create it if it doesn't exist
3756 */
3757 json_object_string_add(json_source, "source", src_str);
3758 json_object_string_add(json_source, "group", grp_str);
3759 json_object_int_add(json_source, "installed",
3760 c_oil->installed);
3761 json_object_int_add(json_source, "refCount",
3762 c_oil->oil_ref_count);
3763 json_object_int_add(json_source, "oilSize",
3764 c_oil->oil_size);
3765 json_object_int_add(json_source, "OilInheritedRescan",
3766 c_oil->oil_inherited_rescan);
3767 json_object_int_add(json_source, "oilInheritedRescan",
3768 c_oil->oil_inherited_rescan);
3769 json_object_string_add(json_source, "iif", in_ifname);
3770 json_object_string_add(json_source, "upTime",
3771 mroute_uptime);
3772 json_oil = NULL;
3773 }
3774
3775 for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
3776 ++oif_vif_index) {
3777 struct interface *ifp_out;
3778 int ttl;
3779
3780 ttl = oil_if_has(c_oil, oif_vif_index);
3781 if (ttl < 1)
3782 continue;
3783
3784 /* do not display muted OIFs */
3785 if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_MUTE)
3786 continue;
3787
3788 if (*oil_parent(c_oil) == oif_vif_index &&
3789 !pim_mroute_allow_iif_in_oil(c_oil, oif_vif_index))
3790 continue;
3791
3792 ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
3793 found_oif = 1;
3794
3795 if (ifp_out)
3796 strlcpy(out_ifname, ifp_out->name,
3797 sizeof(out_ifname));
3798 else
3799 strlcpy(out_ifname, "<oif?>",
3800 sizeof(out_ifname));
3801
3802 if (json) {
3803 json_ifp_out = json_object_new_object();
3804 json_object_string_add(json_ifp_out, "source",
3805 src_str);
3806 json_object_string_add(json_ifp_out, "group",
3807 grp_str);
3808
3809 if (c_oil->oif_flags[oif_vif_index] &
3810 PIM_OIF_FLAG_PROTO_PIM)
3811 json_object_boolean_true_add(
3812 json_ifp_out, "protocolPim");
3813
3814 if (c_oil->oif_flags[oif_vif_index] &
3815 PIM_OIF_FLAG_PROTO_GM)
3816 #if PIM_IPV == 4
3817 json_object_boolean_true_add(
3818 json_ifp_out, "protocolIgmp");
3819 #else
3820 json_object_boolean_true_add(
3821 json_ifp_out, "protocolMld");
3822 #endif
3823
3824 if (c_oil->oif_flags[oif_vif_index] &
3825 PIM_OIF_FLAG_PROTO_VXLAN)
3826 json_object_boolean_true_add(
3827 json_ifp_out, "protocolVxlan");
3828
3829 if (c_oil->oif_flags[oif_vif_index] &
3830 PIM_OIF_FLAG_PROTO_STAR)
3831 json_object_boolean_true_add(
3832 json_ifp_out,
3833 "protocolInherited");
3834
3835 json_object_string_add(json_ifp_out,
3836 "inboundInterface",
3837 in_ifname);
3838 json_object_int_add(json_ifp_out, "iVifI",
3839 *oil_parent(c_oil));
3840 json_object_string_add(json_ifp_out,
3841 "outboundInterface",
3842 out_ifname);
3843 json_object_int_add(json_ifp_out, "oVifI",
3844 oif_vif_index);
3845 json_object_int_add(json_ifp_out, "ttl", ttl);
3846 json_object_string_add(json_ifp_out, "upTime",
3847 mroute_uptime);
3848 json_object_string_add(json_source, "flags",
3849 state_str);
3850 if (!json_oil) {
3851 json_oil = json_object_new_object();
3852 json_object_object_add(json_source,
3853 "oil", json_oil);
3854 }
3855 json_object_object_add(json_oil, out_ifname,
3856 json_ifp_out);
3857 } else {
3858 proto[0] = '\0';
3859 if (c_oil->oif_flags[oif_vif_index] &
3860 PIM_OIF_FLAG_PROTO_PIM) {
3861 strlcpy(proto, "PIM", sizeof(proto));
3862 }
3863
3864 if (c_oil->oif_flags[oif_vif_index] &
3865 PIM_OIF_FLAG_PROTO_GM) {
3866 #if PIM_IPV == 4
3867 strlcpy(proto, "IGMP", sizeof(proto));
3868 #else
3869 strlcpy(proto, "MLD", sizeof(proto));
3870 #endif
3871 }
3872
3873 if (c_oil->oif_flags[oif_vif_index] &
3874 PIM_OIF_FLAG_PROTO_VXLAN) {
3875 strlcpy(proto, "VxLAN", sizeof(proto));
3876 }
3877
3878 if (c_oil->oif_flags[oif_vif_index] &
3879 PIM_OIF_FLAG_PROTO_STAR) {
3880 strlcpy(proto, "STAR", sizeof(proto));
3881 }
3882
3883 ttable_add_row(tt, "%s|%s|%s|%s|%s|%s|%d|%s",
3884 src_str, grp_str, state_str,
3885 proto, in_ifname, out_ifname,
3886 ttl, mroute_uptime);
3887
3888 if (first) {
3889 src_str[0] = '\0';
3890 grp_str[0] = '\0';
3891 in_ifname[0] = '\0';
3892 state_str[0] = '\0';
3893 mroute_uptime[0] = '\0';
3894 first = 0;
3895 }
3896 }
3897 }
3898
3899 if (!json && !found_oif) {
3900 ttable_add_row(tt, "%pPAs|%pPAs|%s|%s|%s|%s|%d|%s",
3901 oil_origin(c_oil), oil_mcastgrp(c_oil),
3902 state_str, "none", in_ifname, "none", 0,
3903 "--:--:--");
3904 }
3905 }
3906
3907 /* Print list of static routes */
3908 for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
3909 first = 1;
3910
3911 if (!s_route->c_oil.installed)
3912 continue;
3913
3914 snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &s_route->group);
3915 snprintfrr(src_str, sizeof(src_str), "%pPAs", &s_route->source);
3916 ifp_in = pim_if_find_by_vif_index(pim, s_route->iif);
3917 found_oif = 0;
3918
3919 if (ifp_in)
3920 strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
3921 else
3922 strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
3923
3924 if (json) {
3925
3926 /* Find the group, create it if it doesn't exist */
3927 json_object_object_get_ex(json, grp_str, &json_group);
3928
3929 if (!json_group) {
3930 json_group = json_object_new_object();
3931 json_object_object_add(json, grp_str,
3932 json_group);
3933 }
3934
3935 /* Find the source nested under the group, create it if
3936 * it doesn't exist
3937 */
3938 json_object_object_get_ex(json_group, src_str,
3939 &json_source);
3940
3941 if (!json_source) {
3942 json_source = json_object_new_object();
3943 json_object_object_add(json_group, src_str,
3944 json_source);
3945 }
3946
3947 json_object_string_add(json_source, "iif", in_ifname);
3948 json_oil = NULL;
3949 } else {
3950 strlcpy(proto, "STATIC", sizeof(proto));
3951 }
3952
3953 for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
3954 ++oif_vif_index) {
3955 struct interface *ifp_out;
3956 char oif_uptime[10];
3957 int ttl;
3958
3959 ttl = s_route->oif_ttls[oif_vif_index];
3960 if (ttl < 1)
3961 continue;
3962
3963 ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
3964 pim_time_uptime(
3965 oif_uptime, sizeof(oif_uptime),
3966 now - s_route->c_oil
3967 .oif_creation[oif_vif_index]);
3968 found_oif = 1;
3969
3970 if (ifp_out)
3971 strlcpy(out_ifname, ifp_out->name,
3972 sizeof(out_ifname));
3973 else
3974 strlcpy(out_ifname, "<oif?>",
3975 sizeof(out_ifname));
3976
3977 if (json) {
3978 json_ifp_out = json_object_new_object();
3979 json_object_string_add(json_ifp_out, "source",
3980 src_str);
3981 json_object_string_add(json_ifp_out, "group",
3982 grp_str);
3983 json_object_boolean_true_add(json_ifp_out,
3984 "protocolStatic");
3985 json_object_string_add(json_ifp_out,
3986 "inboundInterface",
3987 in_ifname);
3988 json_object_int_add(
3989 json_ifp_out, "iVifI",
3990 *oil_parent(&s_route->c_oil));
3991 json_object_string_add(json_ifp_out,
3992 "outboundInterface",
3993 out_ifname);
3994 json_object_int_add(json_ifp_out, "oVifI",
3995 oif_vif_index);
3996 json_object_int_add(json_ifp_out, "ttl", ttl);
3997 json_object_string_add(json_ifp_out, "upTime",
3998 oif_uptime);
3999 if (!json_oil) {
4000 json_oil = json_object_new_object();
4001 json_object_object_add(json_source,
4002 "oil", json_oil);
4003 }
4004 json_object_object_add(json_oil, out_ifname,
4005 json_ifp_out);
4006 } else {
4007 ttable_add_row(
4008 tt, "%pPAs|%pPAs|%s|%s|%s|%s|%d|%s",
4009 &s_route->source, &s_route->group, "-",
4010 proto, in_ifname, out_ifname, ttl,
4011 oif_uptime);
4012 if (first && !fill) {
4013 src_str[0] = '\0';
4014 grp_str[0] = '\0';
4015 in_ifname[0] = '\0';
4016 first = 0;
4017 }
4018 }
4019 }
4020
4021 if (!json && !found_oif) {
4022 ttable_add_row(tt, "%pPAs|%pPAs|%s|%s|%s|%s|%d|%s",
4023 &s_route->source, &s_route->group, "-",
4024 proto, in_ifname, "none", 0, "--:--:--");
4025 }
4026 }
4027 /* Dump the generated table. */
4028 if (!json) {
4029 table = ttable_dump(tt, "\n");
4030 vty_out(vty, "%s\n", table);
4031 XFREE(MTYPE_TMP, table);
4032 ttable_del(tt);
4033 }
4034 }
4035
4036 static void show_mroute_count_per_channel_oil(struct channel_oil *c_oil,
4037 json_object *json,
4038 struct ttable *tt)
4039 {
4040 json_object *json_group = NULL;
4041 json_object *json_source = NULL;
4042
4043 if (!c_oil->installed)
4044 return;
4045
4046 pim_mroute_update_counters(c_oil);
4047
4048 if (json) {
4049 char group_str[PIM_ADDRSTRLEN];
4050 char source_str[PIM_ADDRSTRLEN];
4051
4052 snprintfrr(group_str, sizeof(group_str), "%pPAs",
4053 oil_mcastgrp(c_oil));
4054 snprintfrr(source_str, sizeof(source_str), "%pPAs",
4055 oil_origin(c_oil));
4056
4057 json_object_object_get_ex(json, group_str, &json_group);
4058
4059 if (!json_group) {
4060 json_group = json_object_new_object();
4061 json_object_object_add(json, group_str, json_group);
4062 }
4063
4064 json_source = json_object_new_object();
4065 json_object_object_add(json_group, source_str, json_source);
4066 json_object_int_add(json_source, "lastUsed",
4067 c_oil->cc.lastused / 100);
4068 json_object_int_add(json_source, "packets", c_oil->cc.pktcnt);
4069 json_object_int_add(json_source, "bytes", c_oil->cc.bytecnt);
4070 json_object_int_add(json_source, "wrongIf", c_oil->cc.wrong_if);
4071
4072 } else {
4073 ttable_add_row(tt, "%pPAs|%pPAs|%llu|%ld|%ld|%ld",
4074 oil_origin(c_oil), oil_mcastgrp(c_oil),
4075 c_oil->cc.lastused / 100,
4076 c_oil->cc.pktcnt - c_oil->cc.origpktcnt,
4077 c_oil->cc.bytecnt - c_oil->cc.origbytecnt,
4078 c_oil->cc.wrong_if - c_oil->cc.origwrong_if);
4079 }
4080 }
4081
4082 void show_mroute_count(struct pim_instance *pim, struct vty *vty,
4083 json_object *json)
4084 {
4085 struct listnode *node;
4086 struct channel_oil *c_oil;
4087 struct static_route *sr;
4088 struct ttable *tt = NULL;
4089 char *table = NULL;
4090
4091 if (!json) {
4092 vty_out(vty, "\n");
4093
4094 /* Prepare table. */
4095 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
4096 ttable_add_row(tt,
4097 "Source|Group|LastUsed|Packets|Bytes|WrongIf");
4098 tt->style.cell.rpad = 2;
4099 tt->style.corner = '+';
4100 ttable_restyle(tt);
4101 }
4102
4103 /* Print PIM and IGMP route counts */
4104 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil)
4105 show_mroute_count_per_channel_oil(c_oil, json, tt);
4106
4107 for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sr))
4108 show_mroute_count_per_channel_oil(&sr->c_oil, json, tt);
4109
4110 /* Dump the generated table. */
4111 if (!json) {
4112 table = ttable_dump(tt, "\n");
4113 vty_out(vty, "%s\n", table);
4114 XFREE(MTYPE_TMP, table);
4115 ttable_del(tt);
4116 }
4117 }
4118
4119 void show_mroute_summary(struct pim_instance *pim, struct vty *vty,
4120 json_object *json)
4121 {
4122 struct listnode *node;
4123 struct channel_oil *c_oil;
4124 struct static_route *s_route;
4125 uint32_t starg_sw_mroute_cnt = 0;
4126 uint32_t sg_sw_mroute_cnt = 0;
4127 uint32_t starg_hw_mroute_cnt = 0;
4128 uint32_t sg_hw_mroute_cnt = 0;
4129 json_object *json_starg = NULL;
4130 json_object *json_sg = NULL;
4131
4132 if (!json)
4133 vty_out(vty, "Mroute Type Installed/Total\n");
4134
4135 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
4136 if (!c_oil->installed) {
4137 if (pim_addr_is_any(*oil_origin(c_oil)))
4138 starg_sw_mroute_cnt++;
4139 else
4140 sg_sw_mroute_cnt++;
4141 } else {
4142 if (pim_addr_is_any(*oil_origin(c_oil)))
4143 starg_hw_mroute_cnt++;
4144 else
4145 sg_hw_mroute_cnt++;
4146 }
4147 }
4148
4149 for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
4150 if (!s_route->c_oil.installed) {
4151 if (pim_addr_is_any(*oil_origin(&s_route->c_oil)))
4152 starg_sw_mroute_cnt++;
4153 else
4154 sg_sw_mroute_cnt++;
4155 } else {
4156 if (pim_addr_is_any(*oil_origin(&s_route->c_oil)))
4157 starg_hw_mroute_cnt++;
4158 else
4159 sg_hw_mroute_cnt++;
4160 }
4161 }
4162
4163 if (!json) {
4164 vty_out(vty, "%-20s %u/%u\n", "(*, G)", starg_hw_mroute_cnt,
4165 starg_sw_mroute_cnt + starg_hw_mroute_cnt);
4166 vty_out(vty, "%-20s %u/%u\n", "(S, G)", sg_hw_mroute_cnt,
4167 sg_sw_mroute_cnt + sg_hw_mroute_cnt);
4168 vty_out(vty, "------\n");
4169 vty_out(vty, "%-20s %u/%u\n", "Total",
4170 (starg_hw_mroute_cnt + sg_hw_mroute_cnt),
4171 (starg_sw_mroute_cnt + starg_hw_mroute_cnt +
4172 sg_sw_mroute_cnt + sg_hw_mroute_cnt));
4173 } else {
4174 /* (*,G) route details */
4175 json_starg = json_object_new_object();
4176 json_object_object_add(json, "wildcardGroup", json_starg);
4177
4178 json_object_int_add(json_starg, "installed",
4179 starg_hw_mroute_cnt);
4180 json_object_int_add(json_starg, "total",
4181 starg_sw_mroute_cnt + starg_hw_mroute_cnt);
4182
4183 /* (S, G) route details */
4184 json_sg = json_object_new_object();
4185 json_object_object_add(json, "sourceGroup", json_sg);
4186
4187 json_object_int_add(json_sg, "installed", sg_hw_mroute_cnt);
4188 json_object_int_add(json_sg, "total",
4189 sg_sw_mroute_cnt + sg_hw_mroute_cnt);
4190
4191 json_object_int_add(json, "totalNumOfInstalledMroutes",
4192 starg_hw_mroute_cnt + sg_hw_mroute_cnt);
4193 json_object_int_add(json, "totalNumOfMroutes",
4194 starg_sw_mroute_cnt + starg_hw_mroute_cnt +
4195 sg_sw_mroute_cnt +
4196 sg_hw_mroute_cnt);
4197 }
4198 }
4199
4200 int clear_ip_mroute_count_command(struct vty *vty, const char *name)
4201 {
4202 struct listnode *node;
4203 struct channel_oil *c_oil;
4204 struct static_route *sr;
4205 struct vrf *v = pim_cmd_lookup(vty, name);
4206 struct pim_instance *pim;
4207
4208 if (!v)
4209 return CMD_WARNING;
4210
4211 pim = v->info;
4212 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
4213 if (!c_oil->installed)
4214 continue;
4215
4216 pim_mroute_update_counters(c_oil);
4217 c_oil->cc.origpktcnt = c_oil->cc.pktcnt;
4218 c_oil->cc.origbytecnt = c_oil->cc.bytecnt;
4219 c_oil->cc.origwrong_if = c_oil->cc.wrong_if;
4220 }
4221
4222 for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sr)) {
4223 if (!sr->c_oil.installed)
4224 continue;
4225
4226 pim_mroute_update_counters(&sr->c_oil);
4227
4228 sr->c_oil.cc.origpktcnt = sr->c_oil.cc.pktcnt;
4229 sr->c_oil.cc.origbytecnt = sr->c_oil.cc.bytecnt;
4230 sr->c_oil.cc.origwrong_if = sr->c_oil.cc.wrong_if;
4231 }
4232 return CMD_SUCCESS;
4233 }
4234
4235 struct vrf *pim_cmd_lookup(struct vty *vty, const char *name)
4236 {
4237 struct vrf *vrf;
4238
4239 if (name)
4240 vrf = vrf_lookup_by_name(name);
4241 else
4242 vrf = vrf_lookup_by_id(VRF_DEFAULT);
4243
4244 if (!vrf)
4245 vty_out(vty, "Specified VRF: %s does not exist\n", name);
4246
4247 return vrf;
4248 }
4249
4250 void clear_mroute(struct pim_instance *pim)
4251 {
4252 struct pim_upstream *up;
4253 struct interface *ifp;
4254
4255 /* scan interfaces */
4256 FOR_ALL_INTERFACES (pim->vrf, ifp) {
4257 struct pim_interface *pim_ifp = ifp->info;
4258 struct pim_ifchannel *ch;
4259
4260 if (!pim_ifp)
4261 continue;
4262
4263 /* deleting all ifchannels */
4264 while (!RB_EMPTY(pim_ifchannel_rb, &pim_ifp->ifchannel_rb)) {
4265 ch = RB_ROOT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb);
4266
4267 pim_ifchannel_delete(ch);
4268 }
4269
4270 #if PIM_IPV == 4
4271 /* clean up all igmp groups */
4272 struct gm_group *grp;
4273
4274 if (pim_ifp->gm_group_list) {
4275 while (pim_ifp->gm_group_list->count) {
4276 grp = listnode_head(pim_ifp->gm_group_list);
4277 igmp_group_delete(grp);
4278 }
4279 }
4280 #else
4281 struct gm_if *gm_ifp;
4282
4283 gm_ifp = pim_ifp->mld;
4284 if (gm_ifp)
4285 gm_group_delete(gm_ifp);
4286 #endif
4287 }
4288
4289 /* clean up all upstreams*/
4290 while ((up = rb_pim_upstream_first(&pim->upstream_head)))
4291 pim_upstream_del(pim, up, __func__);
4292 }
4293
4294 void clear_pim_statistics(struct pim_instance *pim)
4295 {
4296 struct interface *ifp;
4297
4298 pim->bsm_rcvd = 0;
4299 pim->bsm_sent = 0;
4300 pim->bsm_dropped = 0;
4301
4302 /* scan interfaces */
4303 FOR_ALL_INTERFACES (pim->vrf, ifp) {
4304 struct pim_interface *pim_ifp = ifp->info;
4305
4306 if (!pim_ifp)
4307 continue;
4308
4309 pim_ifp->pim_ifstat_bsm_cfg_miss = 0;
4310 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss = 0;
4311 pim_ifp->pim_ifstat_bsm_invalid_sz = 0;
4312 }
4313 }
4314
4315 int clear_pim_interface_traffic(const char *vrf, struct vty *vty)
4316 {
4317 struct interface *ifp = NULL;
4318 struct pim_interface *pim_ifp = NULL;
4319
4320 struct vrf *v = pim_cmd_lookup(vty, vrf);
4321
4322 if (!v)
4323 return CMD_WARNING;
4324
4325 FOR_ALL_INTERFACES (v, ifp) {
4326 pim_ifp = ifp->info;
4327
4328 if (!pim_ifp)
4329 continue;
4330
4331 pim_ifp->pim_ifstat_hello_recv = 0;
4332 pim_ifp->pim_ifstat_hello_sent = 0;
4333 pim_ifp->pim_ifstat_join_recv = 0;
4334 pim_ifp->pim_ifstat_join_send = 0;
4335 pim_ifp->pim_ifstat_prune_recv = 0;
4336 pim_ifp->pim_ifstat_prune_send = 0;
4337 pim_ifp->pim_ifstat_reg_recv = 0;
4338 pim_ifp->pim_ifstat_reg_send = 0;
4339 pim_ifp->pim_ifstat_reg_stop_recv = 0;
4340 pim_ifp->pim_ifstat_reg_stop_send = 0;
4341 pim_ifp->pim_ifstat_assert_recv = 0;
4342 pim_ifp->pim_ifstat_assert_send = 0;
4343 pim_ifp->pim_ifstat_bsm_rx = 0;
4344 pim_ifp->pim_ifstat_bsm_tx = 0;
4345 #if PIM_IPV == 4
4346 pim_ifp->igmp_ifstat_joins_sent = 0;
4347 pim_ifp->igmp_ifstat_joins_failed = 0;
4348 pim_ifp->igmp_peak_group_count = 0;
4349 #endif
4350 }
4351
4352 return CMD_SUCCESS;
4353 }
4354
4355 int pim_debug_pim_cmd(void)
4356 {
4357 PIM_DO_DEBUG_PIM_EVENTS;
4358 PIM_DO_DEBUG_PIM_PACKETS;
4359 PIM_DO_DEBUG_PIM_TRACE;
4360 PIM_DO_DEBUG_MSDP_EVENTS;
4361 PIM_DO_DEBUG_MSDP_PACKETS;
4362 PIM_DO_DEBUG_BSM;
4363 PIM_DO_DEBUG_VXLAN;
4364 return CMD_SUCCESS;
4365 }
4366
4367 int pim_no_debug_pim_cmd(void)
4368 {
4369 PIM_DONT_DEBUG_PIM_EVENTS;
4370 PIM_DONT_DEBUG_PIM_PACKETS;
4371 PIM_DONT_DEBUG_PIM_TRACE;
4372 PIM_DONT_DEBUG_MSDP_EVENTS;
4373 PIM_DONT_DEBUG_MSDP_PACKETS;
4374
4375 PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND;
4376 PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV;
4377 PIM_DONT_DEBUG_BSM;
4378 PIM_DONT_DEBUG_VXLAN;
4379 return CMD_SUCCESS;
4380 }
4381
4382 int pim_debug_pim_packets_cmd(const char *hello, const char *joins,
4383 const char *registers, struct vty *vty)
4384 {
4385 if (hello) {
4386 PIM_DO_DEBUG_PIM_HELLO;
4387 vty_out(vty, "PIM Hello debugging is on\n");
4388 } else if (joins) {
4389 PIM_DO_DEBUG_PIM_J_P;
4390 vty_out(vty, "PIM Join/Prune debugging is on\n");
4391 } else if (registers) {
4392 PIM_DO_DEBUG_PIM_REG;
4393 vty_out(vty, "PIM Register debugging is on\n");
4394 } else {
4395 PIM_DO_DEBUG_PIM_PACKETS;
4396 vty_out(vty, "PIM Packet debugging is on\n");
4397 }
4398 return CMD_SUCCESS;
4399 }
4400
4401 int pim_no_debug_pim_packets_cmd(const char *hello, const char *joins,
4402 const char *registers, struct vty *vty)
4403 {
4404 if (hello) {
4405 PIM_DONT_DEBUG_PIM_HELLO;
4406 vty_out(vty, "PIM Hello debugging is off\n");
4407 } else if (joins) {
4408 PIM_DONT_DEBUG_PIM_J_P;
4409 vty_out(vty, "PIM Join/Prune debugging is off\n");
4410 } else if (registers) {
4411 PIM_DONT_DEBUG_PIM_REG;
4412 vty_out(vty, "PIM Register debugging is off\n");
4413 } else {
4414 PIM_DONT_DEBUG_PIM_PACKETS;
4415 vty_out(vty, "PIM Packet debugging is off\n");
4416 }
4417
4418 return CMD_SUCCESS;
4419 }
4420
4421 int pim_show_rpf_helper(const char *vrf, struct vty *vty, bool json)
4422 {
4423 struct pim_instance *pim;
4424 struct vrf *v;
4425 json_object *json_parent = NULL;
4426
4427 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4428
4429 if (!v)
4430 return CMD_WARNING;
4431
4432 pim = v->info;
4433
4434 if (!pim) {
4435 vty_out(vty, "%% Unable to find pim instance\n");
4436 return CMD_WARNING;
4437 }
4438
4439 if (json)
4440 json_parent = json_object_new_object();
4441
4442 pim_show_rpf(pim, vty, json_parent);
4443
4444 if (json)
4445 vty_json(vty, json_parent);
4446
4447 return CMD_SUCCESS;
4448 }
4449
4450 int pim_show_rpf_vrf_all_helper(struct vty *vty, bool json)
4451 {
4452 struct vrf *vrf;
4453 json_object *json_parent = NULL;
4454 json_object *json_vrf = NULL;
4455
4456 if (json)
4457 json_parent = json_object_new_object();
4458
4459 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4460 if (!json)
4461 vty_out(vty, "VRF: %s\n", vrf->name);
4462 else
4463 json_vrf = json_object_new_object();
4464 pim_show_rpf(vrf->info, vty, json_vrf);
4465 if (json)
4466 json_object_object_add(json_parent, vrf->name,
4467 json_vrf);
4468 }
4469 if (json)
4470 vty_json(vty, json_parent);
4471
4472 return CMD_SUCCESS;
4473 }
4474
4475 int pim_show_rp_helper(const char *vrf, struct vty *vty, const char *group_str,
4476 const struct prefix *group, bool json)
4477 {
4478 struct pim_instance *pim;
4479 struct vrf *v;
4480 json_object *json_parent = NULL;
4481 struct prefix *range = NULL;
4482
4483 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4484
4485 if (!v)
4486 return CMD_WARNING;
4487
4488 pim = v->info;
4489
4490 if (!pim) {
4491 vty_out(vty, "%% Unable to find pim instance\n");
4492 return CMD_WARNING;
4493 }
4494
4495 if (group_str) {
4496 range = prefix_new();
4497 prefix_copy(range, group);
4498 apply_mask(range);
4499 }
4500
4501 if (json)
4502 json_parent = json_object_new_object();
4503
4504 pim_rp_show_information(pim, range, vty, json_parent);
4505
4506 if (json)
4507 vty_json(vty, json_parent);
4508
4509 prefix_free(&range);
4510
4511 return CMD_SUCCESS;
4512 }
4513
4514 int pim_show_rp_vrf_all_helper(struct vty *vty, const char *group_str,
4515 const struct prefix *group, bool json)
4516 {
4517 struct vrf *vrf;
4518 json_object *json_parent = NULL;
4519 json_object *json_vrf = NULL;
4520 struct prefix *range = NULL;
4521
4522 if (group_str) {
4523 range = prefix_new();
4524 prefix_copy(range, group);
4525 apply_mask(range);
4526 }
4527
4528 if (json)
4529 json_parent = json_object_new_object();
4530
4531 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4532 if (!json)
4533 vty_out(vty, "VRF: %s\n", vrf->name);
4534 else
4535 json_vrf = json_object_new_object();
4536 pim_rp_show_information(vrf->info, range, vty, json_vrf);
4537 if (json)
4538 json_object_object_add(json_parent, vrf->name,
4539 json_vrf);
4540 }
4541 if (json)
4542 vty_json(vty, json_parent);
4543
4544 prefix_free(&range);
4545
4546 return CMD_SUCCESS;
4547 }
4548
4549 int pim_show_secondary_helper(const char *vrf, struct vty *vty)
4550 {
4551 struct pim_instance *pim;
4552 struct vrf *v;
4553
4554 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4555
4556 if (!v)
4557 return CMD_WARNING;
4558
4559 pim = v->info;
4560
4561 if (!pim) {
4562 vty_out(vty, "%% Unable to find pim instance\n");
4563 return CMD_WARNING;
4564 }
4565
4566 pim_show_neighbors_secondary(pim, vty);
4567
4568 return CMD_SUCCESS;
4569 }
4570
4571 int pim_show_statistics_helper(const char *vrf, struct vty *vty,
4572 const char *word, bool uj)
4573 {
4574 struct pim_instance *pim;
4575 struct vrf *v;
4576
4577 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4578
4579 if (!v)
4580 return CMD_WARNING;
4581
4582 pim = v->info;
4583
4584 if (!pim) {
4585 vty_out(vty, "%% Unable to find pim instance\n");
4586 return CMD_WARNING;
4587 }
4588
4589 if (word)
4590 pim_show_statistics(pim, vty, word, uj);
4591 else
4592 pim_show_statistics(pim, vty, NULL, uj);
4593
4594 return CMD_SUCCESS;
4595 }
4596
4597 int pim_show_upstream_helper(const char *vrf, struct vty *vty, pim_addr s_or_g,
4598 pim_addr g, bool json)
4599 {
4600 pim_sgaddr sg = {0};
4601 struct vrf *v;
4602 struct pim_instance *pim;
4603 json_object *json_parent = NULL;
4604
4605 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4606
4607 if (!v) {
4608 vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
4609 return CMD_WARNING;
4610 }
4611 pim = v->info;
4612
4613 if (!pim) {
4614 vty_out(vty, "%% Unable to find pim instance\n");
4615 return CMD_WARNING;
4616 }
4617
4618 if (json)
4619 json_parent = json_object_new_object();
4620
4621 if (!pim_addr_is_any(s_or_g)) {
4622 if (!pim_addr_is_any(g)) {
4623 sg.src = s_or_g;
4624 sg.grp = g;
4625 } else
4626 sg.grp = s_or_g;
4627 }
4628
4629 pim_show_upstream(pim, vty, &sg, json_parent);
4630
4631 if (json)
4632 vty_json(vty, json_parent);
4633
4634 return CMD_SUCCESS;
4635 }
4636
4637 int pim_show_upstream_vrf_all_helper(struct vty *vty, bool json)
4638 {
4639 pim_sgaddr sg = {0};
4640 struct vrf *vrf;
4641 json_object *json_parent = NULL;
4642 json_object *json_vrf = NULL;
4643
4644 if (json)
4645 json_parent = json_object_new_object();
4646
4647 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4648 if (!json)
4649 vty_out(vty, "VRF: %s\n", vrf->name);
4650 else
4651 json_vrf = json_object_new_object();
4652 pim_show_upstream(vrf->info, vty, &sg, json_vrf);
4653 if (json)
4654 json_object_object_add(json_parent, vrf->name,
4655 json_vrf);
4656 }
4657
4658 if (json)
4659 vty_json(vty, json_parent);
4660
4661 return CMD_SUCCESS;
4662 }
4663
4664 int pim_show_upstream_join_desired_helper(const char *vrf, struct vty *vty,
4665 bool uj)
4666 {
4667 struct pim_instance *pim;
4668 struct vrf *v;
4669
4670 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4671
4672 if (!v)
4673 return CMD_WARNING;
4674
4675 pim = v->info;
4676
4677 if (!pim) {
4678 vty_out(vty, "%% Unable to find pim instance\n");
4679 return CMD_WARNING;
4680 }
4681
4682 pim_show_join_desired(pim, vty, uj);
4683
4684 return CMD_SUCCESS;
4685 }
4686
4687 int pim_show_upstream_rpf_helper(const char *vrf, struct vty *vty, bool uj)
4688 {
4689 struct pim_instance *pim;
4690 struct vrf *v;
4691
4692 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4693
4694 if (!v)
4695 return CMD_WARNING;
4696
4697 pim = v->info;
4698
4699 if (!pim) {
4700 vty_out(vty, "%% Unable to find pim instance\n");
4701 return CMD_WARNING;
4702 }
4703
4704 pim_show_upstream_rpf(pim, vty, uj);
4705
4706 return CMD_SUCCESS;
4707 }
4708
4709 int pim_show_state_helper(const char *vrf, struct vty *vty,
4710 const char *s_or_g_str, const char *g_str, 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 pim_show_state(pim, vty, s_or_g_str, g_str, json_parent);
4732
4733 if (json)
4734 vty_json(vty, json_parent);
4735
4736 return CMD_SUCCESS;
4737 }
4738
4739 int pim_show_state_vrf_all_helper(struct vty *vty, const char *s_or_g_str,
4740 const char *g_str, bool json)
4741 {
4742 struct vrf *vrf;
4743 json_object *json_parent = NULL;
4744 json_object *json_vrf = NULL;
4745
4746 if (json)
4747 json_parent = json_object_new_object();
4748
4749 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4750 if (!json)
4751 vty_out(vty, "VRF: %s\n", vrf->name);
4752 else
4753 json_vrf = json_object_new_object();
4754 pim_show_state(vrf->info, vty, s_or_g_str, g_str, 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_multicast_helper(const char *vrf, struct vty *vty)
4766 {
4767 struct vrf *v;
4768 struct pim_instance *pim;
4769
4770 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4771
4772 if (!v)
4773 return CMD_WARNING;
4774
4775 pim = v->info;
4776
4777 if (!pim) {
4778 vty_out(vty, "%% Unable to find pim instance\n");
4779 return CMD_WARNING;
4780 }
4781
4782 pim_cmd_show_ip_multicast_helper(pim, vty);
4783
4784 return CMD_SUCCESS;
4785 }
4786
4787 int pim_show_multicast_vrf_all_helper(struct vty *vty)
4788 {
4789 struct vrf *vrf;
4790
4791 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4792 vty_out(vty, "VRF: %s\n", vrf->name);
4793 pim_cmd_show_ip_multicast_helper(vrf->info, vty);
4794 }
4795
4796 return CMD_SUCCESS;
4797 }
4798
4799 int pim_show_multicast_count_helper(const char *vrf, struct vty *vty, bool json)
4800 {
4801 struct pim_instance *pim;
4802 struct vrf *v;
4803 json_object *json_parent = NULL;
4804
4805 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4806
4807 if (!v)
4808 return CMD_WARNING;
4809
4810 pim = v->info;
4811
4812 if (!pim) {
4813 vty_out(vty, "%% Unable to find pim instance\n");
4814 return CMD_WARNING;
4815 }
4816
4817 if (json)
4818 json_parent = json_object_new_object();
4819
4820 show_multicast_interfaces(pim, vty, json_parent);
4821
4822 if (json)
4823 vty_json(vty, json_parent);
4824
4825 return CMD_SUCCESS;
4826 }
4827
4828 int pim_show_multicast_count_vrf_all_helper(struct vty *vty, bool json)
4829 {
4830 struct vrf *vrf;
4831 json_object *json_parent = NULL;
4832 json_object *json_vrf = NULL;
4833
4834 if (json)
4835 json_parent = json_object_new_object();
4836
4837 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4838 if (!json)
4839 vty_out(vty, "VRF: %s\n", vrf->name);
4840 else
4841 json_vrf = json_object_new_object();
4842
4843 show_multicast_interfaces(vrf->info, vty, json_vrf);
4844 if (json)
4845 json_object_object_add(json_parent, vrf->name,
4846 json_vrf);
4847 }
4848 if (json)
4849 vty_json(vty, json_parent);
4850
4851 return CMD_SUCCESS;
4852 }
4853
4854 int pim_show_mroute_helper(const char *vrf, struct vty *vty, pim_addr s_or_g,
4855 pim_addr g, bool fill, bool json)
4856 {
4857 pim_sgaddr sg = {0};
4858 struct pim_instance *pim;
4859 struct vrf *v;
4860 json_object *json_parent = NULL;
4861
4862 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4863
4864 if (!v)
4865 return CMD_WARNING;
4866
4867 pim = v->info;
4868
4869 if (!pim) {
4870 vty_out(vty, "%% Unable to find pim instance\n");
4871 return CMD_WARNING;
4872 }
4873
4874 if (json)
4875 json_parent = json_object_new_object();
4876
4877 if (!pim_addr_is_any(s_or_g)) {
4878 if (!pim_addr_is_any(g)) {
4879 sg.src = s_or_g;
4880 sg.grp = g;
4881 } else
4882 sg.grp = s_or_g;
4883 }
4884
4885 show_mroute(pim, vty, &sg, fill, json_parent);
4886
4887 if (json)
4888 vty_json(vty, json_parent);
4889
4890 return CMD_SUCCESS;
4891 }
4892
4893 int pim_show_mroute_vrf_all_helper(struct vty *vty, bool fill, bool json)
4894 {
4895 pim_sgaddr sg = {0};
4896 struct vrf *vrf;
4897 json_object *json_parent = NULL;
4898 json_object *json_vrf = NULL;
4899
4900 if (json)
4901 json_parent = json_object_new_object();
4902
4903 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4904 if (!json)
4905 vty_out(vty, "VRF: %s\n", vrf->name);
4906 else
4907 json_vrf = json_object_new_object();
4908 show_mroute(vrf->info, vty, &sg, fill, json_vrf);
4909 if (json)
4910 json_object_object_add(json_parent, vrf->name,
4911 json_vrf);
4912 }
4913 if (json)
4914 vty_json(vty, json_parent);
4915
4916 return CMD_SUCCESS;
4917 }
4918
4919 int pim_show_mroute_count_helper(const char *vrf, struct vty *vty, bool json)
4920 {
4921 struct pim_instance *pim;
4922 struct vrf *v;
4923 json_object *json_parent = NULL;
4924
4925 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4926
4927 if (!v)
4928 return CMD_WARNING;
4929
4930 pim = v->info;
4931
4932 if (!pim) {
4933 vty_out(vty, "%% Unable to find pim instance\n");
4934 return CMD_WARNING;
4935 }
4936
4937 if (json)
4938 json_parent = json_object_new_object();
4939
4940 show_mroute_count(pim, vty, json_parent);
4941
4942 if (json)
4943 vty_json(vty, json_parent);
4944
4945 return CMD_SUCCESS;
4946 }
4947
4948 int pim_show_mroute_count_vrf_all_helper(struct vty *vty, bool json)
4949 {
4950 struct vrf *vrf;
4951 json_object *json_parent = NULL;
4952 json_object *json_vrf = NULL;
4953
4954 if (json)
4955 json_parent = json_object_new_object();
4956
4957 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4958 if (!json)
4959 vty_out(vty, "VRF: %s\n", vrf->name);
4960 else
4961 json_vrf = json_object_new_object();
4962
4963 show_mroute_count(vrf->info, vty, json_vrf);
4964
4965 if (json)
4966 json_object_object_add(json_parent, vrf->name,
4967 json_vrf);
4968 }
4969 if (json)
4970 vty_json(vty, json_parent);
4971
4972 return CMD_SUCCESS;
4973 }
4974
4975 int pim_show_mroute_summary_helper(const char *vrf, struct vty *vty, bool json)
4976 {
4977 struct pim_instance *pim;
4978 struct vrf *v;
4979 json_object *json_parent = NULL;
4980
4981 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4982
4983 if (!v)
4984 return CMD_WARNING;
4985
4986 pim = v->info;
4987
4988 if (!pim) {
4989 vty_out(vty, "%% Unable to find pim instance\n");
4990 return CMD_WARNING;
4991 }
4992
4993 if (json)
4994 json_parent = json_object_new_object();
4995
4996 show_mroute_summary(pim, vty, json_parent);
4997
4998 if (json)
4999 vty_json(vty, json_parent);
5000
5001 return CMD_SUCCESS;
5002 }
5003
5004 int pim_show_mroute_summary_vrf_all_helper(struct vty *vty, bool json)
5005 {
5006 struct vrf *vrf;
5007 json_object *json_parent = NULL;
5008 json_object *json_vrf = NULL;
5009
5010 if (json)
5011 json_parent = json_object_new_object();
5012
5013 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
5014 if (!json)
5015 vty_out(vty, "VRF: %s\n", vrf->name);
5016 else
5017 json_vrf = json_object_new_object();
5018
5019 show_mroute_summary(vrf->info, vty, json_vrf);
5020
5021 if (json)
5022 json_object_object_add(json_parent, vrf->name,
5023 json_vrf);
5024 }
5025
5026 if (json)
5027 vty_json(vty, json_parent);
5028
5029 return CMD_SUCCESS;
5030 }
5031
5032 void pim_show_interface_traffic(struct pim_instance *pim, struct vty *vty,
5033 bool uj)
5034 {
5035 struct interface *ifp = NULL;
5036 struct pim_interface *pim_ifp = NULL;
5037 json_object *json = NULL;
5038 json_object *json_row = NULL;
5039
5040 if (uj)
5041 json = json_object_new_object();
5042 else {
5043 vty_out(vty, "\n");
5044 vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n",
5045 "Interface", " HELLO", " JOIN",
5046 " PRUNE", " REGISTER", "REGISTER-STOP",
5047 " ASSERT", " BSM");
5048 vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n", "",
5049 " Rx/Tx", " Rx/Tx", " Rx/Tx",
5050 " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx");
5051 vty_out(vty,
5052 "---------------------------------------------------------------------------------------------------------------\n");
5053 }
5054
5055 FOR_ALL_INTERFACES (pim->vrf, ifp) {
5056 pim_ifp = ifp->info;
5057
5058 if (!pim_ifp)
5059 continue;
5060
5061 if (uj) {
5062 json_row = json_object_new_object();
5063 json_object_pim_ifp_add(json_row, ifp);
5064 json_object_int_add(json_row, "helloRx",
5065 pim_ifp->pim_ifstat_hello_recv);
5066 json_object_int_add(json_row, "helloTx",
5067 pim_ifp->pim_ifstat_hello_sent);
5068 json_object_int_add(json_row, "joinRx",
5069 pim_ifp->pim_ifstat_join_recv);
5070 json_object_int_add(json_row, "joinTx",
5071 pim_ifp->pim_ifstat_join_send);
5072 json_object_int_add(json_row, "pruneRx",
5073 pim_ifp->pim_ifstat_prune_recv);
5074 json_object_int_add(json_row, "pruneTx",
5075 pim_ifp->pim_ifstat_prune_send);
5076 json_object_int_add(json_row, "registerRx",
5077 pim_ifp->pim_ifstat_reg_recv);
5078 json_object_int_add(json_row, "registerTx",
5079 pim_ifp->pim_ifstat_reg_send);
5080 json_object_int_add(json_row, "registerStopRx",
5081 pim_ifp->pim_ifstat_reg_stop_recv);
5082 json_object_int_add(json_row, "registerStopTx",
5083 pim_ifp->pim_ifstat_reg_stop_send);
5084 json_object_int_add(json_row, "assertRx",
5085 pim_ifp->pim_ifstat_assert_recv);
5086 json_object_int_add(json_row, "assertTx",
5087 pim_ifp->pim_ifstat_assert_send);
5088 json_object_int_add(json_row, "bsmRx",
5089 pim_ifp->pim_ifstat_bsm_rx);
5090 json_object_int_add(json_row, "bsmTx",
5091 pim_ifp->pim_ifstat_bsm_tx);
5092 json_object_object_add(json, ifp->name, json_row);
5093 } else {
5094 vty_out(vty,
5095 "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7" PRIu64
5096 "/%-7" PRIu64 "\n",
5097 ifp->name, pim_ifp->pim_ifstat_hello_recv,
5098 pim_ifp->pim_ifstat_hello_sent,
5099 pim_ifp->pim_ifstat_join_recv,
5100 pim_ifp->pim_ifstat_join_send,
5101 pim_ifp->pim_ifstat_prune_recv,
5102 pim_ifp->pim_ifstat_prune_send,
5103 pim_ifp->pim_ifstat_reg_recv,
5104 pim_ifp->pim_ifstat_reg_send,
5105 pim_ifp->pim_ifstat_reg_stop_recv,
5106 pim_ifp->pim_ifstat_reg_stop_send,
5107 pim_ifp->pim_ifstat_assert_recv,
5108 pim_ifp->pim_ifstat_assert_send,
5109 pim_ifp->pim_ifstat_bsm_rx,
5110 pim_ifp->pim_ifstat_bsm_tx);
5111 }
5112 }
5113 if (uj)
5114 vty_json(vty, json);
5115 }
5116
5117 void pim_show_interface_traffic_single(struct pim_instance *pim,
5118 struct vty *vty, const char *ifname,
5119 bool uj)
5120 {
5121 struct interface *ifp = NULL;
5122 struct pim_interface *pim_ifp = NULL;
5123 json_object *json = NULL;
5124 json_object *json_row = NULL;
5125 uint8_t found_ifname = 0;
5126
5127 if (uj)
5128 json = json_object_new_object();
5129 else {
5130 vty_out(vty, "\n");
5131 vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n",
5132 "Interface", " HELLO", " JOIN", " PRUNE",
5133 " REGISTER", " REGISTER-STOP", " ASSERT",
5134 " BSM");
5135 vty_out(vty, "%-14s%-18s%-17s%-17s%-17s%-17s%-17s%-17s\n", "",
5136 " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx",
5137 " Rx/Tx", " Rx/Tx", " Rx/Tx");
5138 vty_out(vty,
5139 "-------------------------------------------------------------------------------------------------------------------------------\n");
5140 }
5141
5142 FOR_ALL_INTERFACES (pim->vrf, ifp) {
5143 if (strcmp(ifname, ifp->name))
5144 continue;
5145
5146 pim_ifp = ifp->info;
5147
5148 if (!pim_ifp)
5149 continue;
5150
5151 found_ifname = 1;
5152 if (uj) {
5153 json_row = json_object_new_object();
5154 json_object_pim_ifp_add(json_row, ifp);
5155 json_object_int_add(json_row, "helloRx",
5156 pim_ifp->pim_ifstat_hello_recv);
5157 json_object_int_add(json_row, "helloTx",
5158 pim_ifp->pim_ifstat_hello_sent);
5159 json_object_int_add(json_row, "joinRx",
5160 pim_ifp->pim_ifstat_join_recv);
5161 json_object_int_add(json_row, "joinTx",
5162 pim_ifp->pim_ifstat_join_send);
5163 json_object_int_add(json_row, "pruneRx",
5164 pim_ifp->pim_ifstat_prune_recv);
5165 json_object_int_add(json_row, "pruneTx",
5166 pim_ifp->pim_ifstat_prune_send);
5167 json_object_int_add(json_row, "registerRx",
5168 pim_ifp->pim_ifstat_reg_recv);
5169 json_object_int_add(json_row, "registerTx",
5170 pim_ifp->pim_ifstat_reg_send);
5171 json_object_int_add(json_row, "registerStopRx",
5172 pim_ifp->pim_ifstat_reg_stop_recv);
5173 json_object_int_add(json_row, "registerStopTx",
5174 pim_ifp->pim_ifstat_reg_stop_send);
5175 json_object_int_add(json_row, "assertRx",
5176 pim_ifp->pim_ifstat_assert_recv);
5177 json_object_int_add(json_row, "assertTx",
5178 pim_ifp->pim_ifstat_assert_send);
5179 json_object_int_add(json_row, "bsmRx",
5180 pim_ifp->pim_ifstat_bsm_rx);
5181 json_object_int_add(json_row, "bsmTx",
5182 pim_ifp->pim_ifstat_bsm_tx);
5183
5184 json_object_object_add(json, ifp->name, json_row);
5185 } else {
5186 vty_out(vty,
5187 "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7" PRIu64
5188 "/%-7" PRIu64 "\n",
5189 ifp->name, pim_ifp->pim_ifstat_hello_recv,
5190 pim_ifp->pim_ifstat_hello_sent,
5191 pim_ifp->pim_ifstat_join_recv,
5192 pim_ifp->pim_ifstat_join_send,
5193 pim_ifp->pim_ifstat_prune_recv,
5194 pim_ifp->pim_ifstat_prune_send,
5195 pim_ifp->pim_ifstat_reg_recv,
5196 pim_ifp->pim_ifstat_reg_send,
5197 pim_ifp->pim_ifstat_reg_stop_recv,
5198 pim_ifp->pim_ifstat_reg_stop_send,
5199 pim_ifp->pim_ifstat_assert_recv,
5200 pim_ifp->pim_ifstat_assert_send,
5201 pim_ifp->pim_ifstat_bsm_rx,
5202 pim_ifp->pim_ifstat_bsm_tx);
5203 }
5204 }
5205 if (uj)
5206 vty_json(vty, json);
5207 else if (!found_ifname)
5208 vty_out(vty, "%% No such interface\n");
5209 }
5210
5211 int pim_show_interface_traffic_helper(const char *vrf, const char *if_name,
5212 struct vty *vty, bool uj)
5213 {
5214 struct pim_instance *pim;
5215 struct vrf *v;
5216
5217 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
5218
5219 if (!v)
5220 return CMD_WARNING;
5221
5222 pim = v->info;
5223
5224 if (!pim) {
5225 vty_out(vty, "%% Unable to find pim instance\n");
5226 return CMD_WARNING;
5227 }
5228
5229 if (if_name)
5230 pim_show_interface_traffic_single(v->info, vty, if_name, uj);
5231 else
5232 pim_show_interface_traffic(v->info, vty, uj);
5233
5234 return CMD_SUCCESS;
5235 }
5236
5237 void clear_pim_interfaces(struct pim_instance *pim)
5238 {
5239 struct interface *ifp;
5240
5241 FOR_ALL_INTERFACES (pim->vrf, ifp) {
5242 if (ifp->info)
5243 pim_neighbor_delete_all(ifp, "interface cleared");
5244 }
5245 }