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