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