pimd: Candidate-RP support

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Signed-off-by: Jafar Al-Gharaibeh <jafar@atcorp.com>
This commit is contained in:
Jafar Al-Gharaibeh 2024-07-23 00:45:02 -05:00
parent fbd743197a
commit a110bb7798
18 changed files with 1205 additions and 13 deletions

View file

@ -1259,6 +1259,41 @@ DEFPY (no_ipv6_pim_ucast_bsm,
return pim_process_no_unicast_bsm_cmd(vty);
}
DEFPY (pim6_bsr_candidate_rp,
pim6_bsr_candidate_rp_cmd,
"[no] bsr candidate-rp [{priority (0-255)|interval (1-4294967295)|source <address X:X::X:X|interface IFNAME|loopback$loopback|any$any>}]",
NO_STR
"Bootstrap Router configuration\n"
"Make this router a Candidate RP\n"
"RP Priority (lower wins)\n"
"RP Priority (lower wins)\n"
"Advertisement interval (seconds)\n"
"Advertisement interval (seconds)\n"
"Specify IP address for RP operation\n"
"Local address to use\n"
"Local address to use\n"
"Interface to pick address from\n"
"Interface to pick address from\n"
"Pick highest loopback address (default)\n"
"Pick highest address from any interface\n")
{
return pim_process_bsr_candidate_cmd(vty, FRR_PIM_CAND_RP_XPATH, no,
true, any, ifname, address_str,
priority_str, interval_str);
}
DEFPY (pim6_bsr_candidate_rp_group,
pim6_bsr_candidate_rp_group_cmd,
"[no] bsr candidate-rp group X:X::X:X/M",
NO_STR
"Bootstrap Router configuration\n"
"Make this router a Candidate RP\n"
"Configure groups to become candidate RP for\n"
"Multicast group prefix\n")
{
return pim_process_bsr_crp_grp_cmd(vty, group_str, no);
}
DEFPY (pim6_ssmpingd,
pim6_ssmpingd_cmd,
"ssmpingd [X:X::X:X]$source",
@ -1719,6 +1754,61 @@ DEFPY (show_ipv6_pim_secondary,
return pim_show_secondary_helper(vrf, vty);
}
DEFPY (show_ipv6_pim_cand_rp,
show_ipv6_pim_cand_rp_cmd,
"show ipv6 pim candidate-rp [vrf VRF_NAME] [json$uj]",
SHOW_STR
IPV6_STR
PIM_STR
"PIM Candidate RP state\n"
VRF_CMD_HELP_STR
JSON_STR)
{
struct vrf *vrf = pim_cmd_lookup(vty, vrf_name);
struct pim_instance *pim;
struct bsm_scope *scope;
json_object *json = NULL;
if (!vrf || !vrf->info)
return CMD_WARNING;
pim = (struct pim_instance *)vrf->info;
scope = &pim->global_scope;
if (!scope->cand_rp_addrsel.run) {
if (uj)
vty_out(vty, "{}\n");
else
vty_out(vty,
"This router is not currently operating as Candidate RP\n");
return CMD_SUCCESS;
}
if (uj) {
json = json_object_new_object();
json_object_string_addf(json, "address", "%pPA",
&scope->cand_rp_addrsel.run_addr);
json_object_int_add(json, "priority", scope->cand_rp_prio);
json_object_int_add(json, "nextAdvertisementMsec",
event_timer_remain_msec(
scope->cand_rp_adv_timer));
vty_out(vty, "%s\n",
json_object_to_json_string_ext(json,
JSON_C_TO_STRING_PRETTY));
json_object_free(json);
return CMD_SUCCESS;
}
vty_out(vty, "Candidate-RP\nAddress: %pPA\nPriority: %u\n\n",
&scope->cand_rp_addrsel.run_addr, scope->cand_rp_prio);
vty_out(vty, "Next adv.: %lu msec\n",
event_timer_remain_msec(scope->cand_rp_adv_timer));
return CMD_SUCCESS;
}
DEFPY (show_ipv6_pim_statistics,
show_ipv6_pim_statistics_cmd,
"show ipv6 pim [vrf NAME] statistics [interface WORD$word] [json$json]",
@ -2650,6 +2740,8 @@ void pim_cmd_init(void)
install_element(PIM6_NODE, &no_pim6_rp_prefix_list_cmd);
install_element(PIM6_NODE, &pim6_ssmpingd_cmd);
install_element(PIM6_NODE, &no_pim6_ssmpingd_cmd);
install_element(PIM6_NODE, &pim6_bsr_candidate_rp_cmd);
install_element(PIM6_NODE, &pim6_bsr_candidate_rp_group_cmd);
install_element(CONFIG_NODE, &ipv6_mld_group_watermark_cmd);
install_element(VRF_NODE, &ipv6_mld_group_watermark_cmd);
@ -2705,6 +2797,7 @@ void pim_cmd_init(void)
install_element(VIEW_NODE, &show_ipv6_pim_rpf_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_rpf_vrf_all_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_secondary_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_cand_rp_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_statistics_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_upstream_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_upstream_vrf_all_cmd);

View file

@ -103,6 +103,7 @@ static const struct frr_yang_module_info *const pim6d_yang_modules[] = {
&frr_routing_info,
&frr_pim_info,
&frr_pim_rp_info,
&frr_pim_candidate_info,
&frr_gmp_info,
};

View file

@ -23,6 +23,12 @@
#include "pim_time.h"
#include "pim_zebra.h"
#include "pim_util.h"
#include "pim_sock.h"
#include <lib/network.h>
#include <lib/iana_afi.h>
#include <lib/sockunion.h>
#include <lib/sockopt.h>
/* Functions forward declaration */
static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout);
@ -35,6 +41,16 @@ DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info");
DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_INFO, "PIM BSR advertised RP info");
DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_FRAG, "PIM BSM fragment");
DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet");
DEFINE_MTYPE_STATIC(PIMD, PIM_CAND_RP_GRP, "PIM Candidate RP group");
static int cand_rp_group_cmp(const struct cand_rp_group *a,
const struct cand_rp_group *b)
{
return prefix_cmp(&a->p, &b->p);
}
DECLARE_RBTREE_UNIQ(cand_rp_groups, struct cand_rp_group, item,
cand_rp_group_cmp);
/* All bsm packets forwarded shall be fit within ip mtu less iphdr(max) */
#define MAX_IP_HDR_LEN 24
@ -214,34 +230,57 @@ static inline void pim_bs_timer_restart(struct bsm_scope *scope, int bs_timeout)
void pim_bsm_proc_init(struct pim_instance *pim)
{
memset(&pim->global_scope, 0, sizeof(struct bsm_scope));
struct bsm_scope *scope = &pim->global_scope;
pim->global_scope.sz_id = PIM_GBL_SZ_ID;
pim->global_scope.bsrp_table = route_table_init();
pim->global_scope.accept_nofwd_bsm = true;
pim->global_scope.state = NO_INFO;
pim->global_scope.pim = pim;
bsm_frags_init(pim->global_scope.bsm_frags);
pim_bs_timer_start(&pim->global_scope, PIM_BS_TIME);
memset(scope, 0, sizeof(*scope));
scope->sz_id = PIM_GBL_SZ_ID;
scope->bsrp_table = route_table_init();
scope->accept_nofwd_bsm = true;
scope->state = NO_INFO;
scope->pim = pim;
bsm_frags_init(scope->bsm_frags);
pim_bs_timer_start(scope, PIM_BS_TIME);
scope->cand_rp_interval = PIM_CRP_ADV_INTERVAL;
cand_rp_groups_init(scope->cand_rp_groups);
scope->unicast_sock = pim_socket_raw(IPPROTO_PIM);
set_nonblocking(scope->unicast_sock);
sockopt_reuseaddr(scope->unicast_sock);
setsockopt_ipv6_pktinfo(scope->unicast_sock, 1);
pim_socket_ip_hdr(scope->unicast_sock);
frr_with_privs (&pimd_privs) {
vrf_bind(pim->vrf->vrf_id, scope->unicast_sock, NULL);
}
}
void pim_bsm_proc_free(struct pim_instance *pim)
{
struct bsm_scope *scope = &pim->global_scope;
struct route_node *rn;
struct bsgrp_node *bsgrp;
struct cand_rp_group *crpgrp;
pim_bs_timer_stop(&pim->global_scope);
pim_bsm_frags_free(&pim->global_scope);
close(scope->unicast_sock);
for (rn = route_top(pim->global_scope.bsrp_table); rn;
rn = route_next(rn)) {
pim_bs_timer_stop(scope);
pim_bsm_frags_free(scope);
for (rn = route_top(scope->bsrp_table); rn; rn = route_next(rn)) {
bsgrp = rn->info;
if (!bsgrp)
continue;
pim_free_bsgrp_data(bsgrp);
}
route_table_finish(pim->global_scope.bsrp_table);
while ((crpgrp = cand_rp_groups_pop(scope->cand_rp_groups)))
XFREE(MTYPE_PIM_CAND_RP_GRP, crpgrp);
cand_rp_groups_fini(scope->cand_rp_groups);
route_table_finish(scope->bsrp_table);
}
static bool is_hold_time_elapsed(void *data)
@ -538,6 +577,8 @@ static void pim_bsm_update(struct pim_instance *pim, pim_addr bsr,
pim->global_scope.current_bsr_first_ts =
pim_time_monotonic_sec();
pim->global_scope.state = ACCEPT_PREFERRED;
pim_cand_rp_trigger(&pim->global_scope);
}
pim->global_scope.current_bsr_prio = bsr_prio;
pim->global_scope.current_bsr_last_ts = pim_time_monotonic_sec();
@ -1452,6 +1493,366 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
return 0;
}
static inline pim_addr if_highest_addr(pim_addr cur, struct interface *ifp)
{
struct connected *connected;
frr_each (if_connected, ifp->connected, connected) {
pim_addr conn_addr;
if (connected->address->family != PIM_AF)
continue;
conn_addr = pim_addr_from_prefix(connected->address);
/* highest address */
if (pim_addr_cmp(conn_addr, cur) > 0)
cur = conn_addr;
}
return cur;
}
static void cand_addrsel_clear(struct cand_addrsel *asel)
{
asel->run = false;
asel->run_addr = PIMADDR_ANY;
}
/* returns whether address or active changed */
static bool cand_addrsel_update(struct cand_addrsel *asel, struct vrf *vrf)
{
bool is_any = false, prev_run = asel->run;
struct interface *ifp = NULL;
pim_addr new_addr = PIMADDR_ANY;
if (!asel->cfg_enable)
goto out_disable;
switch (asel->cfg_mode) {
case CAND_ADDR_EXPLICIT:
new_addr = asel->cfg_addr;
ifp = if_lookup_address_local(&asel->cfg_addr, PIM_AF,
vrf->vrf_id);
break;
case CAND_ADDR_IFACE:
ifp = if_lookup_by_name_vrf(asel->cfg_ifname, vrf);
if (ifp)
new_addr = if_highest_addr(PIMADDR_ANY, ifp);
break;
case CAND_ADDR_ANY:
is_any = true;
/* fallthru */
case CAND_ADDR_LO:
FOR_ALL_INTERFACES (vrf, ifp) {
if (!if_is_up(ifp))
continue;
if (is_any || if_is_loopback(ifp) || if_is_vrf(ifp))
new_addr = if_highest_addr(new_addr, ifp);
}
break;
}
if (ifp && !if_is_up(ifp))
goto out_disable;
if (pim_addr_is_any(new_addr))
goto out_disable;
/* nothing changed re. address (don't care about interface changes) */
if (asel->run && !pim_addr_cmp(asel->run_addr, new_addr))
return !prev_run;
asel->run = true;
asel->run_addr = new_addr;
return true;
out_disable:
asel->run = false;
asel->run_addr = PIMADDR_ANY;
return prev_run;
}
static void pim_cand_rp_adv_stop_maybe(struct bsm_scope *scope)
{
/* actual check whether stop should be sent - covers address
* changes as well as run_addr = 0.0.0.0 (C-RP shutdown)
*/
if (pim_addr_is_any(scope->cand_rp_prev_addr) ||
!pim_addr_cmp(scope->cand_rp_prev_addr,
scope->cand_rp_addrsel.run_addr))
return;
switch (scope->state) {
case ACCEPT_PREFERRED:
/* TBD: BSR_ELECTED */
break;
case NO_INFO:
case ACCEPT_ANY:
default:
return;
}
if (PIM_DEBUG_BSM)
zlog_debug("Candidate-RP (-, %pPA) deregistering self to %pPA",
&scope->cand_rp_prev_addr, &scope->current_bsr);
struct cand_rp_msg *msg;
uint8_t buf[PIM_MSG_HEADER_LEN + sizeof(*msg) + sizeof(pim_encoded_group)];
msg = (struct cand_rp_msg *)(&buf[PIM_MSG_HEADER_LEN]);
msg->prefix_cnt = 0;
msg->rp_prio = 255;
msg->rp_holdtime = 0;
msg->rp_addr.family = PIM_IANA_AFI;
msg->rp_addr.reserved = 0;
msg->rp_addr.addr = scope->cand_rp_prev_addr;
pim_msg_build_header(PIMADDR_ANY, scope->current_bsr, buf, sizeof(buf),
PIM_MSG_TYPE_CANDIDATE, false);
if (pim_msg_send(scope->unicast_sock, PIMADDR_ANY, scope->current_bsr,
buf, sizeof(buf), NULL)) {
zlog_warn("failed to send Cand-RP message: %m");
}
scope->cand_rp_prev_addr = PIMADDR_ANY;
}
static void pim_cand_rp_adv(struct event *t)
{
struct bsm_scope *scope = EVENT_ARG(t);
int next_msec;
pim_cand_rp_adv_stop_maybe(scope);
if (!scope->cand_rp_addrsel.run) {
scope->cand_rp_adv_trigger = 0;
return;
}
switch (scope->state) {
case ACCEPT_PREFERRED:
/* TBD: BSR_ELECTED */
break;
case ACCEPT_ANY:
case NO_INFO:
default:
/* state change will retrigger */
scope->cand_rp_adv_trigger = 0;
zlog_warn("Candidate-RP advertisement not sent in state %d",
scope->state);
return;
}
if (PIM_DEBUG_BSM)
zlog_debug("Candidate-RP (%u, %pPA) advertising %zu groups to %pPA",
scope->cand_rp_prio, &scope->cand_rp_addrsel.run_addr,
cand_rp_groups_count(scope->cand_rp_groups),
&scope->current_bsr);
struct cand_rp_group *grp;
struct cand_rp_msg *msg;
uint8_t buf[PIM_MSG_HEADER_LEN + sizeof(*msg) +
sizeof(pim_encoded_group) *
cand_rp_groups_count(scope->cand_rp_groups)];
size_t i = 0;
msg = (struct cand_rp_msg *)(&buf[PIM_MSG_HEADER_LEN]);
msg->prefix_cnt = cand_rp_groups_count(scope->cand_rp_groups);
msg->rp_prio = scope->cand_rp_prio;
msg->rp_holdtime =
htons(MAX(151, (scope->cand_rp_interval * 5 + 1) / 2));
msg->rp_addr.family = PIM_IANA_AFI;
msg->rp_addr.reserved = 0;
msg->rp_addr.addr = scope->cand_rp_addrsel.run_addr;
frr_each (cand_rp_groups, scope->cand_rp_groups, grp) {
memset(&msg->groups[i], 0, sizeof(msg->groups[i]));
msg->groups[i].family = PIM_IANA_AFI;
msg->groups[i].mask = grp->p.prefixlen;
msg->groups[i].addr = grp->p.prefix;
i++;
}
scope->cand_rp_prev_addr = scope->cand_rp_addrsel.run_addr;
pim_msg_build_header(scope->cand_rp_addrsel.run_addr, scope->current_bsr,
buf, sizeof(buf), PIM_MSG_TYPE_CANDIDATE, false);
if (pim_msg_send(scope->unicast_sock, scope->cand_rp_addrsel.run_addr,
scope->current_bsr, buf, sizeof(buf), NULL)) {
zlog_warn("failed to send Cand-RP message: %m");
}
/* -1s...+1s */
next_msec = (frr_weak_random() & 2047) - 1024;
if (scope->cand_rp_adv_trigger) {
scope->cand_rp_adv_trigger--;
next_msec += 2000;
} else
next_msec += scope->cand_rp_interval * 1000;
event_add_timer_msec(router->master, pim_cand_rp_adv, scope, next_msec,
&scope->cand_rp_adv_timer);
}
void pim_cand_rp_trigger(struct bsm_scope *scope)
{
if (scope->cand_rp_adv_trigger && scope->cand_rp_addrsel.run) {
scope->cand_rp_adv_trigger = PIM_CRP_ADV_TRIGCOUNT;
/* already scheduled to send triggered advertisements, don't
* reschedule so burst changes don't result in an advertisement
* burst
*/
return;
}
EVENT_OFF(scope->cand_rp_adv_timer);
if (!scope->cand_rp_addrsel.run)
return;
scope->cand_rp_adv_trigger = PIM_CRP_ADV_TRIGCOUNT;
struct event t;
t.arg = scope;
pim_cand_rp_adv(&t);
}
void pim_cand_rp_apply(struct bsm_scope *scope)
{
if (!cand_addrsel_update(&scope->cand_rp_addrsel, scope->pim->vrf))
return;
if (!scope->cand_rp_addrsel.run) {
if (PIM_DEBUG_BSM)
zlog_debug("Candidate RP ceasing operation");
cand_addrsel_clear(&scope->cand_rp_addrsel);
EVENT_OFF(scope->cand_rp_adv_timer);
pim_cand_rp_adv_stop_maybe(scope);
scope->cand_rp_adv_trigger = 0;
return;
}
if (PIM_DEBUG_BSM)
zlog_debug("Candidate RP: %pPA, priority %u",
&scope->cand_rp_addrsel.run_addr,
scope->cand_rp_prio);
pim_cand_rp_trigger(scope);
}
void pim_cand_rp_grp_add(struct bsm_scope *scope, const prefix_pim *p)
{
struct cand_rp_group *grp, ref;
ref.p = *p;
grp = cand_rp_groups_find(scope->cand_rp_groups, &ref);
if (grp)
return;
grp = XCALLOC(MTYPE_PIM_CAND_RP_GRP, sizeof(*grp));
grp->p = *p;
cand_rp_groups_add(scope->cand_rp_groups, grp);
pim_cand_rp_trigger(scope);
}
void pim_cand_rp_grp_del(struct bsm_scope *scope, const prefix_pim *p)
{
struct cand_rp_group *grp, ref;
ref.p = *p;
grp = cand_rp_groups_find(scope->cand_rp_groups, &ref);
if (!grp)
return;
cand_rp_groups_del(scope->cand_rp_groups, grp);
XFREE(MTYPE_PIM_CAND_RP_GRP, grp);
pim_cand_rp_trigger(scope);
}
static struct event *t_cand_addrs_reapply;
static void pim_cand_addrs_reapply(struct event *t)
{
struct vrf *vrf;
RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
struct pim_instance *pi = vrf->info;
if (!pi)
continue;
/* this calls cand_addrsel_update() and applies changes */
pim_cand_rp_apply(&pi->global_scope);
}
}
void pim_cand_addrs_changed(void)
{
EVENT_OFF(t_cand_addrs_reapply);
event_add_timer_msec(router->master, pim_cand_addrs_reapply, NULL, 1,
&t_cand_addrs_reapply);
}
static void cand_addrsel_config_write(struct vty *vty,
struct cand_addrsel *addrsel)
{
switch (addrsel->cfg_mode) {
case CAND_ADDR_LO:
break;
case CAND_ADDR_ANY:
vty_out(vty, " source any");
break;
case CAND_ADDR_IFACE:
vty_out(vty, " source interface %s", addrsel->cfg_ifname);
break;
case CAND_ADDR_EXPLICIT:
vty_out(vty, " source address %pPA", &addrsel->cfg_addr);
break;
}
}
int pim_cand_config_write(struct pim_instance *pim, struct vty *vty)
{
struct bsm_scope *scope = &pim->global_scope;
int ret = 0;
if (scope->cand_rp_addrsel.cfg_enable) {
vty_out(vty, " bsr candidate-rp");
if (scope->cand_rp_prio != 192)
vty_out(vty, " priority %u", scope->cand_rp_prio);
if (scope->cand_rp_interval != PIM_CRP_ADV_INTERVAL)
vty_out(vty, " interval %u", scope->cand_rp_interval);
cand_addrsel_config_write(vty, &scope->cand_rp_addrsel);
vty_out(vty, "\n");
ret++;
struct cand_rp_group *group;
frr_each (cand_rp_groups, scope->cand_rp_groups, group) {
vty_out(vty, " bsr candidate-rp group %pFX\n",
&group->p);
ret++;
}
}
return ret;
}
void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc)
{
/* stub for Candidate-RP */

View file

@ -21,6 +21,10 @@
#define PIM_BS_TIME 60 /* RFC 5059 - Sec 5 */
#define PIM_BSR_DEFAULT_TIMEOUT 130 /* RFC 5059 - Sec 5 */
#define PIM_CRP_ADV_TRIGCOUNT 3
#define PIM_CRP_ADV_INTERVAL 60
#define PIM_CRP_HOLDTIME 150
/* These structures are only encoded IPv4 specific */
#define PIM_BSM_HDR_LEN sizeof(struct bsm_hdr)
#define PIM_BSM_GRP_LEN sizeof(struct bsmmsg_grpinfo)
@ -40,7 +44,31 @@ enum ncbsr_state {
ACCEPT_PREFERRED
};
enum cand_addr {
CAND_ADDR_LO = 0,
CAND_ADDR_ANY,
CAND_ADDR_IFACE,
CAND_ADDR_EXPLICIT,
};
/* used separately for Cand-RP, and (TBD) Cand-BSR */
struct cand_addrsel {
bool cfg_enable;
enum cand_addr cfg_mode : 8;
/* only valid for mode==CAND_ADDR_IFACE */
char cfg_ifname[IFNAMSIZ];
/* only valid for mode==CAND_ADDR_EXPLICIT */
pim_addr cfg_addr;
/* running state updated based on above on zebra events */
pim_addr run_addr;
bool run;
};
PREDECL_DLIST(bsm_frags);
PREDECL_RBTREE_UNIQ(cand_rp_groups);
/* BSM scope - bsm processing is per scope */
struct bsm_scope {
@ -60,6 +88,27 @@ struct bsm_scope {
struct route_table *bsrp_table; /* group2rp mapping rcvd from BSR */
struct event *bs_timer; /* Boot strap timer */
/* Candidate RP config */
struct cand_addrsel cand_rp_addrsel;
uint8_t cand_rp_prio;
unsigned int cand_rp_interval; /* default: PIM_CRP_ADV_INTERVAL=60 */
/* holdtime is not configurable, always 2.5 * interval. */
struct cand_rp_groups_head cand_rp_groups[1];
/* Candidate RP state */
int unicast_sock;
struct event *cand_rp_adv_timer;
unsigned int cand_rp_adv_trigger; /* # trigg. C-RP-Adv left to send */
/* for sending holdtime=0 zap */
pim_addr cand_rp_prev_addr;
};
struct cand_rp_group {
struct cand_rp_groups_item item;
prefix_pim p;
};
/* BSM packet (= fragment) - this is stored as list in bsm_frags inside scope
@ -200,6 +249,14 @@ struct bsmmsg_rpinfo {
uint8_t reserved;
} __attribute__((packed));
struct cand_rp_msg {
uint8_t prefix_cnt;
uint8_t rp_prio;
uint16_t rp_holdtime;
pim_encoded_unicast rp_addr;
pim_encoded_group groups[0];
} __attribute__((packed));
/* API */
void pim_bsm_proc_init(struct pim_instance *pim);
void pim_bsm_proc_free(struct pim_instance *pim);
@ -210,4 +267,14 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
bool pim_bsm_new_nbr_fwd(struct pim_neighbor *neigh, struct interface *ifp);
struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope,
struct prefix *grp);
void pim_cand_rp_apply(struct bsm_scope *scope);
void pim_cand_rp_trigger(struct bsm_scope *scope);
void pim_cand_rp_grp_add(struct bsm_scope *scope, const prefix_pim *p);
void pim_cand_rp_grp_del(struct bsm_scope *scope, const prefix_pim *p);
void pim_cand_addrs_changed(void);
int pim_cand_config_write(struct pim_instance *pim, struct vty *vty);
#endif

View file

@ -2877,6 +2877,66 @@ DEFPY (show_ip_pim_bsrp,
return pim_show_group_rp_mappings_info_helper(vrf, vty, !!json);
}
DEFUN (show_ip_pim_cand_rp,
show_ip_pim_cand_rp_cmd,
"show ip pim candidate-rp [vrf NAME] [json]",
SHOW_STR
IP_STR
PIM_STR
"PIM Candidate RP state\n"
VRF_CMD_HELP_STR
JSON_STR)
{
bool uj = use_json(argc, argv);
int idx = 2;
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj);
struct pim_instance *pim;
struct bsm_scope *scope;
json_object *json = NULL;
if (!vrf || !vrf->info)
return CMD_WARNING;
pim = (struct pim_instance *)vrf->info;
scope = &pim->global_scope;
if (!scope->cand_rp_addrsel.run) {
if (uj)
vty_out(vty, "{}\n");
else
vty_out(vty,
"This router is not currently operating as Candidate RP\n");
return CMD_SUCCESS;
}
if (uj) {
char buf[INET_ADDRSTRLEN];
json = json_object_new_object();
inet_ntop(AF_INET, &scope->cand_rp_addrsel.run_addr, buf,
sizeof(buf));
json_object_string_add(json, "address", buf);
json_object_int_add(json, "priority", scope->cand_rp_prio);
json_object_int_add(json, "nextAdvertisementMsec",
pim_time_timer_remain_msec(
scope->cand_rp_adv_timer));
vty_out(vty, "%s\n",
json_object_to_json_string_ext(json,
JSON_C_TO_STRING_PRETTY));
json_object_free(json);
return CMD_SUCCESS;
}
vty_out(vty, "Candidate-RP\nAddress: %pI4\nPriority: %u\n\n",
&scope->cand_rp_addrsel.run_addr, scope->cand_rp_prio);
vty_out(vty, "Next adv.: %lu msec\n",
pim_time_timer_remain_msec(scope->cand_rp_adv_timer));
return CMD_SUCCESS;
}
DEFPY (show_ip_pim_statistics,
show_ip_pim_statistics_cmd,
"show ip pim [vrf NAME] statistics [interface WORD$word] [json$json]",
@ -4376,6 +4436,41 @@ DEFPY_ATTR(no_ip_pim_rp_prefix_list,
return ret;
}
DEFPY (pim_bsr_candidate_rp,
pim_bsr_candidate_rp_cmd,
"[no] bsr candidate-rp [{priority (0-255)|interval (1-4294967295)|source <address A.B.C.D|interface IFNAME|loopback$loopback|any$any>}]",
NO_STR
BSR_STR
"Make this router a Candidate RP\n"
"RP Priority (lower wins)\n"
"RP Priority (lower wins)\n"
"Advertisement interval (seconds)\n"
"Advertisement interval (seconds)\n"
"Specify IP address for RP operation\n"
"Local address to use\n"
"Local address to use\n"
"Interface to pick address from\n"
"Interface to pick address from\n"
"Pick highest loopback address (default)\n"
"Pick highest address from any interface\n")
{
return pim_process_bsr_candidate_cmd(vty, FRR_PIM_CAND_RP_XPATH, no,
true, any, ifname, address_str,
priority_str, interval_str);
}
DEFPY (pim_bsr_candidate_rp_group,
pim_bsr_candidate_rp_group_cmd,
"[no] bsr candidate-rp group A.B.C.D/M",
NO_STR
BSR_STR
"Make this router a Candidate RP\n"
"Configure groups to become candidate RP for\n"
"Multicast group prefix\n")
{
return pim_process_bsr_crp_grp_cmd(vty, group_str, no);
}
DEFPY (pim_ssm_prefix_list,
pim_ssm_prefix_list_cmd,
"ssm prefix-list PREFIXLIST4_NAME$plist",
@ -8550,6 +8645,9 @@ void pim_cmd_init(void)
install_element(PIM_NODE, &no_pim_msdp_mesh_group_source_cmd);
install_element(PIM_NODE, &no_pim_msdp_mesh_group_cmd);
install_element(PIM_NODE, &pim_bsr_candidate_rp_cmd);
install_element(PIM_NODE, &pim_bsr_candidate_rp_group_cmd);
install_element(INTERFACE_NODE, &interface_ip_igmp_cmd);
install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd);
install_element(INTERFACE_NODE, &interface_ip_igmp_join_cmd);
@ -8670,6 +8768,7 @@ void pim_cmd_init(void)
install_element(VIEW_NODE, &show_ip_pim_nexthop_lookup_cmd);
install_element(VIEW_NODE, &show_ip_pim_bsrp_cmd);
install_element(VIEW_NODE, &show_ip_pim_bsm_db_cmd);
install_element(VIEW_NODE, &show_ip_pim_cand_rp_cmd);
install_element(VIEW_NODE, &show_ip_pim_statistics_cmd);
install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd);
install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd);

View file

@ -24,6 +24,7 @@
#define IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR "IGMP max query response value (deciseconds)\n"
#define IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR "IGMP last member query interval\n"
#define IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR "IGMP last member query count\n"
#define BSR_STR "Bootstrap Router configuration\n"
#define DEBUG_IGMP_STR "IGMP protocol activity\n"
#define DEBUG_IGMP_EVENTS_STR "IGMP protocol events\n"
#define DEBUG_IGMP_PACKETS_STR "IGMP protocol packets\n"

View file

@ -3389,6 +3389,55 @@ int pim_process_no_unicast_bsm_cmd(struct vty *vty)
FRR_PIM_AF_XPATH_VAL);
}
/* helper for bsr/rp candidate commands*/
int pim_process_bsr_candidate_cmd(struct vty *vty, const char *cand_str,
bool no, bool is_rp, bool any,
const char *ifname, const char *addr,
const char *prio, const char *interval)
{
if (no)
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
else {
nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
if (any)
nb_cli_enqueue_change(vty, "./if-any", NB_OP_CREATE,
NULL);
else if (ifname)
nb_cli_enqueue_change(vty, "./interface", NB_OP_CREATE,
ifname);
else if (addr)
nb_cli_enqueue_change(vty, "./address", NB_OP_CREATE,
addr);
else
nb_cli_enqueue_change(vty, "./if-loopback",
NB_OP_CREATE, NULL);
if (prio)
nb_cli_enqueue_change(vty,
(is_rp ? "./rp-priority"
: "./bsr-priority"),
NB_OP_MODIFY, prio);
/* only valid for rp candidate case*/
if (is_rp && interval)
nb_cli_enqueue_change(vty, "./advertisement-interval",
NB_OP_MODIFY, interval);
}
return nb_cli_apply_changes(vty, "%s", cand_str);
}
int pim_process_bsr_crp_grp_cmd(struct vty *vty, const char *grp, bool no)
{
if (no)
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, grp);
else
nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, grp);
return nb_cli_apply_changes(vty, "%s/group-list", FRR_PIM_CAND_RP_XPATH);
}
static void show_scan_oil_stats(struct pim_instance *pim, struct vty *vty,
time_t now)
{

View file

@ -53,6 +53,13 @@ int pim_process_bsm_cmd(struct vty *vty);
int pim_process_no_bsm_cmd(struct vty *vty);
int pim_process_unicast_bsm_cmd(struct vty *vty);
int pim_process_no_unicast_bsm_cmd(struct vty *vty);
int pim_process_bsr_candidate_cmd(struct vty *vty, const char *cand_str,
bool no, bool is_rp, bool any,
const char *ifname, const char *addr,
const char *prio, const char *interval);
int pim_process_bsr_crp_grp_cmd(struct vty *vty, const char *grp, bool no);
void json_object_pim_upstream_add(json_object *json, struct pim_upstream *up);
void pim_show_rpf(struct pim_instance *pim, struct vty *vty, json_object *json);
void pim_show_neighbors_secondary(struct pim_instance *pim, struct vty *vty);

View file

@ -1844,6 +1844,8 @@ static int pim_ifp_up(struct interface *ifp)
}
}
}
pim_cand_addrs_changed();
return 0;
}
@ -1880,6 +1882,7 @@ static int pim_ifp_down(struct interface *ifp)
pim_ifstat_reset(ifp);
}
pim_cand_addrs_changed();
return 0;
}

View file

@ -68,6 +68,7 @@ static const struct frr_yang_module_info *const pimd_yang_modules[] = {
&frr_routing_info,
&frr_pim_info,
&frr_pim_rp_info,
&frr_pim_candidate_info,
&frr_gmp_info,
};

View file

@ -385,6 +385,70 @@ const struct frr_yang_module_info frr_pim_rp_info = {
}
};
const struct frr_yang_module_info frr_pim_candidate_info = {
.name = "frr-pim-candidate",
.nodes = {
/* Candidate-RP */
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp",
.cbs = {
.create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_create,
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_destroy,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/rp-priority",
.cbs = {
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_priority_modify,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/advertisement-interval",
.cbs = {
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_adv_interval_modify,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/group-list",
.cbs = {
.create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_create,
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_destroy,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/address",
.cbs = {
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_modify,
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/interface",
.cbs = {
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_modify,
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/if-loopback",
.cbs = {
.create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_create,
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/if-any",
.cbs = {
.create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_create,
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy,
}
},
{
.xpath = NULL,
},
}
};
/* clang-format off */
const struct frr_yang_module_info frr_gmp_info = {
.name = "frr-gmp",

View file

@ -9,6 +9,7 @@
extern const struct frr_yang_module_info frr_pim_info;
extern const struct frr_yang_module_info frr_pim_rp_info;
extern const struct frr_yang_module_info frr_pim_candidate_info;
extern const struct frr_yang_module_info frr_gmp_info;
/* frr-pim prototypes*/
@ -159,6 +160,26 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_destroy(
struct nb_cb_destroy_args *args);
/* frr-candidate */
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_create(
struct nb_cb_create_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_destroy(
struct nb_cb_destroy_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_priority_modify(
struct nb_cb_modify_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_adv_interval_modify(
struct nb_cb_modify_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_create(
struct nb_cb_create_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_destroy(
struct nb_cb_destroy_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_create(
struct nb_cb_create_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_modify(
struct nb_cb_modify_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy(
struct nb_cb_destroy_args *args);
/* frr-gmp prototypes*/
int lib_interface_gmp_address_family_create(
struct nb_cb_create_args *args);
@ -219,6 +240,8 @@ int routing_control_plane_protocols_name_validate(
"mroute[source-addr='%s'][group-addr='%s']"
#define FRR_PIM_STATIC_RP_XPATH \
"frr-pim-rp:rp/static-rp/rp-list[rp-address='%s']"
#define FRR_PIM_CAND_RP_XPATH \
"./frr-pim-candidate:candidate-rp"
#define FRR_GMP_INTERFACE_XPATH \
"./frr-gmp:gmp/address-family[address-family='%s']"
#define FRR_GMP_ENABLE_XPATH \

View file

@ -2671,6 +2671,245 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp
return NB_OK;
}
static void yang_addrsel(struct cand_addrsel *addrsel,
const struct lyd_node *node)
{
memset(addrsel->cfg_ifname, 0, sizeof(addrsel->cfg_ifname));
addrsel->cfg_addr = PIMADDR_ANY;
if (yang_dnode_exists(node, "if-any")) {
addrsel->cfg_mode = CAND_ADDR_ANY;
} else if (yang_dnode_exists(node, "address")) {
addrsel->cfg_mode = CAND_ADDR_EXPLICIT;
yang_dnode_get_pimaddr(&addrsel->cfg_addr, node, "address");
} else if (yang_dnode_exists(node, "interface")) {
addrsel->cfg_mode = CAND_ADDR_IFACE;
strlcpy(addrsel->cfg_ifname,
yang_dnode_get_string(node, "interface"),
sizeof(addrsel->cfg_ifname));
} else if (yang_dnode_exists(node, "if-loopback")) {
addrsel->cfg_mode = CAND_ADDR_LO;
}
}
static int candidate_rp_addrsel(struct bsm_scope *scope,
const struct lyd_node *cand_rp_node)
{
yang_addrsel(&scope->cand_rp_addrsel, cand_rp_node);
pim_cand_rp_apply(scope);
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_create(
struct nb_cb_create_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
struct bsm_scope *scope;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
vrf = nb_running_get_entry(args->dnode, NULL, true);
pim = vrf->info;
scope = &pim->global_scope;
scope->cand_rp_addrsel.cfg_enable = true;
scope->cand_rp_prio = yang_dnode_get_uint8(args->dnode,
"rp-priority");
scope->cand_rp_interval =
yang_dnode_get_uint32(args->dnode,
"advertisement-interval");
candidate_rp_addrsel(scope, args->dnode);
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_destroy(
struct nb_cb_destroy_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
struct bsm_scope *scope;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
vrf = nb_running_get_entry(args->dnode, NULL, true);
pim = vrf->info;
scope = &pim->global_scope;
scope->cand_rp_addrsel.cfg_enable = false;
pim_cand_rp_apply(scope);
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_priority_modify(
struct nb_cb_modify_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
struct bsm_scope *scope;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
vrf = nb_running_get_entry(args->dnode, NULL, true);
pim = vrf->info;
scope = &pim->global_scope;
scope->cand_rp_prio = yang_dnode_get_uint8(args->dnode, NULL);
pim_cand_rp_trigger(scope);
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_adv_interval_modify(
struct nb_cb_modify_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
struct bsm_scope *scope;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
vrf = nb_running_get_entry(args->dnode, NULL, true);
pim = vrf->info;
scope = &pim->global_scope;
scope->cand_rp_interval = yang_dnode_get_uint32(args->dnode,
NULL);
pim_cand_rp_trigger(scope);
break;
}
return NB_OK;
}
#if PIM_IPV == 4
#define yang_dnode_get_pim_p yang_dnode_get_ipv4p
#else
#define yang_dnode_get_pim_p yang_dnode_get_ipv6p
#endif
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_create(
struct nb_cb_create_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
struct bsm_scope *scope;
prefix_pim p;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
vrf = nb_running_get_entry(args->dnode, NULL, true);
pim = vrf->info;
scope = &pim->global_scope;
yang_dnode_get_pim_p(&p, args->dnode, ".");
pim_cand_rp_grp_add(scope, &p);
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_destroy(
struct nb_cb_destroy_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
struct bsm_scope *scope;
prefix_pim p;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
vrf = nb_running_get_entry(args->dnode, NULL, true);
pim = vrf->info;
scope = &pim->global_scope;
yang_dnode_get_pim_p(&p, args->dnode, ".");
pim_cand_rp_grp_del(scope, &p);
break;
}
return NB_OK;
}
static int candidate_rp_addrsel_common(enum nb_event event,
const struct lyd_node *dnode)
{
struct vrf *vrf;
struct pim_instance *pim;
struct bsm_scope *scope;
dnode = lyd_parent(dnode);
switch (event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
vrf = nb_running_get_entry(dnode, NULL, true);
pim = vrf->info;
scope = &pim->global_scope;
candidate_rp_addrsel(scope, dnode);
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_create(
struct nb_cb_create_args *args)
{
return candidate_rp_addrsel_common(args->event, args->dnode);
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_modify(
struct nb_cb_modify_args *args)
{
return candidate_rp_addrsel_common(args->event, args->dnode);
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy(
struct nb_cb_destroy_args *args)
{
/* nothing to do here - we'll get a create or modify event too */
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family
*/

View file

@ -182,6 +182,7 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty)
}
writes += pim_rp_config_write(pim, vty);
writes += pim_cand_config_write(pim, vty);
if (pim->vrf->vrf_id == VRF_DEFAULT) {
if (router->register_suppress_time

View file

@ -157,6 +157,8 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
pim_if_addr_add_all(ifp);
}
}
pim_cand_addrs_changed();
return 0;
}
@ -205,6 +207,8 @@ static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
}
connected_free(&c);
pim_cand_addrs_changed();
return 0;
}

View file

@ -76,6 +76,7 @@ pimd_pimd_SOURCES = \
nodist_pimd_pimd_SOURCES = \
yang/frr-pim.yang.c \
yang/frr-pim-rp.yang.c \
yang/frr-pim-candidate.yang.c \
yang/frr-gmp.yang.c \
# end
@ -89,6 +90,7 @@ pimd_pim6d_SOURCES = \
nodist_pimd_pim6d_SOURCES = \
yang/frr-pim.yang.c \
yang/frr-pim-rp.yang.c \
yang/frr-pim-candidate.yang.c \
yang/frr-gmp.yang.c \
# end

136
yang/frr-pim-candidate.yang Normal file
View file

@ -0,0 +1,136 @@
module frr-pim-candidate {
yang-version "1.1";
namespace "http://frrouting.org/yang/pim-candidate";
prefix frr-pim-candidate;
import frr-interface {
prefix frr-interface;
}
import ietf-inet-types {
prefix "inet";
}
import frr-routing {
prefix "frr-rt";
}
import frr-pim {
prefix "frr-pim";
}
import frr-route-types {
prefix frr-route-types;
}
organization
"FRRouting";
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
description
"The module defines a collection of YANG definitions common for
all PIM (Protocol Independent Multicast) Candidate RP & BSR
(Rendezvous Point & Bootstrap Router) operation.
Copyright 2020 FRRouting
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2021-05-04 {
description
"Initial revision.";
reference
"TBD";
}
/*
* Groupings
*/
grouping candidate-rp-container {
description
"Grouping of Candidate RP settings.";
container candidate-rp {
presence
"Enable router to be a Candidate RP.";
description
"Candidate RP settings";
leaf rp-priority {
type uint8;
default "192";
description
"RP priority for this router, lower values win.";
}
leaf advertisement-interval {
type uint32 {
range 1..4294967295;
}
default "60";
description
"RP advertisement interval (seconds). Holdtime is 2.5 times this.";
}
leaf-list group-list {
type frr-route-types:ip-multicast-group-prefix;
description
"List of multicast group address.";
}
choice source-address-or-interface {
description "IP address to use for RP operation";
default if-loopback;
leaf address {
type inet:ip-address;
}
leaf interface {
type frr-interface:interface-ref;
}
leaf if-loopback {
type empty;
}
leaf if-any {
type empty;
}
}
}
}
/*
* Configuration data nodes
*/
augment "/frr-rt:routing/frr-rt:control-plane-protocols/"
+ "frr-rt:control-plane-protocol/frr-pim:pim/"
+ "frr-pim:address-family" {
description "PIM Candidate RP augmentation.";
uses candidate-rp-container;
}
}

View file

@ -80,6 +80,7 @@ if PIMD
dist_yangmodels_DATA += yang/frr-gmp.yang
dist_yangmodels_DATA += yang/frr-pim.yang
dist_yangmodels_DATA += yang/frr-pim-rp.yang
dist_yangmodels_DATA += yang/frr-pim-candidate.yang
endif
if BGPD