mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
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:
parent
fbd743197a
commit
a110bb7798
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
427
pimd/pim_bsm.c
427
pimd/pim_bsm.c
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
136
yang/frr-pim-candidate.yang
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue