]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_cmd_common.c
Merge pull request #12334 from ylopez/patch-1
[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
2828 for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
2829 first_ifindex = nh_node->ifindex;
2830
2831 ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
2832
2833 vty_out(vty, "%-15pPA ", &pnc->rpf.rpf_addr);
2834 vty_out(vty, "%-16s ", ifp ? ifp->name : "NULL");
2835 #if PIM_IPV == 4
2836 vty_out(vty, "%pI4 ", &nh_node->gate.ipv4);
2837 #else
2838 vty_out(vty, "%pI6 ", &nh_node->gate.ipv6);
2839 #endif
2840 vty_out(vty, "\n");
2841 }
2842 return CMD_SUCCESS;
2843 }
2844
2845 static int pim_print_json_pnc_cache_walkcb(struct hash_bucket *backet,
2846 void *arg)
2847 {
2848 struct pim_nexthop_cache *pnc = backet->data;
2849 struct json_pnc_cache_walk_data *cwd = arg;
2850 struct pim_instance *pim = cwd->pim;
2851 struct nexthop *nh_node = NULL;
2852 ifindex_t first_ifindex;
2853 struct interface *ifp = NULL;
2854 char addr_str[PIM_ADDRSTRLEN];
2855 json_object *json_row = NULL;
2856 json_object *json_ifp = NULL;
2857 json_object *json_arr = NULL;
2858
2859 for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
2860 first_ifindex = nh_node->ifindex;
2861 ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
2862 snprintfrr(addr_str, sizeof(addr_str), "%pPA",
2863 &pnc->rpf.rpf_addr);
2864 json_object_object_get_ex(cwd->json_obj, addr_str, &json_row);
2865 if (!json_row) {
2866 json_row = json_object_new_object();
2867 json_object_string_addf(json_row, "address", "%pPA",
2868 &pnc->rpf.rpf_addr);
2869 json_object_object_addf(cwd->json_obj, json_row, "%pPA",
2870 &pnc->rpf.rpf_addr);
2871 json_arr = json_object_new_array();
2872 json_object_object_add(json_row, "nexthops", json_arr);
2873 }
2874 json_ifp = json_object_new_object();
2875 json_object_string_add(json_ifp, "interface",
2876 ifp ? ifp->name : "NULL");
2877 #if PIM_IPV == 4
2878 json_object_string_addf(json_ifp, "nexthop", "%pI4",
2879 &nh_node->gate.ipv4);
2880 #else
2881 json_object_string_addf(json_ifp, "nexthop", "%pI6",
2882 &nh_node->gate.ipv6);
2883 #endif
2884 json_object_array_add(json_arr, json_ifp);
2885 }
2886 return CMD_SUCCESS;
2887 }
2888
2889 int pim_show_nexthop_lookup_cmd_helper(const char *vrf, struct vty *vty,
2890 pim_addr source, pim_addr group)
2891 {
2892 int result = 0;
2893 pim_addr vif_source;
2894 struct prefix grp;
2895 struct pim_nexthop nexthop;
2896 struct vrf *v;
2897 char grp_str[PREFIX_STRLEN];
2898
2899 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
2900
2901 if (!v)
2902 return CMD_WARNING;
2903
2904 #if PIM_IPV == 4
2905 if (pim_is_group_224_4(source)) {
2906 vty_out(vty,
2907 "Invalid argument. Expected Valid Source Address.\n");
2908 return CMD_WARNING;
2909 }
2910
2911 if (!pim_is_group_224_4(group)) {
2912 vty_out(vty,
2913 "Invalid argument. Expected Valid Multicast Group Address.\n");
2914 return CMD_WARNING;
2915 }
2916 #endif
2917
2918 if (!pim_rp_set_upstream_addr(v->info, &vif_source, source, group))
2919 return CMD_SUCCESS;
2920
2921 pim_addr_to_prefix(&grp, group);
2922 memset(&nexthop, 0, sizeof(nexthop));
2923
2924 result =
2925 pim_ecmp_nexthop_lookup(v->info, &nexthop, vif_source, &grp, 0);
2926
2927 if (!result) {
2928 vty_out(vty,
2929 "Nexthop Lookup failed, no usable routes returned.\n");
2930 return CMD_SUCCESS;
2931 }
2932
2933 pim_addr_dump("<grp?>", &grp, grp_str, sizeof(grp_str));
2934
2935 vty_out(vty, "Group %s --- Nexthop %pPAs Interface %s\n", grp_str,
2936 &nexthop.mrib_nexthop_addr, nexthop.interface->name);
2937
2938 return CMD_SUCCESS;
2939 }
2940
2941 int pim_show_nexthop_cmd_helper(const char *vrf, struct vty *vty, bool uj)
2942 {
2943 struct vrf *v;
2944
2945 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
2946
2947 if (!v)
2948 return CMD_WARNING;
2949
2950 pim_show_nexthop(v->info, vty, uj);
2951
2952 return CMD_SUCCESS;
2953 }
2954
2955 void pim_show_nexthop(struct pim_instance *pim, struct vty *vty, bool uj)
2956 {
2957 struct vty_pnc_cache_walk_data cwd;
2958 struct json_pnc_cache_walk_data jcwd;
2959
2960 cwd.vty = vty;
2961 cwd.pim = pim;
2962 jcwd.pim = pim;
2963
2964 if (uj) {
2965 jcwd.json_obj = json_object_new_object();
2966 } else {
2967 vty_out(vty, "Number of registered addresses: %lu\n",
2968 pim->rpf_hash->count);
2969 vty_out(vty, "Address Interface Nexthop\n");
2970 vty_out(vty, "---------------------------------------------\n");
2971 }
2972
2973 if (uj) {
2974 hash_walk(pim->rpf_hash, pim_print_json_pnc_cache_walkcb,
2975 &jcwd);
2976 vty_json(vty, jcwd.json_obj);
2977 } else
2978 hash_walk(pim->rpf_hash, pim_print_vty_pnc_cache_walkcb, &cwd);
2979 }
2980
2981 int pim_show_neighbors_cmd_helper(const char *vrf, struct vty *vty,
2982 const char *json, const char *interface)
2983 {
2984 struct vrf *v;
2985 json_object *json_parent = NULL;
2986
2987 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
2988
2989 if (!v)
2990 return CMD_WARNING;
2991
2992 if (json)
2993 json_parent = json_object_new_object();
2994
2995 if (interface)
2996 pim_show_neighbors_single(v->info, vty, interface, json_parent);
2997 else
2998 pim_show_neighbors(v->info, vty, json_parent);
2999
3000 if (json)
3001 vty_json(vty, json_parent);
3002
3003 return CMD_SUCCESS;
3004 }
3005
3006 int pim_show_neighbors_vrf_all_cmd_helper(struct vty *vty, const char *json,
3007 const char *interface)
3008 {
3009 struct vrf *v;
3010 json_object *json_parent = NULL;
3011 json_object *json_vrf = NULL;
3012
3013 if (json)
3014 json_parent = json_object_new_object();
3015 RB_FOREACH (v, vrf_name_head, &vrfs_by_name) {
3016 if (!json)
3017 vty_out(vty, "VRF: %s\n", v->name);
3018 else
3019 json_vrf = json_object_new_object();
3020
3021 if (interface)
3022 pim_show_neighbors_single(v->info, vty, interface,
3023 json_vrf);
3024 else
3025 pim_show_neighbors(v->info, vty, json_vrf);
3026
3027 if (json)
3028 json_object_object_add(json_parent, v->name, json_vrf);
3029 }
3030 if (json)
3031 vty_json(vty, json_parent);
3032
3033 return CMD_SUCCESS;
3034 }
3035
3036 void pim_show_neighbors_single(struct pim_instance *pim, struct vty *vty,
3037 const char *neighbor, json_object *json)
3038 {
3039 struct listnode *neighnode;
3040 struct interface *ifp;
3041 struct pim_interface *pim_ifp;
3042 struct pim_neighbor *neigh;
3043 time_t now;
3044 int found_neighbor = 0;
3045 int option_address_list;
3046 int option_dr_priority;
3047 int option_generation_id;
3048 int option_holdtime;
3049 int option_lan_prune_delay;
3050 int option_t_bit;
3051 char uptime[10];
3052 char expire[10];
3053 char neigh_src_str[PIM_ADDRSTRLEN];
3054
3055 json_object *json_ifp = NULL;
3056 json_object *json_row = NULL;
3057
3058 now = pim_time_monotonic_sec();
3059
3060 FOR_ALL_INTERFACES (pim->vrf, ifp) {
3061 pim_ifp = ifp->info;
3062
3063 if (!pim_ifp)
3064 continue;
3065
3066 if (pim_ifp->pim_sock_fd < 0)
3067 continue;
3068
3069 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
3070 neigh)) {
3071 snprintfrr(neigh_src_str, sizeof(neigh_src_str),
3072 "%pPAs", &neigh->source_addr);
3073
3074 /*
3075 * The user can specify either the interface name or the
3076 * PIM neighbor IP.
3077 * If this pim_ifp matches neither then skip.
3078 */
3079 if (strcmp(neighbor, "detail") &&
3080 strcmp(neighbor, ifp->name) &&
3081 strcmp(neighbor, neigh_src_str))
3082 continue;
3083
3084 found_neighbor = 1;
3085 pim_time_uptime(uptime, sizeof(uptime),
3086 now - neigh->creation);
3087 pim_time_timer_to_hhmmss(expire, sizeof(expire),
3088 neigh->t_expire_timer);
3089
3090 option_address_list = 0;
3091 option_dr_priority = 0;
3092 option_generation_id = 0;
3093 option_holdtime = 0;
3094 option_lan_prune_delay = 0;
3095 option_t_bit = 0;
3096
3097 if (PIM_OPTION_IS_SET(neigh->hello_options,
3098 PIM_OPTION_MASK_ADDRESS_LIST))
3099 option_address_list = 1;
3100
3101 if (PIM_OPTION_IS_SET(neigh->hello_options,
3102 PIM_OPTION_MASK_DR_PRIORITY))
3103 option_dr_priority = 1;
3104
3105 if (PIM_OPTION_IS_SET(neigh->hello_options,
3106 PIM_OPTION_MASK_GENERATION_ID))
3107 option_generation_id = 1;
3108
3109 if (PIM_OPTION_IS_SET(neigh->hello_options,
3110 PIM_OPTION_MASK_HOLDTIME))
3111 option_holdtime = 1;
3112
3113 if (PIM_OPTION_IS_SET(neigh->hello_options,
3114 PIM_OPTION_MASK_LAN_PRUNE_DELAY))
3115 option_lan_prune_delay = 1;
3116
3117 if (PIM_OPTION_IS_SET(
3118 neigh->hello_options,
3119 PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION))
3120 option_t_bit = 1;
3121
3122 if (json) {
3123
3124 /* Does this ifp live in json? If not create it
3125 */
3126 json_object_object_get_ex(json, ifp->name,
3127 &json_ifp);
3128
3129 if (!json_ifp) {
3130 json_ifp = json_object_new_object();
3131 json_object_pim_ifp_add(json_ifp, ifp);
3132 json_object_object_add(json, ifp->name,
3133 json_ifp);
3134 }
3135
3136 json_row = json_object_new_object();
3137 json_object_string_add(json_row, "interface",
3138 ifp->name);
3139 json_object_string_add(json_row, "address",
3140 neigh_src_str);
3141 json_object_string_add(json_row, "upTime",
3142 uptime);
3143 json_object_string_add(json_row, "holdtime",
3144 expire);
3145 json_object_int_add(json_row, "drPriority",
3146 neigh->dr_priority);
3147 json_object_int_add(json_row, "generationId",
3148 neigh->generation_id);
3149
3150 if (option_address_list)
3151 json_object_boolean_true_add(
3152 json_row,
3153 "helloOptionAddressList");
3154
3155 if (option_dr_priority)
3156 json_object_boolean_true_add(
3157 json_row,
3158 "helloOptionDrPriority");
3159
3160 if (option_generation_id)
3161 json_object_boolean_true_add(
3162 json_row,
3163 "helloOptionGenerationId");
3164
3165 if (option_holdtime)
3166 json_object_boolean_true_add(
3167 json_row,
3168 "helloOptionHoldtime");
3169
3170 if (option_lan_prune_delay)
3171 json_object_boolean_true_add(
3172 json_row,
3173 "helloOptionLanPruneDelay");
3174
3175 if (option_t_bit)
3176 json_object_boolean_true_add(
3177 json_row, "helloOptionTBit");
3178
3179 json_object_object_add(json_ifp, neigh_src_str,
3180 json_row);
3181
3182 } else {
3183 vty_out(vty, "Interface : %s\n", ifp->name);
3184 vty_out(vty, "Neighbor : %s\n", neigh_src_str);
3185 vty_out(vty,
3186 " Uptime : %s\n",
3187 uptime);
3188 vty_out(vty,
3189 " Holdtime : %s\n",
3190 expire);
3191 vty_out(vty,
3192 " DR Priority : %d\n",
3193 neigh->dr_priority);
3194 vty_out(vty,
3195 " Generation ID : %08x\n",
3196 neigh->generation_id);
3197 vty_out(vty,
3198 " Override Interval (msec) : %d\n",
3199 neigh->override_interval_msec);
3200 vty_out(vty,
3201 " Propagation Delay (msec) : %d\n",
3202 neigh->propagation_delay_msec);
3203 vty_out(vty,
3204 " Hello Option - Address List : %s\n",
3205 option_address_list ? "yes" : "no");
3206 vty_out(vty,
3207 " Hello Option - DR Priority : %s\n",
3208 option_dr_priority ? "yes" : "no");
3209 vty_out(vty,
3210 " Hello Option - Generation ID : %s\n",
3211 option_generation_id ? "yes" : "no");
3212 vty_out(vty,
3213 " Hello Option - Holdtime : %s\n",
3214 option_holdtime ? "yes" : "no");
3215 vty_out(vty,
3216 " Hello Option - LAN Prune Delay : %s\n",
3217 option_lan_prune_delay ? "yes" : "no");
3218 vty_out(vty,
3219 " Hello Option - T-bit : %s\n",
3220 option_t_bit ? "yes" : "no");
3221 bfd_sess_show(vty, json_ifp,
3222 neigh->bfd_session);
3223 vty_out(vty, "\n");
3224 }
3225 }
3226 }
3227
3228 if (!found_neighbor)
3229 vty_out(vty, "%% No such interface or neighbor\n");
3230 }
3231
3232 void pim_show_neighbors(struct pim_instance *pim, struct vty *vty,
3233 json_object *json)
3234 {
3235 struct listnode *neighnode;
3236 struct interface *ifp;
3237 struct pim_interface *pim_ifp;
3238 struct pim_neighbor *neigh;
3239 struct ttable *tt = NULL;
3240 char *table = NULL;
3241 time_t now;
3242 char uptime[10];
3243 char expire[10];
3244 char neigh_src_str[PIM_ADDRSTRLEN];
3245 json_object *json_ifp_rows = NULL;
3246 json_object *json_row = NULL;
3247
3248 now = pim_time_monotonic_sec();
3249
3250 if (!json) {
3251 /* Prepare table. */
3252 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
3253 ttable_add_row(tt, "Interface|Neighbor|Uptime|Holdtime|DR Pri");
3254 tt->style.cell.rpad = 2;
3255 tt->style.corner = '+';
3256 ttable_restyle(tt);
3257 }
3258
3259 FOR_ALL_INTERFACES (pim->vrf, ifp) {
3260 pim_ifp = ifp->info;
3261
3262 if (!pim_ifp)
3263 continue;
3264
3265 if (pim_ifp->pim_sock_fd < 0)
3266 continue;
3267
3268 if (json)
3269 json_ifp_rows = json_object_new_object();
3270
3271 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
3272 neigh)) {
3273 snprintfrr(neigh_src_str, sizeof(neigh_src_str),
3274 "%pPAs", &neigh->source_addr);
3275 pim_time_uptime(uptime, sizeof(uptime),
3276 now - neigh->creation);
3277 pim_time_timer_to_hhmmss(expire, sizeof(expire),
3278 neigh->t_expire_timer);
3279
3280 if (json) {
3281 json_row = json_object_new_object();
3282 json_object_string_add(json_row, "interface",
3283 ifp->name);
3284 json_object_string_add(json_row, "neighbor",
3285 neigh_src_str);
3286 json_object_string_add(json_row, "upTime",
3287 uptime);
3288 json_object_string_add(json_row, "holdTime",
3289 expire);
3290 json_object_int_add(json_row, "holdTimeMax",
3291 neigh->holdtime);
3292 json_object_int_add(json_row, "drPriority",
3293 neigh->dr_priority);
3294 json_object_object_add(json_ifp_rows,
3295 neigh_src_str, json_row);
3296
3297 } else {
3298 ttable_add_row(tt, "%s|%pPAs|%s|%s|%d",
3299 ifp->name, &neigh->source_addr,
3300 uptime, expire,
3301 neigh->dr_priority);
3302 }
3303 }
3304
3305 if (json) {
3306 json_object_object_add(json, ifp->name, json_ifp_rows);
3307 json_ifp_rows = NULL;
3308 }
3309 }
3310 /* Dump the generated table. */
3311 if (!json) {
3312 table = ttable_dump(tt, "\n");
3313 vty_out(vty, "%s\n", table);
3314 XFREE(MTYPE_TMP, table);
3315 ttable_del(tt);
3316 }
3317 }
3318
3319 int gm_process_query_max_response_time_cmd(struct vty *vty,
3320 const char *qmrt_str)
3321 {
3322 const struct lyd_node *pim_enable_dnode;
3323
3324 pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
3325 FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH,
3326 FRR_PIM_AF_XPATH_VAL);
3327
3328 if (!pim_enable_dnode) {
3329 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true");
3330 } else {
3331 if (!yang_dnode_get_bool(pim_enable_dnode, "."))
3332 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY,
3333 "true");
3334 }
3335
3336 nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY,
3337 qmrt_str);
3338 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3339 FRR_PIM_AF_XPATH_VAL);
3340 }
3341
3342 int gm_process_no_query_max_response_time_cmd(struct vty *vty)
3343 {
3344 nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_DESTROY,
3345 NULL);
3346 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3347 FRR_PIM_AF_XPATH_VAL);
3348 }
3349
3350 int gm_process_last_member_query_count_cmd(struct vty *vty,
3351 const char *lmqc_str)
3352 {
3353 const struct lyd_node *pim_enable_dnode;
3354
3355 pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
3356 FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH,
3357 FRR_PIM_AF_XPATH_VAL);
3358 if (!pim_enable_dnode) {
3359 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true");
3360 } else {
3361 if (!yang_dnode_get_bool(pim_enable_dnode, "."))
3362 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY,
3363 "true");
3364 }
3365
3366 nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_MODIFY,
3367 lmqc_str);
3368 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3369 FRR_PIM_AF_XPATH_VAL);
3370 }
3371
3372 int gm_process_no_last_member_query_count_cmd(struct vty *vty)
3373 {
3374 nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_DESTROY,
3375 NULL);
3376 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3377 FRR_PIM_AF_XPATH_VAL);
3378 }
3379
3380 int gm_process_last_member_query_interval_cmd(struct vty *vty,
3381 const char *lmqi_str)
3382 {
3383 const struct lyd_node *pim_enable_dnode;
3384
3385 pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
3386 FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH,
3387 FRR_PIM_AF_XPATH_VAL);
3388 if (!pim_enable_dnode) {
3389 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true");
3390 } else {
3391 if (!yang_dnode_get_bool(pim_enable_dnode, "."))
3392 nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY,
3393 "true");
3394 }
3395
3396 nb_cli_enqueue_change(vty, "./last-member-query-interval", NB_OP_MODIFY,
3397 lmqi_str);
3398 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3399 FRR_PIM_AF_XPATH_VAL);
3400 }
3401
3402 int gm_process_no_last_member_query_interval_cmd(struct vty *vty)
3403 {
3404 nb_cli_enqueue_change(vty, "./last-member-query-interval",
3405 NB_OP_DESTROY, NULL);
3406 return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
3407 FRR_PIM_AF_XPATH_VAL);
3408 }
3409
3410 int pim_process_ssmpingd_cmd(struct vty *vty, enum nb_operation operation,
3411 const char *src_str)
3412 {
3413 const char *vrfname;
3414 char ssmpingd_ip_xpath[XPATH_MAXLEN];
3415
3416 vrfname = pim_cli_get_vrf_name(vty);
3417 if (vrfname == NULL)
3418 return CMD_WARNING_CONFIG_FAILED;
3419
3420 snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath),
3421 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
3422 FRR_PIM_AF_XPATH_VAL);
3423 strlcat(ssmpingd_ip_xpath, "/ssm-pingd-source-ip",
3424 sizeof(ssmpingd_ip_xpath));
3425
3426 nb_cli_enqueue_change(vty, ssmpingd_ip_xpath, operation, src_str);
3427
3428 return nb_cli_apply_changes(vty, NULL);
3429 }
3430
3431 int pim_process_bsm_cmd(struct vty *vty)
3432 {
3433 const struct lyd_node *gm_enable_dnode;
3434
3435 gm_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
3436 FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
3437 FRR_PIM_AF_XPATH_VAL);
3438 if (!gm_enable_dnode)
3439 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
3440 "true");
3441 else {
3442 if (!yang_dnode_get_bool(gm_enable_dnode, "."))
3443 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
3444 "true");
3445 }
3446
3447 nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "true");
3448
3449 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
3450 FRR_PIM_AF_XPATH_VAL);
3451 }
3452
3453 int pim_process_no_bsm_cmd(struct vty *vty)
3454 {
3455 nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "false");
3456
3457 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
3458 FRR_PIM_AF_XPATH_VAL);
3459 }
3460
3461 int pim_process_unicast_bsm_cmd(struct vty *vty)
3462 {
3463 const struct lyd_node *gm_enable_dnode;
3464
3465 gm_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
3466 FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
3467 FRR_PIM_AF_XPATH_VAL);
3468 if (!gm_enable_dnode)
3469 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
3470 "true");
3471 else {
3472 if (!yang_dnode_get_bool(gm_enable_dnode, "."))
3473 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
3474 "true");
3475 }
3476
3477 nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "true");
3478
3479 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
3480 FRR_PIM_AF_XPATH_VAL);
3481 }
3482
3483 int pim_process_no_unicast_bsm_cmd(struct vty *vty)
3484 {
3485 nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "false");
3486
3487 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
3488 FRR_PIM_AF_XPATH_VAL);
3489 }
3490
3491 static void show_scan_oil_stats(struct pim_instance *pim, struct vty *vty,
3492 time_t now)
3493 {
3494 char uptime_scan_oil[10];
3495 char uptime_mroute_add[10];
3496 char uptime_mroute_del[10];
3497
3498 pim_time_uptime_begin(uptime_scan_oil, sizeof(uptime_scan_oil), now,
3499 pim->scan_oil_last);
3500 pim_time_uptime_begin(uptime_mroute_add, sizeof(uptime_mroute_add), now,
3501 pim->mroute_add_last);
3502 pim_time_uptime_begin(uptime_mroute_del, sizeof(uptime_mroute_del), now,
3503 pim->mroute_del_last);
3504
3505 vty_out(vty,
3506 "Scan OIL - Last: %s Events: %lld\n"
3507 "MFC Add - Last: %s Events: %lld\n"
3508 "MFC Del - Last: %s Events: %lld\n",
3509 uptime_scan_oil, (long long)pim->scan_oil_events,
3510 uptime_mroute_add, (long long)pim->mroute_add_events,
3511 uptime_mroute_del, (long long)pim->mroute_del_events);
3512 }
3513
3514 void show_multicast_interfaces(struct pim_instance *pim, struct vty *vty,
3515 json_object *json)
3516 {
3517 struct interface *ifp;
3518 struct ttable *tt = NULL;
3519 char *table = NULL;
3520 json_object *json_row = NULL;
3521
3522 vty_out(vty, "\n");
3523
3524 if (!json) {
3525 /* Prepare table. */
3526 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
3527 ttable_add_row(
3528 tt,
3529 "Interface|Address|ifi|Vif|PktsIn|PktsOut|BytesIn|BytesOut");
3530 tt->style.cell.rpad = 2;
3531 tt->style.corner = '+';
3532 ttable_restyle(tt);
3533 }
3534
3535 FOR_ALL_INTERFACES (pim->vrf, ifp) {
3536 struct pim_interface *pim_ifp;
3537 #if PIM_IPV == 4
3538 struct sioc_vif_req vreq;
3539 #else
3540 struct sioc_mif_req6 vreq;
3541 #endif
3542
3543 pim_ifp = ifp->info;
3544
3545 if (!pim_ifp)
3546 continue;
3547
3548 memset(&vreq, 0, sizeof(vreq));
3549 #if PIM_IPV == 4
3550 vreq.vifi = pim_ifp->mroute_vif_index;
3551 if (ioctl(pim->mroute_socket, SIOCGETVIFCNT, &vreq)) {
3552 zlog_warn(
3553 "ioctl(SIOCGETVIFCNT=%lu) failure for interface %s vif_index=%d: errno=%d: %s",
3554 (unsigned long)SIOCGETVIFCNT, ifp->name,
3555 pim_ifp->mroute_vif_index, errno,
3556 safe_strerror(errno));
3557 }
3558 #else
3559 vreq.mifi = pim_ifp->mroute_vif_index;
3560 if (ioctl(pim->mroute_socket, SIOCGETMIFCNT_IN6, &vreq)) {
3561 zlog_warn(
3562 "ioctl(SIOCGETMIFCNT_IN6=%lu) failure for interface %s vif_index=%d: errno=%d: %s",
3563 (unsigned long)SIOCGETMIFCNT_IN6, ifp->name,
3564 pim_ifp->mroute_vif_index, errno,
3565 safe_strerror(errno));
3566 }
3567 #endif
3568
3569 if (json) {
3570 json_row = json_object_new_object();
3571 json_object_string_add(json_row, "name", ifp->name);
3572 json_object_string_add(json_row, "state",
3573 if_is_up(ifp) ? "up" : "down");
3574 json_object_string_addf(json_row, "address", "%pPA",
3575 &pim_ifp->primary_address);
3576 json_object_int_add(json_row, "ifIndex", ifp->ifindex);
3577 json_object_int_add(json_row, "vif",
3578 pim_ifp->mroute_vif_index);
3579 json_object_int_add(json_row, "pktsIn",
3580 (unsigned long)vreq.icount);
3581 json_object_int_add(json_row, "pktsOut",
3582 (unsigned long)vreq.ocount);
3583 json_object_int_add(json_row, "bytesIn",
3584 (unsigned long)vreq.ibytes);
3585 json_object_int_add(json_row, "bytesOut",
3586 (unsigned long)vreq.obytes);
3587 json_object_object_add(json, ifp->name, json_row);
3588 } else {
3589 ttable_add_row(tt, "%s|%pPAs|%d|%d|%lu|%lu|%lu|%lu",
3590 ifp->name, &pim_ifp->primary_address,
3591 ifp->ifindex, pim_ifp->mroute_vif_index,
3592 (unsigned long)vreq.icount,
3593 (unsigned long)vreq.ocount,
3594 (unsigned long)vreq.ibytes,
3595 (unsigned long)vreq.obytes);
3596 }
3597 }
3598 /* Dump the generated table. */
3599 if (!json) {
3600 table = ttable_dump(tt, "\n");
3601 vty_out(vty, "%s\n", table);
3602 XFREE(MTYPE_TMP, table);
3603 ttable_del(tt);
3604 }
3605 }
3606
3607 void pim_cmd_show_ip_multicast_helper(struct pim_instance *pim, struct vty *vty)
3608 {
3609 struct vrf *vrf = pim->vrf;
3610 time_t now = pim_time_monotonic_sec();
3611 char uptime[10];
3612 char mlag_role[80];
3613
3614 pim = vrf->info;
3615
3616 vty_out(vty, "Router MLAG Role: %s\n",
3617 mlag_role2str(router->mlag_role, mlag_role, sizeof(mlag_role)));
3618 vty_out(vty, "Mroute socket descriptor:");
3619
3620 vty_out(vty, " %d(%s)\n", pim->mroute_socket, vrf->name);
3621 vty_out(vty, "PIM Register socket descriptor:");
3622 vty_out(vty, " %d(%s)\n", pim->reg_sock, vrf->name);
3623
3624 pim_time_uptime(uptime, sizeof(uptime),
3625 now - pim->mroute_socket_creation);
3626 vty_out(vty, "Mroute socket uptime: %s\n", uptime);
3627
3628 vty_out(vty, "\n");
3629
3630 pim_zebra_zclient_update(vty);
3631 pim_zlookup_show_ip_multicast(vty);
3632
3633 vty_out(vty, "\n");
3634 vty_out(vty, "Maximum highest VifIndex: %d\n", PIM_MAX_USABLE_VIFS);
3635
3636 vty_out(vty, "\n");
3637 vty_out(vty, "Upstream Join Timer: %d secs\n", router->t_periodic);
3638 vty_out(vty, "Join/Prune Holdtime: %d secs\n", PIM_JP_HOLDTIME);
3639 vty_out(vty, "PIM ECMP: %s\n", pim->ecmp_enable ? "Enable" : "Disable");
3640 vty_out(vty, "PIM ECMP Rebalance: %s\n",
3641 pim->ecmp_rebalance_enable ? "Enable" : "Disable");
3642
3643 vty_out(vty, "\n");
3644
3645 pim_show_rpf_refresh_stats(vty, pim, now, NULL);
3646
3647 vty_out(vty, "\n");
3648
3649 show_scan_oil_stats(pim, vty, now);
3650
3651 show_multicast_interfaces(pim, vty, NULL);
3652 }
3653
3654 void show_mroute(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg,
3655 bool fill, json_object *json)
3656 {
3657 struct listnode *node;
3658 struct channel_oil *c_oil;
3659 struct static_route *s_route;
3660 struct ttable *tt = NULL;
3661 char *table = NULL;
3662 time_t now;
3663 json_object *json_group = NULL;
3664 json_object *json_source = NULL;
3665 json_object *json_oil = NULL;
3666 json_object *json_ifp_out = NULL;
3667 int found_oif;
3668 int first;
3669 char grp_str[PIM_ADDRSTRLEN];
3670 char src_str[PIM_ADDRSTRLEN];
3671 char in_ifname[INTERFACE_NAMSIZ + 1];
3672 char out_ifname[INTERFACE_NAMSIZ + 1];
3673 int oif_vif_index;
3674 struct interface *ifp_in;
3675 char proto[100];
3676 char state_str[PIM_REG_STATE_STR_LEN];
3677 char mroute_uptime[10];
3678
3679 if (!json) {
3680 vty_out(vty, "IP Multicast Routing Table\n");
3681 vty_out(vty, "Flags: S - Sparse, C - Connected, P - Pruned\n");
3682 vty_out(vty,
3683 " R - SGRpt Pruned, F - Register flag, T - SPT-bit set\n");
3684
3685 /* Prepare table. */
3686 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
3687 ttable_add_row(
3688 tt, "Source|Group|Flags|Proto|Input|Output|TTL|Uptime");
3689 tt->style.cell.rpad = 2;
3690 tt->style.corner = '+';
3691 ttable_restyle(tt);
3692 }
3693
3694 now = pim_time_monotonic_sec();
3695
3696 /* print list of PIM and IGMP routes */
3697 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
3698 found_oif = 0;
3699 first = 1;
3700 if (!c_oil->installed)
3701 continue;
3702
3703 if (!pim_addr_is_any(sg->grp) &&
3704 pim_addr_cmp(sg->grp, *oil_mcastgrp(c_oil)))
3705 continue;
3706 if (!pim_addr_is_any(sg->src) &&
3707 pim_addr_cmp(sg->src, *oil_origin(c_oil)))
3708 continue;
3709
3710 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
3711 oil_mcastgrp(c_oil));
3712 snprintfrr(src_str, sizeof(src_str), "%pPAs",
3713 oil_origin(c_oil));
3714
3715 strlcpy(state_str, "S", sizeof(state_str));
3716 /* When a non DR receives a igmp join, it creates a (*,G)
3717 * channel_oil without any upstream creation
3718 */
3719 if (c_oil->up) {
3720 if (PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(c_oil->up->flags))
3721 strlcat(state_str, "C", sizeof(state_str));
3722 if (pim_upstream_is_sg_rpt(c_oil->up))
3723 strlcat(state_str, "R", sizeof(state_str));
3724 if (PIM_UPSTREAM_FLAG_TEST_FHR(c_oil->up->flags))
3725 strlcat(state_str, "F", sizeof(state_str));
3726 if (c_oil->up->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
3727 strlcat(state_str, "T", sizeof(state_str));
3728 }
3729 if (pim_channel_oil_empty(c_oil))
3730 strlcat(state_str, "P", sizeof(state_str));
3731
3732 ifp_in = pim_if_find_by_vif_index(pim, *oil_parent(c_oil));
3733
3734 if (ifp_in)
3735 strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
3736 else
3737 strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
3738
3739
3740 pim_time_uptime(mroute_uptime, sizeof(mroute_uptime),
3741 now - c_oil->mroute_creation);
3742
3743 if (json) {
3744
3745 /* Find the group, create it if it doesn't exist */
3746 json_object_object_get_ex(json, grp_str, &json_group);
3747
3748 if (!json_group) {
3749 json_group = json_object_new_object();
3750 json_object_object_add(json, grp_str,
3751 json_group);
3752 }
3753
3754 /* Find the source nested under the group, create it if
3755 * it doesn't exist
3756 */
3757 json_object_object_get_ex(json_group, src_str,
3758 &json_source);
3759
3760 if (!json_source) {
3761 json_source = json_object_new_object();
3762 json_object_object_add(json_group, src_str,
3763 json_source);
3764 }
3765
3766 /* Find the inbound interface nested under the source,
3767 * create it if it doesn't exist
3768 */
3769 json_object_string_add(json_source, "source", src_str);
3770 json_object_string_add(json_source, "group", grp_str);
3771 json_object_int_add(json_source, "installed",
3772 c_oil->installed);
3773 json_object_int_add(json_source, "refCount",
3774 c_oil->oil_ref_count);
3775 json_object_int_add(json_source, "oilSize",
3776 c_oil->oil_size);
3777 json_object_int_add(json_source, "OilInheritedRescan",
3778 c_oil->oil_inherited_rescan);
3779 json_object_int_add(json_source, "oilInheritedRescan",
3780 c_oil->oil_inherited_rescan);
3781 json_object_string_add(json_source, "iif", in_ifname);
3782 json_object_string_add(json_source, "upTime",
3783 mroute_uptime);
3784 json_oil = NULL;
3785 }
3786
3787 for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
3788 ++oif_vif_index) {
3789 struct interface *ifp_out;
3790 int ttl;
3791
3792 ttl = oil_if_has(c_oil, oif_vif_index);
3793 if (ttl < 1)
3794 continue;
3795
3796 /* do not display muted OIFs */
3797 if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_MUTE)
3798 continue;
3799
3800 if (*oil_parent(c_oil) == oif_vif_index &&
3801 !pim_mroute_allow_iif_in_oil(c_oil, oif_vif_index))
3802 continue;
3803
3804 ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
3805 found_oif = 1;
3806
3807 if (ifp_out)
3808 strlcpy(out_ifname, ifp_out->name,
3809 sizeof(out_ifname));
3810 else
3811 strlcpy(out_ifname, "<oif?>",
3812 sizeof(out_ifname));
3813
3814 if (json) {
3815 json_ifp_out = json_object_new_object();
3816 json_object_string_add(json_ifp_out, "source",
3817 src_str);
3818 json_object_string_add(json_ifp_out, "group",
3819 grp_str);
3820
3821 if (c_oil->oif_flags[oif_vif_index] &
3822 PIM_OIF_FLAG_PROTO_PIM)
3823 json_object_boolean_true_add(
3824 json_ifp_out, "protocolPim");
3825
3826 if (c_oil->oif_flags[oif_vif_index] &
3827 PIM_OIF_FLAG_PROTO_GM)
3828 #if PIM_IPV == 4
3829 json_object_boolean_true_add(
3830 json_ifp_out, "protocolIgmp");
3831 #else
3832 json_object_boolean_true_add(
3833 json_ifp_out, "protocolMld");
3834 #endif
3835
3836 if (c_oil->oif_flags[oif_vif_index] &
3837 PIM_OIF_FLAG_PROTO_VXLAN)
3838 json_object_boolean_true_add(
3839 json_ifp_out, "protocolVxlan");
3840
3841 if (c_oil->oif_flags[oif_vif_index] &
3842 PIM_OIF_FLAG_PROTO_STAR)
3843 json_object_boolean_true_add(
3844 json_ifp_out,
3845 "protocolInherited");
3846
3847 json_object_string_add(json_ifp_out,
3848 "inboundInterface",
3849 in_ifname);
3850 json_object_int_add(json_ifp_out, "iVifI",
3851 *oil_parent(c_oil));
3852 json_object_string_add(json_ifp_out,
3853 "outboundInterface",
3854 out_ifname);
3855 json_object_int_add(json_ifp_out, "oVifI",
3856 oif_vif_index);
3857 json_object_int_add(json_ifp_out, "ttl", ttl);
3858 json_object_string_add(json_ifp_out, "upTime",
3859 mroute_uptime);
3860 json_object_string_add(json_source, "flags",
3861 state_str);
3862 if (!json_oil) {
3863 json_oil = json_object_new_object();
3864 json_object_object_add(json_source,
3865 "oil", json_oil);
3866 }
3867 json_object_object_add(json_oil, out_ifname,
3868 json_ifp_out);
3869 } else {
3870 proto[0] = '\0';
3871 if (c_oil->oif_flags[oif_vif_index] &
3872 PIM_OIF_FLAG_PROTO_PIM) {
3873 strlcpy(proto, "PIM", sizeof(proto));
3874 }
3875
3876 if (c_oil->oif_flags[oif_vif_index] &
3877 PIM_OIF_FLAG_PROTO_GM) {
3878 #if PIM_IPV == 4
3879 strlcpy(proto, "IGMP", sizeof(proto));
3880 #else
3881 strlcpy(proto, "MLD", sizeof(proto));
3882 #endif
3883 }
3884
3885 if (c_oil->oif_flags[oif_vif_index] &
3886 PIM_OIF_FLAG_PROTO_VXLAN) {
3887 strlcpy(proto, "VxLAN", sizeof(proto));
3888 }
3889
3890 if (c_oil->oif_flags[oif_vif_index] &
3891 PIM_OIF_FLAG_PROTO_STAR) {
3892 strlcpy(proto, "STAR", sizeof(proto));
3893 }
3894
3895 ttable_add_row(tt, "%s|%s|%s|%s|%s|%s|%d|%s",
3896 src_str, grp_str, state_str,
3897 proto, in_ifname, out_ifname,
3898 ttl, mroute_uptime);
3899
3900 if (first) {
3901 src_str[0] = '\0';
3902 grp_str[0] = '\0';
3903 in_ifname[0] = '\0';
3904 state_str[0] = '\0';
3905 mroute_uptime[0] = '\0';
3906 first = 0;
3907 }
3908 }
3909 }
3910
3911 if (!json && !found_oif) {
3912 ttable_add_row(tt, "%pPAs|%pPAs|%s|%s|%s|%s|%d|%s",
3913 oil_origin(c_oil), oil_mcastgrp(c_oil),
3914 state_str, "none", in_ifname, "none", 0,
3915 "--:--:--");
3916 }
3917 }
3918
3919 /* Print list of static routes */
3920 for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
3921 first = 1;
3922
3923 if (!s_route->c_oil.installed)
3924 continue;
3925
3926 snprintfrr(grp_str, sizeof(grp_str), "%pPAs", &s_route->group);
3927 snprintfrr(src_str, sizeof(src_str), "%pPAs", &s_route->source);
3928 ifp_in = pim_if_find_by_vif_index(pim, s_route->iif);
3929 found_oif = 0;
3930
3931 if (ifp_in)
3932 strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
3933 else
3934 strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
3935
3936 if (json) {
3937
3938 /* Find the group, create it if it doesn't exist */
3939 json_object_object_get_ex(json, grp_str, &json_group);
3940
3941 if (!json_group) {
3942 json_group = json_object_new_object();
3943 json_object_object_add(json, grp_str,
3944 json_group);
3945 }
3946
3947 /* Find the source nested under the group, create it if
3948 * it doesn't exist
3949 */
3950 json_object_object_get_ex(json_group, src_str,
3951 &json_source);
3952
3953 if (!json_source) {
3954 json_source = json_object_new_object();
3955 json_object_object_add(json_group, src_str,
3956 json_source);
3957 }
3958
3959 json_object_string_add(json_source, "iif", in_ifname);
3960 json_oil = NULL;
3961 } else {
3962 strlcpy(proto, "STATIC", sizeof(proto));
3963 }
3964
3965 for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
3966 ++oif_vif_index) {
3967 struct interface *ifp_out;
3968 char oif_uptime[10];
3969 int ttl;
3970
3971 ttl = s_route->oif_ttls[oif_vif_index];
3972 if (ttl < 1)
3973 continue;
3974
3975 ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
3976 pim_time_uptime(
3977 oif_uptime, sizeof(oif_uptime),
3978 now - s_route->c_oil
3979 .oif_creation[oif_vif_index]);
3980 found_oif = 1;
3981
3982 if (ifp_out)
3983 strlcpy(out_ifname, ifp_out->name,
3984 sizeof(out_ifname));
3985 else
3986 strlcpy(out_ifname, "<oif?>",
3987 sizeof(out_ifname));
3988
3989 if (json) {
3990 json_ifp_out = json_object_new_object();
3991 json_object_string_add(json_ifp_out, "source",
3992 src_str);
3993 json_object_string_add(json_ifp_out, "group",
3994 grp_str);
3995 json_object_boolean_true_add(json_ifp_out,
3996 "protocolStatic");
3997 json_object_string_add(json_ifp_out,
3998 "inboundInterface",
3999 in_ifname);
4000 json_object_int_add(
4001 json_ifp_out, "iVifI",
4002 *oil_parent(&s_route->c_oil));
4003 json_object_string_add(json_ifp_out,
4004 "outboundInterface",
4005 out_ifname);
4006 json_object_int_add(json_ifp_out, "oVifI",
4007 oif_vif_index);
4008 json_object_int_add(json_ifp_out, "ttl", ttl);
4009 json_object_string_add(json_ifp_out, "upTime",
4010 oif_uptime);
4011 if (!json_oil) {
4012 json_oil = json_object_new_object();
4013 json_object_object_add(json_source,
4014 "oil", json_oil);
4015 }
4016 json_object_object_add(json_oil, out_ifname,
4017 json_ifp_out);
4018 } else {
4019 ttable_add_row(
4020 tt, "%pPAs|%pPAs|%s|%s|%s|%s|%d|%s",
4021 &s_route->source, &s_route->group, "-",
4022 proto, in_ifname, out_ifname, ttl,
4023 oif_uptime);
4024 if (first && !fill) {
4025 src_str[0] = '\0';
4026 grp_str[0] = '\0';
4027 in_ifname[0] = '\0';
4028 first = 0;
4029 }
4030 }
4031 }
4032
4033 if (!json && !found_oif) {
4034 ttable_add_row(tt, "%pPAs|%pPAs|%s|%s|%s|%s|%d|%s",
4035 &s_route->source, &s_route->group, "-",
4036 proto, in_ifname, "none", 0, "--:--:--");
4037 }
4038 }
4039 /* Dump the generated table. */
4040 if (!json) {
4041 table = ttable_dump(tt, "\n");
4042 vty_out(vty, "%s\n", table);
4043 XFREE(MTYPE_TMP, table);
4044 ttable_del(tt);
4045 }
4046 }
4047
4048 static void show_mroute_count_per_channel_oil(struct channel_oil *c_oil,
4049 json_object *json,
4050 struct ttable *tt)
4051 {
4052 json_object *json_group = NULL;
4053 json_object *json_source = NULL;
4054
4055 if (!c_oil->installed)
4056 return;
4057
4058 pim_mroute_update_counters(c_oil);
4059
4060 if (json) {
4061 char group_str[PIM_ADDRSTRLEN];
4062 char source_str[PIM_ADDRSTRLEN];
4063
4064 snprintfrr(group_str, sizeof(group_str), "%pPAs",
4065 oil_mcastgrp(c_oil));
4066 snprintfrr(source_str, sizeof(source_str), "%pPAs",
4067 oil_origin(c_oil));
4068
4069 json_object_object_get_ex(json, group_str, &json_group);
4070
4071 if (!json_group) {
4072 json_group = json_object_new_object();
4073 json_object_object_add(json, group_str, json_group);
4074 }
4075
4076 json_source = json_object_new_object();
4077 json_object_object_add(json_group, source_str, json_source);
4078 json_object_int_add(json_source, "lastUsed",
4079 c_oil->cc.lastused / 100);
4080 json_object_int_add(json_source, "packets", c_oil->cc.pktcnt);
4081 json_object_int_add(json_source, "bytes", c_oil->cc.bytecnt);
4082 json_object_int_add(json_source, "wrongIf", c_oil->cc.wrong_if);
4083
4084 } else {
4085 ttable_add_row(tt, "%pPAs|%pPAs|%llu|%ld|%ld|%ld",
4086 oil_origin(c_oil), oil_mcastgrp(c_oil),
4087 c_oil->cc.lastused / 100,
4088 c_oil->cc.pktcnt - c_oil->cc.origpktcnt,
4089 c_oil->cc.bytecnt - c_oil->cc.origbytecnt,
4090 c_oil->cc.wrong_if - c_oil->cc.origwrong_if);
4091 }
4092 }
4093
4094 void show_mroute_count(struct pim_instance *pim, struct vty *vty,
4095 json_object *json)
4096 {
4097 struct listnode *node;
4098 struct channel_oil *c_oil;
4099 struct static_route *sr;
4100 struct ttable *tt = NULL;
4101 char *table = NULL;
4102
4103 if (!json) {
4104 vty_out(vty, "\n");
4105
4106 /* Prepare table. */
4107 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
4108 ttable_add_row(tt,
4109 "Source|Group|LastUsed|Packets|Bytes|WrongIf");
4110 tt->style.cell.rpad = 2;
4111 tt->style.corner = '+';
4112 ttable_restyle(tt);
4113 }
4114
4115 /* Print PIM and IGMP route counts */
4116 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil)
4117 show_mroute_count_per_channel_oil(c_oil, json, tt);
4118
4119 for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sr))
4120 show_mroute_count_per_channel_oil(&sr->c_oil, json, tt);
4121
4122 /* Dump the generated table. */
4123 if (!json) {
4124 table = ttable_dump(tt, "\n");
4125 vty_out(vty, "%s\n", table);
4126 XFREE(MTYPE_TMP, table);
4127 ttable_del(tt);
4128 }
4129 }
4130
4131 void show_mroute_summary(struct pim_instance *pim, struct vty *vty,
4132 json_object *json)
4133 {
4134 struct listnode *node;
4135 struct channel_oil *c_oil;
4136 struct static_route *s_route;
4137 uint32_t starg_sw_mroute_cnt = 0;
4138 uint32_t sg_sw_mroute_cnt = 0;
4139 uint32_t starg_hw_mroute_cnt = 0;
4140 uint32_t sg_hw_mroute_cnt = 0;
4141 json_object *json_starg = NULL;
4142 json_object *json_sg = NULL;
4143
4144 if (!json)
4145 vty_out(vty, "Mroute Type Installed/Total\n");
4146
4147 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
4148 if (!c_oil->installed) {
4149 if (pim_addr_is_any(*oil_origin(c_oil)))
4150 starg_sw_mroute_cnt++;
4151 else
4152 sg_sw_mroute_cnt++;
4153 } else {
4154 if (pim_addr_is_any(*oil_origin(c_oil)))
4155 starg_hw_mroute_cnt++;
4156 else
4157 sg_hw_mroute_cnt++;
4158 }
4159 }
4160
4161 for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
4162 if (!s_route->c_oil.installed) {
4163 if (pim_addr_is_any(*oil_origin(&s_route->c_oil)))
4164 starg_sw_mroute_cnt++;
4165 else
4166 sg_sw_mroute_cnt++;
4167 } else {
4168 if (pim_addr_is_any(*oil_origin(&s_route->c_oil)))
4169 starg_hw_mroute_cnt++;
4170 else
4171 sg_hw_mroute_cnt++;
4172 }
4173 }
4174
4175 if (!json) {
4176 vty_out(vty, "%-20s %u/%u\n", "(*, G)", starg_hw_mroute_cnt,
4177 starg_sw_mroute_cnt + starg_hw_mroute_cnt);
4178 vty_out(vty, "%-20s %u/%u\n", "(S, G)", sg_hw_mroute_cnt,
4179 sg_sw_mroute_cnt + sg_hw_mroute_cnt);
4180 vty_out(vty, "------\n");
4181 vty_out(vty, "%-20s %u/%u\n", "Total",
4182 (starg_hw_mroute_cnt + sg_hw_mroute_cnt),
4183 (starg_sw_mroute_cnt + starg_hw_mroute_cnt +
4184 sg_sw_mroute_cnt + sg_hw_mroute_cnt));
4185 } else {
4186 /* (*,G) route details */
4187 json_starg = json_object_new_object();
4188 json_object_object_add(json, "wildcardGroup", json_starg);
4189
4190 json_object_int_add(json_starg, "installed",
4191 starg_hw_mroute_cnt);
4192 json_object_int_add(json_starg, "total",
4193 starg_sw_mroute_cnt + starg_hw_mroute_cnt);
4194
4195 /* (S, G) route details */
4196 json_sg = json_object_new_object();
4197 json_object_object_add(json, "sourceGroup", json_sg);
4198
4199 json_object_int_add(json_sg, "installed", sg_hw_mroute_cnt);
4200 json_object_int_add(json_sg, "total",
4201 sg_sw_mroute_cnt + sg_hw_mroute_cnt);
4202
4203 json_object_int_add(json, "totalNumOfInstalledMroutes",
4204 starg_hw_mroute_cnt + sg_hw_mroute_cnt);
4205 json_object_int_add(json, "totalNumOfMroutes",
4206 starg_sw_mroute_cnt + starg_hw_mroute_cnt +
4207 sg_sw_mroute_cnt +
4208 sg_hw_mroute_cnt);
4209 }
4210 }
4211
4212 int clear_ip_mroute_count_command(struct vty *vty, const char *name)
4213 {
4214 struct listnode *node;
4215 struct channel_oil *c_oil;
4216 struct static_route *sr;
4217 struct vrf *v = pim_cmd_lookup(vty, name);
4218 struct pim_instance *pim;
4219
4220 if (!v)
4221 return CMD_WARNING;
4222
4223 pim = v->info;
4224 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
4225 if (!c_oil->installed)
4226 continue;
4227
4228 pim_mroute_update_counters(c_oil);
4229 c_oil->cc.origpktcnt = c_oil->cc.pktcnt;
4230 c_oil->cc.origbytecnt = c_oil->cc.bytecnt;
4231 c_oil->cc.origwrong_if = c_oil->cc.wrong_if;
4232 }
4233
4234 for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sr)) {
4235 if (!sr->c_oil.installed)
4236 continue;
4237
4238 pim_mroute_update_counters(&sr->c_oil);
4239
4240 sr->c_oil.cc.origpktcnt = sr->c_oil.cc.pktcnt;
4241 sr->c_oil.cc.origbytecnt = sr->c_oil.cc.bytecnt;
4242 sr->c_oil.cc.origwrong_if = sr->c_oil.cc.wrong_if;
4243 }
4244 return CMD_SUCCESS;
4245 }
4246
4247 struct vrf *pim_cmd_lookup(struct vty *vty, const char *name)
4248 {
4249 struct vrf *vrf;
4250
4251 if (name)
4252 vrf = vrf_lookup_by_name(name);
4253 else
4254 vrf = vrf_lookup_by_id(VRF_DEFAULT);
4255
4256 if (!vrf)
4257 vty_out(vty, "Specified VRF: %s does not exist\n", name);
4258
4259 return vrf;
4260 }
4261
4262 void clear_mroute(struct pim_instance *pim)
4263 {
4264 struct pim_upstream *up;
4265 struct interface *ifp;
4266
4267 /* scan interfaces */
4268 FOR_ALL_INTERFACES (pim->vrf, ifp) {
4269 struct pim_interface *pim_ifp = ifp->info;
4270 struct pim_ifchannel *ch;
4271
4272 if (!pim_ifp)
4273 continue;
4274
4275 /* deleting all ifchannels */
4276 while (!RB_EMPTY(pim_ifchannel_rb, &pim_ifp->ifchannel_rb)) {
4277 ch = RB_ROOT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb);
4278
4279 pim_ifchannel_delete(ch);
4280 }
4281
4282 #if PIM_IPV == 4
4283 /* clean up all igmp groups */
4284 struct gm_group *grp;
4285
4286 if (pim_ifp->gm_group_list) {
4287 while (pim_ifp->gm_group_list->count) {
4288 grp = listnode_head(pim_ifp->gm_group_list);
4289 igmp_group_delete(grp);
4290 }
4291 }
4292 #else
4293 struct gm_if *gm_ifp;
4294
4295 gm_ifp = pim_ifp->mld;
4296 if (gm_ifp)
4297 gm_group_delete(gm_ifp);
4298 #endif
4299 }
4300
4301 /* clean up all upstreams*/
4302 while ((up = rb_pim_upstream_first(&pim->upstream_head)))
4303 pim_upstream_del(pim, up, __func__);
4304 }
4305
4306 void clear_pim_statistics(struct pim_instance *pim)
4307 {
4308 struct interface *ifp;
4309
4310 pim->bsm_rcvd = 0;
4311 pim->bsm_sent = 0;
4312 pim->bsm_dropped = 0;
4313
4314 /* scan interfaces */
4315 FOR_ALL_INTERFACES (pim->vrf, ifp) {
4316 struct pim_interface *pim_ifp = ifp->info;
4317
4318 if (!pim_ifp)
4319 continue;
4320
4321 pim_ifp->pim_ifstat_bsm_cfg_miss = 0;
4322 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss = 0;
4323 pim_ifp->pim_ifstat_bsm_invalid_sz = 0;
4324 }
4325 }
4326
4327 int clear_pim_interface_traffic(const char *vrf, struct vty *vty)
4328 {
4329 struct interface *ifp = NULL;
4330 struct pim_interface *pim_ifp = NULL;
4331
4332 struct vrf *v = pim_cmd_lookup(vty, vrf);
4333
4334 if (!v)
4335 return CMD_WARNING;
4336
4337 FOR_ALL_INTERFACES (v, ifp) {
4338 pim_ifp = ifp->info;
4339
4340 if (!pim_ifp)
4341 continue;
4342
4343 pim_ifp->pim_ifstat_hello_recv = 0;
4344 pim_ifp->pim_ifstat_hello_sent = 0;
4345 pim_ifp->pim_ifstat_join_recv = 0;
4346 pim_ifp->pim_ifstat_join_send = 0;
4347 pim_ifp->pim_ifstat_prune_recv = 0;
4348 pim_ifp->pim_ifstat_prune_send = 0;
4349 pim_ifp->pim_ifstat_reg_recv = 0;
4350 pim_ifp->pim_ifstat_reg_send = 0;
4351 pim_ifp->pim_ifstat_reg_stop_recv = 0;
4352 pim_ifp->pim_ifstat_reg_stop_send = 0;
4353 pim_ifp->pim_ifstat_assert_recv = 0;
4354 pim_ifp->pim_ifstat_assert_send = 0;
4355 pim_ifp->pim_ifstat_bsm_rx = 0;
4356 pim_ifp->pim_ifstat_bsm_tx = 0;
4357 #if PIM_IPV == 4
4358 pim_ifp->igmp_ifstat_joins_sent = 0;
4359 pim_ifp->igmp_ifstat_joins_failed = 0;
4360 pim_ifp->igmp_peak_group_count = 0;
4361 #endif
4362 }
4363
4364 return CMD_SUCCESS;
4365 }
4366
4367 int pim_debug_pim_cmd(void)
4368 {
4369 PIM_DO_DEBUG_PIM_EVENTS;
4370 PIM_DO_DEBUG_PIM_PACKETS;
4371 PIM_DO_DEBUG_PIM_TRACE;
4372 PIM_DO_DEBUG_MSDP_EVENTS;
4373 PIM_DO_DEBUG_MSDP_PACKETS;
4374 PIM_DO_DEBUG_BSM;
4375 PIM_DO_DEBUG_VXLAN;
4376 return CMD_SUCCESS;
4377 }
4378
4379 int pim_no_debug_pim_cmd(void)
4380 {
4381 PIM_DONT_DEBUG_PIM_EVENTS;
4382 PIM_DONT_DEBUG_PIM_PACKETS;
4383 PIM_DONT_DEBUG_PIM_TRACE;
4384 PIM_DONT_DEBUG_MSDP_EVENTS;
4385 PIM_DONT_DEBUG_MSDP_PACKETS;
4386
4387 PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND;
4388 PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV;
4389 PIM_DONT_DEBUG_BSM;
4390 PIM_DONT_DEBUG_VXLAN;
4391 return CMD_SUCCESS;
4392 }
4393
4394 int pim_debug_pim_packets_cmd(const char *hello, const char *joins,
4395 const char *registers, struct vty *vty)
4396 {
4397 if (hello) {
4398 PIM_DO_DEBUG_PIM_HELLO;
4399 vty_out(vty, "PIM Hello debugging is on\n");
4400 } else if (joins) {
4401 PIM_DO_DEBUG_PIM_J_P;
4402 vty_out(vty, "PIM Join/Prune debugging is on\n");
4403 } else if (registers) {
4404 PIM_DO_DEBUG_PIM_REG;
4405 vty_out(vty, "PIM Register debugging is on\n");
4406 } else {
4407 PIM_DO_DEBUG_PIM_PACKETS;
4408 vty_out(vty, "PIM Packet debugging is on\n");
4409 }
4410 return CMD_SUCCESS;
4411 }
4412
4413 int pim_no_debug_pim_packets_cmd(const char *hello, const char *joins,
4414 const char *registers, struct vty *vty)
4415 {
4416 if (hello) {
4417 PIM_DONT_DEBUG_PIM_HELLO;
4418 vty_out(vty, "PIM Hello debugging is off\n");
4419 } else if (joins) {
4420 PIM_DONT_DEBUG_PIM_J_P;
4421 vty_out(vty, "PIM Join/Prune debugging is off\n");
4422 } else if (registers) {
4423 PIM_DONT_DEBUG_PIM_REG;
4424 vty_out(vty, "PIM Register debugging is off\n");
4425 } else {
4426 PIM_DONT_DEBUG_PIM_PACKETS;
4427 vty_out(vty, "PIM Packet debugging is off\n");
4428 }
4429
4430 return CMD_SUCCESS;
4431 }
4432
4433 int pim_show_rpf_helper(const char *vrf, struct vty *vty, bool json)
4434 {
4435 struct pim_instance *pim;
4436 struct vrf *v;
4437 json_object *json_parent = NULL;
4438
4439 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4440
4441 if (!v)
4442 return CMD_WARNING;
4443
4444 pim = v->info;
4445
4446 if (!pim) {
4447 vty_out(vty, "%% Unable to find pim instance\n");
4448 return CMD_WARNING;
4449 }
4450
4451 if (json)
4452 json_parent = json_object_new_object();
4453
4454 pim_show_rpf(pim, vty, json_parent);
4455
4456 if (json)
4457 vty_json(vty, json_parent);
4458
4459 return CMD_SUCCESS;
4460 }
4461
4462 int pim_show_rpf_vrf_all_helper(struct vty *vty, bool json)
4463 {
4464 struct vrf *vrf;
4465 json_object *json_parent = NULL;
4466 json_object *json_vrf = NULL;
4467
4468 if (json)
4469 json_parent = json_object_new_object();
4470
4471 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4472 if (!json)
4473 vty_out(vty, "VRF: %s\n", vrf->name);
4474 else
4475 json_vrf = json_object_new_object();
4476 pim_show_rpf(vrf->info, vty, json_vrf);
4477 if (json)
4478 json_object_object_add(json_parent, vrf->name,
4479 json_vrf);
4480 }
4481 if (json)
4482 vty_json(vty, json_parent);
4483
4484 return CMD_SUCCESS;
4485 }
4486
4487 int pim_show_rp_helper(const char *vrf, struct vty *vty, const char *group_str,
4488 const struct prefix *group, bool json)
4489 {
4490 struct pim_instance *pim;
4491 struct vrf *v;
4492 json_object *json_parent = NULL;
4493 struct prefix *range = NULL;
4494
4495 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4496
4497 if (!v)
4498 return CMD_WARNING;
4499
4500 pim = v->info;
4501
4502 if (!pim) {
4503 vty_out(vty, "%% Unable to find pim instance\n");
4504 return CMD_WARNING;
4505 }
4506
4507 if (group_str) {
4508 range = prefix_new();
4509 prefix_copy(range, group);
4510 apply_mask(range);
4511 }
4512
4513 if (json)
4514 json_parent = json_object_new_object();
4515
4516 pim_rp_show_information(pim, range, vty, json_parent);
4517
4518 if (json)
4519 vty_json(vty, json_parent);
4520
4521 prefix_free(&range);
4522
4523 return CMD_SUCCESS;
4524 }
4525
4526 int pim_show_rp_vrf_all_helper(struct vty *vty, const char *group_str,
4527 const struct prefix *group, bool json)
4528 {
4529 struct vrf *vrf;
4530 json_object *json_parent = NULL;
4531 json_object *json_vrf = NULL;
4532 struct prefix *range = NULL;
4533
4534 if (group_str) {
4535 range = prefix_new();
4536 prefix_copy(range, group);
4537 apply_mask(range);
4538 }
4539
4540 if (json)
4541 json_parent = json_object_new_object();
4542
4543 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4544 if (!json)
4545 vty_out(vty, "VRF: %s\n", vrf->name);
4546 else
4547 json_vrf = json_object_new_object();
4548 pim_rp_show_information(vrf->info, range, vty, json_vrf);
4549 if (json)
4550 json_object_object_add(json_parent, vrf->name,
4551 json_vrf);
4552 }
4553 if (json)
4554 vty_json(vty, json_parent);
4555
4556 prefix_free(&range);
4557
4558 return CMD_SUCCESS;
4559 }
4560
4561 int pim_show_secondary_helper(const char *vrf, struct vty *vty)
4562 {
4563 struct pim_instance *pim;
4564 struct vrf *v;
4565
4566 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4567
4568 if (!v)
4569 return CMD_WARNING;
4570
4571 pim = v->info;
4572
4573 if (!pim) {
4574 vty_out(vty, "%% Unable to find pim instance\n");
4575 return CMD_WARNING;
4576 }
4577
4578 pim_show_neighbors_secondary(pim, vty);
4579
4580 return CMD_SUCCESS;
4581 }
4582
4583 int pim_show_statistics_helper(const char *vrf, struct vty *vty,
4584 const char *word, bool uj)
4585 {
4586 struct pim_instance *pim;
4587 struct vrf *v;
4588
4589 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4590
4591 if (!v)
4592 return CMD_WARNING;
4593
4594 pim = v->info;
4595
4596 if (!pim) {
4597 vty_out(vty, "%% Unable to find pim instance\n");
4598 return CMD_WARNING;
4599 }
4600
4601 if (word)
4602 pim_show_statistics(pim, vty, word, uj);
4603 else
4604 pim_show_statistics(pim, vty, NULL, uj);
4605
4606 return CMD_SUCCESS;
4607 }
4608
4609 int pim_show_upstream_helper(const char *vrf, struct vty *vty, pim_addr s_or_g,
4610 pim_addr g, bool json)
4611 {
4612 pim_sgaddr sg = {0};
4613 struct vrf *v;
4614 struct pim_instance *pim;
4615 json_object *json_parent = NULL;
4616
4617 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4618
4619 if (!v) {
4620 vty_out(vty, "%% Vrf specified: %s does not exist\n", vrf);
4621 return CMD_WARNING;
4622 }
4623 pim = v->info;
4624
4625 if (!pim) {
4626 vty_out(vty, "%% Unable to find pim instance\n");
4627 return CMD_WARNING;
4628 }
4629
4630 if (json)
4631 json_parent = json_object_new_object();
4632
4633 if (!pim_addr_is_any(s_or_g)) {
4634 if (!pim_addr_is_any(g)) {
4635 sg.src = s_or_g;
4636 sg.grp = g;
4637 } else
4638 sg.grp = s_or_g;
4639 }
4640
4641 pim_show_upstream(pim, vty, &sg, json_parent);
4642
4643 if (json)
4644 vty_json(vty, json_parent);
4645
4646 return CMD_SUCCESS;
4647 }
4648
4649 int pim_show_upstream_vrf_all_helper(struct vty *vty, bool json)
4650 {
4651 pim_sgaddr sg = {0};
4652 struct vrf *vrf;
4653 json_object *json_parent = NULL;
4654 json_object *json_vrf = NULL;
4655
4656 if (json)
4657 json_parent = json_object_new_object();
4658
4659 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4660 if (!json)
4661 vty_out(vty, "VRF: %s\n", vrf->name);
4662 else
4663 json_vrf = json_object_new_object();
4664 pim_show_upstream(vrf->info, vty, &sg, json_vrf);
4665 if (json)
4666 json_object_object_add(json_parent, vrf->name,
4667 json_vrf);
4668 }
4669
4670 if (json)
4671 vty_json(vty, json_parent);
4672
4673 return CMD_SUCCESS;
4674 }
4675
4676 int pim_show_upstream_join_desired_helper(const char *vrf, struct vty *vty,
4677 bool uj)
4678 {
4679 struct pim_instance *pim;
4680 struct vrf *v;
4681
4682 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4683
4684 if (!v)
4685 return CMD_WARNING;
4686
4687 pim = v->info;
4688
4689 if (!pim) {
4690 vty_out(vty, "%% Unable to find pim instance\n");
4691 return CMD_WARNING;
4692 }
4693
4694 pim_show_join_desired(pim, vty, uj);
4695
4696 return CMD_SUCCESS;
4697 }
4698
4699 int pim_show_upstream_rpf_helper(const char *vrf, struct vty *vty, bool uj)
4700 {
4701 struct pim_instance *pim;
4702 struct vrf *v;
4703
4704 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4705
4706 if (!v)
4707 return CMD_WARNING;
4708
4709 pim = v->info;
4710
4711 if (!pim) {
4712 vty_out(vty, "%% Unable to find pim instance\n");
4713 return CMD_WARNING;
4714 }
4715
4716 pim_show_upstream_rpf(pim, vty, uj);
4717
4718 return CMD_SUCCESS;
4719 }
4720
4721 int pim_show_state_helper(const char *vrf, struct vty *vty,
4722 const char *s_or_g_str, const char *g_str, bool json)
4723 {
4724 struct pim_instance *pim;
4725 struct vrf *v;
4726 json_object *json_parent = NULL;
4727
4728 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4729
4730 if (!v)
4731 return CMD_WARNING;
4732
4733 pim = v->info;
4734
4735 if (!pim) {
4736 vty_out(vty, "%% Unable to find pim instance\n");
4737 return CMD_WARNING;
4738 }
4739
4740 if (json)
4741 json_parent = json_object_new_object();
4742
4743 pim_show_state(pim, vty, s_or_g_str, g_str, json_parent);
4744
4745 if (json)
4746 vty_json(vty, json_parent);
4747
4748 return CMD_SUCCESS;
4749 }
4750
4751 int pim_show_state_vrf_all_helper(struct vty *vty, const char *s_or_g_str,
4752 const char *g_str, bool json)
4753 {
4754 struct vrf *vrf;
4755 json_object *json_parent = NULL;
4756 json_object *json_vrf = NULL;
4757
4758 if (json)
4759 json_parent = json_object_new_object();
4760
4761 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4762 if (!json)
4763 vty_out(vty, "VRF: %s\n", vrf->name);
4764 else
4765 json_vrf = json_object_new_object();
4766 pim_show_state(vrf->info, vty, s_or_g_str, g_str, json_vrf);
4767 if (json)
4768 json_object_object_add(json_parent, vrf->name,
4769 json_vrf);
4770 }
4771 if (json)
4772 vty_json(vty, json_parent);
4773
4774 return CMD_SUCCESS;
4775 }
4776
4777 int pim_show_multicast_helper(const char *vrf, struct vty *vty)
4778 {
4779 struct vrf *v;
4780 struct pim_instance *pim;
4781
4782 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4783
4784 if (!v)
4785 return CMD_WARNING;
4786
4787 pim = v->info;
4788
4789 if (!pim) {
4790 vty_out(vty, "%% Unable to find pim instance\n");
4791 return CMD_WARNING;
4792 }
4793
4794 pim_cmd_show_ip_multicast_helper(pim, vty);
4795
4796 return CMD_SUCCESS;
4797 }
4798
4799 int pim_show_multicast_vrf_all_helper(struct vty *vty)
4800 {
4801 struct vrf *vrf;
4802
4803 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4804 vty_out(vty, "VRF: %s\n", vrf->name);
4805 pim_cmd_show_ip_multicast_helper(vrf->info, vty);
4806 }
4807
4808 return CMD_SUCCESS;
4809 }
4810
4811 int pim_show_multicast_count_helper(const char *vrf, struct vty *vty, bool json)
4812 {
4813 struct pim_instance *pim;
4814 struct vrf *v;
4815 json_object *json_parent = NULL;
4816
4817 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4818
4819 if (!v)
4820 return CMD_WARNING;
4821
4822 pim = v->info;
4823
4824 if (!pim) {
4825 vty_out(vty, "%% Unable to find pim instance\n");
4826 return CMD_WARNING;
4827 }
4828
4829 if (json)
4830 json_parent = json_object_new_object();
4831
4832 show_multicast_interfaces(pim, vty, json_parent);
4833
4834 if (json)
4835 vty_json(vty, json_parent);
4836
4837 return CMD_SUCCESS;
4838 }
4839
4840 int pim_show_multicast_count_vrf_all_helper(struct vty *vty, bool json)
4841 {
4842 struct vrf *vrf;
4843 json_object *json_parent = NULL;
4844 json_object *json_vrf = NULL;
4845
4846 if (json)
4847 json_parent = json_object_new_object();
4848
4849 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4850 if (!json)
4851 vty_out(vty, "VRF: %s\n", vrf->name);
4852 else
4853 json_vrf = json_object_new_object();
4854
4855 show_multicast_interfaces(vrf->info, vty, json_vrf);
4856 if (json)
4857 json_object_object_add(json_parent, vrf->name,
4858 json_vrf);
4859 }
4860 if (json)
4861 vty_json(vty, json_parent);
4862
4863 return CMD_SUCCESS;
4864 }
4865
4866 int pim_show_mroute_helper(const char *vrf, struct vty *vty, pim_addr s_or_g,
4867 pim_addr g, bool fill, bool json)
4868 {
4869 pim_sgaddr sg = {0};
4870 struct pim_instance *pim;
4871 struct vrf *v;
4872 json_object *json_parent = NULL;
4873
4874 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4875
4876 if (!v)
4877 return CMD_WARNING;
4878
4879 pim = v->info;
4880
4881 if (!pim) {
4882 vty_out(vty, "%% Unable to find pim instance\n");
4883 return CMD_WARNING;
4884 }
4885
4886 if (json)
4887 json_parent = json_object_new_object();
4888
4889 if (!pim_addr_is_any(s_or_g)) {
4890 if (!pim_addr_is_any(g)) {
4891 sg.src = s_or_g;
4892 sg.grp = g;
4893 } else
4894 sg.grp = s_or_g;
4895 }
4896
4897 show_mroute(pim, vty, &sg, fill, json_parent);
4898
4899 if (json)
4900 vty_json(vty, json_parent);
4901
4902 return CMD_SUCCESS;
4903 }
4904
4905 int pim_show_mroute_vrf_all_helper(struct vty *vty, bool fill, bool json)
4906 {
4907 pim_sgaddr sg = {0};
4908 struct vrf *vrf;
4909 json_object *json_parent = NULL;
4910 json_object *json_vrf = NULL;
4911
4912 if (json)
4913 json_parent = json_object_new_object();
4914
4915 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4916 if (!json)
4917 vty_out(vty, "VRF: %s\n", vrf->name);
4918 else
4919 json_vrf = json_object_new_object();
4920 show_mroute(vrf->info, vty, &sg, fill, json_vrf);
4921 if (json)
4922 json_object_object_add(json_parent, vrf->name,
4923 json_vrf);
4924 }
4925 if (json)
4926 vty_json(vty, json_parent);
4927
4928 return CMD_SUCCESS;
4929 }
4930
4931 int pim_show_mroute_count_helper(const char *vrf, struct vty *vty, bool json)
4932 {
4933 struct pim_instance *pim;
4934 struct vrf *v;
4935 json_object *json_parent = NULL;
4936
4937 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4938
4939 if (!v)
4940 return CMD_WARNING;
4941
4942 pim = v->info;
4943
4944 if (!pim) {
4945 vty_out(vty, "%% Unable to find pim instance\n");
4946 return CMD_WARNING;
4947 }
4948
4949 if (json)
4950 json_parent = json_object_new_object();
4951
4952 show_mroute_count(pim, vty, json_parent);
4953
4954 if (json)
4955 vty_json(vty, json_parent);
4956
4957 return CMD_SUCCESS;
4958 }
4959
4960 int pim_show_mroute_count_vrf_all_helper(struct vty *vty, bool json)
4961 {
4962 struct vrf *vrf;
4963 json_object *json_parent = NULL;
4964 json_object *json_vrf = NULL;
4965
4966 if (json)
4967 json_parent = json_object_new_object();
4968
4969 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
4970 if (!json)
4971 vty_out(vty, "VRF: %s\n", vrf->name);
4972 else
4973 json_vrf = json_object_new_object();
4974
4975 show_mroute_count(vrf->info, vty, json_vrf);
4976
4977 if (json)
4978 json_object_object_add(json_parent, vrf->name,
4979 json_vrf);
4980 }
4981 if (json)
4982 vty_json(vty, json_parent);
4983
4984 return CMD_SUCCESS;
4985 }
4986
4987 int pim_show_mroute_summary_helper(const char *vrf, struct vty *vty, bool json)
4988 {
4989 struct pim_instance *pim;
4990 struct vrf *v;
4991 json_object *json_parent = NULL;
4992
4993 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
4994
4995 if (!v)
4996 return CMD_WARNING;
4997
4998 pim = v->info;
4999
5000 if (!pim) {
5001 vty_out(vty, "%% Unable to find pim instance\n");
5002 return CMD_WARNING;
5003 }
5004
5005 if (json)
5006 json_parent = json_object_new_object();
5007
5008 show_mroute_summary(pim, vty, json_parent);
5009
5010 if (json)
5011 vty_json(vty, json_parent);
5012
5013 return CMD_SUCCESS;
5014 }
5015
5016 int pim_show_mroute_summary_vrf_all_helper(struct vty *vty, bool json)
5017 {
5018 struct vrf *vrf;
5019 json_object *json_parent = NULL;
5020 json_object *json_vrf = NULL;
5021
5022 if (json)
5023 json_parent = json_object_new_object();
5024
5025 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
5026 if (!json)
5027 vty_out(vty, "VRF: %s\n", vrf->name);
5028 else
5029 json_vrf = json_object_new_object();
5030
5031 show_mroute_summary(vrf->info, vty, json_vrf);
5032
5033 if (json)
5034 json_object_object_add(json_parent, vrf->name,
5035 json_vrf);
5036 }
5037
5038 if (json)
5039 vty_json(vty, json_parent);
5040
5041 return CMD_SUCCESS;
5042 }
5043
5044 void pim_show_interface_traffic(struct pim_instance *pim, struct vty *vty,
5045 bool uj)
5046 {
5047 struct interface *ifp = NULL;
5048 struct pim_interface *pim_ifp = NULL;
5049 json_object *json = NULL;
5050 json_object *json_row = NULL;
5051
5052 if (uj)
5053 json = json_object_new_object();
5054 else {
5055 vty_out(vty, "\n");
5056 vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n",
5057 "Interface", " HELLO", " JOIN",
5058 " PRUNE", " REGISTER", "REGISTER-STOP",
5059 " ASSERT", " BSM");
5060 vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n", "",
5061 " Rx/Tx", " Rx/Tx", " Rx/Tx",
5062 " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx");
5063 vty_out(vty,
5064 "---------------------------------------------------------------------------------------------------------------\n");
5065 }
5066
5067 FOR_ALL_INTERFACES (pim->vrf, ifp) {
5068 pim_ifp = ifp->info;
5069
5070 if (!pim_ifp)
5071 continue;
5072
5073 if (uj) {
5074 json_row = json_object_new_object();
5075 json_object_pim_ifp_add(json_row, ifp);
5076 json_object_int_add(json_row, "helloRx",
5077 pim_ifp->pim_ifstat_hello_recv);
5078 json_object_int_add(json_row, "helloTx",
5079 pim_ifp->pim_ifstat_hello_sent);
5080 json_object_int_add(json_row, "joinRx",
5081 pim_ifp->pim_ifstat_join_recv);
5082 json_object_int_add(json_row, "joinTx",
5083 pim_ifp->pim_ifstat_join_send);
5084 json_object_int_add(json_row, "pruneRx",
5085 pim_ifp->pim_ifstat_prune_recv);
5086 json_object_int_add(json_row, "pruneTx",
5087 pim_ifp->pim_ifstat_prune_send);
5088 json_object_int_add(json_row, "registerRx",
5089 pim_ifp->pim_ifstat_reg_recv);
5090 json_object_int_add(json_row, "registerTx",
5091 pim_ifp->pim_ifstat_reg_send);
5092 json_object_int_add(json_row, "registerStopRx",
5093 pim_ifp->pim_ifstat_reg_stop_recv);
5094 json_object_int_add(json_row, "registerStopTx",
5095 pim_ifp->pim_ifstat_reg_stop_send);
5096 json_object_int_add(json_row, "assertRx",
5097 pim_ifp->pim_ifstat_assert_recv);
5098 json_object_int_add(json_row, "assertTx",
5099 pim_ifp->pim_ifstat_assert_send);
5100 json_object_int_add(json_row, "bsmRx",
5101 pim_ifp->pim_ifstat_bsm_rx);
5102 json_object_int_add(json_row, "bsmTx",
5103 pim_ifp->pim_ifstat_bsm_tx);
5104 json_object_object_add(json, ifp->name, json_row);
5105 } else {
5106 vty_out(vty,
5107 "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7" PRIu64
5108 "/%-7" PRIu64 "\n",
5109 ifp->name, pim_ifp->pim_ifstat_hello_recv,
5110 pim_ifp->pim_ifstat_hello_sent,
5111 pim_ifp->pim_ifstat_join_recv,
5112 pim_ifp->pim_ifstat_join_send,
5113 pim_ifp->pim_ifstat_prune_recv,
5114 pim_ifp->pim_ifstat_prune_send,
5115 pim_ifp->pim_ifstat_reg_recv,
5116 pim_ifp->pim_ifstat_reg_send,
5117 pim_ifp->pim_ifstat_reg_stop_recv,
5118 pim_ifp->pim_ifstat_reg_stop_send,
5119 pim_ifp->pim_ifstat_assert_recv,
5120 pim_ifp->pim_ifstat_assert_send,
5121 pim_ifp->pim_ifstat_bsm_rx,
5122 pim_ifp->pim_ifstat_bsm_tx);
5123 }
5124 }
5125 if (uj)
5126 vty_json(vty, json);
5127 }
5128
5129 void pim_show_interface_traffic_single(struct pim_instance *pim,
5130 struct vty *vty, const char *ifname,
5131 bool uj)
5132 {
5133 struct interface *ifp = NULL;
5134 struct pim_interface *pim_ifp = NULL;
5135 json_object *json = NULL;
5136 json_object *json_row = NULL;
5137 uint8_t found_ifname = 0;
5138
5139 if (uj)
5140 json = json_object_new_object();
5141 else {
5142 vty_out(vty, "\n");
5143 vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s%-17s\n",
5144 "Interface", " HELLO", " JOIN", " PRUNE",
5145 " REGISTER", " REGISTER-STOP", " ASSERT",
5146 " BSM");
5147 vty_out(vty, "%-14s%-18s%-17s%-17s%-17s%-17s%-17s%-17s\n", "",
5148 " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx",
5149 " Rx/Tx", " Rx/Tx", " Rx/Tx");
5150 vty_out(vty,
5151 "-------------------------------------------------------------------------------------------------------------------------------\n");
5152 }
5153
5154 FOR_ALL_INTERFACES (pim->vrf, ifp) {
5155 if (strcmp(ifname, ifp->name))
5156 continue;
5157
5158 pim_ifp = ifp->info;
5159
5160 if (!pim_ifp)
5161 continue;
5162
5163 found_ifname = 1;
5164 if (uj) {
5165 json_row = json_object_new_object();
5166 json_object_pim_ifp_add(json_row, ifp);
5167 json_object_int_add(json_row, "helloRx",
5168 pim_ifp->pim_ifstat_hello_recv);
5169 json_object_int_add(json_row, "helloTx",
5170 pim_ifp->pim_ifstat_hello_sent);
5171 json_object_int_add(json_row, "joinRx",
5172 pim_ifp->pim_ifstat_join_recv);
5173 json_object_int_add(json_row, "joinTx",
5174 pim_ifp->pim_ifstat_join_send);
5175 json_object_int_add(json_row, "pruneRx",
5176 pim_ifp->pim_ifstat_prune_recv);
5177 json_object_int_add(json_row, "pruneTx",
5178 pim_ifp->pim_ifstat_prune_send);
5179 json_object_int_add(json_row, "registerRx",
5180 pim_ifp->pim_ifstat_reg_recv);
5181 json_object_int_add(json_row, "registerTx",
5182 pim_ifp->pim_ifstat_reg_send);
5183 json_object_int_add(json_row, "registerStopRx",
5184 pim_ifp->pim_ifstat_reg_stop_recv);
5185 json_object_int_add(json_row, "registerStopTx",
5186 pim_ifp->pim_ifstat_reg_stop_send);
5187 json_object_int_add(json_row, "assertRx",
5188 pim_ifp->pim_ifstat_assert_recv);
5189 json_object_int_add(json_row, "assertTx",
5190 pim_ifp->pim_ifstat_assert_send);
5191 json_object_int_add(json_row, "bsmRx",
5192 pim_ifp->pim_ifstat_bsm_rx);
5193 json_object_int_add(json_row, "bsmTx",
5194 pim_ifp->pim_ifstat_bsm_tx);
5195
5196 json_object_object_add(json, ifp->name, json_row);
5197 } else {
5198 vty_out(vty,
5199 "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7" PRIu64
5200 "/%-7" PRIu64 "\n",
5201 ifp->name, pim_ifp->pim_ifstat_hello_recv,
5202 pim_ifp->pim_ifstat_hello_sent,
5203 pim_ifp->pim_ifstat_join_recv,
5204 pim_ifp->pim_ifstat_join_send,
5205 pim_ifp->pim_ifstat_prune_recv,
5206 pim_ifp->pim_ifstat_prune_send,
5207 pim_ifp->pim_ifstat_reg_recv,
5208 pim_ifp->pim_ifstat_reg_send,
5209 pim_ifp->pim_ifstat_reg_stop_recv,
5210 pim_ifp->pim_ifstat_reg_stop_send,
5211 pim_ifp->pim_ifstat_assert_recv,
5212 pim_ifp->pim_ifstat_assert_send,
5213 pim_ifp->pim_ifstat_bsm_rx,
5214 pim_ifp->pim_ifstat_bsm_tx);
5215 }
5216 }
5217 if (uj)
5218 vty_json(vty, json);
5219 else if (!found_ifname)
5220 vty_out(vty, "%% No such interface\n");
5221 }
5222
5223 int pim_show_interface_traffic_helper(const char *vrf, const char *if_name,
5224 struct vty *vty, bool uj)
5225 {
5226 struct pim_instance *pim;
5227 struct vrf *v;
5228
5229 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
5230
5231 if (!v)
5232 return CMD_WARNING;
5233
5234 pim = v->info;
5235
5236 if (!pim) {
5237 vty_out(vty, "%% Unable to find pim instance\n");
5238 return CMD_WARNING;
5239 }
5240
5241 if (if_name)
5242 pim_show_interface_traffic_single(v->info, vty, if_name, uj);
5243 else
5244 pim_show_interface_traffic(v->info, vty, uj);
5245
5246 return CMD_SUCCESS;
5247 }
5248
5249 void clear_pim_interfaces(struct pim_instance *pim)
5250 {
5251 struct interface *ifp;
5252
5253 FOR_ALL_INTERFACES (pim->vrf, ifp) {
5254 if (ifp->info)
5255 pim_neighbor_delete_all(ifp, "interface cleared");
5256 }
5257 }
5258
5259 void pim_show_bsr(struct pim_instance *pim, struct vty *vty, bool uj)
5260 {
5261 char uptime[10];
5262 char last_bsm_seen[10];
5263 time_t now;
5264 char bsr_state[20];
5265 json_object *json = NULL;
5266
5267 if (pim_addr_is_any(pim->global_scope.current_bsr)) {
5268 pim_time_uptime(uptime, sizeof(uptime),
5269 pim->global_scope.current_bsr_first_ts);
5270 pim_time_uptime(last_bsm_seen, sizeof(last_bsm_seen),
5271 pim->global_scope.current_bsr_last_ts);
5272 }
5273
5274 else {
5275 now = pim_time_monotonic_sec();
5276 pim_time_uptime(uptime, sizeof(uptime),
5277 (now - pim->global_scope.current_bsr_first_ts));
5278 pim_time_uptime(last_bsm_seen, sizeof(last_bsm_seen),
5279 now - pim->global_scope.current_bsr_last_ts);
5280 }
5281
5282 switch (pim->global_scope.state) {
5283 case NO_INFO:
5284 strlcpy(bsr_state, "NO_INFO", sizeof(bsr_state));
5285 break;
5286 case ACCEPT_ANY:
5287 strlcpy(bsr_state, "ACCEPT_ANY", sizeof(bsr_state));
5288 break;
5289 case ACCEPT_PREFERRED:
5290 strlcpy(bsr_state, "ACCEPT_PREFERRED", sizeof(bsr_state));
5291 break;
5292 default:
5293 strlcpy(bsr_state, "", sizeof(bsr_state));
5294 }
5295
5296
5297 if (uj) {
5298 json = json_object_new_object();
5299 json_object_string_addf(json, "bsr", "%pPA",
5300 &pim->global_scope.current_bsr);
5301 json_object_int_add(json, "priority",
5302 pim->global_scope.current_bsr_prio);
5303 json_object_int_add(json, "fragmentTag",
5304 pim->global_scope.bsm_frag_tag);
5305 json_object_string_add(json, "state", bsr_state);
5306 json_object_string_add(json, "upTime", uptime);
5307 json_object_string_add(json, "lastBsmSeen", last_bsm_seen);
5308 }
5309
5310 else {
5311 vty_out(vty, "PIMv2 Bootstrap information\n");
5312 vty_out(vty, "Current preferred BSR address: %pPA\n",
5313 &pim->global_scope.current_bsr);
5314 vty_out(vty,
5315 "Priority Fragment-Tag State UpTime\n");
5316 vty_out(vty, " %-12d %-12d %-13s %7s\n",
5317 pim->global_scope.current_bsr_prio,
5318 pim->global_scope.bsm_frag_tag, bsr_state, uptime);
5319 vty_out(vty, "Last BSM seen: %s\n", last_bsm_seen);
5320 }
5321
5322 if (uj)
5323 vty_json(vty, json);
5324 }
5325
5326 int pim_show_bsr_helper(const char *vrf, struct vty *vty, bool uj)
5327 {
5328 struct pim_instance *pim;
5329 struct vrf *v;
5330
5331 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
5332
5333 if (!v)
5334 return CMD_WARNING;
5335
5336 pim = pim_get_pim_instance(v->vrf_id);
5337
5338 if (!pim) {
5339 vty_out(vty, "%% Unable to find pim instance\n");
5340 return CMD_WARNING;
5341 }
5342
5343 pim_show_bsr(v->info, vty, uj);
5344
5345 return CMD_SUCCESS;
5346 }
5347
5348 /*Display the group-rp mappings */
5349 static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
5350 struct vty *vty, bool uj)
5351 {
5352 struct bsgrp_node *bsgrp;
5353 struct bsm_rpinfo *bsm_rp;
5354 struct route_node *rn;
5355 json_object *json = NULL;
5356 json_object *json_group = NULL;
5357 json_object *json_row = NULL;
5358
5359 if (uj) {
5360 json = json_object_new_object();
5361 json_object_string_addf(json, "BSR Address", "%pPA",
5362 &pim->global_scope.current_bsr);
5363 } else
5364 vty_out(vty, "BSR Address %pPA\n",
5365 &pim->global_scope.current_bsr);
5366
5367 for (rn = route_top(pim->global_scope.bsrp_table); rn;
5368 rn = route_next(rn)) {
5369 bsgrp = (struct bsgrp_node *)rn->info;
5370
5371 if (!bsgrp)
5372 continue;
5373
5374 char grp_str[PREFIX_STRLEN];
5375
5376 prefix2str(&bsgrp->group, grp_str, sizeof(grp_str));
5377
5378 if (uj) {
5379 json_object_object_get_ex(json, grp_str, &json_group);
5380 if (!json_group) {
5381 json_group = json_object_new_object();
5382 json_object_object_add(json, grp_str,
5383 json_group);
5384 }
5385 } else {
5386 vty_out(vty, "Group Address %pFX\n", &bsgrp->group);
5387 vty_out(vty, "--------------------------\n");
5388 vty_out(vty, "%-15s %-15s %-15s %-15s\n", "Rp Address",
5389 "priority", "Holdtime", "Hash");
5390
5391 vty_out(vty, "(ACTIVE)\n");
5392 }
5393
5394 frr_each (bsm_rpinfos, bsgrp->bsrp_list, bsm_rp) {
5395 if (uj) {
5396 json_row = json_object_new_object();
5397 json_object_string_addf(json_row, "Rp Address",
5398 "%pPA",
5399 &bsm_rp->rp_address);
5400 json_object_int_add(json_row, "Rp HoldTime",
5401 bsm_rp->rp_holdtime);
5402 json_object_int_add(json_row, "Rp Priority",
5403 bsm_rp->rp_prio);
5404 json_object_int_add(json_row, "Hash Val",
5405 bsm_rp->hash);
5406 json_object_object_addf(json_group, json_row,
5407 "%pPA",
5408 &bsm_rp->rp_address);
5409
5410 } else {
5411 vty_out(vty, "%-15pPA %-15u %-15u %-15u\n",
5412 &bsm_rp->rp_address, bsm_rp->rp_prio,
5413 bsm_rp->rp_holdtime, bsm_rp->hash);
5414 }
5415 }
5416 if (!bsm_rpinfos_count(bsgrp->bsrp_list) && !uj)
5417 vty_out(vty, "Active List is empty.\n");
5418
5419 if (uj) {
5420 json_object_int_add(json_group, "Pending RP count",
5421 bsgrp->pend_rp_cnt);
5422 } else {
5423 vty_out(vty, "(PENDING)\n");
5424 vty_out(vty, "Pending RP count :%d\n",
5425 bsgrp->pend_rp_cnt);
5426 if (bsgrp->pend_rp_cnt)
5427 vty_out(vty, "%-15s %-15s %-15s %-15s\n",
5428 "Rp Address", "priority", "Holdtime",
5429 "Hash");
5430 }
5431
5432 frr_each (bsm_rpinfos, bsgrp->partial_bsrp_list, bsm_rp) {
5433 if (uj) {
5434 json_row = json_object_new_object();
5435 json_object_string_addf(json_row, "Rp Address",
5436 "%pPA",
5437 &bsm_rp->rp_address);
5438 json_object_int_add(json_row, "Rp HoldTime",
5439 bsm_rp->rp_holdtime);
5440 json_object_int_add(json_row, "Rp Priority",
5441 bsm_rp->rp_prio);
5442 json_object_int_add(json_row, "Hash Val",
5443 bsm_rp->hash);
5444 json_object_object_addf(json_group, json_row,
5445 "%pPA",
5446 &bsm_rp->rp_address);
5447 } else {
5448 vty_out(vty, "%-15pPA %-15u %-15u %-15u\n",
5449 &bsm_rp->rp_address, bsm_rp->rp_prio,
5450 bsm_rp->rp_holdtime, bsm_rp->hash);
5451 }
5452 }
5453 if (!bsm_rpinfos_count(bsgrp->partial_bsrp_list) && !uj)
5454 vty_out(vty, "Partial List is empty\n");
5455
5456 if (!uj)
5457 vty_out(vty, "\n");
5458 }
5459
5460 if (uj)
5461 vty_json(vty, json);
5462 }
5463
5464 int pim_show_group_rp_mappings_info_helper(const char *vrf, struct vty *vty,
5465 bool uj)
5466 {
5467 struct pim_instance *pim;
5468 struct vrf *v;
5469
5470 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
5471
5472 if (!v)
5473 return CMD_WARNING;
5474
5475 pim = v->info;
5476
5477 if (!pim) {
5478 vty_out(vty, "%% Unable to find pim instance\n");
5479 return CMD_WARNING;
5480 }
5481
5482 pim_show_group_rp_mappings_info(v->info, vty, uj);
5483
5484 return CMD_SUCCESS;
5485 }
5486
5487 /* Display the bsm database details */
5488 static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
5489 {
5490 int count = 0;
5491 int fragment = 1;
5492 struct bsm_frag *bsfrag;
5493 json_object *json = NULL;
5494 json_object *json_group = NULL;
5495 json_object *json_row = NULL;
5496
5497 count = bsm_frags_count(pim->global_scope.bsm_frags);
5498
5499 if (uj) {
5500 json = json_object_new_object();
5501 json_object_int_add(json, "Number of the fragments", count);
5502 } else {
5503 vty_out(vty, "Scope Zone: Global\n");
5504 vty_out(vty, "Number of the fragments: %d\n", count);
5505 vty_out(vty, "\n");
5506 }
5507
5508 frr_each (bsm_frags, pim->global_scope.bsm_frags, bsfrag) {
5509 char grp_str[PREFIX_STRLEN];
5510 struct bsmmsg_grpinfo *group;
5511 struct bsmmsg_rpinfo *bsm_rpinfo;
5512 struct prefix grp;
5513 struct bsm_hdr *hdr;
5514 pim_addr bsr_addr;
5515 uint32_t offset = 0;
5516 uint8_t *buf;
5517 uint32_t len = 0;
5518 uint32_t frag_rp_cnt = 0;
5519
5520 buf = bsfrag->data;
5521 len = bsfrag->size;
5522
5523 /* skip pim header */
5524 buf += PIM_MSG_HEADER_LEN;
5525 len -= PIM_MSG_HEADER_LEN;
5526
5527 hdr = (struct bsm_hdr *)buf;
5528 /* NB: bshdr->bsr_addr.addr is packed/unaligned => memcpy */
5529 memcpy(&bsr_addr, &hdr->bsr_addr.addr, sizeof(bsr_addr));
5530
5531 /* BSM starts with bsr header */
5532 buf += sizeof(struct bsm_hdr);
5533 len -= sizeof(struct bsm_hdr);
5534
5535 if (uj) {
5536 json_object_string_addf(json, "BSR address", "%pPA",
5537 &bsr_addr);
5538 json_object_int_add(json, "BSR priority",
5539 hdr->bsr_prio);
5540 json_object_int_add(json, "Hashmask Length",
5541 hdr->hm_len);
5542 json_object_int_add(json, "Fragment Tag",
5543 ntohs(hdr->frag_tag));
5544 } else {
5545 vty_out(vty, "BSM Fragment : %d\n", fragment);
5546 vty_out(vty, "------------------\n");
5547 vty_out(vty, "%-15s %-15s %-15s %-15s\n", "BSR-Address",
5548 "BSR-Priority", "Hashmask-len", "Fragment-Tag");
5549 vty_out(vty, "%-15pPA %-15d %-15d %-15d\n", &bsr_addr,
5550 hdr->bsr_prio, hdr->hm_len,
5551 ntohs(hdr->frag_tag));
5552 }
5553
5554 vty_out(vty, "\n");
5555
5556 while (offset < len) {
5557 group = (struct bsmmsg_grpinfo *)buf;
5558
5559 if (group->group.family == PIM_MSG_ADDRESS_FAMILY_IPV4)
5560 grp.family = AF_INET;
5561 else if (group->group.family ==
5562 PIM_MSG_ADDRESS_FAMILY_IPV6)
5563 grp.family = AF_INET6;
5564
5565 grp.prefixlen = group->group.mask;
5566 #if PIM_IPV == 4
5567 grp.u.prefix4 = group->group.addr;
5568 #else
5569 grp.u.prefix6 = group->group.addr;
5570 #endif
5571
5572 prefix2str(&grp, grp_str, sizeof(grp_str));
5573
5574 buf += sizeof(struct bsmmsg_grpinfo);
5575 offset += sizeof(struct bsmmsg_grpinfo);
5576
5577 if (uj) {
5578 json_object_object_get_ex(json, grp_str,
5579 &json_group);
5580 if (!json_group) {
5581 json_group = json_object_new_object();
5582 json_object_int_add(json_group,
5583 "Rp Count",
5584 group->rp_count);
5585 json_object_int_add(
5586 json_group, "Fragment Rp count",
5587 group->frag_rp_count);
5588 json_object_object_add(json, grp_str,
5589 json_group);
5590 }
5591 } else {
5592 vty_out(vty, "Group : %s\n", grp_str);
5593 vty_out(vty, "-------------------\n");
5594 vty_out(vty, "Rp Count:%d\n", group->rp_count);
5595 vty_out(vty, "Fragment Rp Count : %d\n",
5596 group->frag_rp_count);
5597 }
5598
5599 frag_rp_cnt = group->frag_rp_count;
5600
5601 if (!frag_rp_cnt)
5602 continue;
5603
5604 if (!uj)
5605 vty_out(vty,
5606 "RpAddress HoldTime Priority\n");
5607
5608 while (frag_rp_cnt--) {
5609 pim_addr rp_addr;
5610
5611 bsm_rpinfo = (struct bsmmsg_rpinfo *)buf;
5612 /* unaligned, again */
5613 memcpy(&rp_addr, &bsm_rpinfo->rpaddr.addr,
5614 sizeof(rp_addr));
5615
5616 buf += sizeof(struct bsmmsg_rpinfo);
5617 offset += sizeof(struct bsmmsg_rpinfo);
5618
5619 if (uj) {
5620 json_row = json_object_new_object();
5621 json_object_string_addf(
5622 json_row, "Rp Address", "%pPA",
5623 &rp_addr);
5624 json_object_int_add(
5625 json_row, "Rp HoldTime",
5626 ntohs(bsm_rpinfo->rp_holdtime));
5627 json_object_int_add(json_row,
5628 "Rp Priority",
5629 bsm_rpinfo->rp_pri);
5630 json_object_object_addf(
5631 json_group, json_row, "%pPA",
5632 &rp_addr);
5633 } else {
5634 vty_out(vty, "%-15pPA %-12d %d\n",
5635 &rp_addr,
5636 ntohs(bsm_rpinfo->rp_holdtime),
5637 bsm_rpinfo->rp_pri);
5638 }
5639 }
5640 vty_out(vty, "\n");
5641 }
5642
5643 fragment++;
5644 }
5645
5646 if (uj)
5647 vty_json(vty, json);
5648 }
5649
5650 int pim_show_bsm_db_helper(const char *vrf, struct vty *vty, bool uj)
5651 {
5652 struct pim_instance *pim;
5653 struct vrf *v;
5654
5655 v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
5656
5657 if (!v)
5658 return CMD_WARNING;
5659
5660 pim = v->info;
5661
5662 if (!pim) {
5663 vty_out(vty, "%% Unable to find pim instance\n");
5664 return CMD_WARNING;
5665 }
5666
5667 pim_show_bsm_db(v->info, vty, uj);
5668
5669 return CMD_SUCCESS;
5670 }