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