]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_cmd_common.c
pim6d: Implementing "show ipv6 pim upstream" CLI
[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
35 #include "pimd.h"
36 #include "pim_vty.h"
37 #include "lib/northbound_cli.h"
38 #include "pim_errors.h"
39 #include "pim_nb.h"
40 #include "pim_cmd_common.h"
41 #include "pim_mroute.h"
42 #include "pim_cmd.h"
43 #include "pim6_cmd.h"
44 #include "pim_cmd_common.h"
45 #include "pim_time.h"
46 #include "pim_zebra.h"
47 #include "pim_zlookup.h"
48 #include "pim_iface.h"
49 #include "lib/linklist.h"
50 #include "pim_neighbor.h"
51
52 /**
53 * Get current node VRF name.
54 *
55 * NOTE:
56 * In case of failure it will print error message to user.
57 *
58 * \returns name or NULL if failed to get VRF.
59 */
60 const char *pim_cli_get_vrf_name(struct vty *vty)
61 {
62 const struct lyd_node *vrf_node;
63
64 /* Not inside any VRF context. */
65 if (vty->xpath_index == 0)
66 return VRF_DEFAULT_NAME;
67
68 vrf_node = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
69 if (vrf_node == NULL) {
70 vty_out(vty, "%% Failed to get vrf dnode in configuration\n");
71 return NULL;
72 }
73
74 return yang_dnode_get_string(vrf_node, "./name");
75 }
76
77 int pim_process_join_prune_cmd(struct vty *vty, const char *jpi_str)
78 {
79 char xpath[XPATH_MAXLEN];
80
81 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
82 FRR_PIM_AF_XPATH_VAL);
83 strlcat(xpath, "/join-prune-interval", sizeof(xpath));
84
85 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, jpi_str);
86
87 return nb_cli_apply_changes(vty, NULL);
88 }
89
90 int pim_process_no_join_prune_cmd(struct vty *vty)
91 {
92 char xpath[XPATH_MAXLEN];
93
94 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
95 FRR_PIM_AF_XPATH_VAL);
96 strlcat(xpath, "/join-prune-interval", sizeof(xpath));
97
98 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
99
100 return nb_cli_apply_changes(vty, NULL);
101 }
102
103 int pim_process_spt_switchover_infinity_cmd(struct vty *vty)
104 {
105 const char *vrfname;
106 char spt_plist_xpath[XPATH_MAXLEN];
107 char spt_action_xpath[XPATH_MAXLEN];
108
109 vrfname = pim_cli_get_vrf_name(vty);
110 if (vrfname == NULL)
111 return CMD_WARNING_CONFIG_FAILED;
112
113 snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
114 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
115 FRR_PIM_AF_XPATH_VAL);
116 strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
117 sizeof(spt_plist_xpath));
118
119 snprintf(spt_action_xpath, sizeof(spt_action_xpath),
120 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
121 FRR_PIM_AF_XPATH_VAL);
122 strlcat(spt_action_xpath, "/spt-switchover/spt-action",
123 sizeof(spt_action_xpath));
124
125 if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath))
126 nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY,
127 NULL);
128 nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
129 "PIM_SPT_INFINITY");
130
131 return nb_cli_apply_changes(vty, NULL);
132 }
133
134 int pim_process_spt_switchover_prefixlist_cmd(struct vty *vty,
135 const char *plist)
136 {
137 const char *vrfname;
138 char spt_plist_xpath[XPATH_MAXLEN];
139 char spt_action_xpath[XPATH_MAXLEN];
140
141 vrfname = pim_cli_get_vrf_name(vty);
142 if (vrfname == NULL)
143 return CMD_WARNING_CONFIG_FAILED;
144
145 snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
146 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
147 FRR_PIM_AF_XPATH_VAL);
148 strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
149 sizeof(spt_plist_xpath));
150
151 snprintf(spt_action_xpath, sizeof(spt_action_xpath),
152 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
153 FRR_PIM_AF_XPATH_VAL);
154 strlcat(spt_action_xpath, "/spt-switchover/spt-action",
155 sizeof(spt_action_xpath));
156
157 nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
158 "PIM_SPT_INFINITY");
159 nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY,
160 plist);
161
162 return nb_cli_apply_changes(vty, NULL);
163 }
164
165 int pim_process_no_spt_switchover_cmd(struct vty *vty)
166 {
167 const char *vrfname;
168 char spt_plist_xpath[XPATH_MAXLEN];
169 char spt_action_xpath[XPATH_MAXLEN];
170
171 vrfname = pim_cli_get_vrf_name(vty);
172 if (vrfname == NULL)
173 return CMD_WARNING_CONFIG_FAILED;
174
175 snprintf(spt_plist_xpath, sizeof(spt_plist_xpath),
176 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
177 FRR_PIM_AF_XPATH_VAL);
178 strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list",
179 sizeof(spt_plist_xpath));
180
181 snprintf(spt_action_xpath, sizeof(spt_action_xpath),
182 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
183 FRR_PIM_AF_XPATH_VAL);
184 strlcat(spt_action_xpath, "/spt-switchover/spt-action",
185 sizeof(spt_action_xpath));
186
187 nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL);
188 nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY,
189 "PIM_SPT_IMMEDIATE");
190
191 return nb_cli_apply_changes(vty, NULL);
192 }
193
194 int pim_process_pim_packet_cmd(struct vty *vty, const char *packet)
195 {
196 char xpath[XPATH_MAXLEN];
197
198 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
199 FRR_PIM_AF_XPATH_VAL);
200 strlcat(xpath, "/packets", sizeof(xpath));
201
202 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, packet);
203
204 return nb_cli_apply_changes(vty, NULL);
205 }
206
207 int pim_process_no_pim_packet_cmd(struct vty *vty)
208 {
209 char xpath[XPATH_MAXLEN];
210
211 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
212 FRR_PIM_AF_XPATH_VAL);
213 strlcat(xpath, "/packets", sizeof(xpath));
214
215 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
216
217 return nb_cli_apply_changes(vty, NULL);
218 }
219
220 int pim_process_keepalivetimer_cmd(struct vty *vty, const char *kat)
221 {
222 const char *vrfname;
223 char ka_timer_xpath[XPATH_MAXLEN];
224
225 vrfname = pim_cli_get_vrf_name(vty);
226 if (vrfname == NULL)
227 return CMD_WARNING_CONFIG_FAILED;
228
229 snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH,
230 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL);
231 strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
232
233 nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY,
234 kat);
235
236 return nb_cli_apply_changes(vty, NULL);
237 }
238
239 int pim_process_no_keepalivetimer_cmd(struct vty *vty)
240 {
241 const char *vrfname;
242 char ka_timer_xpath[XPATH_MAXLEN];
243
244 vrfname = pim_cli_get_vrf_name(vty);
245 if (vrfname == NULL)
246 return CMD_WARNING_CONFIG_FAILED;
247
248 snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH,
249 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL);
250 strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath));
251
252 nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_DESTROY, NULL);
253
254 return nb_cli_apply_changes(vty, NULL);
255 }
256
257 int pim_process_rp_kat_cmd(struct vty *vty, const char *rpkat)
258 {
259 const char *vrfname;
260 char rp_ka_timer_xpath[XPATH_MAXLEN];
261
262 vrfname = pim_cli_get_vrf_name(vty);
263 if (vrfname == NULL)
264 return CMD_WARNING_CONFIG_FAILED;
265
266 snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
267 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
268 FRR_PIM_AF_XPATH_VAL);
269 strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
270 sizeof(rp_ka_timer_xpath));
271
272 nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
273 rpkat);
274
275 return nb_cli_apply_changes(vty, NULL);
276 }
277
278 int pim_process_no_rp_kat_cmd(struct vty *vty)
279 {
280 const char *vrfname;
281 char rp_ka_timer[6];
282 char rp_ka_timer_xpath[XPATH_MAXLEN];
283 uint v;
284 char rs_timer_xpath[XPATH_MAXLEN];
285
286 snprintf(rs_timer_xpath, sizeof(rs_timer_xpath),
287 FRR_PIM_ROUTER_XPATH, FRR_PIM_AF_XPATH_VAL);
288 strlcat(rs_timer_xpath, "/register-suppress-time",
289 sizeof(rs_timer_xpath));
290
291 /* RFC4601 */
292 v = yang_dnode_get_uint16(vty->candidate_config->dnode,
293 rs_timer_xpath);
294 v = 3 * v + PIM_REGISTER_PROBE_TIME_DEFAULT;
295 if (v > UINT16_MAX)
296 v = UINT16_MAX;
297 snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%u", v);
298
299 vrfname = pim_cli_get_vrf_name(vty);
300 if (vrfname == NULL)
301 return CMD_WARNING_CONFIG_FAILED;
302
303 snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath),
304 FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname,
305 FRR_PIM_AF_XPATH_VAL);
306 strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer",
307 sizeof(rp_ka_timer_xpath));
308
309 nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY,
310 rp_ka_timer);
311
312 return nb_cli_apply_changes(vty, NULL);
313 }
314
315 int pim_process_register_suppress_cmd(struct vty *vty, const char *rst)
316 {
317 char xpath[XPATH_MAXLEN];
318
319 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
320 FRR_PIM_AF_XPATH_VAL);
321 strlcat(xpath, "/register-suppress-time", sizeof(xpath));
322
323 nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, rst);
324
325 return nb_cli_apply_changes(vty, NULL);
326 }
327
328 int pim_process_no_register_suppress_cmd(struct vty *vty)
329 {
330 char xpath[XPATH_MAXLEN];
331
332 snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH,
333 FRR_PIM_AF_XPATH_VAL);
334 strlcat(xpath, "/register-suppress-time", sizeof(xpath));
335
336 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
337
338 return nb_cli_apply_changes(vty, NULL);
339 }
340
341 int pim_process_ip_pim_cmd(struct vty *vty)
342 {
343 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true");
344
345 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
346 FRR_PIM_AF_XPATH_VAL);
347 }
348
349 int pim_process_no_ip_pim_cmd(struct vty *vty)
350 {
351 const struct lyd_node *mld_enable_dnode;
352 char mld_if_xpath[XPATH_MAXLEN];
353
354 int printed =
355 snprintf(mld_if_xpath, sizeof(mld_if_xpath),
356 "%s/frr-gmp:gmp/address-family[address-family='%s']",
357 VTY_CURR_XPATH, FRR_PIM_AF_XPATH_VAL);
358
359 if (printed >= (int)(sizeof(mld_if_xpath))) {
360 vty_out(vty, "Xpath too long (%d > %u)", printed + 1,
361 XPATH_MAXLEN);
362 return CMD_WARNING_CONFIG_FAILED;
363 }
364
365 mld_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
366 FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
367 FRR_PIM_AF_XPATH_VAL);
368
369 if (!mld_enable_dnode) {
370 nb_cli_enqueue_change(vty, mld_if_xpath, NB_OP_DESTROY, NULL);
371 nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
372 } else {
373 if (!yang_dnode_get_bool(mld_enable_dnode, ".")) {
374 nb_cli_enqueue_change(vty, mld_if_xpath, NB_OP_DESTROY,
375 NULL);
376 nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
377 } else
378 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
379 "false");
380 }
381
382 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
383 FRR_PIM_AF_XPATH_VAL);
384 }
385
386 int pim_process_ip_pim_drprio_cmd(struct vty *vty, const char *drpriority_str)
387 {
388 nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY,
389 drpriority_str);
390
391 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
392 FRR_PIM_AF_XPATH_VAL);
393 }
394
395 int pim_process_no_ip_pim_drprio_cmd(struct vty *vty)
396 {
397 nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_DESTROY, NULL);
398
399 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
400 FRR_PIM_AF_XPATH_VAL);
401 }
402
403 int pim_process_ip_pim_hello_cmd(struct vty *vty, const char *hello_str,
404 const char *hold_str)
405 {
406 const struct lyd_node *mld_enable_dnode;
407
408 mld_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
409 FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
410 FRR_PIM_AF_XPATH_VAL);
411
412 if (!mld_enable_dnode) {
413 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
414 "true");
415 } else {
416 if (!yang_dnode_get_bool(mld_enable_dnode, "."))
417 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
418 "true");
419 }
420
421 nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_MODIFY, hello_str);
422
423 if (hold_str)
424 nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_MODIFY,
425 hold_str);
426
427 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
428 FRR_PIM_AF_XPATH_VAL);
429 }
430
431 int pim_process_no_ip_pim_hello_cmd(struct vty *vty)
432 {
433 nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_DESTROY, NULL);
434 nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_DESTROY, NULL);
435
436 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
437 FRR_PIM_AF_XPATH_VAL);
438 }
439
440 int pim_process_ip_pim_activeactive_cmd(struct vty *vty, const char *no)
441 {
442 if (no)
443 nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY,
444 "false");
445 else {
446 nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
447 "true");
448
449 nb_cli_enqueue_change(vty, "./active-active", NB_OP_MODIFY,
450 "true");
451 }
452
453 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
454 FRR_PIM_AF_XPATH_VAL);
455 }
456
457 int pim_process_ip_pim_boundary_oil_cmd(struct vty *vty, const char *oil)
458 {
459 nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_MODIFY,
460 oil);
461
462 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
463 FRR_PIM_AF_XPATH_VAL);
464 }
465
466 int pim_process_no_ip_pim_boundary_oil_cmd(struct vty *vty)
467 {
468 nb_cli_enqueue_change(vty, "./multicast-boundary-oil", NB_OP_DESTROY,
469 NULL);
470
471 return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
472 FRR_PIM_AF_XPATH_VAL);
473 }
474
475 int pim_process_ip_mroute_cmd(struct vty *vty, const char *interface,
476 const char *group_str, const char *source_str)
477 {
478 nb_cli_enqueue_change(vty, "./oif", NB_OP_MODIFY, interface);
479
480 if (!source_str) {
481 char buf[SRCDEST2STR_BUFFER];
482
483 inet_ntop(AF_INET6, &in6addr_any, buf, sizeof(buf));
484 return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH,
485 FRR_PIM_AF_XPATH_VAL, buf,
486 group_str);
487 }
488
489 return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH,
490 FRR_PIM_AF_XPATH_VAL, source_str,
491 group_str);
492 }
493
494 int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface,
495 const char *group_str, const char *source_str)
496 {
497 nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
498
499 if (!source_str) {
500 char buf[SRCDEST2STR_BUFFER];
501
502 inet_ntop(AF_INET6, &in6addr_any, buf, sizeof(buf));
503 return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH,
504 FRR_PIM_AF_XPATH_VAL, buf,
505 group_str);
506 }
507
508 return nb_cli_apply_changes(vty, FRR_PIM_MROUTE_XPATH,
509 FRR_PIM_AF_XPATH_VAL, source_str,
510 group_str);
511 }
512
513 int pim_process_rp_cmd(struct vty *vty, const char *rp_str,
514 const char *group_str)
515 {
516 const char *vrfname;
517 char rp_group_xpath[XPATH_MAXLEN];
518 int result = 0;
519 struct prefix group;
520 pim_addr rp_addr;
521
522 result = str2prefix(group_str, &group);
523 if (result) {
524 struct prefix temp;
525
526 prefix_copy(&temp, &group);
527 apply_mask(&temp);
528 if (!prefix_same(&group, &temp)) {
529 vty_out(vty, "%% Inconsistent address and mask: %s\n",
530 group_str);
531 return CMD_WARNING_CONFIG_FAILED;
532 }
533 }
534
535 if (!result) {
536 vty_out(vty, "%% Bad group address specified: %s\n", group_str);
537 return CMD_WARNING_CONFIG_FAILED;
538 }
539
540 result = inet_pton(PIM_AF, rp_str, &rp_addr);
541 if (result <= 0) {
542 vty_out(vty, "%% Bad RP address specified: %s\n", rp_str);
543 return CMD_WARNING_CONFIG_FAILED;
544 }
545
546 vrfname = pim_cli_get_vrf_name(vty);
547 if (vrfname == NULL)
548 return CMD_WARNING_CONFIG_FAILED;
549
550 snprintf(rp_group_xpath, sizeof(rp_group_xpath),
551 FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname,
552 FRR_PIM_AF_XPATH_VAL, rp_str);
553 strlcat(rp_group_xpath, "/group-list", sizeof(rp_group_xpath));
554
555 nb_cli_enqueue_change(vty, rp_group_xpath, NB_OP_CREATE, group_str);
556
557 return nb_cli_apply_changes(vty, NULL);
558 }
559
560 int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str,
561 const char *group_str)
562 {
563 char group_list_xpath[XPATH_MAXLEN];
564 char group_xpath[XPATH_MAXLEN];
565 char rp_xpath[XPATH_MAXLEN];
566 int printed;
567 const char *vrfname;
568 const struct lyd_node *group_dnode;
569
570 vrfname = pim_cli_get_vrf_name(vty);
571 if (vrfname == NULL)
572 return CMD_WARNING_CONFIG_FAILED;
573
574 snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH,
575 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str);
576
577 printed = snprintf(group_list_xpath, sizeof(group_list_xpath),
578 "%s/group-list", rp_xpath);
579
580 if (printed >= (int)(sizeof(group_list_xpath))) {
581 vty_out(vty, "Xpath too long (%d > %u)", printed + 1,
582 XPATH_MAXLEN);
583 return CMD_WARNING_CONFIG_FAILED;
584 }
585
586 printed = snprintf(group_xpath, sizeof(group_xpath), "%s[.='%s']",
587 group_list_xpath, group_str);
588
589 if (printed >= (int)(sizeof(group_xpath))) {
590 vty_out(vty, "Xpath too long (%d > %u)", printed + 1,
591 XPATH_MAXLEN);
592 return CMD_WARNING_CONFIG_FAILED;
593 }
594
595 group_dnode = yang_dnode_get(vty->candidate_config->dnode, group_xpath);
596 if (!group_dnode) {
597 vty_out(vty, "%% Unable to find specified RP\n");
598 return NB_OK;
599 }
600
601 if (yang_is_last_list_dnode(group_dnode))
602 nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL);
603 else
604 nb_cli_enqueue_change(vty, group_list_xpath, NB_OP_DESTROY,
605 group_str);
606
607 return nb_cli_apply_changes(vty, NULL);
608 }
609
610 int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str,
611 const char *prefix_list)
612 {
613 const char *vrfname;
614 char rp_plist_xpath[XPATH_MAXLEN];
615
616 vrfname = pim_cli_get_vrf_name(vty);
617 if (vrfname == NULL)
618 return CMD_WARNING_CONFIG_FAILED;
619
620 snprintf(rp_plist_xpath, sizeof(rp_plist_xpath),
621 FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname,
622 FRR_PIM_AF_XPATH_VAL, rp_str);
623 strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath));
624
625 nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY, prefix_list);
626
627 return nb_cli_apply_changes(vty, NULL);
628 }
629
630 int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str,
631 const char *prefix_list)
632 {
633 char rp_xpath[XPATH_MAXLEN];
634 char plist_xpath[XPATH_MAXLEN];
635 const char *vrfname;
636 const struct lyd_node *plist_dnode;
637 const char *plist;
638
639 vrfname = pim_cli_get_vrf_name(vty);
640 if (vrfname == NULL)
641 return CMD_WARNING_CONFIG_FAILED;
642
643 snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH,
644 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str);
645
646 snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH,
647 "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str);
648 strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath));
649
650 plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath);
651 if (!plist_dnode) {
652 vty_out(vty, "%% Unable to find specified RP\n");
653 return NB_OK;
654 }
655
656 plist = yang_dnode_get_string(plist_dnode, plist_xpath);
657 if (strcmp(prefix_list, plist)) {
658 vty_out(vty, "%% Unable to find specified RP\n");
659 return NB_OK;
660 }
661
662 nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL);
663
664 return nb_cli_apply_changes(vty, NULL);
665 }
666
667 bool pim_sgaddr_match(pim_sgaddr item, pim_sgaddr match)
668 {
669 return (pim_addr_is_any(match.grp) ||
670 !pim_addr_cmp(match.grp, item.grp)) &&
671 (pim_addr_is_any(match.src) ||
672 !pim_addr_cmp(match.src, item.src));
673 }
674
675 void json_object_pim_upstream_add(json_object *json, struct pim_upstream *up)
676 {
677 if (up->flags & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
678 json_object_boolean_true_add(json, "drJoinDesired");
679
680 if (up->flags & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
681 json_object_boolean_true_add(json, "drJoinDesiredUpdated");
682
683 if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR)
684 json_object_boolean_true_add(json, "firstHopRouter");
685
686 if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
687 json_object_boolean_true_add(json, "sourceIgmp");
688
689 if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
690 json_object_boolean_true_add(json, "sourcePim");
691
692 if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
693 json_object_boolean_true_add(json, "sourceStream");
694
695 /* XXX: need to print ths flag in the plain text display as well */
696 if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
697 json_object_boolean_true_add(json, "sourceMsdp");
698
699 if (up->flags & PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
700 json_object_boolean_true_add(json, "sendSGRptPrune");
701
702 if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
703 json_object_boolean_true_add(json, "lastHopRouter");
704
705 if (up->flags & PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY)
706 json_object_boolean_true_add(json, "disableKATExpiry");
707
708 if (up->flags & PIM_UPSTREAM_FLAG_MASK_STATIC_IIF)
709 json_object_boolean_true_add(json, "staticIncomingInterface");
710
711 if (up->flags & PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL)
712 json_object_boolean_true_add(json,
713 "allowIncomingInterfaceinOil");
714
715 if (up->flags & PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA)
716 json_object_boolean_true_add(json, "noPimRegistrationData");
717
718 if (up->flags & PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG)
719 json_object_boolean_true_add(json, "forcePimRegistration");
720
721 if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG)
722 json_object_boolean_true_add(json, "sourceVxlanOrigination");
723
724 if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM)
725 json_object_boolean_true_add(json, "sourceVxlanTermination");
726
727 if (up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN)
728 json_object_boolean_true_add(json, "mlagVxlan");
729
730 if (up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF)
731 json_object_boolean_true_add(json,
732 "mlagNonDesignatedForwarder");
733 }
734
735 static const char *
736 pim_upstream_state2brief_str(enum pim_upstream_state join_state,
737 char *state_str, size_t state_str_len)
738 {
739 switch (join_state) {
740 case PIM_UPSTREAM_NOTJOINED:
741 strlcpy(state_str, "NotJ", state_str_len);
742 break;
743 case PIM_UPSTREAM_JOINED:
744 strlcpy(state_str, "J", state_str_len);
745 break;
746 default:
747 strlcpy(state_str, "Unk", state_str_len);
748 }
749 return state_str;
750 }
751
752 static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state,
753 char *state_str,
754 size_t state_str_len)
755 {
756 switch (reg_state) {
757 case PIM_REG_NOINFO:
758 strlcpy(state_str, "RegNI", state_str_len);
759 break;
760 case PIM_REG_JOIN:
761 strlcpy(state_str, "RegJ", state_str_len);
762 break;
763 case PIM_REG_JOIN_PENDING:
764 case PIM_REG_PRUNE:
765 strlcpy(state_str, "RegP", state_str_len);
766 break;
767 }
768 return state_str;
769 }
770
771 void pim_show_rpf_refresh_stats(struct vty *vty, struct pim_instance *pim,
772 time_t now, json_object *json)
773 {
774 char refresh_uptime[10];
775
776 pim_time_uptime_begin(refresh_uptime, sizeof(refresh_uptime), now,
777 pim->rpf_cache_refresh_last);
778
779 if (json) {
780 json_object_int_add(json, "rpfCacheRefreshDelayMsecs",
781 router->rpf_cache_refresh_delay_msec);
782 json_object_int_add(
783 json, "rpfCacheRefreshTimer",
784 pim_time_timer_remain_msec(pim->rpf_cache_refresher));
785 json_object_int_add(json, "rpfCacheRefreshRequests",
786 pim->rpf_cache_refresh_requests);
787 json_object_int_add(json, "rpfCacheRefreshEvents",
788 pim->rpf_cache_refresh_events);
789 json_object_string_add(json, "rpfCacheRefreshLast",
790 refresh_uptime);
791 json_object_int_add(json, "nexthopLookups",
792 pim->nexthop_lookups);
793 json_object_int_add(json, "nexthopLookupsAvoided",
794 pim->nexthop_lookups_avoided);
795 } else {
796 vty_out(vty,
797 "RPF Cache Refresh Delay: %ld msecs\n"
798 "RPF Cache Refresh Timer: %ld msecs\n"
799 "RPF Cache Refresh Requests: %lld\n"
800 "RPF Cache Refresh Events: %lld\n"
801 "RPF Cache Refresh Last: %s\n"
802 "Nexthop Lookups: %lld\n"
803 "Nexthop Lookups Avoided: %lld\n",
804 router->rpf_cache_refresh_delay_msec,
805 pim_time_timer_remain_msec(pim->rpf_cache_refresher),
806 (long long)pim->rpf_cache_refresh_requests,
807 (long long)pim->rpf_cache_refresh_events,
808 refresh_uptime, (long long)pim->nexthop_lookups,
809 (long long)pim->nexthop_lookups_avoided);
810 }
811 }
812
813 void pim_show_rpf(struct pim_instance *pim, struct vty *vty, json_object *json)
814 {
815 struct pim_upstream *up;
816 time_t now = pim_time_monotonic_sec();
817 json_object *json_group = NULL;
818 json_object *json_row = NULL;
819
820 pim_show_rpf_refresh_stats(vty, pim, now, json);
821
822 if (!json) {
823 vty_out(vty, "\n");
824 vty_out(vty,
825 "Source Group RpfIface RpfAddress RibNextHop Metric Pref\n");
826 }
827
828 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
829 char rpf_addr_str[PREFIX_STRLEN];
830 char rib_nexthop_str[PREFIX_STRLEN];
831 const char *rpf_ifname;
832 struct pim_rpf *rpf = &up->rpf;
833
834 pim_addr_dump("<rpf?>", &rpf->rpf_addr, rpf_addr_str,
835 sizeof(rpf_addr_str));
836 pim_addr_dump("<nexthop?>",
837 &rpf->source_nexthop.mrib_nexthop_addr,
838 rib_nexthop_str, sizeof(rib_nexthop_str));
839
840 rpf_ifname =
841 rpf->source_nexthop.interface ? rpf->source_nexthop
842 .interface->name
843 : "<ifname?>";
844
845 if (json) {
846 char grp_str[PIM_ADDRSTRLEN];
847 char src_str[PIM_ADDRSTRLEN];
848
849 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
850 &up->sg.grp);
851 snprintfrr(src_str, sizeof(src_str), "%pPAs",
852 &up->sg.src);
853
854 json_object_object_get_ex(json, grp_str, &json_group);
855
856 if (!json_group) {
857 json_group = json_object_new_object();
858 json_object_object_add(json, grp_str,
859 json_group);
860 }
861
862 json_row = json_object_new_object();
863 json_object_string_add(json_row, "source", src_str);
864 json_object_string_add(json_row, "group", grp_str);
865 json_object_string_add(json_row, "rpfInterface",
866 rpf_ifname);
867 json_object_string_add(json_row, "rpfAddress",
868 rpf_addr_str);
869 json_object_string_add(json_row, "ribNexthop",
870 rib_nexthop_str);
871 json_object_int_add(
872 json_row, "routeMetric",
873 rpf->source_nexthop.mrib_route_metric);
874 json_object_int_add(
875 json_row, "routePreference",
876 rpf->source_nexthop.mrib_metric_preference);
877 json_object_object_add(json_group, src_str, json_row);
878
879 } else {
880 vty_out(vty,
881 "%-15pPAs %-15pPAs %-16s %-15s %-15s %6d %4d\n",
882 &up->sg.src, &up->sg.grp, rpf_ifname,
883 rpf_addr_str, rib_nexthop_str,
884 rpf->source_nexthop.mrib_route_metric,
885 rpf->source_nexthop.mrib_metric_preference);
886 }
887 }
888 }
889
890 void pim_show_neighbors_secondary(struct pim_instance *pim, struct vty *vty)
891 {
892 struct interface *ifp;
893
894 vty_out(vty,
895 "Interface Address Neighbor Secondary \n");
896
897 FOR_ALL_INTERFACES (pim->vrf, ifp) {
898 struct pim_interface *pim_ifp;
899 pim_addr ifaddr;
900 struct listnode *neighnode;
901 struct pim_neighbor *neigh;
902
903 pim_ifp = ifp->info;
904
905 if (!pim_ifp)
906 continue;
907
908 if (pim_ifp->pim_sock_fd < 0)
909 continue;
910
911 ifaddr = pim_ifp->primary_address;
912
913 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
914 neigh)) {
915 struct listnode *prefix_node;
916 struct prefix *p;
917
918 if (!neigh->prefix_list)
919 continue;
920
921 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list,
922 prefix_node, p))
923 vty_out(vty,
924 "%-16s %-15pPAs %-15pPAs %-15pFX\n",
925 ifp->name, &ifaddr, &neigh->source_addr,
926 p);
927 }
928 }
929 }
930
931 void pim_show_state(struct pim_instance *pim, struct vty *vty,
932 const char *src_or_group, const char *group, bool uj)
933 {
934 struct channel_oil *c_oil;
935 json_object *json = NULL;
936 json_object *json_group = NULL;
937 json_object *json_ifp_in = NULL;
938 json_object *json_ifp_out = NULL;
939 json_object *json_source = NULL;
940 time_t now;
941 int first_oif;
942
943 now = pim_time_monotonic_sec();
944
945 if (uj) {
946 json = json_object_new_object();
947 } else {
948 vty_out(vty,
949 "Codes: J -> Pim Join, I -> IGMP Report, S -> Source, * -> Inherited from (*,G), V -> VxLAN, M -> Muted");
950 vty_out(vty,
951 "\nActive Source Group RPT IIF OIL\n");
952 }
953
954 frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
955 char grp_str[INET_ADDRSTRLEN];
956 char src_str[INET_ADDRSTRLEN];
957 char in_ifname[INTERFACE_NAMSIZ + 1];
958 char out_ifname[INTERFACE_NAMSIZ + 1];
959 int oif_vif_index;
960 struct interface *ifp_in;
961 bool isRpt;
962
963 first_oif = 1;
964
965 if ((c_oil->up &&
966 PIM_UPSTREAM_FLAG_TEST_USE_RPT(c_oil->up->flags)) ||
967 c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
968 isRpt = true;
969 else
970 isRpt = false;
971
972 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, grp_str,
973 sizeof(grp_str));
974 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, src_str,
975 sizeof(src_str));
976 ifp_in = pim_if_find_by_vif_index(pim, c_oil->oil.mfcc_parent);
977
978 if (ifp_in)
979 strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
980 else
981 strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
982
983 if (src_or_group) {
984 if (strcmp(src_or_group, src_str) &&
985 strcmp(src_or_group, grp_str))
986 continue;
987
988 if (group && strcmp(group, grp_str))
989 continue;
990 }
991
992 if (uj) {
993
994 /* Find the group, create it if it doesn't exist */
995 json_object_object_get_ex(json, grp_str, &json_group);
996
997 if (!json_group) {
998 json_group = json_object_new_object();
999 json_object_object_add(json, grp_str,
1000 json_group);
1001 }
1002
1003 /* Find the source nested under the group, create it if
1004 * it doesn't exist
1005 */
1006 json_object_object_get_ex(json_group, src_str,
1007 &json_source);
1008
1009 if (!json_source) {
1010 json_source = json_object_new_object();
1011 json_object_object_add(json_group, src_str,
1012 json_source);
1013 }
1014
1015 /* Find the inbound interface nested under the source,
1016 * create it if it doesn't exist
1017 */
1018 json_object_object_get_ex(json_source, in_ifname,
1019 &json_ifp_in);
1020
1021 if (!json_ifp_in) {
1022 json_ifp_in = json_object_new_object();
1023 json_object_object_add(json_source, in_ifname,
1024 json_ifp_in);
1025 json_object_int_add(json_source, "Installed",
1026 c_oil->installed);
1027 json_object_int_add(json_source, "installed",
1028 c_oil->installed);
1029 if (isRpt)
1030 json_object_boolean_true_add(
1031 json_source, "isRpt");
1032 else
1033 json_object_boolean_false_add(
1034 json_source, "isRpt");
1035 json_object_int_add(json_source, "RefCount",
1036 c_oil->oil_ref_count);
1037 json_object_int_add(json_source, "refCount",
1038 c_oil->oil_ref_count);
1039 json_object_int_add(json_source, "OilListSize",
1040 c_oil->oil_size);
1041 json_object_int_add(json_source, "oilListSize",
1042 c_oil->oil_size);
1043 json_object_int_add(
1044 json_source, "OilRescan",
1045 c_oil->oil_inherited_rescan);
1046 json_object_int_add(
1047 json_source, "oilRescan",
1048 c_oil->oil_inherited_rescan);
1049 json_object_int_add(json_source, "LastUsed",
1050 c_oil->cc.lastused);
1051 json_object_int_add(json_source, "lastUsed",
1052 c_oil->cc.lastused);
1053 json_object_int_add(json_source, "PacketCount",
1054 c_oil->cc.pktcnt);
1055 json_object_int_add(json_source, "packetCount",
1056 c_oil->cc.pktcnt);
1057 json_object_int_add(json_source, "ByteCount",
1058 c_oil->cc.bytecnt);
1059 json_object_int_add(json_source, "byteCount",
1060 c_oil->cc.bytecnt);
1061 json_object_int_add(json_source,
1062 "WrongInterface",
1063 c_oil->cc.wrong_if);
1064 json_object_int_add(json_source,
1065 "wrongInterface",
1066 c_oil->cc.wrong_if);
1067 }
1068 } else {
1069 vty_out(vty, "%-6d %-15s %-15s %-3s %-16s ",
1070 c_oil->installed, src_str, grp_str,
1071 isRpt ? "y" : "n", in_ifname);
1072 }
1073
1074 for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
1075 ++oif_vif_index) {
1076 struct interface *ifp_out;
1077 char oif_uptime[10];
1078 int ttl;
1079
1080 ttl = c_oil->oil.mfcc_ttls[oif_vif_index];
1081 if (ttl < 1)
1082 continue;
1083
1084 ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
1085 pim_time_uptime(
1086 oif_uptime, sizeof(oif_uptime),
1087 now - c_oil->oif_creation[oif_vif_index]);
1088
1089 if (ifp_out)
1090 strlcpy(out_ifname, ifp_out->name,
1091 sizeof(out_ifname));
1092 else
1093 strlcpy(out_ifname, "<oif?>",
1094 sizeof(out_ifname));
1095
1096 if (uj) {
1097 json_ifp_out = json_object_new_object();
1098 json_object_string_add(json_ifp_out, "source",
1099 src_str);
1100 json_object_string_add(json_ifp_out, "group",
1101 grp_str);
1102 json_object_string_add(json_ifp_out,
1103 "inboundInterface",
1104 in_ifname);
1105 json_object_string_add(json_ifp_out,
1106 "outboundInterface",
1107 out_ifname);
1108 json_object_int_add(json_ifp_out, "installed",
1109 c_oil->installed);
1110
1111 json_object_object_add(json_ifp_in, out_ifname,
1112 json_ifp_out);
1113 } else {
1114 if (first_oif) {
1115 first_oif = 0;
1116 vty_out(vty, "%s(%c%c%c%c%c)",
1117 out_ifname,
1118 (c_oil->oif_flags
1119 [oif_vif_index] &
1120 PIM_OIF_FLAG_PROTO_IGMP)
1121 ? 'I'
1122 : ' ',
1123 (c_oil->oif_flags
1124 [oif_vif_index] &
1125 PIM_OIF_FLAG_PROTO_PIM)
1126 ? 'J'
1127 : ' ',
1128 (c_oil->oif_flags
1129 [oif_vif_index] &
1130 PIM_OIF_FLAG_PROTO_VXLAN)
1131 ? 'V'
1132 : ' ',
1133 (c_oil->oif_flags
1134 [oif_vif_index] &
1135 PIM_OIF_FLAG_PROTO_STAR)
1136 ? '*'
1137 : ' ',
1138 (c_oil->oif_flags
1139 [oif_vif_index] &
1140 PIM_OIF_FLAG_MUTE)
1141 ? 'M'
1142 : ' ');
1143 } else
1144 vty_out(vty, ", %s(%c%c%c%c%c)",
1145 out_ifname,
1146 (c_oil->oif_flags
1147 [oif_vif_index] &
1148 PIM_OIF_FLAG_PROTO_IGMP)
1149 ? 'I'
1150 : ' ',
1151 (c_oil->oif_flags
1152 [oif_vif_index] &
1153 PIM_OIF_FLAG_PROTO_PIM)
1154 ? 'J'
1155 : ' ',
1156 (c_oil->oif_flags
1157 [oif_vif_index] &
1158 PIM_OIF_FLAG_PROTO_VXLAN)
1159 ? 'V'
1160 : ' ',
1161 (c_oil->oif_flags
1162 [oif_vif_index] &
1163 PIM_OIF_FLAG_PROTO_STAR)
1164 ? '*'
1165 : ' ',
1166 (c_oil->oif_flags
1167 [oif_vif_index] &
1168 PIM_OIF_FLAG_MUTE)
1169 ? 'M'
1170 : ' ');
1171 }
1172 }
1173
1174 if (!uj)
1175 vty_out(vty, "\n");
1176 }
1177
1178
1179 if (uj)
1180 vty_json(vty, json);
1181 else
1182 vty_out(vty, "\n");
1183 }
1184
1185 /* pim statistics - just adding only bsm related now.
1186 * We can continue to add all pim related stats here.
1187 */
1188 void pim_show_statistics(struct pim_instance *pim, struct vty *vty,
1189 const char *ifname, bool uj)
1190 {
1191 json_object *json = NULL;
1192 struct interface *ifp;
1193
1194 if (uj) {
1195 json = json_object_new_object();
1196 json_object_int_add(json, "bsmRx", pim->bsm_rcvd);
1197 json_object_int_add(json, "bsmTx", pim->bsm_sent);
1198 json_object_int_add(json, "bsmDropped", pim->bsm_dropped);
1199 } else {
1200 vty_out(vty, "BSM Statistics :\n");
1201 vty_out(vty, "----------------\n");
1202 vty_out(vty, "Number of Received BSMs : %" PRIu64 "\n",
1203 pim->bsm_rcvd);
1204 vty_out(vty, "Number of Forwared BSMs : %" PRIu64 "\n",
1205 pim->bsm_sent);
1206 vty_out(vty, "Number of Dropped BSMs : %" PRIu64 "\n",
1207 pim->bsm_dropped);
1208 }
1209
1210 vty_out(vty, "\n");
1211
1212 /* scan interfaces */
1213 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1214 struct pim_interface *pim_ifp = ifp->info;
1215
1216 if (ifname && strcmp(ifname, ifp->name))
1217 continue;
1218
1219 if (!pim_ifp)
1220 continue;
1221
1222 if (!uj) {
1223 vty_out(vty, "Interface : %s\n", ifp->name);
1224 vty_out(vty, "-------------------\n");
1225 vty_out(vty,
1226 "Number of BSMs dropped due to config miss : %u\n",
1227 pim_ifp->pim_ifstat_bsm_cfg_miss);
1228 vty_out(vty, "Number of unicast BSMs dropped : %u\n",
1229 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss);
1230 vty_out(vty,
1231 "Number of BSMs dropped due to invalid scope zone : %u\n",
1232 pim_ifp->pim_ifstat_bsm_invalid_sz);
1233 } else {
1234
1235 json_object *json_row = NULL;
1236
1237 json_row = json_object_new_object();
1238
1239 json_object_string_add(json_row, "If Name", ifp->name);
1240 json_object_int_add(json_row, "bsmDroppedConfig",
1241 pim_ifp->pim_ifstat_bsm_cfg_miss);
1242 json_object_int_add(
1243 json_row, "bsmDroppedUnicast",
1244 pim_ifp->pim_ifstat_ucast_bsm_cfg_miss);
1245 json_object_int_add(json_row,
1246 "bsmDroppedInvalidScopeZone",
1247 pim_ifp->pim_ifstat_bsm_invalid_sz);
1248 json_object_object_add(json, ifp->name, json_row);
1249 }
1250 vty_out(vty, "\n");
1251 }
1252
1253 if (uj)
1254 vty_json(vty, json);
1255 }
1256
1257 void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
1258 pim_sgaddr *sg, json_object *json)
1259 {
1260 struct pim_upstream *up;
1261 time_t now;
1262 json_object *json_group = NULL;
1263 json_object *json_row = NULL;
1264
1265 now = pim_time_monotonic_sec();
1266
1267 if (!json)
1268 vty_out(vty,
1269 "Iif Source Group State Uptime JoinTimer RSTimer KATimer RefCnt\n");
1270
1271 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1272 char uptime[10];
1273 char join_timer[10];
1274 char rs_timer[10];
1275 char ka_timer[10];
1276 char msdp_reg_timer[10];
1277 char state_str[PIM_REG_STATE_STR_LEN];
1278
1279 if (!pim_sgaddr_match(up->sg, *sg))
1280 continue;
1281
1282 pim_time_uptime(uptime, sizeof(uptime),
1283 now - up->state_transition);
1284 pim_time_timer_to_hhmmss(join_timer, sizeof(join_timer),
1285 up->t_join_timer);
1286
1287 /*
1288 * If the upstream is not dummy and it has a J/P timer for the
1289 * neighbor display that
1290 */
1291 if (!up->t_join_timer && up->rpf.source_nexthop.interface) {
1292 struct pim_neighbor *nbr;
1293
1294 nbr = pim_neighbor_find_prefix(
1295 up->rpf.source_nexthop.interface,
1296 &up->rpf.rpf_addr);
1297 if (nbr)
1298 pim_time_timer_to_hhmmss(join_timer,
1299 sizeof(join_timer),
1300 nbr->jp_timer);
1301 }
1302
1303 pim_time_timer_to_hhmmss(rs_timer, sizeof(rs_timer),
1304 up->t_rs_timer);
1305 pim_time_timer_to_hhmmss(ka_timer, sizeof(ka_timer),
1306 up->t_ka_timer);
1307 pim_time_timer_to_hhmmss(msdp_reg_timer, sizeof(msdp_reg_timer),
1308 up->t_msdp_reg_timer);
1309
1310 pim_upstream_state2brief_str(up->join_state, state_str,
1311 sizeof(state_str));
1312 if (up->reg_state != PIM_REG_NOINFO) {
1313 char tmp_str[PIM_REG_STATE_STR_LEN];
1314 char tmp[sizeof(state_str) + 1];
1315
1316 snprintf(tmp, sizeof(tmp), ",%s",
1317 pim_reg_state2brief_str(up->reg_state, tmp_str,
1318 sizeof(tmp_str)));
1319 strlcat(state_str, tmp, sizeof(state_str));
1320 }
1321
1322 if (json) {
1323 char grp_str[PIM_ADDRSTRLEN];
1324 char src_str[PIM_ADDRSTRLEN];
1325
1326 snprintfrr(grp_str, sizeof(grp_str), "%pPAs",
1327 &up->sg.grp);
1328 snprintfrr(src_str, sizeof(src_str), "%pPAs",
1329 &up->sg.src);
1330
1331 json_object_object_get_ex(json, grp_str, &json_group);
1332
1333 if (!json_group) {
1334 json_group = json_object_new_object();
1335 json_object_object_add(json, grp_str,
1336 json_group);
1337 }
1338
1339 json_row = json_object_new_object();
1340 json_object_pim_upstream_add(json_row, up);
1341 json_object_string_add(
1342 json_row, "inboundInterface",
1343 up->rpf.source_nexthop.interface
1344 ? up->rpf.source_nexthop.interface->name
1345 : "Unknown");
1346
1347 /*
1348 * The RPF address we use is slightly different
1349 * based upon what we are looking up.
1350 * If we have a S, list that unless
1351 * we are the FHR, else we just put
1352 * the RP as the rpfAddress
1353 */
1354 if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR ||
1355 pim_addr_is_any(up->sg.src)) {
1356 struct pim_rpf *rpg;
1357
1358 rpg = RP(pim, up->sg.grp);
1359 json_object_string_addf(json_row, "rpfAddress",
1360 "%pFX", &rpg->rpf_addr);
1361 } else {
1362 json_object_string_add(json_row, "rpfAddress",
1363 src_str);
1364 }
1365
1366 json_object_string_add(json_row, "source", src_str);
1367 json_object_string_add(json_row, "group", grp_str);
1368 json_object_string_add(json_row, "state", state_str);
1369 json_object_string_add(
1370 json_row, "joinState",
1371 pim_upstream_state2str(up->join_state));
1372 json_object_string_add(
1373 json_row, "regState",
1374 pim_reg_state2str(up->reg_state, state_str,
1375 sizeof(state_str)));
1376 json_object_string_add(json_row, "upTime", uptime);
1377 json_object_string_add(json_row, "joinTimer",
1378 join_timer);
1379 json_object_string_add(json_row, "resetTimer",
1380 rs_timer);
1381 json_object_string_add(json_row, "keepaliveTimer",
1382 ka_timer);
1383 json_object_string_add(json_row, "msdpRegTimer",
1384 msdp_reg_timer);
1385 json_object_int_add(json_row, "refCount",
1386 up->ref_count);
1387 json_object_int_add(json_row, "sptBit", up->sptbit);
1388 json_object_object_add(json_group, src_str, json_row);
1389 } else {
1390 vty_out(vty,
1391 "%-16s%-15pPAs %-15pPAs %-11s %-8s %-9s %-9s %-9s %6d\n",
1392 up->rpf.source_nexthop.interface
1393 ? up->rpf.source_nexthop.interface->name
1394 : "Unknown",
1395 &up->sg.src, &up->sg.grp, state_str, uptime,
1396 join_timer, rs_timer, ka_timer, up->ref_count);
1397 }
1398 }
1399 }
1400
1401 static void pim_show_join_desired_helper(struct pim_instance *pim,
1402 struct vty *vty,
1403 struct pim_upstream *up,
1404 json_object *json, bool uj)
1405 {
1406 json_object *json_group = NULL;
1407 char src_str[INET_ADDRSTRLEN];
1408 char grp_str[INET_ADDRSTRLEN];
1409 json_object *json_row = NULL;
1410
1411 pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
1412 pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
1413
1414 if (uj) {
1415 json_object_object_get_ex(json, grp_str, &json_group);
1416
1417 if (!json_group) {
1418 json_group = json_object_new_object();
1419 json_object_object_add(json, grp_str, json_group);
1420 }
1421
1422 json_row = json_object_new_object();
1423 json_object_pim_upstream_add(json_row, up);
1424 json_object_string_add(json_row, "source", src_str);
1425 json_object_string_add(json_row, "group", grp_str);
1426
1427 if (pim_upstream_evaluate_join_desired(pim, up))
1428 json_object_boolean_true_add(json_row,
1429 "evaluateJoinDesired");
1430
1431 json_object_object_add(json_group, src_str, json_row);
1432
1433 } else {
1434 vty_out(vty, "%-15s %-15s %-6s\n", src_str, grp_str,
1435 pim_upstream_evaluate_join_desired(pim, up) ? "yes"
1436 : "no");
1437 }
1438 }
1439
1440 void pim_show_join_desired(struct pim_instance *pim, struct vty *vty, bool uj)
1441 {
1442 struct pim_upstream *up;
1443
1444 json_object *json = NULL;
1445
1446 if (uj)
1447 json = json_object_new_object();
1448 else
1449 vty_out(vty, "Source Group EvalJD\n");
1450
1451 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1452 /* scan all interfaces */
1453 pim_show_join_desired_helper(pim, vty, up, json, uj);
1454 }
1455
1456 if (uj)
1457 vty_json(vty, json);
1458 }
1459
1460 void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, bool uj)
1461 {
1462 struct pim_upstream *up;
1463 json_object *json = NULL;
1464 json_object *json_group = NULL;
1465 json_object *json_row = NULL;
1466
1467 if (uj)
1468 json = json_object_new_object();
1469 else
1470 vty_out(vty,
1471 "Source Group RpfIface RibNextHop RpfAddress \n");
1472
1473 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1474 char src_str[INET_ADDRSTRLEN];
1475 char grp_str[INET_ADDRSTRLEN];
1476 char rpf_nexthop_str[PREFIX_STRLEN];
1477 char rpf_addr_str[PREFIX_STRLEN];
1478 struct pim_rpf *rpf;
1479 const char *rpf_ifname;
1480
1481 rpf = &up->rpf;
1482
1483 pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str));
1484 pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str));
1485 pim_addr_dump("<nexthop?>",
1486 &rpf->source_nexthop.mrib_nexthop_addr,
1487 rpf_nexthop_str, sizeof(rpf_nexthop_str));
1488 pim_addr_dump("<rpf?>", &rpf->rpf_addr, rpf_addr_str,
1489 sizeof(rpf_addr_str));
1490
1491 rpf_ifname =
1492 rpf->source_nexthop.interface ? rpf->source_nexthop
1493 .interface->name
1494 : "<ifname?>";
1495
1496 if (uj) {
1497 json_object_object_get_ex(json, grp_str, &json_group);
1498
1499 if (!json_group) {
1500 json_group = json_object_new_object();
1501 json_object_object_add(json, grp_str,
1502 json_group);
1503 }
1504
1505 json_row = json_object_new_object();
1506 json_object_pim_upstream_add(json_row, up);
1507 json_object_string_add(json_row, "source", src_str);
1508 json_object_string_add(json_row, "group", grp_str);
1509 json_object_string_add(json_row, "rpfInterface",
1510 rpf_ifname);
1511 json_object_string_add(json_row, "ribNexthop",
1512 rpf_nexthop_str);
1513 json_object_string_add(json_row, "rpfAddress",
1514 rpf_addr_str);
1515 json_object_object_add(json_group, src_str, json_row);
1516 } else {
1517 vty_out(vty, "%-15s %-15s %-16s %-15s %-15s\n", src_str,
1518 grp_str, rpf_ifname, rpf_nexthop_str,
1519 rpf_addr_str);
1520 }
1521 }
1522
1523 if (uj)
1524 vty_json(vty, json);
1525 }