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