3 * Copyright (C) 2022 Vmware, Inc.
4 * Mobashshera Rasool <mrasool@vmware.com>
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.
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.
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
33 #include "lib/srcdest_table.h"
37 #include "lib/northbound_cli.h"
38 #include "pim_errors.h"
40 #include "pim_cmd_common.h"
41 #include "pim_mroute.h"
44 #include "pim_cmd_common.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"
53 * Get current node VRF name.
56 * In case of failure it will print error message to user.
58 * \returns name or NULL if failed to get VRF.
60 const char *pim_cli_get_vrf_name(struct vty
*vty
)
62 const struct lyd_node
*vrf_node
;
64 /* Not inside any VRF context. */
65 if (vty
->xpath_index
== 0)
66 return VRF_DEFAULT_NAME
;
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");
74 return yang_dnode_get_string(vrf_node
, "./name");
77 int pim_process_join_prune_cmd(struct vty
*vty
, const char *jpi_str
)
79 char xpath
[XPATH_MAXLEN
];
81 snprintf(xpath
, sizeof(xpath
), FRR_PIM_ROUTER_XPATH
,
82 FRR_PIM_AF_XPATH_VAL
);
83 strlcat(xpath
, "/join-prune-interval", sizeof(xpath
));
85 nb_cli_enqueue_change(vty
, xpath
, NB_OP_MODIFY
, jpi_str
);
87 return nb_cli_apply_changes(vty
, NULL
);
90 int pim_process_no_join_prune_cmd(struct vty
*vty
)
92 char xpath
[XPATH_MAXLEN
];
94 snprintf(xpath
, sizeof(xpath
), FRR_PIM_ROUTER_XPATH
,
95 FRR_PIM_AF_XPATH_VAL
);
96 strlcat(xpath
, "/join-prune-interval", sizeof(xpath
));
98 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
100 return nb_cli_apply_changes(vty
, NULL
);
103 int pim_process_spt_switchover_infinity_cmd(struct vty
*vty
)
106 char spt_plist_xpath
[XPATH_MAXLEN
];
107 char spt_action_xpath
[XPATH_MAXLEN
];
109 vrfname
= pim_cli_get_vrf_name(vty
);
111 return CMD_WARNING_CONFIG_FAILED
;
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
));
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
));
125 if (yang_dnode_exists(vty
->candidate_config
->dnode
, spt_plist_xpath
))
126 nb_cli_enqueue_change(vty
, spt_plist_xpath
, NB_OP_DESTROY
,
128 nb_cli_enqueue_change(vty
, spt_action_xpath
, NB_OP_MODIFY
,
131 return nb_cli_apply_changes(vty
, NULL
);
134 int pim_process_spt_switchover_prefixlist_cmd(struct vty
*vty
,
138 char spt_plist_xpath
[XPATH_MAXLEN
];
139 char spt_action_xpath
[XPATH_MAXLEN
];
141 vrfname
= pim_cli_get_vrf_name(vty
);
143 return CMD_WARNING_CONFIG_FAILED
;
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
));
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
));
157 nb_cli_enqueue_change(vty
, spt_action_xpath
, NB_OP_MODIFY
,
159 nb_cli_enqueue_change(vty
, spt_plist_xpath
, NB_OP_MODIFY
,
162 return nb_cli_apply_changes(vty
, NULL
);
165 int pim_process_no_spt_switchover_cmd(struct vty
*vty
)
168 char spt_plist_xpath
[XPATH_MAXLEN
];
169 char spt_action_xpath
[XPATH_MAXLEN
];
171 vrfname
= pim_cli_get_vrf_name(vty
);
173 return CMD_WARNING_CONFIG_FAILED
;
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
));
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
));
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");
191 return nb_cli_apply_changes(vty
, NULL
);
194 int pim_process_pim_packet_cmd(struct vty
*vty
, const char *packet
)
196 char xpath
[XPATH_MAXLEN
];
198 snprintf(xpath
, sizeof(xpath
), FRR_PIM_ROUTER_XPATH
,
199 FRR_PIM_AF_XPATH_VAL
);
200 strlcat(xpath
, "/packets", sizeof(xpath
));
202 nb_cli_enqueue_change(vty
, xpath
, NB_OP_MODIFY
, packet
);
204 return nb_cli_apply_changes(vty
, NULL
);
207 int pim_process_no_pim_packet_cmd(struct vty
*vty
)
209 char xpath
[XPATH_MAXLEN
];
211 snprintf(xpath
, sizeof(xpath
), FRR_PIM_ROUTER_XPATH
,
212 FRR_PIM_AF_XPATH_VAL
);
213 strlcat(xpath
, "/packets", sizeof(xpath
));
215 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
217 return nb_cli_apply_changes(vty
, NULL
);
220 int pim_process_keepalivetimer_cmd(struct vty
*vty
, const char *kat
)
223 char ka_timer_xpath
[XPATH_MAXLEN
];
225 vrfname
= pim_cli_get_vrf_name(vty
);
227 return CMD_WARNING_CONFIG_FAILED
;
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
));
233 nb_cli_enqueue_change(vty
, ka_timer_xpath
, NB_OP_MODIFY
,
236 return nb_cli_apply_changes(vty
, NULL
);
239 int pim_process_no_keepalivetimer_cmd(struct vty
*vty
)
242 char ka_timer_xpath
[XPATH_MAXLEN
];
244 vrfname
= pim_cli_get_vrf_name(vty
);
246 return CMD_WARNING_CONFIG_FAILED
;
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
));
252 nb_cli_enqueue_change(vty
, ka_timer_xpath
, NB_OP_DESTROY
, NULL
);
254 return nb_cli_apply_changes(vty
, NULL
);
257 int pim_process_rp_kat_cmd(struct vty
*vty
, const char *rpkat
)
260 char rp_ka_timer_xpath
[XPATH_MAXLEN
];
262 vrfname
= pim_cli_get_vrf_name(vty
);
264 return CMD_WARNING_CONFIG_FAILED
;
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
));
272 nb_cli_enqueue_change(vty
, rp_ka_timer_xpath
, NB_OP_MODIFY
,
275 return nb_cli_apply_changes(vty
, NULL
);
278 int pim_process_no_rp_kat_cmd(struct vty
*vty
)
282 char rp_ka_timer_xpath
[XPATH_MAXLEN
];
284 char rs_timer_xpath
[XPATH_MAXLEN
];
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
));
292 v
= yang_dnode_get_uint16(vty
->candidate_config
->dnode
,
294 v
= 3 * v
+ PIM_REGISTER_PROBE_TIME_DEFAULT
;
297 snprintf(rp_ka_timer
, sizeof(rp_ka_timer
), "%u", v
);
299 vrfname
= pim_cli_get_vrf_name(vty
);
301 return CMD_WARNING_CONFIG_FAILED
;
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
));
309 nb_cli_enqueue_change(vty
, rp_ka_timer_xpath
, NB_OP_MODIFY
,
312 return nb_cli_apply_changes(vty
, NULL
);
315 int pim_process_register_suppress_cmd(struct vty
*vty
, const char *rst
)
317 char xpath
[XPATH_MAXLEN
];
319 snprintf(xpath
, sizeof(xpath
), FRR_PIM_ROUTER_XPATH
,
320 FRR_PIM_AF_XPATH_VAL
);
321 strlcat(xpath
, "/register-suppress-time", sizeof(xpath
));
323 nb_cli_enqueue_change(vty
, xpath
, NB_OP_MODIFY
, rst
);
325 return nb_cli_apply_changes(vty
, NULL
);
328 int pim_process_no_register_suppress_cmd(struct vty
*vty
)
330 char xpath
[XPATH_MAXLEN
];
332 snprintf(xpath
, sizeof(xpath
), FRR_PIM_ROUTER_XPATH
,
333 FRR_PIM_AF_XPATH_VAL
);
334 strlcat(xpath
, "/register-suppress-time", sizeof(xpath
));
336 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
338 return nb_cli_apply_changes(vty
, NULL
);
341 int pim_process_ip_pim_cmd(struct vty
*vty
)
343 nb_cli_enqueue_change(vty
, "./pim-enable", NB_OP_MODIFY
, "true");
345 return nb_cli_apply_changes(vty
, FRR_PIM_INTERFACE_XPATH
,
346 FRR_PIM_AF_XPATH_VAL
);
349 int pim_process_no_ip_pim_cmd(struct vty
*vty
)
351 const struct lyd_node
*mld_enable_dnode
;
352 char mld_if_xpath
[XPATH_MAXLEN
];
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
);
359 if (printed
>= (int)(sizeof(mld_if_xpath
))) {
360 vty_out(vty
, "Xpath too long (%d > %u)", printed
+ 1,
362 return CMD_WARNING_CONFIG_FAILED
;
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
);
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
);
373 if (!yang_dnode_get_bool(mld_enable_dnode
, ".")) {
374 nb_cli_enqueue_change(vty
, mld_if_xpath
, NB_OP_DESTROY
,
376 nb_cli_enqueue_change(vty
, ".", NB_OP_DESTROY
, NULL
);
378 nb_cli_enqueue_change(vty
, "./pim-enable", NB_OP_MODIFY
,
382 return nb_cli_apply_changes(vty
, FRR_PIM_INTERFACE_XPATH
,
383 FRR_PIM_AF_XPATH_VAL
);
386 int pim_process_ip_pim_drprio_cmd(struct vty
*vty
, const char *drpriority_str
)
388 nb_cli_enqueue_change(vty
, "./dr-priority", NB_OP_MODIFY
,
391 return nb_cli_apply_changes(vty
, FRR_PIM_INTERFACE_XPATH
,
392 FRR_PIM_AF_XPATH_VAL
);
395 int pim_process_no_ip_pim_drprio_cmd(struct vty
*vty
)
397 nb_cli_enqueue_change(vty
, "./dr-priority", NB_OP_DESTROY
, NULL
);
399 return nb_cli_apply_changes(vty
, FRR_PIM_INTERFACE_XPATH
,
400 FRR_PIM_AF_XPATH_VAL
);
403 int pim_process_ip_pim_hello_cmd(struct vty
*vty
, const char *hello_str
,
404 const char *hold_str
)
406 const struct lyd_node
*mld_enable_dnode
;
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
);
412 if (!mld_enable_dnode
) {
413 nb_cli_enqueue_change(vty
, "./pim-enable", NB_OP_MODIFY
,
416 if (!yang_dnode_get_bool(mld_enable_dnode
, "."))
417 nb_cli_enqueue_change(vty
, "./pim-enable", NB_OP_MODIFY
,
421 nb_cli_enqueue_change(vty
, "./hello-interval", NB_OP_MODIFY
, hello_str
);
424 nb_cli_enqueue_change(vty
, "./hello-holdtime", NB_OP_MODIFY
,
427 return nb_cli_apply_changes(vty
, FRR_PIM_INTERFACE_XPATH
,
428 FRR_PIM_AF_XPATH_VAL
);
431 int pim_process_no_ip_pim_hello_cmd(struct vty
*vty
)
433 nb_cli_enqueue_change(vty
, "./hello-interval", NB_OP_DESTROY
, NULL
);
434 nb_cli_enqueue_change(vty
, "./hello-holdtime", NB_OP_DESTROY
, NULL
);
436 return nb_cli_apply_changes(vty
, FRR_PIM_INTERFACE_XPATH
,
437 FRR_PIM_AF_XPATH_VAL
);
440 int pim_process_ip_pim_activeactive_cmd(struct vty
*vty
, const char *no
)
443 nb_cli_enqueue_change(vty
, "./active-active", NB_OP_MODIFY
,
446 nb_cli_enqueue_change(vty
, "./pim-enable", NB_OP_MODIFY
,
449 nb_cli_enqueue_change(vty
, "./active-active", NB_OP_MODIFY
,
453 return nb_cli_apply_changes(vty
, FRR_PIM_INTERFACE_XPATH
,
454 FRR_PIM_AF_XPATH_VAL
);
457 int pim_process_ip_pim_boundary_oil_cmd(struct vty
*vty
, const char *oil
)
459 nb_cli_enqueue_change(vty
, "./multicast-boundary-oil", NB_OP_MODIFY
,
462 return nb_cli_apply_changes(vty
, FRR_PIM_INTERFACE_XPATH
,
463 FRR_PIM_AF_XPATH_VAL
);
466 int pim_process_no_ip_pim_boundary_oil_cmd(struct vty
*vty
)
468 nb_cli_enqueue_change(vty
, "./multicast-boundary-oil", NB_OP_DESTROY
,
471 return nb_cli_apply_changes(vty
, FRR_PIM_INTERFACE_XPATH
,
472 FRR_PIM_AF_XPATH_VAL
);
475 int pim_process_ip_mroute_cmd(struct vty
*vty
, const char *interface
,
476 const char *group_str
, const char *source_str
)
478 nb_cli_enqueue_change(vty
, "./oif", NB_OP_MODIFY
, interface
);
481 char buf
[SRCDEST2STR_BUFFER
];
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
,
489 return nb_cli_apply_changes(vty
, FRR_PIM_MROUTE_XPATH
,
490 FRR_PIM_AF_XPATH_VAL
, source_str
,
494 int pim_process_no_ip_mroute_cmd(struct vty
*vty
, const char *interface
,
495 const char *group_str
, const char *source_str
)
497 nb_cli_enqueue_change(vty
, ".", NB_OP_DESTROY
, NULL
);
500 char buf
[SRCDEST2STR_BUFFER
];
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
,
508 return nb_cli_apply_changes(vty
, FRR_PIM_MROUTE_XPATH
,
509 FRR_PIM_AF_XPATH_VAL
, source_str
,
513 int pim_process_rp_cmd(struct vty
*vty
, const char *rp_str
,
514 const char *group_str
)
517 char rp_group_xpath
[XPATH_MAXLEN
];
522 result
= str2prefix(group_str
, &group
);
526 prefix_copy(&temp
, &group
);
528 if (!prefix_same(&group
, &temp
)) {
529 vty_out(vty
, "%% Inconsistent address and mask: %s\n",
531 return CMD_WARNING_CONFIG_FAILED
;
536 vty_out(vty
, "%% Bad group address specified: %s\n", group_str
);
537 return CMD_WARNING_CONFIG_FAILED
;
540 result
= inet_pton(PIM_AF
, rp_str
, &rp_addr
);
542 vty_out(vty
, "%% Bad RP address specified: %s\n", rp_str
);
543 return CMD_WARNING_CONFIG_FAILED
;
546 vrfname
= pim_cli_get_vrf_name(vty
);
548 return CMD_WARNING_CONFIG_FAILED
;
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
));
555 nb_cli_enqueue_change(vty
, rp_group_xpath
, NB_OP_CREATE
, group_str
);
557 return nb_cli_apply_changes(vty
, NULL
);
560 int pim_process_no_rp_cmd(struct vty
*vty
, const char *rp_str
,
561 const char *group_str
)
563 char group_list_xpath
[XPATH_MAXLEN
];
564 char group_xpath
[XPATH_MAXLEN
];
565 char rp_xpath
[XPATH_MAXLEN
];
568 const struct lyd_node
*group_dnode
;
570 vrfname
= pim_cli_get_vrf_name(vty
);
572 return CMD_WARNING_CONFIG_FAILED
;
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
);
577 printed
= snprintf(group_list_xpath
, sizeof(group_list_xpath
),
578 "%s/group-list", rp_xpath
);
580 if (printed
>= (int)(sizeof(group_list_xpath
))) {
581 vty_out(vty
, "Xpath too long (%d > %u)", printed
+ 1,
583 return CMD_WARNING_CONFIG_FAILED
;
586 printed
= snprintf(group_xpath
, sizeof(group_xpath
), "%s[.='%s']",
587 group_list_xpath
, group_str
);
589 if (printed
>= (int)(sizeof(group_xpath
))) {
590 vty_out(vty
, "Xpath too long (%d > %u)", printed
+ 1,
592 return CMD_WARNING_CONFIG_FAILED
;
595 group_dnode
= yang_dnode_get(vty
->candidate_config
->dnode
, group_xpath
);
597 vty_out(vty
, "%% Unable to find specified RP\n");
601 if (yang_is_last_list_dnode(group_dnode
))
602 nb_cli_enqueue_change(vty
, rp_xpath
, NB_OP_DESTROY
, NULL
);
604 nb_cli_enqueue_change(vty
, group_list_xpath
, NB_OP_DESTROY
,
607 return nb_cli_apply_changes(vty
, NULL
);
610 int pim_process_rp_plist_cmd(struct vty
*vty
, const char *rp_str
,
611 const char *prefix_list
)
614 char rp_plist_xpath
[XPATH_MAXLEN
];
616 vrfname
= pim_cli_get_vrf_name(vty
);
618 return CMD_WARNING_CONFIG_FAILED
;
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
));
625 nb_cli_enqueue_change(vty
, rp_plist_xpath
, NB_OP_MODIFY
, prefix_list
);
627 return nb_cli_apply_changes(vty
, NULL
);
630 int pim_process_no_rp_plist_cmd(struct vty
*vty
, const char *rp_str
,
631 const char *prefix_list
)
633 char rp_xpath
[XPATH_MAXLEN
];
634 char plist_xpath
[XPATH_MAXLEN
];
636 const struct lyd_node
*plist_dnode
;
639 vrfname
= pim_cli_get_vrf_name(vty
);
641 return CMD_WARNING_CONFIG_FAILED
;
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
);
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
));
650 plist_dnode
= yang_dnode_get(vty
->candidate_config
->dnode
, plist_xpath
);
652 vty_out(vty
, "%% Unable to find specified RP\n");
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");
662 nb_cli_enqueue_change(vty
, rp_xpath
, NB_OP_DESTROY
, NULL
);
664 return nb_cli_apply_changes(vty
, NULL
);
667 bool pim_sgaddr_match(pim_sgaddr item
, pim_sgaddr match
)
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
));
675 void json_object_pim_upstream_add(json_object
*json
, struct pim_upstream
*up
)
677 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED
)
678 json_object_boolean_true_add(json
, "drJoinDesired");
680 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED
)
681 json_object_boolean_true_add(json
, "drJoinDesiredUpdated");
683 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_FHR
)
684 json_object_boolean_true_add(json
, "firstHopRouter");
686 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_SRC_IGMP
)
687 json_object_boolean_true_add(json
, "sourceIgmp");
689 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_SRC_PIM
)
690 json_object_boolean_true_add(json
, "sourcePim");
692 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_SRC_STREAM
)
693 json_object_boolean_true_add(json
, "sourceStream");
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");
699 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE
)
700 json_object_boolean_true_add(json
, "sendSGRptPrune");
702 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_SRC_LHR
)
703 json_object_boolean_true_add(json
, "lastHopRouter");
705 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_DISABLE_KAT_EXPIRY
)
706 json_object_boolean_true_add(json
, "disableKATExpiry");
708 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_STATIC_IIF
)
709 json_object_boolean_true_add(json
, "staticIncomingInterface");
711 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_ALLOW_IIF_IN_OIL
)
712 json_object_boolean_true_add(json
,
713 "allowIncomingInterfaceinOil");
715 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_NO_PIMREG_DATA
)
716 json_object_boolean_true_add(json
, "noPimRegistrationData");
718 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_FORCE_PIMREG
)
719 json_object_boolean_true_add(json
, "forcePimRegistration");
721 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG
)
722 json_object_boolean_true_add(json
, "sourceVxlanOrigination");
724 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM
)
725 json_object_boolean_true_add(json
, "sourceVxlanTermination");
727 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN
)
728 json_object_boolean_true_add(json
, "mlagVxlan");
730 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF
)
731 json_object_boolean_true_add(json
,
732 "mlagNonDesignatedForwarder");
736 pim_upstream_state2brief_str(enum pim_upstream_state join_state
,
737 char *state_str
, size_t state_str_len
)
739 switch (join_state
) {
740 case PIM_UPSTREAM_NOTJOINED
:
741 strlcpy(state_str
, "NotJ", state_str_len
);
743 case PIM_UPSTREAM_JOINED
:
744 strlcpy(state_str
, "J", state_str_len
);
747 strlcpy(state_str
, "Unk", state_str_len
);
752 static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state
,
754 size_t state_str_len
)
758 strlcpy(state_str
, "RegNI", state_str_len
);
761 strlcpy(state_str
, "RegJ", state_str_len
);
763 case PIM_REG_JOIN_PENDING
:
765 strlcpy(state_str
, "RegP", state_str_len
);
771 void pim_show_rpf_refresh_stats(struct vty
*vty
, struct pim_instance
*pim
,
772 time_t now
, json_object
*json
)
774 char refresh_uptime
[10];
776 pim_time_uptime_begin(refresh_uptime
, sizeof(refresh_uptime
), now
,
777 pim
->rpf_cache_refresh_last
);
780 json_object_int_add(json
, "rpfCacheRefreshDelayMsecs",
781 router
->rpf_cache_refresh_delay_msec
);
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",
791 json_object_int_add(json
, "nexthopLookups",
792 pim
->nexthop_lookups
);
793 json_object_int_add(json
, "nexthopLookupsAvoided",
794 pim
->nexthop_lookups_avoided
);
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
);
813 void pim_show_rpf(struct pim_instance
*pim
, struct vty
*vty
, json_object
*json
)
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
;
820 pim_show_rpf_refresh_stats(vty
, pim
, now
, json
);
825 "Source Group RpfIface RpfAddress RibNextHop Metric Pref\n");
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
;
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
));
841 rpf
->source_nexthop
.interface
? rpf
->source_nexthop
846 char grp_str
[PIM_ADDRSTRLEN
];
847 char src_str
[PIM_ADDRSTRLEN
];
849 snprintfrr(grp_str
, sizeof(grp_str
), "%pPAs",
851 snprintfrr(src_str
, sizeof(src_str
), "%pPAs",
854 json_object_object_get_ex(json
, grp_str
, &json_group
);
857 json_group
= json_object_new_object();
858 json_object_object_add(json
, grp_str
,
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",
867 json_object_string_add(json_row
, "rpfAddress",
869 json_object_string_add(json_row
, "ribNexthop",
872 json_row
, "routeMetric",
873 rpf
->source_nexthop
.mrib_route_metric
);
875 json_row
, "routePreference",
876 rpf
->source_nexthop
.mrib_metric_preference
);
877 json_object_object_add(json_group
, src_str
, json_row
);
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
);
890 void pim_show_neighbors_secondary(struct pim_instance
*pim
, struct vty
*vty
)
892 struct interface
*ifp
;
895 "Interface Address Neighbor Secondary \n");
897 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
898 struct pim_interface
*pim_ifp
;
900 struct listnode
*neighnode
;
901 struct pim_neighbor
*neigh
;
908 if (pim_ifp
->pim_sock_fd
< 0)
911 ifaddr
= pim_ifp
->primary_address
;
913 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neighnode
,
915 struct listnode
*prefix_node
;
918 if (!neigh
->prefix_list
)
921 for (ALL_LIST_ELEMENTS_RO(neigh
->prefix_list
,
924 "%-16s %-15pPAs %-15pPAs %-15pFX\n",
925 ifp
->name
, &ifaddr
, &neigh
->source_addr
,
931 void pim_show_state(struct pim_instance
*pim
, struct vty
*vty
,
932 const char *src_or_group
, const char *group
, bool uj
)
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
;
943 now
= pim_time_monotonic_sec();
946 json
= json_object_new_object();
949 "Codes: J -> Pim Join, I -> IGMP Report, S -> Source, * -> Inherited from (*,G), V -> VxLAN, M -> Muted");
951 "\nActive Source Group RPT IIF OIL\n");
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];
960 struct interface
*ifp_in
;
966 PIM_UPSTREAM_FLAG_TEST_USE_RPT(c_oil
->up
->flags
)) ||
967 c_oil
->oil
.mfcc_origin
.s_addr
== INADDR_ANY
)
972 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, grp_str
,
974 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, src_str
,
976 ifp_in
= pim_if_find_by_vif_index(pim
, c_oil
->oil
.mfcc_parent
);
979 strlcpy(in_ifname
, ifp_in
->name
, sizeof(in_ifname
));
981 strlcpy(in_ifname
, "<iif?>", sizeof(in_ifname
));
984 if (strcmp(src_or_group
, src_str
) &&
985 strcmp(src_or_group
, grp_str
))
988 if (group
&& strcmp(group
, grp_str
))
994 /* Find the group, create it if it doesn't exist */
995 json_object_object_get_ex(json
, grp_str
, &json_group
);
998 json_group
= json_object_new_object();
999 json_object_object_add(json
, grp_str
,
1003 /* Find the source nested under the group, create it if
1006 json_object_object_get_ex(json_group
, src_str
,
1010 json_source
= json_object_new_object();
1011 json_object_object_add(json_group
, src_str
,
1015 /* Find the inbound interface nested under the source,
1016 * create it if it doesn't exist
1018 json_object_object_get_ex(json_source
, in_ifname
,
1022 json_ifp_in
= json_object_new_object();
1023 json_object_object_add(json_source
, in_ifname
,
1025 json_object_int_add(json_source
, "Installed",
1027 json_object_int_add(json_source
, "installed",
1030 json_object_boolean_true_add(
1031 json_source
, "isRpt");
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",
1041 json_object_int_add(json_source
, "oilListSize",
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",
1055 json_object_int_add(json_source
, "packetCount",
1057 json_object_int_add(json_source
, "ByteCount",
1059 json_object_int_add(json_source
, "byteCount",
1061 json_object_int_add(json_source
,
1063 c_oil
->cc
.wrong_if
);
1064 json_object_int_add(json_source
,
1066 c_oil
->cc
.wrong_if
);
1069 vty_out(vty
, "%-6d %-15s %-15s %-3s %-16s ",
1070 c_oil
->installed
, src_str
, grp_str
,
1071 isRpt
? "y" : "n", in_ifname
);
1074 for (oif_vif_index
= 0; oif_vif_index
< MAXVIFS
;
1076 struct interface
*ifp_out
;
1077 char oif_uptime
[10];
1080 ttl
= c_oil
->oil
.mfcc_ttls
[oif_vif_index
];
1084 ifp_out
= pim_if_find_by_vif_index(pim
, oif_vif_index
);
1086 oif_uptime
, sizeof(oif_uptime
),
1087 now
- c_oil
->oif_creation
[oif_vif_index
]);
1090 strlcpy(out_ifname
, ifp_out
->name
,
1091 sizeof(out_ifname
));
1093 strlcpy(out_ifname
, "<oif?>",
1094 sizeof(out_ifname
));
1097 json_ifp_out
= json_object_new_object();
1098 json_object_string_add(json_ifp_out
, "source",
1100 json_object_string_add(json_ifp_out
, "group",
1102 json_object_string_add(json_ifp_out
,
1105 json_object_string_add(json_ifp_out
,
1106 "outboundInterface",
1108 json_object_int_add(json_ifp_out
, "installed",
1111 json_object_object_add(json_ifp_in
, out_ifname
,
1116 vty_out(vty
, "%s(%c%c%c%c%c)",
1120 PIM_OIF_FLAG_PROTO_IGMP
)
1125 PIM_OIF_FLAG_PROTO_PIM
)
1130 PIM_OIF_FLAG_PROTO_VXLAN
)
1135 PIM_OIF_FLAG_PROTO_STAR
)
1144 vty_out(vty
, ", %s(%c%c%c%c%c)",
1148 PIM_OIF_FLAG_PROTO_IGMP
)
1153 PIM_OIF_FLAG_PROTO_PIM
)
1158 PIM_OIF_FLAG_PROTO_VXLAN
)
1163 PIM_OIF_FLAG_PROTO_STAR
)
1180 vty_json(vty
, json
);
1185 /* pim statistics - just adding only bsm related now.
1186 * We can continue to add all pim related stats here.
1188 void pim_show_statistics(struct pim_instance
*pim
, struct vty
*vty
,
1189 const char *ifname
, bool uj
)
1191 json_object
*json
= NULL
;
1192 struct interface
*ifp
;
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
);
1200 vty_out(vty
, "BSM Statistics :\n");
1201 vty_out(vty
, "----------------\n");
1202 vty_out(vty
, "Number of Received BSMs : %" PRIu64
"\n",
1204 vty_out(vty
, "Number of Forwared BSMs : %" PRIu64
"\n",
1206 vty_out(vty
, "Number of Dropped BSMs : %" PRIu64
"\n",
1212 /* scan interfaces */
1213 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
1214 struct pim_interface
*pim_ifp
= ifp
->info
;
1216 if (ifname
&& strcmp(ifname
, ifp
->name
))
1223 vty_out(vty
, "Interface : %s\n", ifp
->name
);
1224 vty_out(vty
, "-------------------\n");
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
);
1231 "Number of BSMs dropped due to invalid scope zone : %u\n",
1232 pim_ifp
->pim_ifstat_bsm_invalid_sz
);
1235 json_object
*json_row
= NULL
;
1237 json_row
= json_object_new_object();
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
);
1254 vty_json(vty
, json
);
1257 void pim_show_upstream(struct pim_instance
*pim
, struct vty
*vty
,
1258 pim_sgaddr
*sg
, json_object
*json
)
1260 struct pim_upstream
*up
;
1262 json_object
*json_group
= NULL
;
1263 json_object
*json_row
= NULL
;
1265 now
= pim_time_monotonic_sec();
1269 "Iif Source Group State Uptime JoinTimer RSTimer KATimer RefCnt\n");
1271 frr_each (rb_pim_upstream
, &pim
->upstream_head
, up
) {
1273 char join_timer
[10];
1276 char msdp_reg_timer
[10];
1277 char state_str
[PIM_REG_STATE_STR_LEN
];
1279 if (!pim_sgaddr_match(up
->sg
, *sg
))
1282 pim_time_uptime(uptime
, sizeof(uptime
),
1283 now
- up
->state_transition
);
1284 pim_time_timer_to_hhmmss(join_timer
, sizeof(join_timer
),
1288 * If the upstream is not dummy and it has a J/P timer for the
1289 * neighbor display that
1291 if (!up
->t_join_timer
&& up
->rpf
.source_nexthop
.interface
) {
1292 struct pim_neighbor
*nbr
;
1294 nbr
= pim_neighbor_find_prefix(
1295 up
->rpf
.source_nexthop
.interface
,
1298 pim_time_timer_to_hhmmss(join_timer
,
1303 pim_time_timer_to_hhmmss(rs_timer
, sizeof(rs_timer
),
1305 pim_time_timer_to_hhmmss(ka_timer
, sizeof(ka_timer
),
1307 pim_time_timer_to_hhmmss(msdp_reg_timer
, sizeof(msdp_reg_timer
),
1308 up
->t_msdp_reg_timer
);
1310 pim_upstream_state2brief_str(up
->join_state
, 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];
1316 snprintf(tmp
, sizeof(tmp
), ",%s",
1317 pim_reg_state2brief_str(up
->reg_state
, tmp_str
,
1319 strlcat(state_str
, tmp
, sizeof(state_str
));
1323 char grp_str
[PIM_ADDRSTRLEN
];
1324 char src_str
[PIM_ADDRSTRLEN
];
1326 snprintfrr(grp_str
, sizeof(grp_str
), "%pPAs",
1328 snprintfrr(src_str
, sizeof(src_str
), "%pPAs",
1331 json_object_object_get_ex(json
, grp_str
, &json_group
);
1334 json_group
= json_object_new_object();
1335 json_object_object_add(json
, grp_str
,
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
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
1354 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_FHR
||
1355 pim_addr_is_any(up
->sg
.src
)) {
1356 struct pim_rpf
*rpg
;
1358 rpg
= RP(pim
, up
->sg
.grp
);
1359 json_object_string_addf(json_row
, "rpfAddress",
1360 "%pFX", &rpg
->rpf_addr
);
1362 json_object_string_add(json_row
, "rpfAddress",
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",
1379 json_object_string_add(json_row
, "resetTimer",
1381 json_object_string_add(json_row
, "keepaliveTimer",
1383 json_object_string_add(json_row
, "msdpRegTimer",
1385 json_object_int_add(json_row
, "refCount",
1387 json_object_int_add(json_row
, "sptBit", up
->sptbit
);
1388 json_object_object_add(json_group
, src_str
, json_row
);
1391 "%-16s%-15pPAs %-15pPAs %-11s %-8s %-9s %-9s %-9s %6d\n",
1392 up
->rpf
.source_nexthop
.interface
1393 ? up
->rpf
.source_nexthop
.interface
->name
1395 &up
->sg
.src
, &up
->sg
.grp
, state_str
, uptime
,
1396 join_timer
, rs_timer
, ka_timer
, up
->ref_count
);
1401 static void pim_show_join_desired_helper(struct pim_instance
*pim
,
1403 struct pim_upstream
*up
,
1404 json_object
*json
, bool uj
)
1406 json_object
*json_group
= NULL
;
1407 char src_str
[INET_ADDRSTRLEN
];
1408 char grp_str
[INET_ADDRSTRLEN
];
1409 json_object
*json_row
= NULL
;
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
));
1415 json_object_object_get_ex(json
, grp_str
, &json_group
);
1418 json_group
= json_object_new_object();
1419 json_object_object_add(json
, grp_str
, json_group
);
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
);
1427 if (pim_upstream_evaluate_join_desired(pim
, up
))
1428 json_object_boolean_true_add(json_row
,
1429 "evaluateJoinDesired");
1431 json_object_object_add(json_group
, src_str
, json_row
);
1434 vty_out(vty
, "%-15s %-15s %-6s\n", src_str
, grp_str
,
1435 pim_upstream_evaluate_join_desired(pim
, up
) ? "yes"
1440 void pim_show_join_desired(struct pim_instance
*pim
, struct vty
*vty
, bool uj
)
1442 struct pim_upstream
*up
;
1444 json_object
*json
= NULL
;
1447 json
= json_object_new_object();
1449 vty_out(vty
, "Source Group EvalJD\n");
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
);
1457 vty_json(vty
, json
);
1460 void pim_show_upstream_rpf(struct pim_instance
*pim
, struct vty
*vty
, bool uj
)
1462 struct pim_upstream
*up
;
1463 json_object
*json
= NULL
;
1464 json_object
*json_group
= NULL
;
1465 json_object
*json_row
= NULL
;
1468 json
= json_object_new_object();
1471 "Source Group RpfIface RibNextHop RpfAddress \n");
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
;
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
));
1492 rpf
->source_nexthop
.interface
? rpf
->source_nexthop
1497 json_object_object_get_ex(json
, grp_str
, &json_group
);
1500 json_group
= json_object_new_object();
1501 json_object_object_add(json
, grp_str
,
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",
1511 json_object_string_add(json_row
, "ribNexthop",
1513 json_object_string_add(json_row
, "rpfAddress",
1515 json_object_object_add(json_group
, src_str
, json_row
);
1517 vty_out(vty
, "%-15s %-15s %-16s %-15s %-15s\n", src_str
,
1518 grp_str
, rpf_ifname
, rpf_nexthop_str
,
1524 vty_json(vty
, json
);