mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
pimd: Candidate-BSR support
Signed-off-by: David Lamparter <equinox@opensourcerouting.org> Signed-off-by: Jafar Al-Gharaibeh <jafar@atcorp.com>
This commit is contained in:
parent
a110bb7798
commit
2d0812373c
|
@ -1259,6 +1259,27 @@ DEFPY (no_ipv6_pim_ucast_bsm,
|
||||||
return pim_process_no_unicast_bsm_cmd(vty);
|
return pim_process_no_unicast_bsm_cmd(vty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFPY (pim6_bsr_candidate_bsr,
|
||||||
|
pim6_bsr_candidate_bsr_cmd,
|
||||||
|
"[no] bsr candidate-bsr [{priority (0-255)|source <address X:X::X:X|interface IFNAME|loopback$loopback|any$any>}]",
|
||||||
|
NO_STR
|
||||||
|
BSR_STR
|
||||||
|
"Make this router a Candidate BSR\n"
|
||||||
|
"BSR Priority (higher wins)\n"
|
||||||
|
"BSR Priority (higher wins)\n"
|
||||||
|
"Specify IP address for BSR 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_BSR_XPATH, no,
|
||||||
|
false, any, ifname, address_str,
|
||||||
|
priority_str, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
DEFPY (pim6_bsr_candidate_rp,
|
DEFPY (pim6_bsr_candidate_rp,
|
||||||
pim6_bsr_candidate_rp_cmd,
|
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] bsr candidate-rp [{priority (0-255)|interval (1-4294967295)|source <address X:X::X:X|interface IFNAME|loopback$loopback|any$any>}]",
|
||||||
|
@ -1809,6 +1830,51 @@ DEFPY (show_ipv6_pim_cand_rp,
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFPY (show_ipv6_pim_bsr_rpdb,
|
||||||
|
show_ipv6_pim_bsr_rpdb_cmd,
|
||||||
|
"show ipv6 pim bsr candidate-rps [vrf VRF_NAME] [json$uj]",
|
||||||
|
SHOW_STR
|
||||||
|
IPV6_STR
|
||||||
|
PIM_STR
|
||||||
|
"boot-strap router information\n"
|
||||||
|
"Candidate RPs\n"
|
||||||
|
VRF_CMD_HELP_STR
|
||||||
|
JSON_STR)
|
||||||
|
{
|
||||||
|
struct vrf *vrf = pim_cmd_lookup(vty, vrf_name);
|
||||||
|
|
||||||
|
if (!vrf || !vrf->info)
|
||||||
|
return CMD_WARNING;
|
||||||
|
|
||||||
|
struct pim_instance *pim = vrf->info;
|
||||||
|
struct bsm_scope *scope = &pim->global_scope;
|
||||||
|
|
||||||
|
return pim_crp_db_show(vty, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY (show_ipv6_pim_bsr_groups,
|
||||||
|
show_ipv6_pim_bsr_groups_cmd,
|
||||||
|
"show ipv6 pim bsr groups [vrf VRF_NAME] [json$uj]",
|
||||||
|
SHOW_STR
|
||||||
|
IPV6_STR
|
||||||
|
PIM_STR
|
||||||
|
"boot-strap router information\n"
|
||||||
|
"Candidate RP groups\n"
|
||||||
|
VRF_CMD_HELP_STR
|
||||||
|
JSON_STR)
|
||||||
|
{
|
||||||
|
struct vrf *vrf = pim_cmd_lookup(vty, vrf_name);
|
||||||
|
|
||||||
|
if (!vrf || !vrf->info)
|
||||||
|
return CMD_WARNING;
|
||||||
|
|
||||||
|
struct pim_instance *pim = vrf->info;
|
||||||
|
struct bsm_scope *scope = &pim->global_scope;
|
||||||
|
|
||||||
|
return pim_crp_groups_show(vty, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
DEFPY (show_ipv6_pim_statistics,
|
DEFPY (show_ipv6_pim_statistics,
|
||||||
show_ipv6_pim_statistics_cmd,
|
show_ipv6_pim_statistics_cmd,
|
||||||
"show ipv6 pim [vrf NAME] statistics [interface WORD$word] [json$json]",
|
"show ipv6 pim [vrf NAME] statistics [interface WORD$word] [json$json]",
|
||||||
|
@ -2742,6 +2808,7 @@ void pim_cmd_init(void)
|
||||||
install_element(PIM6_NODE, &no_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_cmd);
|
||||||
install_element(PIM6_NODE, &pim6_bsr_candidate_rp_group_cmd);
|
install_element(PIM6_NODE, &pim6_bsr_candidate_rp_group_cmd);
|
||||||
|
install_element(PIM6_NODE, &pim6_bsr_candidate_bsr_cmd);
|
||||||
|
|
||||||
install_element(CONFIG_NODE, &ipv6_mld_group_watermark_cmd);
|
install_element(CONFIG_NODE, &ipv6_mld_group_watermark_cmd);
|
||||||
install_element(VRF_NODE, &ipv6_mld_group_watermark_cmd);
|
install_element(VRF_NODE, &ipv6_mld_group_watermark_cmd);
|
||||||
|
@ -2798,6 +2865,8 @@ void pim_cmd_init(void)
|
||||||
install_element(VIEW_NODE, &show_ipv6_pim_rpf_vrf_all_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_secondary_cmd);
|
||||||
install_element(VIEW_NODE, &show_ipv6_pim_cand_rp_cmd);
|
install_element(VIEW_NODE, &show_ipv6_pim_cand_rp_cmd);
|
||||||
|
install_element(VIEW_NODE, &show_ipv6_pim_bsr_rpdb_cmd);
|
||||||
|
install_element(VIEW_NODE, &show_ipv6_pim_bsr_groups_cmd);
|
||||||
install_element(VIEW_NODE, &show_ipv6_pim_statistics_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_cmd);
|
||||||
install_element(VIEW_NODE, &show_ipv6_pim_upstream_vrf_all_cmd);
|
install_element(VIEW_NODE, &show_ipv6_pim_upstream_vrf_all_cmd);
|
||||||
|
|
524
pimd/pim_bsm.c
524
pimd/pim_bsm.c
|
@ -10,6 +10,17 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <lib/network.h>
|
||||||
|
#include <lib/iana_afi.h>
|
||||||
|
#include <lib/sockunion.h>
|
||||||
|
#include <lib/sockopt.h>
|
||||||
|
|
||||||
#include "if.h"
|
#include "if.h"
|
||||||
#include "pimd.h"
|
#include "pimd.h"
|
||||||
#include "pim_iface.h"
|
#include "pim_iface.h"
|
||||||
|
@ -25,21 +36,19 @@
|
||||||
#include "pim_util.h"
|
#include "pim_util.h"
|
||||||
#include "pim_sock.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 */
|
/* Functions forward declaration */
|
||||||
static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout);
|
static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout);
|
||||||
static void pim_g2rp_timer_start(struct bsm_rpinfo *bsrp, int hold_time);
|
static void pim_g2rp_timer_start(struct bsm_rpinfo *bsrp, int hold_time);
|
||||||
static inline void pim_g2rp_timer_restart(struct bsm_rpinfo *bsrp,
|
static inline void pim_g2rp_timer_restart(struct bsm_rpinfo *bsrp,
|
||||||
int hold_time);
|
int hold_time);
|
||||||
|
static void pim_bsm_accept_any(struct bsm_scope *scope);
|
||||||
|
static void pim_cand_bsr_trigger(struct bsm_scope *scope, bool verbose);
|
||||||
|
static void pim_cand_bsr_pending(struct bsm_scope *scope);
|
||||||
|
|
||||||
/* Memory Types */
|
/* Memory Types */
|
||||||
DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info");
|
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_BSRP_INFO, "PIM BSR advertised RP info");
|
||||||
DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_FRAG, "PIM BSM fragment");
|
DEFINE_MTYPE(PIMD, PIM_BSM_FRAG, "PIM BSM fragment");
|
||||||
DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet");
|
DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet");
|
||||||
DEFINE_MTYPE_STATIC(PIMD, PIM_CAND_RP_GRP, "PIM Candidate RP group");
|
DEFINE_MTYPE_STATIC(PIMD, PIM_CAND_RP_GRP, "PIM Candidate RP group");
|
||||||
|
|
||||||
|
@ -106,7 +115,7 @@ static void pim_bsm_frag_free(struct bsm_frag *bsfrag)
|
||||||
XFREE(MTYPE_PIM_BSM_FRAG, bsfrag);
|
XFREE(MTYPE_PIM_BSM_FRAG, bsfrag);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pim_bsm_frags_free(struct bsm_scope *scope)
|
void pim_bsm_frags_free(struct bsm_scope *scope)
|
||||||
{
|
{
|
||||||
struct bsm_frag *bsfrag;
|
struct bsm_frag *bsfrag;
|
||||||
|
|
||||||
|
@ -156,12 +165,12 @@ static struct bsgrp_node *pim_bsm_new_bsgrp_node(struct route_table *rt,
|
||||||
return bsgrp;
|
return bsgrp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* BS timer for NO_INFO, ACCEPT_ANY & ACCEPT_PREFERRED.
|
||||||
|
* Candidate BSR handling is separate further below
|
||||||
|
*/
|
||||||
static void pim_on_bs_timer(struct event *t)
|
static void pim_on_bs_timer(struct event *t)
|
||||||
{
|
{
|
||||||
struct route_node *rn;
|
|
||||||
struct bsm_scope *scope;
|
struct bsm_scope *scope;
|
||||||
struct bsgrp_node *bsgrp_node;
|
|
||||||
struct bsm_rpinfo *bsrp;
|
|
||||||
|
|
||||||
scope = EVENT_ARG(t);
|
scope = EVENT_ARG(t);
|
||||||
EVENT_OFF(scope->bs_timer);
|
EVENT_OFF(scope->bs_timer);
|
||||||
|
@ -170,7 +179,20 @@ static void pim_on_bs_timer(struct event *t)
|
||||||
zlog_debug("%s: Bootstrap Timer expired for scope: %d",
|
zlog_debug("%s: Bootstrap Timer expired for scope: %d",
|
||||||
__func__, scope->sz_id);
|
__func__, scope->sz_id);
|
||||||
|
|
||||||
|
assertf(scope->state <= ACCEPT_PREFERRED, "state=%d", scope->state);
|
||||||
pim_nht_bsr_del(scope->pim, scope->current_bsr);
|
pim_nht_bsr_del(scope->pim, scope->current_bsr);
|
||||||
|
|
||||||
|
pim_bsm_accept_any(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pim_bsm_accept_any(struct bsm_scope *scope)
|
||||||
|
{
|
||||||
|
struct route_node *rn;
|
||||||
|
struct bsgrp_node *bsgrp_node;
|
||||||
|
struct bsm_rpinfo *bsrp;
|
||||||
|
|
||||||
|
EVENT_OFF(scope->t_ebsr_regen_bsm);
|
||||||
|
|
||||||
/* Reset scope zone data */
|
/* Reset scope zone data */
|
||||||
scope->state = ACCEPT_ANY;
|
scope->state = ACCEPT_ANY;
|
||||||
scope->current_bsr = PIMADDR_ANY;
|
scope->current_bsr = PIMADDR_ANY;
|
||||||
|
@ -197,6 +219,11 @@ static void pim_on_bs_timer(struct event *t)
|
||||||
pim_bsm_rpinfos_free(bsgrp_node->partial_bsrp_list);
|
pim_bsm_rpinfos_free(bsgrp_node->partial_bsrp_list);
|
||||||
bsgrp_node->pend_rp_cnt = 0;
|
bsgrp_node->pend_rp_cnt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* we're leaving ACCEPT_PREFERRED, which doubles as C-BSR if we're
|
||||||
|
* configured to be a Candidate BSR. See if we're P-BSR now.
|
||||||
|
*/
|
||||||
|
pim_cand_bsr_trigger(scope, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pim_bs_timer_stop(struct bsm_scope *scope)
|
static void pim_bs_timer_stop(struct bsm_scope *scope)
|
||||||
|
@ -228,6 +255,71 @@ static inline void pim_bs_timer_restart(struct bsm_scope *scope, int bs_timeout)
|
||||||
pim_bs_timer_start(scope, bs_timeout);
|
pim_bs_timer_start(scope, bs_timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bsm_unicast_sock_read(struct event *t)
|
||||||
|
{
|
||||||
|
struct bsm_scope *scope = EVENT_ARG(t);
|
||||||
|
struct sockaddr_storage from;
|
||||||
|
struct sockaddr_storage to;
|
||||||
|
socklen_t fromlen = sizeof(from);
|
||||||
|
socklen_t tolen = sizeof(to);
|
||||||
|
ifindex_t ifindex = 0;
|
||||||
|
struct interface *ifp;
|
||||||
|
uint8_t buf[PIM_PIM_BUFSIZE_READ];
|
||||||
|
int len, i;
|
||||||
|
|
||||||
|
event_add_read(router->master, bsm_unicast_sock_read, scope,
|
||||||
|
scope->unicast_sock, &scope->unicast_read);
|
||||||
|
|
||||||
|
for (i = 0; i < router->packet_process; i++) {
|
||||||
|
pim_sgaddr sg;
|
||||||
|
|
||||||
|
len = pim_socket_recvfromto(scope->unicast_sock, buf,
|
||||||
|
sizeof(buf), &from, &fromlen, &to,
|
||||||
|
&tolen, &ifindex);
|
||||||
|
if (len < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (errno == EWOULDBLOCK || errno == EAGAIN)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (PIM_DEBUG_PIM_PACKETS)
|
||||||
|
zlog_debug("Received errno: %d %s", errno,
|
||||||
|
safe_strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if PIM_IPV == 4
|
||||||
|
sg.src = ((struct sockaddr_in *)&from)->sin_addr;
|
||||||
|
sg.grp = ((struct sockaddr_in *)&to)->sin_addr;
|
||||||
|
#else
|
||||||
|
sg.src = ((struct sockaddr_in6 *)&from)->sin6_addr;
|
||||||
|
sg.grp = ((struct sockaddr_in6 *)&to)->sin6_addr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* What? So with vrf's the incoming packet is received
|
||||||
|
* on the vrf interface but recvfromto above returns
|
||||||
|
* the right ifindex, so just use it. We know
|
||||||
|
* it's the right interface because we bind to it
|
||||||
|
*/
|
||||||
|
ifp = if_lookup_by_index(ifindex, scope->pim->vrf->vrf_id);
|
||||||
|
if (!ifp) {
|
||||||
|
zlog_warn("Received incoming PIM packet on unknown ifindex %d",
|
||||||
|
ifindex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fail = pim_pim_packet(ifp, buf, len, sg, false);
|
||||||
|
|
||||||
|
if (fail) {
|
||||||
|
if (PIM_DEBUG_PIM_PACKETS)
|
||||||
|
zlog_debug("%s: pim_pim_packet() return=%d",
|
||||||
|
__func__, fail);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void pim_bsm_proc_init(struct pim_instance *pim)
|
void pim_bsm_proc_init(struct pim_instance *pim)
|
||||||
{
|
{
|
||||||
struct bsm_scope *scope = &pim->global_scope;
|
struct bsm_scope *scope = &pim->global_scope;
|
||||||
|
@ -248,12 +340,19 @@ void pim_bsm_proc_init(struct pim_instance *pim)
|
||||||
scope->unicast_sock = pim_socket_raw(IPPROTO_PIM);
|
scope->unicast_sock = pim_socket_raw(IPPROTO_PIM);
|
||||||
set_nonblocking(scope->unicast_sock);
|
set_nonblocking(scope->unicast_sock);
|
||||||
sockopt_reuseaddr(scope->unicast_sock);
|
sockopt_reuseaddr(scope->unicast_sock);
|
||||||
setsockopt_ipv6_pktinfo(scope->unicast_sock, 1);
|
|
||||||
|
if (setsockopt_ifindex(PIM_AF, scope->unicast_sock, 1) == -1)
|
||||||
|
zlog_warn("%s: Without IP_PKTINFO, src interface can't be determined",
|
||||||
|
__func__);
|
||||||
|
|
||||||
pim_socket_ip_hdr(scope->unicast_sock);
|
pim_socket_ip_hdr(scope->unicast_sock);
|
||||||
|
|
||||||
frr_with_privs (&pimd_privs) {
|
frr_with_privs (&pimd_privs) {
|
||||||
vrf_bind(pim->vrf->vrf_id, scope->unicast_sock, NULL);
|
vrf_bind(pim->vrf->vrf_id, scope->unicast_sock, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event_add_read(router->master, bsm_unicast_sock_read, scope,
|
||||||
|
scope->unicast_sock, &scope->unicast_read);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pim_bsm_proc_free(struct pim_instance *pim)
|
void pim_bsm_proc_free(struct pim_instance *pim)
|
||||||
|
@ -263,6 +362,7 @@ void pim_bsm_proc_free(struct pim_instance *pim)
|
||||||
struct bsgrp_node *bsgrp;
|
struct bsgrp_node *bsgrp;
|
||||||
struct cand_rp_group *crpgrp;
|
struct cand_rp_group *crpgrp;
|
||||||
|
|
||||||
|
EVENT_OFF(scope->unicast_read);
|
||||||
close(scope->unicast_sock);
|
close(scope->unicast_sock);
|
||||||
|
|
||||||
pim_bs_timer_stop(scope);
|
pim_bs_timer_stop(scope);
|
||||||
|
@ -551,9 +651,6 @@ static void pim_instate_pend_list(struct bsgrp_node *bsgrp_node)
|
||||||
static bool is_preferred_bsr(struct pim_instance *pim, pim_addr bsr,
|
static bool is_preferred_bsr(struct pim_instance *pim, pim_addr bsr,
|
||||||
uint32_t bsr_prio)
|
uint32_t bsr_prio)
|
||||||
{
|
{
|
||||||
if (!pim_addr_cmp(bsr, pim->global_scope.current_bsr))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (bsr_prio > pim->global_scope.current_bsr_prio)
|
if (bsr_prio > pim->global_scope.current_bsr_prio)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -562,6 +659,11 @@ static bool is_preferred_bsr(struct pim_instance *pim, pim_addr bsr,
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
} else if (!pim_addr_cmp(bsr, pim->global_scope.current_bsr)) {
|
||||||
|
/* BSR config changed, lower prio now. local BSR check
|
||||||
|
* is handled separately in pim_bsm_update()
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -569,19 +671,52 @@ static bool is_preferred_bsr(struct pim_instance *pim, pim_addr bsr,
|
||||||
static void pim_bsm_update(struct pim_instance *pim, pim_addr bsr,
|
static void pim_bsm_update(struct pim_instance *pim, pim_addr bsr,
|
||||||
uint32_t bsr_prio)
|
uint32_t bsr_prio)
|
||||||
{
|
{
|
||||||
if (pim_addr_cmp(bsr, pim->global_scope.current_bsr)) {
|
|
||||||
pim_nht_bsr_del(pim, pim->global_scope.current_bsr);
|
|
||||||
pim_nht_bsr_add(pim, bsr);
|
|
||||||
|
|
||||||
pim->global_scope.current_bsr = 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_prio = bsr_prio;
|
||||||
pim->global_scope.current_bsr_last_ts = pim_time_monotonic_sec();
|
pim->global_scope.current_bsr_last_ts = pim_time_monotonic_sec();
|
||||||
|
|
||||||
|
if (pim->global_scope.bsr_addrsel.run &&
|
||||||
|
pim->global_scope.cand_bsr_prio > bsr_prio &&
|
||||||
|
pim->global_scope.state < BSR_PENDING) {
|
||||||
|
/* current BSR is now less preferred than ourselves */
|
||||||
|
pim_cand_bsr_pending(&pim->global_scope);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pim_addr_cmp(bsr, pim->global_scope.current_bsr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (pim->global_scope.state) {
|
||||||
|
case BSR_PENDING:
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("Candidate BSR dropping out of BSR election, better BSR (%u, %pPA)",
|
||||||
|
bsr_prio, &bsr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BSR_ELECTED:
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("Lost BSR status, better BSR (%u, %pPA)",
|
||||||
|
bsr_prio, &bsr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NO_INFO:
|
||||||
|
case ACCEPT_ANY:
|
||||||
|
case ACCEPT_PREFERRED:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVENT_OFF(pim->global_scope.t_ebsr_regen_bsm);
|
||||||
|
|
||||||
|
if (pim->global_scope.state == BSR_ELECTED)
|
||||||
|
pim_crp_db_clear(&pim->global_scope);
|
||||||
|
else
|
||||||
|
pim_nht_bsr_del(pim, pim->global_scope.current_bsr);
|
||||||
|
pim_nht_bsr_add(pim, bsr);
|
||||||
|
|
||||||
|
pim->global_scope.current_bsr = 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pim_bsm_clear(struct pim_instance *pim)
|
void pim_bsm_clear(struct pim_instance *pim)
|
||||||
|
@ -596,7 +731,12 @@ void pim_bsm_clear(struct pim_instance *pim)
|
||||||
struct rp_info *rp_info;
|
struct rp_info *rp_info;
|
||||||
bool upstream_updated = false;
|
bool upstream_updated = false;
|
||||||
|
|
||||||
pim_nht_bsr_del(pim, pim->global_scope.current_bsr);
|
EVENT_OFF(pim->global_scope.t_ebsr_regen_bsm);
|
||||||
|
|
||||||
|
if (pim->global_scope.state == BSR_ELECTED)
|
||||||
|
pim_crp_db_clear(&pim->global_scope);
|
||||||
|
else
|
||||||
|
pim_nht_bsr_del(pim, pim->global_scope.current_bsr);
|
||||||
|
|
||||||
/* Reset scope zone data */
|
/* Reset scope zone data */
|
||||||
pim->global_scope.accept_nofwd_bsm = false;
|
pim->global_scope.accept_nofwd_bsm = false;
|
||||||
|
@ -1157,8 +1297,8 @@ static void pim_update_pending_rp_cnt(struct bsm_scope *sz,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parsing BSR packet and adding to partial list of corresponding bsgrp node */
|
/* Parsing BSR packet and adding to partial list of corresponding bsgrp node */
|
||||||
static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
|
bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
|
||||||
int buflen, uint16_t bsm_frag_tag)
|
int buflen, uint16_t bsm_frag_tag)
|
||||||
{
|
{
|
||||||
struct bsmmsg_grpinfo grpinfo;
|
struct bsmmsg_grpinfo grpinfo;
|
||||||
struct bsmmsg_rpinfo rpinfo;
|
struct bsmmsg_rpinfo rpinfo;
|
||||||
|
@ -1379,35 +1519,6 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drop if bsr is not preferred bsr */
|
|
||||||
if (!is_preferred_bsr(pim, bsr_addr, bshdr->bsr_prio)) {
|
|
||||||
if (PIM_DEBUG_BSM)
|
|
||||||
zlog_debug("%s : Received a non-preferred BSM",
|
|
||||||
__func__);
|
|
||||||
pim->bsm_dropped++;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (no_fwd) {
|
|
||||||
/* only accept no-forward BSM if quick refresh on startup */
|
|
||||||
if ((pim->global_scope.accept_nofwd_bsm)
|
|
||||||
|| (frag_tag == pim->global_scope.bsm_frag_tag)) {
|
|
||||||
pim->global_scope.accept_nofwd_bsm = false;
|
|
||||||
} else {
|
|
||||||
if (PIM_DEBUG_BSM)
|
|
||||||
zlog_debug(
|
|
||||||
"%s : nofwd_bsm received on %pPAs when accpt_nofwd_bsm false",
|
|
||||||
__func__, &bsr_addr);
|
|
||||||
pim->bsm_dropped++;
|
|
||||||
pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* BSM packet is seen, so resetting accept_nofwd_bsm to false */
|
|
||||||
if (pim->global_scope.accept_nofwd_bsm)
|
|
||||||
pim->global_scope.accept_nofwd_bsm = false;
|
|
||||||
|
|
||||||
if (!pim_addr_cmp(sg->grp, qpim_all_pim_routers_addr)) {
|
if (!pim_addr_cmp(sg->grp, qpim_all_pim_routers_addr)) {
|
||||||
/* Multicast BSMs are only accepted if source interface & IP
|
/* Multicast BSMs are only accepted if source interface & IP
|
||||||
* match RPF towards the BSR's IP address, or they have
|
* match RPF towards the BSR's IP address, or they have
|
||||||
|
@ -1444,6 +1555,57 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* when the BSR restarts, it can get its own BSR advertisement thrown
|
||||||
|
* back at it, and without this we'll go into ACCEPT_PREFERRED with
|
||||||
|
* ourselves as the BSR when we should be in BSR_ELECTED.
|
||||||
|
*/
|
||||||
|
if (if_address_is_local(&bshdr->bsr_addr.addr, PIM_AF,
|
||||||
|
pim->vrf->vrf_id)) {
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("%s : Dropping BSM from ourselves", __func__);
|
||||||
|
pim->bsm_dropped++;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drop if bsr is not preferred bsr */
|
||||||
|
if (!is_preferred_bsr(pim, bsr_addr, bshdr->bsr_prio)) {
|
||||||
|
if (pim->global_scope.state == BSR_PENDING && !no_fwd) {
|
||||||
|
/* in P-BSR state, non-preferred BSMs are forwarded, but
|
||||||
|
* content is ignored.
|
||||||
|
*/
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("%s : Forwarding non-preferred BSM during Pending-BSR state",
|
||||||
|
__func__);
|
||||||
|
|
||||||
|
pim_bsm_fwd_whole_sz(pim_ifp->pim, buf, buf_size, sz);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("%s : Received a non-preferred BSM",
|
||||||
|
__func__);
|
||||||
|
pim->bsm_dropped++;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (no_fwd) {
|
||||||
|
/* only accept no-forward BSM if quick refresh on startup */
|
||||||
|
if ((pim->global_scope.accept_nofwd_bsm) ||
|
||||||
|
(frag_tag == pim->global_scope.bsm_frag_tag)) {
|
||||||
|
pim->global_scope.accept_nofwd_bsm = false;
|
||||||
|
} else {
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("%s : nofwd_bsm received on %pPAs when accpt_nofwd_bsm false",
|
||||||
|
__func__, &bsr_addr);
|
||||||
|
pim->bsm_dropped++;
|
||||||
|
pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BSM packet is seen, so resetting accept_nofwd_bsm to false */
|
||||||
|
if (pim->global_scope.accept_nofwd_bsm)
|
||||||
|
pim->global_scope.accept_nofwd_bsm = false;
|
||||||
|
|
||||||
if (empty_bsm) {
|
if (empty_bsm) {
|
||||||
if (PIM_DEBUG_BSM)
|
if (PIM_DEBUG_BSM)
|
||||||
zlog_debug("%s : Empty Pref BSM received", __func__);
|
zlog_debug("%s : Empty Pref BSM received", __func__);
|
||||||
|
@ -1454,9 +1616,8 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
|
||||||
(buf + PIM_BSM_HDR_LEN + PIM_MSG_HEADER_LEN),
|
(buf + PIM_BSM_HDR_LEN + PIM_MSG_HEADER_LEN),
|
||||||
(buf_size - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN),
|
(buf_size - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN),
|
||||||
frag_tag)) {
|
frag_tag)) {
|
||||||
if (PIM_DEBUG_BSM) {
|
zlog_warn("BSM from %pPA failed to parse",
|
||||||
zlog_debug("%s, Parsing BSM failed.", __func__);
|
(pim_addr *)&bshdr->bsr_addr.addr);
|
||||||
}
|
|
||||||
pim->bsm_dropped++;
|
pim->bsm_dropped++;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1493,6 +1654,148 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pim_elec_bsr_timer(struct event *t)
|
||||||
|
{
|
||||||
|
struct bsm_scope *scope = EVENT_ARG(t);
|
||||||
|
struct bsm_frag *frag;
|
||||||
|
struct bsm_hdr *hdr;
|
||||||
|
|
||||||
|
assert(scope->state == BSR_ELECTED);
|
||||||
|
|
||||||
|
scope->bsm_frag_tag++;
|
||||||
|
frag = bsm_frags_first(scope->bsm_frags);
|
||||||
|
assert(frag);
|
||||||
|
|
||||||
|
hdr = (struct bsm_hdr *)(frag->data + PIM_MSG_HEADER_LEN);
|
||||||
|
hdr->frag_tag = htons(scope->bsm_frag_tag);
|
||||||
|
|
||||||
|
unsigned int timer = PIM_BS_TIME;
|
||||||
|
|
||||||
|
if (scope->changed_bsm_trigger) {
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("Sending triggered BSM");
|
||||||
|
scope->changed_bsm_trigger--;
|
||||||
|
timer = 5;
|
||||||
|
} else {
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("Sending scheduled BSM");
|
||||||
|
pim_bsm_sent(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
pim_bsm_fwd_whole_sz(scope->pim, frag->data, frag->size, scope->sz_id);
|
||||||
|
scope->current_bsr_last_ts = pim_time_monotonic_sec();
|
||||||
|
|
||||||
|
event_add_timer(router->master, pim_elec_bsr_timer, scope, timer,
|
||||||
|
&scope->bs_timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pim_bsm_changed(struct bsm_scope *scope)
|
||||||
|
{
|
||||||
|
struct event t;
|
||||||
|
|
||||||
|
EVENT_OFF(scope->bs_timer);
|
||||||
|
scope->changed_bsm_trigger = 2;
|
||||||
|
|
||||||
|
t.arg = scope;
|
||||||
|
pim_elec_bsr_timer(&t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pim_cand_bsr_pending_expire(struct event *t)
|
||||||
|
{
|
||||||
|
struct bsm_scope *scope = EVENT_ARG(t);
|
||||||
|
|
||||||
|
assertf(scope->state == BSR_PENDING, "state=%d", scope->state);
|
||||||
|
assertf(pim_addr_is_any(scope->current_bsr), "current_bsr=%pPA",
|
||||||
|
&scope->current_bsr);
|
||||||
|
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("Elected BSR, wait expired without preferable BSMs");
|
||||||
|
|
||||||
|
scope->state = BSR_ELECTED;
|
||||||
|
scope->current_bsr_prio = scope->cand_bsr_prio;
|
||||||
|
scope->current_bsr = scope->bsr_addrsel.run_addr;
|
||||||
|
|
||||||
|
scope->bsm_frag_tag = frr_weak_random();
|
||||||
|
scope->current_bsr_first_ts = pim_time_monotonic_sec();
|
||||||
|
|
||||||
|
pim_cand_rp_trigger(scope);
|
||||||
|
pim_bsm_generate(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if PIM_IPV == 6
|
||||||
|
static float bsr_addr_delay(pim_addr best, pim_addr local)
|
||||||
|
{
|
||||||
|
unsigned int pos;
|
||||||
|
uint32_t best_4b, local_4b;
|
||||||
|
float delay_log;
|
||||||
|
|
||||||
|
for (pos = 0; pos < 12; pos++) {
|
||||||
|
if (best.s6_addr[pos] != local.s6_addr[pos])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&best_4b, &best.s6_addr[pos], 4);
|
||||||
|
memcpy(&local_4b, &local.s6_addr[pos], 4);
|
||||||
|
|
||||||
|
delay_log = log2(1 + ntohl(best_4b) - ntohl(local_4b));
|
||||||
|
delay_log += (12 - pos) * 8;
|
||||||
|
return delay_log / 64.;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void pim_cand_bsr_pending(struct bsm_scope *scope)
|
||||||
|
{
|
||||||
|
unsigned int bs_rand_override;
|
||||||
|
uint8_t best_prio;
|
||||||
|
pim_addr best_addr;
|
||||||
|
float prio_delay, addr_delay;
|
||||||
|
|
||||||
|
EVENT_OFF(scope->bs_timer);
|
||||||
|
EVENT_OFF(scope->t_ebsr_regen_bsm);
|
||||||
|
scope->state = BSR_PENDING;
|
||||||
|
|
||||||
|
best_prio = MAX(scope->cand_bsr_prio, scope->current_bsr_prio);
|
||||||
|
best_addr = pim_addr_cmp(scope->bsr_addrsel.run_addr,
|
||||||
|
scope->current_bsr) > 0
|
||||||
|
? scope->bsr_addrsel.run_addr
|
||||||
|
: scope->current_bsr;
|
||||||
|
|
||||||
|
/* RFC5059 sec.5 */
|
||||||
|
#if PIM_IPV == 4
|
||||||
|
if (scope->cand_bsr_prio == best_prio) {
|
||||||
|
prio_delay = 0.; /* log2(1) = 0 */
|
||||||
|
addr_delay = log2(1 + ntohl(best_addr.s_addr) -
|
||||||
|
ntohl(scope->bsr_addrsel.run_addr.s_addr)) /
|
||||||
|
16.;
|
||||||
|
} else {
|
||||||
|
prio_delay = 2. * log2(1 + best_prio - scope->cand_bsr_prio);
|
||||||
|
addr_delay = 2 - (ntohl(scope->bsr_addrsel.run_addr.s_addr) /
|
||||||
|
(float)(1 << 31));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (scope->cand_bsr_prio == best_prio) {
|
||||||
|
prio_delay = 0.; /* log2(1) = 0 */
|
||||||
|
addr_delay = bsr_addr_delay(best_addr,
|
||||||
|
scope->bsr_addrsel.run_addr);
|
||||||
|
} else {
|
||||||
|
prio_delay = 2. * log2(1 + best_prio - scope->cand_bsr_prio);
|
||||||
|
addr_delay = 2 -
|
||||||
|
(ntohl(scope->bsr_addrsel.run_addr.s6_addr32[0]) /
|
||||||
|
(float)(1 << 31));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bs_rand_override = 5000 + (int)((prio_delay + addr_delay) * 1000.);
|
||||||
|
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("Pending-BSR (%u, %pPA), waiting %ums",
|
||||||
|
scope->cand_bsr_prio, &scope->bsr_addrsel.run_addr,
|
||||||
|
bs_rand_override);
|
||||||
|
|
||||||
|
event_add_timer_msec(router->master, pim_cand_bsr_pending_expire, scope,
|
||||||
|
bs_rand_override, &scope->bs_timer);
|
||||||
|
}
|
||||||
|
|
||||||
static inline pim_addr if_highest_addr(pim_addr cur, struct interface *ifp)
|
static inline pim_addr if_highest_addr(pim_addr cur, struct interface *ifp)
|
||||||
{
|
{
|
||||||
struct connected *connected;
|
struct connected *connected;
|
||||||
|
@ -1575,6 +1878,84 @@ out_disable:
|
||||||
return prev_run;
|
return prev_run;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pim_cand_bsr_stop(struct bsm_scope *scope, bool verbose)
|
||||||
|
{
|
||||||
|
cand_addrsel_clear(&scope->bsr_addrsel);
|
||||||
|
|
||||||
|
switch (scope->state) {
|
||||||
|
case NO_INFO:
|
||||||
|
case ACCEPT_ANY:
|
||||||
|
case ACCEPT_PREFERRED:
|
||||||
|
return;
|
||||||
|
case BSR_PENDING:
|
||||||
|
case BSR_ELECTED:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("Candidate BSR ceasing operation");
|
||||||
|
|
||||||
|
EVENT_OFF(scope->t_ebsr_regen_bsm);
|
||||||
|
EVENT_OFF(scope->bs_timer);
|
||||||
|
pim_crp_db_clear(scope);
|
||||||
|
pim_bsm_accept_any(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pim_cand_bsr_trigger(struct bsm_scope *scope, bool verbose)
|
||||||
|
{
|
||||||
|
/* this is called on all state changes even if we aren't configured
|
||||||
|
* to be C-BSR at all.
|
||||||
|
*/
|
||||||
|
if (!scope->bsr_addrsel.run)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (scope->current_bsr_prio > scope->cand_bsr_prio) {
|
||||||
|
assert(scope->state == ACCEPT_PREFERRED);
|
||||||
|
if (!verbose)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("Candidate BSR: known better BSR %pPA (higher priority %u > %u)",
|
||||||
|
&scope->current_bsr, scope->current_bsr_prio,
|
||||||
|
scope->cand_bsr_prio);
|
||||||
|
return;
|
||||||
|
} else if (scope->current_bsr_prio == scope->cand_bsr_prio &&
|
||||||
|
pim_addr_cmp(scope->current_bsr,
|
||||||
|
scope->bsr_addrsel.run_addr) > 0) {
|
||||||
|
assert(scope->state == ACCEPT_PREFERRED);
|
||||||
|
if (!verbose)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("Candidate BSR: known better BSR %pPA (higher address > %pPA)",
|
||||||
|
&scope->current_bsr,
|
||||||
|
&scope->bsr_addrsel.run_addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pim_addr_cmp(scope->current_bsr, scope->bsr_addrsel.run_addr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
pim_cand_bsr_pending(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pim_cand_bsr_apply(struct bsm_scope *scope)
|
||||||
|
{
|
||||||
|
if (!cand_addrsel_update(&scope->bsr_addrsel, scope->pim->vrf))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!scope->bsr_addrsel.run) {
|
||||||
|
pim_cand_bsr_stop(scope, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("Candidate BSR: %pPA, priority %u",
|
||||||
|
&scope->bsr_addrsel.run_addr, scope->cand_bsr_prio);
|
||||||
|
|
||||||
|
pim_cand_bsr_trigger(scope, true);
|
||||||
|
}
|
||||||
|
|
||||||
static void pim_cand_rp_adv_stop_maybe(struct bsm_scope *scope)
|
static void pim_cand_rp_adv_stop_maybe(struct bsm_scope *scope)
|
||||||
{
|
{
|
||||||
/* actual check whether stop should be sent - covers address
|
/* actual check whether stop should be sent - covers address
|
||||||
|
@ -1587,11 +1968,12 @@ static void pim_cand_rp_adv_stop_maybe(struct bsm_scope *scope)
|
||||||
|
|
||||||
switch (scope->state) {
|
switch (scope->state) {
|
||||||
case ACCEPT_PREFERRED:
|
case ACCEPT_PREFERRED:
|
||||||
/* TBD: BSR_ELECTED */
|
case BSR_ELECTED:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NO_INFO:
|
case NO_INFO:
|
||||||
case ACCEPT_ANY:
|
case ACCEPT_ANY:
|
||||||
|
case BSR_PENDING:
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1636,10 +2018,11 @@ static void pim_cand_rp_adv(struct event *t)
|
||||||
|
|
||||||
switch (scope->state) {
|
switch (scope->state) {
|
||||||
case ACCEPT_PREFERRED:
|
case ACCEPT_PREFERRED:
|
||||||
/* TBD: BSR_ELECTED */
|
case BSR_ELECTED:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACCEPT_ANY:
|
case ACCEPT_ANY:
|
||||||
|
case BSR_PENDING:
|
||||||
case NO_INFO:
|
case NO_INFO:
|
||||||
default:
|
default:
|
||||||
/* state change will retrigger */
|
/* state change will retrigger */
|
||||||
|
@ -1797,7 +2180,8 @@ static void pim_cand_addrs_reapply(struct event *t)
|
||||||
if (!pi)
|
if (!pi)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* this calls cand_addrsel_update() and applies changes */
|
/* these call cand_addrsel_update() and apply changes */
|
||||||
|
pim_cand_bsr_apply(&pi->global_scope);
|
||||||
pim_cand_rp_apply(&pi->global_scope);
|
pim_cand_rp_apply(&pi->global_scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1850,10 +2234,14 @@ int pim_cand_config_write(struct pim_instance *pim, struct vty *vty)
|
||||||
ret++;
|
ret++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scope->bsr_addrsel.cfg_enable) {
|
||||||
|
vty_out(vty, " bsr candidate-bsr");
|
||||||
|
if (scope->cand_bsr_prio != 64)
|
||||||
|
vty_out(vty, " priority %u", scope->cand_bsr_prio);
|
||||||
|
cand_addrsel_config_write(vty, &scope->bsr_addrsel);
|
||||||
|
vty_out(vty, "\n");
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc)
|
|
||||||
{
|
|
||||||
/* stub for Candidate-RP */
|
|
||||||
}
|
|
||||||
|
|
142
pimd/pim_bsm.h
142
pimd/pim_bsm.h
|
@ -21,6 +21,9 @@
|
||||||
#define PIM_BS_TIME 60 /* RFC 5059 - Sec 5 */
|
#define PIM_BS_TIME 60 /* RFC 5059 - Sec 5 */
|
||||||
#define PIM_BSR_DEFAULT_TIMEOUT 130 /* RFC 5059 - Sec 5 */
|
#define PIM_BSR_DEFAULT_TIMEOUT 130 /* RFC 5059 - Sec 5 */
|
||||||
|
|
||||||
|
/* number of times to include rp-count = 0 ranges */
|
||||||
|
#define PIM_BSR_DEAD_COUNT 3
|
||||||
|
|
||||||
#define PIM_CRP_ADV_TRIGCOUNT 3
|
#define PIM_CRP_ADV_TRIGCOUNT 3
|
||||||
#define PIM_CRP_ADV_INTERVAL 60
|
#define PIM_CRP_ADV_INTERVAL 60
|
||||||
#define PIM_CRP_HOLDTIME 150
|
#define PIM_CRP_HOLDTIME 150
|
||||||
|
@ -37,11 +40,21 @@
|
||||||
* ==============
|
* ==============
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Non candidate BSR states */
|
/* BSR states
|
||||||
enum ncbsr_state {
|
*
|
||||||
|
* Candidate BSR starts at BSR_PENDING, moves to AP or E depending on
|
||||||
|
* loss/win. Will never go into AA (because in that case it'd become BSR
|
||||||
|
* itself.)
|
||||||
|
*
|
||||||
|
* Non-Candidate BSR starts at NO_INFO, moves to AP & AA depending on
|
||||||
|
* a BSR being available or not.
|
||||||
|
*/
|
||||||
|
enum bsr_state {
|
||||||
NO_INFO = 0,
|
NO_INFO = 0,
|
||||||
ACCEPT_ANY,
|
ACCEPT_ANY,
|
||||||
ACCEPT_PREFERRED
|
ACCEPT_PREFERRED, /* = same as C-BSR if candidate */
|
||||||
|
BSR_PENDING,
|
||||||
|
BSR_ELECTED,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum cand_addr {
|
enum cand_addr {
|
||||||
|
@ -51,7 +64,7 @@ enum cand_addr {
|
||||||
CAND_ADDR_EXPLICIT,
|
CAND_ADDR_EXPLICIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* used separately for Cand-RP, and (TBD) Cand-BSR */
|
/* used separately for Cand-RP and Cand-BSR */
|
||||||
struct cand_addrsel {
|
struct cand_addrsel {
|
||||||
bool cfg_enable;
|
bool cfg_enable;
|
||||||
enum cand_addr cfg_mode : 8;
|
enum cand_addr cfg_mode : 8;
|
||||||
|
@ -70,10 +83,18 @@ struct cand_addrsel {
|
||||||
PREDECL_DLIST(bsm_frags);
|
PREDECL_DLIST(bsm_frags);
|
||||||
PREDECL_RBTREE_UNIQ(cand_rp_groups);
|
PREDECL_RBTREE_UNIQ(cand_rp_groups);
|
||||||
|
|
||||||
|
/* n*m "table" accessed both by-RP and by-group */
|
||||||
|
PREDECL_RBTREE_UNIQ(bsr_crp_rps);
|
||||||
|
PREDECL_RBTREE_UNIQ(bsr_crp_groups);
|
||||||
|
|
||||||
|
PREDECL_RBTREE_UNIQ(bsr_crp_rp_groups);
|
||||||
|
PREDECL_RBTREE_UNIQ(bsr_crp_group_rps);
|
||||||
|
|
||||||
/* BSM scope - bsm processing is per scope */
|
/* BSM scope - bsm processing is per scope */
|
||||||
struct bsm_scope {
|
struct bsm_scope {
|
||||||
int sz_id; /* scope zone id */
|
int sz_id; /* scope zone id */
|
||||||
enum ncbsr_state state; /* non candidate BSR state */
|
enum bsr_state state; /* BSR state */
|
||||||
|
|
||||||
bool accept_nofwd_bsm; /* no fwd bsm accepted for scope */
|
bool accept_nofwd_bsm; /* no fwd bsm accepted for scope */
|
||||||
pim_addr current_bsr; /* current elected BSR for the sz */
|
pim_addr current_bsr; /* current elected BSR for the sz */
|
||||||
uint32_t current_bsr_prio; /* current BSR priority */
|
uint32_t current_bsr_prio; /* current BSR priority */
|
||||||
|
@ -89,6 +110,31 @@ struct bsm_scope {
|
||||||
struct route_table *bsrp_table; /* group2rp mapping rcvd from BSR */
|
struct route_table *bsrp_table; /* group2rp mapping rcvd from BSR */
|
||||||
struct event *bs_timer; /* Boot strap timer */
|
struct event *bs_timer; /* Boot strap timer */
|
||||||
|
|
||||||
|
/* Candidate BSR config */
|
||||||
|
struct cand_addrsel bsr_addrsel;
|
||||||
|
uint8_t cand_bsr_prio;
|
||||||
|
|
||||||
|
/* Candidate BSR state */
|
||||||
|
uint8_t current_cand_bsr_prio;
|
||||||
|
/* if nothing changed from Cand-RP data we received, less work... */
|
||||||
|
bool elec_rp_data_changed;
|
||||||
|
|
||||||
|
/* data that the E-BSR keeps - not to be confused with Candidate-RP
|
||||||
|
* stuff below. These two here are the info about all the Cand-RPs
|
||||||
|
* that we as a BSR received information for in Cand-RP-adv packets.
|
||||||
|
*/
|
||||||
|
struct bsr_crp_rps_head ebsr_rps[1];
|
||||||
|
struct bsr_crp_groups_head ebsr_groups[1];
|
||||||
|
|
||||||
|
/* set if we have any group ranges where we're currently advertising
|
||||||
|
* rp-count = 0 (includes both ranges without any RPs as well as
|
||||||
|
* ranges with only NHT-unreachable RPs)
|
||||||
|
*/
|
||||||
|
bool ebsr_have_dead_pending;
|
||||||
|
unsigned int changed_bsm_trigger;
|
||||||
|
|
||||||
|
struct event *t_ebsr_regen_bsm;
|
||||||
|
|
||||||
/* Candidate RP config */
|
/* Candidate RP config */
|
||||||
struct cand_addrsel cand_rp_addrsel;
|
struct cand_addrsel cand_rp_addrsel;
|
||||||
uint8_t cand_rp_prio;
|
uint8_t cand_rp_prio;
|
||||||
|
@ -98,6 +144,7 @@ struct bsm_scope {
|
||||||
|
|
||||||
/* Candidate RP state */
|
/* Candidate RP state */
|
||||||
int unicast_sock;
|
int unicast_sock;
|
||||||
|
struct event *unicast_read;
|
||||||
struct event *cand_rp_adv_timer;
|
struct event *cand_rp_adv_timer;
|
||||||
unsigned int cand_rp_adv_trigger; /* # trigg. C-RP-Adv left to send */
|
unsigned int cand_rp_adv_trigger; /* # trigg. C-RP-Adv left to send */
|
||||||
|
|
||||||
|
@ -111,6 +158,46 @@ struct cand_rp_group {
|
||||||
prefix_pim p;
|
prefix_pim p;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct bsr_crp_group {
|
||||||
|
struct bsr_crp_groups_item item;
|
||||||
|
|
||||||
|
prefix_pim range;
|
||||||
|
struct bsr_crp_group_rps_head rps[1];
|
||||||
|
|
||||||
|
size_t n_selected;
|
||||||
|
bool deleted_selected : 1;
|
||||||
|
|
||||||
|
/* number of times we've advertised this range with rp-count = 0 */
|
||||||
|
unsigned int dead_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bsr_crp_rp {
|
||||||
|
struct bsr_crp_rps_item item;
|
||||||
|
|
||||||
|
pim_addr addr;
|
||||||
|
struct bsr_crp_rp_groups_head groups[1];
|
||||||
|
|
||||||
|
struct bsm_scope *scope;
|
||||||
|
struct event *t_hold;
|
||||||
|
time_t seen_first;
|
||||||
|
time_t seen_last;
|
||||||
|
|
||||||
|
uint16_t holdtime;
|
||||||
|
uint8_t prio;
|
||||||
|
bool nht_ok;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* "n * m" RP<->Group tie-in */
|
||||||
|
struct bsr_crp_item {
|
||||||
|
struct bsr_crp_rp_groups_item r_g_item;
|
||||||
|
struct bsr_crp_group_rps_item g_r_item;
|
||||||
|
|
||||||
|
struct bsr_crp_group *group;
|
||||||
|
struct bsr_crp_rp *rp;
|
||||||
|
|
||||||
|
bool selected : 1;
|
||||||
|
};
|
||||||
|
|
||||||
/* BSM packet (= fragment) - this is stored as list in bsm_frags inside scope
|
/* BSM packet (= fragment) - this is stored as list in bsm_frags inside scope
|
||||||
* This is used for forwarding to new neighbors or restarting mcast routers
|
* This is used for forwarding to new neighbors or restarting mcast routers
|
||||||
*/
|
*/
|
||||||
|
@ -268,6 +355,15 @@ 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 bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope,
|
||||||
struct prefix *grp);
|
struct prefix *grp);
|
||||||
|
|
||||||
|
void pim_bsm_generate(struct bsm_scope *scope);
|
||||||
|
void pim_bsm_changed(struct bsm_scope *scope);
|
||||||
|
void pim_bsm_sent(struct bsm_scope *scope);
|
||||||
|
void pim_bsm_frags_free(struct bsm_scope *scope);
|
||||||
|
|
||||||
|
bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf,
|
||||||
|
int buflen, uint16_t bsm_frag_tag);
|
||||||
|
|
||||||
|
void pim_cand_bsr_apply(struct bsm_scope *scope);
|
||||||
void pim_cand_rp_apply(struct bsm_scope *scope);
|
void pim_cand_rp_apply(struct bsm_scope *scope);
|
||||||
void pim_cand_rp_trigger(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_add(struct bsm_scope *scope, const prefix_pim *p);
|
||||||
|
@ -275,6 +371,42 @@ void pim_cand_rp_grp_del(struct bsm_scope *scope, const prefix_pim *p);
|
||||||
|
|
||||||
void pim_cand_addrs_changed(void);
|
void pim_cand_addrs_changed(void);
|
||||||
|
|
||||||
|
int pim_crp_process(struct interface *ifp, pim_sgaddr *src_dst, uint8_t *buf,
|
||||||
|
uint32_t buf_size);
|
||||||
|
|
||||||
|
struct pim_nexthop_cache;
|
||||||
|
void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc);
|
||||||
|
|
||||||
|
void pim_crp_db_clear(struct bsm_scope *scope);
|
||||||
|
int pim_crp_db_show(struct vty *vty, struct bsm_scope *scope);
|
||||||
|
int pim_crp_groups_show(struct vty *vty, struct bsm_scope *scope);
|
||||||
|
|
||||||
|
int pim_crp_process(struct interface *ifp, pim_sgaddr *src_dst, uint8_t *buf,
|
||||||
|
uint32_t buf_size);
|
||||||
|
|
||||||
|
struct pim_nexthop_cache;
|
||||||
|
void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc);
|
||||||
|
|
||||||
|
void pim_crp_db_clear(struct bsm_scope *scope);
|
||||||
|
int pim_crp_db_show(struct vty *vty, struct bsm_scope *scope);
|
||||||
|
int pim_crp_groups_show(struct vty *vty, struct bsm_scope *scope);
|
||||||
|
|
||||||
|
int pim_crp_process(struct interface *ifp, pim_sgaddr *src_dst, uint8_t *buf,
|
||||||
|
uint32_t buf_size);
|
||||||
|
|
||||||
|
struct pim_nexthop_cache;
|
||||||
|
void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc);
|
||||||
|
|
||||||
|
void pim_crp_db_clear(struct bsm_scope *scope);
|
||||||
|
int pim_crp_db_show(struct vty *vty, struct bsm_scope *scope);
|
||||||
|
int pim_crp_groups_show(struct vty *vty, struct bsm_scope *scope);
|
||||||
|
|
||||||
int pim_cand_config_write(struct pim_instance *pim, struct vty *vty);
|
int pim_cand_config_write(struct pim_instance *pim, struct vty *vty);
|
||||||
|
|
||||||
|
DECLARE_MTYPE(PIM_BSM_FRAG);
|
||||||
|
|
||||||
|
DECLARE_MTYPE(PIM_BSM_FRAG);
|
||||||
|
|
||||||
|
DECLARE_MTYPE(PIM_BSM_FRAG);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
634
pimd/pim_bsr_rpdb.c
Normal file
634
pimd/pim_bsr_rpdb.c
Normal file
|
@ -0,0 +1,634 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/* PIM RP database for BSR operation
|
||||||
|
* Copyright (C) 2021 David Lamparter for NetDEF, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <lib/network.h>
|
||||||
|
#include <lib/iana_afi.h>
|
||||||
|
#include <lib/sockunion.h>
|
||||||
|
|
||||||
|
#include "if.h"
|
||||||
|
#include "pimd.h"
|
||||||
|
#include "pim_iface.h"
|
||||||
|
#include "pim_instance.h"
|
||||||
|
#include "pim_rpf.h"
|
||||||
|
#include "pim_hello.h"
|
||||||
|
#include "pim_pim.h"
|
||||||
|
#include "pim_nht.h"
|
||||||
|
#include "pim_bsm.h"
|
||||||
|
#include "pim_time.h"
|
||||||
|
|
||||||
|
/* safety limits to prevent DoS/memory exhaustion attacks against the BSR
|
||||||
|
*
|
||||||
|
* The BSR is more susceptible than other PIM protocol operation because
|
||||||
|
* Candidate-RP messages are unicast to the BSR without any 2-way interaction
|
||||||
|
* and can thus be spoofed blindly(!) from anywhere in the internet.
|
||||||
|
*
|
||||||
|
* Everything else is on-link, multicast, or requires an adjacency - much
|
||||||
|
* harder to mess with.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* total number of RPs we keep information for */
|
||||||
|
static size_t bsr_max_rps = 1024;
|
||||||
|
|
||||||
|
DEFINE_MTYPE_STATIC(PIMD, PIM_BSR_CRP, "PIM BSR C-RP");
|
||||||
|
DEFINE_MTYPE_STATIC(PIMD, PIM_BSR_GROUP, "PIM BSR range");
|
||||||
|
DEFINE_MTYPE_STATIC(PIMD, PIM_BSR_ITEM, "PIM BSR C-RP range item");
|
||||||
|
|
||||||
|
static int rp_cmp(const struct bsr_crp_rp *a, const struct bsr_crp_rp *b)
|
||||||
|
{
|
||||||
|
return pim_addr_cmp(a->addr, b->addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_RBTREE_UNIQ(bsr_crp_rps, struct bsr_crp_rp, item, rp_cmp);
|
||||||
|
|
||||||
|
static int group_cmp(const struct bsr_crp_group *a,
|
||||||
|
const struct bsr_crp_group *b)
|
||||||
|
{
|
||||||
|
return prefix_cmp(&a->range, &b->range);
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_RBTREE_UNIQ(bsr_crp_groups, struct bsr_crp_group, item, group_cmp);
|
||||||
|
|
||||||
|
static int r_g_cmp(const struct bsr_crp_item *a, const struct bsr_crp_item *b)
|
||||||
|
{
|
||||||
|
return prefix_cmp(&a->group->range, &b->group->range);
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_RBTREE_UNIQ(bsr_crp_rp_groups, struct bsr_crp_item, r_g_item, r_g_cmp);
|
||||||
|
|
||||||
|
static int g_r_cmp(const struct bsr_crp_item *a, const struct bsr_crp_item *b)
|
||||||
|
{
|
||||||
|
const struct bsr_crp_rp *rp_a = a->rp, *rp_b = b->rp;
|
||||||
|
|
||||||
|
/* NHT-failed RPs last */
|
||||||
|
if (rp_a->nht_ok > rp_b->nht_ok)
|
||||||
|
return -1;
|
||||||
|
if (rp_a->nht_ok < rp_b->nht_ok)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* This function determines BSR policy in what subset of the received
|
||||||
|
* RP candidates to advertise. The BSR is free to make its choices
|
||||||
|
* any way it deems useful
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* lower numeric values are better */
|
||||||
|
if (rp_a->prio < rp_b->prio)
|
||||||
|
return -1;
|
||||||
|
if (rp_a->prio > rp_b->prio)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* prefer older RP for less churn */
|
||||||
|
if (rp_a->seen_first < rp_b->seen_first)
|
||||||
|
return -1;
|
||||||
|
if (rp_a->seen_first > rp_b->seen_first)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return pim_addr_cmp(rp_a->addr, rp_b->addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_RBTREE_UNIQ(bsr_crp_group_rps, struct bsr_crp_item, g_r_item, g_r_cmp);
|
||||||
|
|
||||||
|
void pim_bsm_generate(struct bsm_scope *scope)
|
||||||
|
{
|
||||||
|
struct bsm_frag *frag;
|
||||||
|
struct bsm_hdr *hdr;
|
||||||
|
bool have_dead = false;
|
||||||
|
|
||||||
|
assertf(scope->state == BSR_ELECTED, "state=%d", scope->state);
|
||||||
|
|
||||||
|
pim_bsm_frags_free(scope);
|
||||||
|
|
||||||
|
struct bsr_crp_group *group;
|
||||||
|
struct bsr_crp_item *item;
|
||||||
|
struct bsr_crp_rp *rp;
|
||||||
|
size_t n_groups = 0, n_rps = 0;
|
||||||
|
|
||||||
|
frr_each (bsr_crp_groups, scope->ebsr_groups, group) {
|
||||||
|
if (group->n_selected == 0) {
|
||||||
|
if (group->dead_count >= PIM_BSR_DEAD_COUNT)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
have_dead = true;
|
||||||
|
} else
|
||||||
|
group->dead_count = 0;
|
||||||
|
|
||||||
|
n_groups++;
|
||||||
|
n_rps += group->n_selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("Generating BSM (%zu ranges, %zu RPs)", n_groups, n_rps);
|
||||||
|
|
||||||
|
size_t datalen = PIM_MSG_HEADER_LEN + sizeof(*hdr) +
|
||||||
|
n_groups * sizeof(struct bsmmsg_grpinfo) +
|
||||||
|
n_rps * sizeof(struct bsmmsg_rpinfo);
|
||||||
|
|
||||||
|
frag = XCALLOC(MTYPE_PIM_BSM_FRAG, sizeof(*frag) + datalen);
|
||||||
|
|
||||||
|
uint8_t *pos = frag->data + PIM_MSG_HEADER_LEN;
|
||||||
|
uint8_t *end = frag->data + datalen;
|
||||||
|
|
||||||
|
hdr = (struct bsm_hdr *)pos;
|
||||||
|
pos += sizeof(*hdr);
|
||||||
|
assert(pos <= end);
|
||||||
|
|
||||||
|
/* TODO: make BSR hashmasklen configurable */
|
||||||
|
#if PIM_IPV == 6
|
||||||
|
hdr->hm_len = 126;
|
||||||
|
#else
|
||||||
|
hdr->hm_len = 30;
|
||||||
|
#endif
|
||||||
|
hdr->bsr_prio = scope->current_bsr_prio;
|
||||||
|
hdr->bsr_addr.family = PIM_IANA_AFI;
|
||||||
|
hdr->bsr_addr.reserved = 0;
|
||||||
|
hdr->bsr_addr.addr = scope->bsr_addrsel.run_addr;
|
||||||
|
|
||||||
|
frr_each (bsr_crp_groups, scope->ebsr_groups, group) {
|
||||||
|
if (group->n_selected == 0 &&
|
||||||
|
group->dead_count >= PIM_BSR_DEAD_COUNT)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
struct bsmmsg_grpinfo *gi = (struct bsmmsg_grpinfo *)pos;
|
||||||
|
|
||||||
|
pos += sizeof(*gi);
|
||||||
|
assert(pos <= end);
|
||||||
|
|
||||||
|
gi->group.family = PIM_MSG_ADDRESS_FAMILY;
|
||||||
|
gi->group.mask = group->range.prefixlen;
|
||||||
|
gi->group.addr = group->range.prefix;
|
||||||
|
|
||||||
|
size_t n_added = 0;
|
||||||
|
|
||||||
|
frr_each (bsr_crp_group_rps, group->rps, item) {
|
||||||
|
if (!item->selected)
|
||||||
|
break;
|
||||||
|
|
||||||
|
struct bsmmsg_rpinfo *ri = (struct bsmmsg_rpinfo *)pos;
|
||||||
|
|
||||||
|
pos += sizeof(*ri);
|
||||||
|
assert(pos <= end);
|
||||||
|
|
||||||
|
rp = item->rp;
|
||||||
|
ri->rpaddr.family = PIM_MSG_ADDRESS_FAMILY;
|
||||||
|
ri->rpaddr.addr = rp->addr;
|
||||||
|
ri->rp_holdtime = htons(rp->holdtime);
|
||||||
|
ri->rp_pri = rp->prio;
|
||||||
|
|
||||||
|
n_added++;
|
||||||
|
}
|
||||||
|
|
||||||
|
gi->rp_count = group->n_selected;
|
||||||
|
gi->frag_rp_count = n_added;
|
||||||
|
assert(n_added == group->n_selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertf(pos == end, "end-pos=%td", end - pos);
|
||||||
|
frag->size = datalen;
|
||||||
|
|
||||||
|
bsm_frags_add_head(scope->bsm_frags, frag);
|
||||||
|
|
||||||
|
scope->ebsr_have_dead_pending = have_dead;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The BSR itself doesn't receive (no loopback) the BSM msgs advertising
|
||||||
|
* the rps. Install the rps directly for the local BSR node.
|
||||||
|
*/
|
||||||
|
pim_bsm_parse_install_g2rp(scope, ((uint8_t *) hdr) + PIM_BSM_HDR_LEN,
|
||||||
|
datalen - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN, scope->bsm_frag_tag);
|
||||||
|
|
||||||
|
pim_bsm_changed(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pim_bsm_generate_timer(struct event *t)
|
||||||
|
{
|
||||||
|
struct bsm_scope *scope = EVENT_ARG(t);
|
||||||
|
|
||||||
|
pim_bsm_generate(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pim_bsm_generate_sched(struct bsm_scope *scope)
|
||||||
|
{
|
||||||
|
assertf(scope->state == BSR_ELECTED, "state=%d", scope->state);
|
||||||
|
|
||||||
|
if (scope->t_ebsr_regen_bsm)
|
||||||
|
return;
|
||||||
|
|
||||||
|
event_add_timer(router->master, pim_bsm_generate_timer, scope, 1,
|
||||||
|
&scope->t_ebsr_regen_bsm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pim_bsm_sent(struct bsm_scope *scope)
|
||||||
|
{
|
||||||
|
struct bsr_crp_group *group;
|
||||||
|
bool have_dead = false, changed = false;
|
||||||
|
|
||||||
|
if (!scope->ebsr_have_dead_pending)
|
||||||
|
return;
|
||||||
|
|
||||||
|
frr_each_safe (bsr_crp_groups, scope->ebsr_groups, group) {
|
||||||
|
if (group->n_selected != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (group->dead_count < PIM_BSR_DEAD_COUNT) {
|
||||||
|
group->dead_count++;
|
||||||
|
have_dead = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
changed = true;
|
||||||
|
|
||||||
|
if (bsr_crp_group_rps_count(group->rps))
|
||||||
|
/* have RPs, but none selected */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* no reason to keep this range anymore */
|
||||||
|
bsr_crp_groups_del(scope->ebsr_groups, group);
|
||||||
|
bsr_crp_group_rps_fini(group->rps);
|
||||||
|
XFREE(MTYPE_PIM_BSR_GROUP, group);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope->ebsr_have_dead_pending = have_dead;
|
||||||
|
if (changed)
|
||||||
|
pim_bsm_generate_sched(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bsr_crp_reselect(struct bsm_scope *scope,
|
||||||
|
struct bsr_crp_group *group)
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
struct bsr_crp_item *item;
|
||||||
|
size_t n_selected = 0;
|
||||||
|
|
||||||
|
frr_each (bsr_crp_group_rps, group->rps, item) {
|
||||||
|
bool select = false;
|
||||||
|
|
||||||
|
/* hardcode best 2 RPs for now */
|
||||||
|
if (item->rp->nht_ok && n_selected < 2) {
|
||||||
|
select = true;
|
||||||
|
n_selected++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item->selected != select) {
|
||||||
|
changed = true;
|
||||||
|
item->selected = select;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
changed |= group->deleted_selected;
|
||||||
|
group->deleted_selected = false;
|
||||||
|
group->n_selected = n_selected;
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
pim_bsm_generate_sched(scope);
|
||||||
|
|
||||||
|
scope->elec_rp_data_changed |= changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* changing rp->nht_ok or rp->prio affects the sort order in group->rp
|
||||||
|
* lists, so need a delete & re-add if either changes
|
||||||
|
*/
|
||||||
|
static void pim_crp_nht_prio_change(struct bsr_crp_rp *rp, bool nht_ok,
|
||||||
|
uint8_t prio)
|
||||||
|
{
|
||||||
|
struct bsr_crp_item *item;
|
||||||
|
|
||||||
|
frr_each (bsr_crp_rp_groups, rp->groups, item)
|
||||||
|
bsr_crp_group_rps_del(item->group->rps, item);
|
||||||
|
|
||||||
|
rp->prio = prio;
|
||||||
|
rp->nht_ok = nht_ok;
|
||||||
|
|
||||||
|
frr_each (bsr_crp_rp_groups, rp->groups, item) {
|
||||||
|
bsr_crp_group_rps_add(item->group->rps, item);
|
||||||
|
bsr_crp_reselect(rp->scope, item->group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct bsr_crp_group *group_get(struct bsm_scope *scope,
|
||||||
|
prefix_pim *range)
|
||||||
|
{
|
||||||
|
struct bsr_crp_group *group, ref;
|
||||||
|
|
||||||
|
ref.range = *range;
|
||||||
|
group = bsr_crp_groups_find(scope->ebsr_groups, &ref);
|
||||||
|
if (!group) {
|
||||||
|
group = XCALLOC(MTYPE_PIM_BSR_GROUP, sizeof(*group));
|
||||||
|
group->range = *range;
|
||||||
|
bsr_crp_group_rps_init(group->rps);
|
||||||
|
bsr_crp_groups_add(scope->ebsr_groups, group);
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pim_crp_update(struct bsr_crp_rp *rp, struct cand_rp_msg *msg,
|
||||||
|
size_t ngroups)
|
||||||
|
{
|
||||||
|
struct bsr_crp_rp_groups_head oldgroups[1];
|
||||||
|
struct bsr_crp_item *item, itemref;
|
||||||
|
struct bsr_crp_group *group, groupref;
|
||||||
|
|
||||||
|
//struct bsm_scope *scope = rp->scope;
|
||||||
|
|
||||||
|
bsr_crp_rp_groups_init(oldgroups);
|
||||||
|
bsr_crp_rp_groups_swap_all(rp->groups, oldgroups);
|
||||||
|
|
||||||
|
itemref.rp = rp;
|
||||||
|
itemref.group = &groupref;
|
||||||
|
|
||||||
|
assert(msg || ngroups == 0);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ngroups; i++) {
|
||||||
|
if (msg->groups[i].family != PIM_MSG_ADDRESS_FAMILY)
|
||||||
|
continue;
|
||||||
|
if (msg->groups[i].bidir)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
prefix_pim pfx;
|
||||||
|
|
||||||
|
pfx.family = PIM_AF;
|
||||||
|
pfx.prefixlen = msg->groups[i].mask;
|
||||||
|
pfx.prefix = msg->groups[i].addr;
|
||||||
|
|
||||||
|
#if PIM_IPV == 4
|
||||||
|
if (pfx.prefixlen < 4)
|
||||||
|
continue;
|
||||||
|
if (!IPV4_CLASS_DE(ntohl(pfx.prefix.s_addr)))
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
apply_mask(&pfx);
|
||||||
|
|
||||||
|
groupref.range = pfx;
|
||||||
|
item = bsr_crp_rp_groups_find(oldgroups, &itemref);
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
bsr_crp_rp_groups_del(oldgroups, item);
|
||||||
|
bsr_crp_rp_groups_add(rp->groups, item);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
group = group_get(rp->scope, &pfx);
|
||||||
|
|
||||||
|
item = XCALLOC(MTYPE_PIM_BSR_ITEM, sizeof(*item));
|
||||||
|
item->rp = rp;
|
||||||
|
item->group = group;
|
||||||
|
|
||||||
|
bsr_crp_group_rps_add(group->rps, item);
|
||||||
|
bsr_crp_rp_groups_add(rp->groups, item);
|
||||||
|
|
||||||
|
bsr_crp_reselect(rp->scope, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((item = bsr_crp_rp_groups_pop(oldgroups))) {
|
||||||
|
group = item->group;
|
||||||
|
if (item->selected)
|
||||||
|
group->deleted_selected = true;
|
||||||
|
|
||||||
|
bsr_crp_group_rps_del(group->rps, item);
|
||||||
|
XFREE(MTYPE_PIM_BSR_ITEM, item);
|
||||||
|
|
||||||
|
bsr_crp_reselect(rp->scope, group);
|
||||||
|
}
|
||||||
|
bsr_crp_rp_groups_fini(oldgroups);
|
||||||
|
|
||||||
|
if (msg && msg->rp_prio != rp->prio)
|
||||||
|
pim_crp_nht_prio_change(rp, rp->nht_ok, msg->rp_prio);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc)
|
||||||
|
{
|
||||||
|
struct bsm_scope *scope = &pim->global_scope;
|
||||||
|
struct bsr_crp_rp *rp, ref;
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
ref.addr = pnc->rpf.rpf_addr;
|
||||||
|
rp = bsr_crp_rps_find(scope->ebsr_rps, &ref);
|
||||||
|
assertf(rp, "addr=%pPA", &ref.addr);
|
||||||
|
|
||||||
|
ok = CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID);
|
||||||
|
if (ok == rp->nht_ok)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("Candidate-RP %pPA NHT %s", &rp->addr, ok ? "UP" : "DOWN");
|
||||||
|
pim_crp_nht_prio_change(rp, ok, rp->prio);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pim_crp_free(struct pim_instance *pim, struct bsr_crp_rp *rp)
|
||||||
|
{
|
||||||
|
EVENT_OFF(rp->t_hold);
|
||||||
|
pim_nht_candrp_del(pim, rp->addr);
|
||||||
|
bsr_crp_rp_groups_fini(rp->groups);
|
||||||
|
|
||||||
|
XFREE(MTYPE_PIM_BSR_CRP, rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pim_crp_expire(struct event *t)
|
||||||
|
{
|
||||||
|
struct bsr_crp_rp *rp = EVENT_ARG(t);
|
||||||
|
struct pim_instance *pim = rp->scope->pim;
|
||||||
|
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("Candidate-RP %pPA holdtime expired", &rp->addr);
|
||||||
|
|
||||||
|
pim_crp_update(rp, NULL, 0);
|
||||||
|
|
||||||
|
bsr_crp_rps_del(rp->scope->ebsr_rps, rp);
|
||||||
|
pim_crp_free(pim, rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pim_crp_process(struct interface *ifp, pim_sgaddr *src_dst, uint8_t *buf,
|
||||||
|
uint32_t buf_size)
|
||||||
|
{
|
||||||
|
struct pim_interface *pim_ifp = NULL;
|
||||||
|
struct pim_instance *pim;
|
||||||
|
struct bsm_scope *scope;
|
||||||
|
|
||||||
|
pim_ifp = ifp->info;
|
||||||
|
if (!pim_ifp) {
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("%s: multicast not enabled on interface %s",
|
||||||
|
__func__, ifp->name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//pim_ifp->pim_ifstat_bsm_rx++;
|
||||||
|
pim = pim_ifp->pim;
|
||||||
|
//pim->bsm_rcvd++;
|
||||||
|
|
||||||
|
if (!pim_ifp->bsm_enable) {
|
||||||
|
zlog_warn("%s: BSM not enabled on interface %s", __func__,
|
||||||
|
ifp->name);
|
||||||
|
//pim_ifp->pim_ifstat_bsm_cfg_miss++;
|
||||||
|
//pim->bsm_dropped++;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf_size < (PIM_MSG_HEADER_LEN + sizeof(struct cand_rp_msg))) {
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("%s: received buffer length of %d which is too small to properly decode",
|
||||||
|
__func__, buf_size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope = &pim->global_scope;
|
||||||
|
|
||||||
|
if (scope->state < BSR_PENDING) {
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("received Candidate-RP message from %pPA while not BSR",
|
||||||
|
&src_dst->src);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t remain = buf_size;
|
||||||
|
struct cand_rp_msg *crp_hdr;
|
||||||
|
|
||||||
|
buf += PIM_MSG_HEADER_LEN;
|
||||||
|
remain -= PIM_MSG_HEADER_LEN;
|
||||||
|
|
||||||
|
crp_hdr = (struct cand_rp_msg *)buf;
|
||||||
|
buf += sizeof(*crp_hdr);
|
||||||
|
remain -= sizeof(*crp_hdr);
|
||||||
|
|
||||||
|
size_t ngroups = crp_hdr->prefix_cnt;
|
||||||
|
|
||||||
|
if (remain < ngroups * sizeof(struct pim_encoded_group_ipv4)) {
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("truncated Candidate-RP advertisement for RP %pPA from %pPA (too short for %zu groups)",
|
||||||
|
(pim_addr *)&crp_hdr->rp_addr.addr,
|
||||||
|
&src_dst->src, ngroups);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("Candidate-RP: %pPA, prio=%u (from %pPA, %zu groups)",
|
||||||
|
(pim_addr *)&crp_hdr->rp_addr.addr, crp_hdr->rp_prio,
|
||||||
|
&src_dst->src, ngroups);
|
||||||
|
|
||||||
|
|
||||||
|
struct bsr_crp_rp *rp, ref;
|
||||||
|
|
||||||
|
ref.addr = crp_hdr->rp_addr.addr;
|
||||||
|
rp = bsr_crp_rps_find(scope->ebsr_rps, &ref);
|
||||||
|
|
||||||
|
if (!rp) {
|
||||||
|
if (bsr_crp_rps_count(scope->ebsr_rps) >= bsr_max_rps) {
|
||||||
|
zlog_err("BSR: number of tracked Candidate RPs (%zu) exceeds DoS-protection limit (%zu), dropping advertisement for RP %pPA (packet source %pPA)",
|
||||||
|
bsr_crp_rps_count(scope->ebsr_rps),
|
||||||
|
bsr_max_rps, (pim_addr *)&crp_hdr->rp_addr.addr,
|
||||||
|
&src_dst->src);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PIM_DEBUG_BSM)
|
||||||
|
zlog_debug("new Candidate-RP: %pPA (from %pPA)",
|
||||||
|
(pim_addr *)&crp_hdr->rp_addr.addr,
|
||||||
|
&src_dst->src);
|
||||||
|
|
||||||
|
rp = XCALLOC(MTYPE_PIM_BSR_CRP, sizeof(*rp));
|
||||||
|
rp->scope = scope;
|
||||||
|
rp->addr = crp_hdr->rp_addr.addr;
|
||||||
|
rp->prio = 255;
|
||||||
|
bsr_crp_rp_groups_init(rp->groups);
|
||||||
|
rp->seen_first = monotime(NULL);
|
||||||
|
|
||||||
|
bsr_crp_rps_add(scope->ebsr_rps, rp);
|
||||||
|
rp->nht_ok = pim_nht_candrp_add(pim, rp->addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
rp->seen_last = monotime(NULL);
|
||||||
|
rp->holdtime = ntohs(crp_hdr->rp_holdtime);
|
||||||
|
|
||||||
|
EVENT_OFF(rp->t_hold);
|
||||||
|
event_add_timer(router->master, pim_crp_expire, rp,
|
||||||
|
ntohs(crp_hdr->rp_holdtime), &rp->t_hold);
|
||||||
|
|
||||||
|
pim_crp_update(rp, crp_hdr, ngroups);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pim_crp_db_clear(struct bsm_scope *scope)
|
||||||
|
{
|
||||||
|
struct bsr_crp_rp *rp;
|
||||||
|
struct bsr_crp_group *group;
|
||||||
|
struct bsr_crp_item *item;
|
||||||
|
|
||||||
|
while ((rp = bsr_crp_rps_pop(scope->ebsr_rps))) {
|
||||||
|
while ((item = bsr_crp_rp_groups_pop(rp->groups))) {
|
||||||
|
group = item->group;
|
||||||
|
|
||||||
|
if (item->selected)
|
||||||
|
group->deleted_selected = true;
|
||||||
|
|
||||||
|
bsr_crp_group_rps_del(group->rps, item);
|
||||||
|
XFREE(MTYPE_PIM_BSR_ITEM, item);
|
||||||
|
}
|
||||||
|
pim_crp_free(scope->pim, rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((group = bsr_crp_groups_pop(scope->ebsr_groups))) {
|
||||||
|
assertf(!bsr_crp_group_rps_count(group->rps),
|
||||||
|
"range=%pFX rp_count=%zu", &group->range,
|
||||||
|
bsr_crp_group_rps_count(group->rps));
|
||||||
|
|
||||||
|
bsr_crp_group_rps_fini(group->rps);
|
||||||
|
XFREE(MTYPE_PIM_BSR_GROUP, group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pim_crp_db_show(struct vty *vty, struct bsm_scope *scope)
|
||||||
|
{
|
||||||
|
struct bsr_crp_rp *rp;
|
||||||
|
struct bsr_crp_item *item;
|
||||||
|
|
||||||
|
vty_out(vty, "RP/Group NHT Prio Uptime Hold\n");
|
||||||
|
|
||||||
|
frr_each (bsr_crp_rps, scope->ebsr_rps, rp) {
|
||||||
|
vty_out(vty, "%-15pPA %4s %4u %8ld %4lu\n", &rp->addr,
|
||||||
|
rp->nht_ok ? "UP" : "DOWN", rp->prio,
|
||||||
|
(long)(monotime(NULL) - rp->seen_first),
|
||||||
|
event_timer_remain_second(rp->t_hold));
|
||||||
|
|
||||||
|
frr_each (bsr_crp_rp_groups, rp->groups, item)
|
||||||
|
vty_out(vty, "%c %-18pFX\n", item->selected ? '>' : ' ',
|
||||||
|
&item->group->range);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pim_crp_groups_show(struct vty *vty, struct bsm_scope *scope)
|
||||||
|
{
|
||||||
|
struct bsr_crp_group *group;
|
||||||
|
struct bsr_crp_item *item;
|
||||||
|
|
||||||
|
if (scope->ebsr_have_dead_pending)
|
||||||
|
vty_out(vty, "have_dead_pending\n");
|
||||||
|
|
||||||
|
frr_each (bsr_crp_groups, scope->ebsr_groups, group) {
|
||||||
|
vty_out(vty, "%c %pFX", group->n_selected ? '^' : '!',
|
||||||
|
&group->range);
|
||||||
|
if (group->n_selected == 0)
|
||||||
|
vty_out(vty, " (dead %u)", group->dead_count);
|
||||||
|
|
||||||
|
vty_out(vty, "\n");
|
||||||
|
|
||||||
|
frr_each (bsr_crp_group_rps, group->rps, item)
|
||||||
|
vty_out(vty, "%c %pPA\n", item->selected ? '>' : ' ',
|
||||||
|
&item->rp->addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
|
@ -2937,6 +2937,54 @@ DEFUN (show_ip_pim_cand_rp,
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN (show_ip_pim_bsr_rpdb,
|
||||||
|
show_ip_pim_bsr_rpdb_cmd,
|
||||||
|
"show ip pim bsr candidate-rps [vrf NAME] [json]",
|
||||||
|
SHOW_STR
|
||||||
|
IP_STR
|
||||||
|
PIM_STR
|
||||||
|
"boot-strap router information\n"
|
||||||
|
"Candidate RPs\n"
|
||||||
|
VRF_CMD_HELP_STR
|
||||||
|
JSON_STR)
|
||||||
|
{
|
||||||
|
int idx = 2;
|
||||||
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false);
|
||||||
|
//bool uj = use_json(argc, argv);
|
||||||
|
|
||||||
|
if (!vrf || !vrf->info)
|
||||||
|
return CMD_WARNING;
|
||||||
|
|
||||||
|
struct pim_instance *pim = vrf->info;
|
||||||
|
struct bsm_scope *scope = &pim->global_scope;
|
||||||
|
|
||||||
|
return pim_crp_db_show(vty, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (show_ip_pim_bsr_groups,
|
||||||
|
show_ip_pim_bsr_groups_cmd,
|
||||||
|
"show ip pim bsr groups [vrf NAME] [json]",
|
||||||
|
SHOW_STR
|
||||||
|
IP_STR
|
||||||
|
PIM_STR
|
||||||
|
"boot-strap router information\n"
|
||||||
|
"Candidate RP groups\n"
|
||||||
|
VRF_CMD_HELP_STR
|
||||||
|
JSON_STR)
|
||||||
|
{
|
||||||
|
int idx = 2;
|
||||||
|
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false);
|
||||||
|
//bool uj = use_json(argc, argv);
|
||||||
|
|
||||||
|
if (!vrf || !vrf->info)
|
||||||
|
return CMD_WARNING;
|
||||||
|
|
||||||
|
struct pim_instance *pim = vrf->info;
|
||||||
|
struct bsm_scope *scope = &pim->global_scope;
|
||||||
|
|
||||||
|
return pim_crp_groups_show(vty, scope);
|
||||||
|
}
|
||||||
|
|
||||||
DEFPY (show_ip_pim_statistics,
|
DEFPY (show_ip_pim_statistics,
|
||||||
show_ip_pim_statistics_cmd,
|
show_ip_pim_statistics_cmd,
|
||||||
"show ip pim [vrf NAME] statistics [interface WORD$word] [json$json]",
|
"show ip pim [vrf NAME] statistics [interface WORD$word] [json$json]",
|
||||||
|
@ -4436,6 +4484,27 @@ DEFPY_ATTR(no_ip_pim_rp_prefix_list,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFPY (pim_bsr_candidate_bsr,
|
||||||
|
pim_bsr_candidate_bsr_cmd,
|
||||||
|
"[no] bsr candidate-bsr [{priority (0-255)|source <address A.B.C.D|interface IFNAME|loopback$loopback|any$any>}]",
|
||||||
|
NO_STR
|
||||||
|
BSR_STR
|
||||||
|
"Make this router a Candidate BSR\n"
|
||||||
|
"BSR Priority (higher wins)\n"
|
||||||
|
"BSR Priority (higher wins)\n"
|
||||||
|
"Specify IP address for BSR 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_BSR_XPATH, no,
|
||||||
|
false, any, ifname, address_str,
|
||||||
|
priority_str, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
DEFPY (pim_bsr_candidate_rp,
|
DEFPY (pim_bsr_candidate_rp,
|
||||||
pim_bsr_candidate_rp_cmd,
|
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] bsr candidate-rp [{priority (0-255)|interval (1-4294967295)|source <address A.B.C.D|interface IFNAME|loopback$loopback|any$any>}]",
|
||||||
|
@ -8647,6 +8716,7 @@ void pim_cmd_init(void)
|
||||||
|
|
||||||
install_element(PIM_NODE, &pim_bsr_candidate_rp_cmd);
|
install_element(PIM_NODE, &pim_bsr_candidate_rp_cmd);
|
||||||
install_element(PIM_NODE, &pim_bsr_candidate_rp_group_cmd);
|
install_element(PIM_NODE, &pim_bsr_candidate_rp_group_cmd);
|
||||||
|
install_element(PIM_NODE, &pim_bsr_candidate_bsr_cmd);
|
||||||
|
|
||||||
install_element(INTERFACE_NODE, &interface_ip_igmp_cmd);
|
install_element(INTERFACE_NODE, &interface_ip_igmp_cmd);
|
||||||
install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd);
|
install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd);
|
||||||
|
@ -8769,6 +8839,8 @@ void pim_cmd_init(void)
|
||||||
install_element(VIEW_NODE, &show_ip_pim_bsrp_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_bsm_db_cmd);
|
||||||
install_element(VIEW_NODE, &show_ip_pim_cand_rp_cmd);
|
install_element(VIEW_NODE, &show_ip_pim_cand_rp_cmd);
|
||||||
|
install_element(VIEW_NODE, &show_ip_pim_bsr_rpdb_cmd);
|
||||||
|
install_element(VIEW_NODE, &show_ip_pim_bsr_groups_cmd);
|
||||||
install_element(VIEW_NODE, &show_ip_pim_statistics_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_cmd);
|
||||||
install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd);
|
install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd);
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#define IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR "IGMP max query response value (deciseconds)\n"
|
#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_INTERVAL_STR "IGMP last member query interval\n"
|
||||||
#define IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR "IGMP last member query count\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_STR "IGMP protocol activity\n"
|
||||||
#define DEBUG_IGMP_EVENTS_STR "IGMP protocol events\n"
|
#define DEBUG_IGMP_EVENTS_STR "IGMP protocol events\n"
|
||||||
#define DEBUG_IGMP_PACKETS_STR "IGMP protocol packets\n"
|
#define DEBUG_IGMP_PACKETS_STR "IGMP protocol packets\n"
|
||||||
|
|
|
@ -5237,6 +5237,12 @@ void pim_show_bsr(struct pim_instance *pim, struct vty *vty, bool uj)
|
||||||
case ACCEPT_PREFERRED:
|
case ACCEPT_PREFERRED:
|
||||||
strlcpy(bsr_state, "ACCEPT_PREFERRED", sizeof(bsr_state));
|
strlcpy(bsr_state, "ACCEPT_PREFERRED", sizeof(bsr_state));
|
||||||
break;
|
break;
|
||||||
|
case BSR_PENDING:
|
||||||
|
strlcpy(bsr_state, "BSR_PENDING", sizeof(bsr_state));
|
||||||
|
break;
|
||||||
|
case BSR_ELECTED:
|
||||||
|
strlcpy(bsr_state, "BSR_ELECTED", sizeof(bsr_state));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
strlcpy(bsr_state, "", sizeof(bsr_state));
|
strlcpy(bsr_state, "", sizeof(bsr_state));
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#ifndef PIM_CMD_COMMON_H
|
#ifndef PIM_CMD_COMMON_H
|
||||||
#define PIM_CMD_COMMON_H
|
#define PIM_CMD_COMMON_H
|
||||||
|
|
||||||
|
#define BSR_STR "Bootstrap Router configuration\n"
|
||||||
|
|
||||||
struct pim_upstream;
|
struct pim_upstream;
|
||||||
struct pim_instance;
|
struct pim_instance;
|
||||||
|
|
||||||
|
|
|
@ -253,6 +253,7 @@ void pim_vrf_terminate(void)
|
||||||
if (!pim)
|
if (!pim)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
pim_crp_db_clear(&pim->global_scope);
|
||||||
pim_ssmpingd_destroy(pim);
|
pim_ssmpingd_destroy(pim);
|
||||||
pim_instance_terminate(pim);
|
pim_instance_terminate(pim);
|
||||||
|
|
||||||
|
|
|
@ -148,6 +148,7 @@ struct pim_encoded_source_ipv6 {
|
||||||
typedef struct pim_encoded_ipv4_unicast pim_encoded_unicast;
|
typedef struct pim_encoded_ipv4_unicast pim_encoded_unicast;
|
||||||
typedef struct pim_encoded_group_ipv4 pim_encoded_group;
|
typedef struct pim_encoded_group_ipv4 pim_encoded_group;
|
||||||
typedef struct pim_encoded_source_ipv4 pim_encoded_source;
|
typedef struct pim_encoded_source_ipv4 pim_encoded_source;
|
||||||
|
#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV4
|
||||||
typedef struct ip ipv_hdr;
|
typedef struct ip ipv_hdr;
|
||||||
#define IPV_SRC(ip_hdr) ((ip_hdr))->ip_src
|
#define IPV_SRC(ip_hdr) ((ip_hdr))->ip_src
|
||||||
#define IPV_DST(ip_hdr) ((ip_hdr))->ip_dst
|
#define IPV_DST(ip_hdr) ((ip_hdr))->ip_dst
|
||||||
|
@ -156,6 +157,7 @@ typedef struct ip ipv_hdr;
|
||||||
typedef struct pim_encoded_ipv6_unicast pim_encoded_unicast;
|
typedef struct pim_encoded_ipv6_unicast pim_encoded_unicast;
|
||||||
typedef struct pim_encoded_group_ipv6 pim_encoded_group;
|
typedef struct pim_encoded_group_ipv6 pim_encoded_group;
|
||||||
typedef struct pim_encoded_source_ipv6 pim_encoded_source;
|
typedef struct pim_encoded_source_ipv6 pim_encoded_source;
|
||||||
|
#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV6
|
||||||
typedef struct ip6_hdr ipv_hdr;
|
typedef struct ip6_hdr ipv_hdr;
|
||||||
#define IPV_SRC(ip_hdr) ((ip_hdr))->ip6_src
|
#define IPV_SRC(ip_hdr) ((ip_hdr))->ip6_src
|
||||||
#define IPV_DST(ip_hdr) ((ip_hdr))->ip6_dst
|
#define IPV_DST(ip_hdr) ((ip_hdr))->ip6_dst
|
||||||
|
|
|
@ -388,6 +388,48 @@ const struct frr_yang_module_info frr_pim_rp_info = {
|
||||||
const struct frr_yang_module_info frr_pim_candidate_info = {
|
const struct frr_yang_module_info frr_pim_candidate_info = {
|
||||||
.name = "frr-pim-candidate",
|
.name = "frr-pim-candidate",
|
||||||
.nodes = {
|
.nodes = {
|
||||||
|
{
|
||||||
|
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr",
|
||||||
|
.cbs = {
|
||||||
|
.create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_create,
|
||||||
|
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_destroy,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr/bsr-priority",
|
||||||
|
.cbs = {
|
||||||
|
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_priority_modify,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr/address",
|
||||||
|
.cbs = {
|
||||||
|
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_modify,
|
||||||
|
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr/interface",
|
||||||
|
.cbs = {
|
||||||
|
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_modify,
|
||||||
|
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr/if-loopback",
|
||||||
|
.cbs = {
|
||||||
|
.create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_create,
|
||||||
|
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr/if-any",
|
||||||
|
.cbs = {
|
||||||
|
.create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_create,
|
||||||
|
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/* Candidate-RP */
|
/* Candidate-RP */
|
||||||
{
|
{
|
||||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp",
|
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp",
|
||||||
|
|
|
@ -160,6 +160,20 @@ 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(
|
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);
|
struct nb_cb_destroy_args *args);
|
||||||
|
|
||||||
|
/* frr-cand-bsr */
|
||||||
|
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_create(
|
||||||
|
struct nb_cb_create_args *args);
|
||||||
|
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_destroy(
|
||||||
|
struct nb_cb_destroy_args *args);
|
||||||
|
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_priority_modify(
|
||||||
|
struct nb_cb_modify_args *args);
|
||||||
|
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_create(
|
||||||
|
struct nb_cb_create_args *args);
|
||||||
|
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_modify(
|
||||||
|
struct nb_cb_modify_args *args);
|
||||||
|
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy(
|
||||||
|
struct nb_cb_destroy_args *args);
|
||||||
|
|
||||||
/* frr-candidate */
|
/* frr-candidate */
|
||||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_create(
|
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_create(
|
||||||
struct nb_cb_create_args *args);
|
struct nb_cb_create_args *args);
|
||||||
|
@ -225,6 +239,9 @@ int routing_control_plane_protocols_name_validate(
|
||||||
#define FRR_PIM_AF_XPATH_VAL "frr-routing:ipv6"
|
#define FRR_PIM_AF_XPATH_VAL "frr-routing:ipv6"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define FRR_PIM_CAND_RP_XPATH "./frr-pim-candidate:candidate-rp"
|
||||||
|
#define FRR_PIM_CAND_BSR_XPATH "./frr-pim-candidate:candidate-bsr"
|
||||||
|
|
||||||
#define FRR_PIM_VRF_XPATH \
|
#define FRR_PIM_VRF_XPATH \
|
||||||
"/frr-routing:routing/control-plane-protocols/" \
|
"/frr-routing:routing/control-plane-protocols/" \
|
||||||
"control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \
|
"control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \
|
||||||
|
@ -240,8 +257,6 @@ int routing_control_plane_protocols_name_validate(
|
||||||
"mroute[source-addr='%s'][group-addr='%s']"
|
"mroute[source-addr='%s'][group-addr='%s']"
|
||||||
#define FRR_PIM_STATIC_RP_XPATH \
|
#define FRR_PIM_STATIC_RP_XPATH \
|
||||||
"frr-pim-rp:rp/static-rp/rp-list[rp-address='%s']"
|
"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 \
|
#define FRR_GMP_INTERFACE_XPATH \
|
||||||
"./frr-gmp:gmp/address-family[address-family='%s']"
|
"./frr-gmp:gmp/address-family[address-family='%s']"
|
||||||
#define FRR_GMP_ENABLE_XPATH \
|
#define FRR_GMP_ENABLE_XPATH \
|
||||||
|
|
|
@ -2692,6 +2692,152 @@ static void yang_addrsel(struct cand_addrsel *addrsel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int candidate_bsr_addrsel(struct bsm_scope *scope,
|
||||||
|
const struct lyd_node *cand_bsr_node)
|
||||||
|
{
|
||||||
|
yang_addrsel(&scope->bsr_addrsel, cand_bsr_node);
|
||||||
|
pim_cand_bsr_apply(scope);
|
||||||
|
return NB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_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->bsr_addrsel.cfg_enable = true;
|
||||||
|
scope->cand_bsr_prio = yang_dnode_get_uint8(args->dnode,
|
||||||
|
"bsr-priority");
|
||||||
|
|
||||||
|
candidate_bsr_addrsel(scope, args->dnode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_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->bsr_addrsel.cfg_enable = false;
|
||||||
|
|
||||||
|
pim_cand_bsr_apply(scope);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_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_bsr_prio = yang_dnode_get_uint8(args->dnode, NULL);
|
||||||
|
|
||||||
|
/* FIXME: force prio update */
|
||||||
|
candidate_bsr_addrsel(scope, args->dnode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_create(
|
||||||
|
struct nb_cb_create_args *args)
|
||||||
|
{
|
||||||
|
struct vrf *vrf;
|
||||||
|
struct pim_instance *pim;
|
||||||
|
struct bsm_scope *scope;
|
||||||
|
const struct lyd_node *cand_bsr_node;
|
||||||
|
|
||||||
|
cand_bsr_node = yang_dnode_get_parent(args->dnode, "candidate-bsr");
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
return candidate_bsr_addrsel(scope, cand_bsr_node);
|
||||||
|
}
|
||||||
|
return NB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_modify(
|
||||||
|
struct nb_cb_modify_args *args)
|
||||||
|
{
|
||||||
|
struct vrf *vrf;
|
||||||
|
struct pim_instance *pim;
|
||||||
|
struct bsm_scope *scope;
|
||||||
|
const struct lyd_node *cand_bsr_node;
|
||||||
|
|
||||||
|
cand_bsr_node = yang_dnode_get_parent(args->dnode, "candidate-bsr");
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
return candidate_bsr_addrsel(scope, cand_bsr_node);
|
||||||
|
}
|
||||||
|
return NB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy(
|
||||||
|
struct nb_cb_destroy_args *args)
|
||||||
|
{
|
||||||
|
/* nothing to do here, we'll get a CREATE for something else */
|
||||||
|
return NB_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int candidate_rp_addrsel(struct bsm_scope *scope,
|
static int candidate_rp_addrsel(struct bsm_scope *scope,
|
||||||
const struct lyd_node *cand_rp_node)
|
const struct lyd_node *cand_rp_node)
|
||||||
{
|
{
|
||||||
|
|
|
@ -139,7 +139,7 @@ static bool pim_pkt_dst_addr_ok(enum pim_msg_type type, pim_addr addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
|
int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
|
||||||
pim_sgaddr sg)
|
pim_sgaddr sg, bool is_mcast)
|
||||||
{
|
{
|
||||||
struct iovec iov[2], *iovp = iov;
|
struct iovec iov[2], *iovp = iov;
|
||||||
#if PIM_IPV == 4
|
#if PIM_IPV == 4
|
||||||
|
@ -274,6 +274,21 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!is_mcast) {
|
||||||
|
if (header->type == PIM_MSG_TYPE_CANDIDATE) {
|
||||||
|
if (PIM_DEBUG_PIM_PACKETS)
|
||||||
|
zlog_debug( "%s %s: Candidate RP PIM message from %pPA on %s",
|
||||||
|
__FILE__, __func__, &sg.src, ifp->name);
|
||||||
|
|
||||||
|
return pim_crp_process(ifp, &sg, pim_msg, pim_msg_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PIM_DEBUG_PIM_PACKETS)
|
||||||
|
zlog_debug(
|
||||||
|
"ignoring link traffic on BSR unicast socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
switch (header->type) {
|
switch (header->type) {
|
||||||
case PIM_MSG_TYPE_HELLO:
|
case PIM_MSG_TYPE_HELLO:
|
||||||
return pim_hello_recv(ifp, sg.src, pim_msg + PIM_MSG_HEADER_LEN,
|
return pim_hello_recv(ifp, sg.src, pim_msg + PIM_MSG_HEADER_LEN,
|
||||||
|
@ -322,6 +337,13 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
|
||||||
return pim_bsm_process(ifp, &sg, pim_msg, pim_msg_len, no_fwd);
|
return pim_bsm_process(ifp, &sg, pim_msg, pim_msg_len, no_fwd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PIM_MSG_TYPE_CANDIDATE:
|
||||||
|
/* return pim_crp_process(ifp, &sg, pim_msg, pim_msg_len); */
|
||||||
|
if (PIM_DEBUG_PIM_PACKETS)
|
||||||
|
zlog_debug(
|
||||||
|
"ignoring Candidate-RP packet on multicast socket");
|
||||||
|
return 0;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (PIM_DEBUG_PIM_PACKETS) {
|
if (PIM_DEBUG_PIM_PACKETS) {
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
|
@ -395,7 +417,7 @@ static void pim_sock_read(struct event *t)
|
||||||
sg.grp = ((struct sockaddr_in6 *)&to)->sin6_addr;
|
sg.grp = ((struct sockaddr_in6 *)&to)->sin6_addr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int fail = pim_pim_packet(ifp, buf, len, sg);
|
int fail = pim_pim_packet(ifp, buf, len, sg, true);
|
||||||
if (fail) {
|
if (fail) {
|
||||||
if (PIM_DEBUG_PIM_PACKETS)
|
if (PIM_DEBUG_PIM_PACKETS)
|
||||||
zlog_debug("%s: pim_pim_packet() return=%d",
|
zlog_debug("%s: pim_pim_packet() return=%d",
|
||||||
|
|
|
@ -42,7 +42,7 @@ void pim_hello_restart_now(struct interface *ifp);
|
||||||
void pim_hello_restart_triggered(struct interface *ifp);
|
void pim_hello_restart_triggered(struct interface *ifp);
|
||||||
|
|
||||||
int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
|
int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
|
||||||
pim_sgaddr sg);
|
pim_sgaddr sg, bool is_mcast);
|
||||||
|
|
||||||
int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
|
int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg,
|
||||||
int pim_msg_size, struct interface *ifp);
|
int pim_msg_size, struct interface *ifp);
|
||||||
|
|
|
@ -26,6 +26,7 @@ struct pim_instance;
|
||||||
|
|
||||||
int pim_socket_bind(int fd, struct interface *ifp);
|
int pim_socket_bind(int fd, struct interface *ifp);
|
||||||
void pim_socket_ip_hdr(int fd);
|
void pim_socket_ip_hdr(int fd);
|
||||||
|
int pim_setsockopt_packetinfo(int fd);
|
||||||
int pim_socket_raw(int protocol);
|
int pim_socket_raw(int protocol);
|
||||||
int pim_socket_mcast(int protocol, pim_addr ifaddr, struct interface *ifp,
|
int pim_socket_mcast(int protocol, pim_addr ifaddr, struct interface *ifp,
|
||||||
uint8_t loop);
|
uint8_t loop);
|
||||||
|
|
|
@ -19,12 +19,6 @@
|
||||||
#include "pim_iface.h"
|
#include "pim_iface.h"
|
||||||
#include "pim_addr.h"
|
#include "pim_addr.h"
|
||||||
|
|
||||||
#if PIM_IPV == 4
|
|
||||||
#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV4
|
|
||||||
#else
|
|
||||||
#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV6
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint8_t *pim_tlv_append_uint16(uint8_t *buf, const uint8_t *buf_pastend,
|
uint8_t *pim_tlv_append_uint16(uint8_t *buf, const uint8_t *buf_pastend,
|
||||||
uint16_t option_type, uint16_t option_value)
|
uint16_t option_type, uint16_t option_value)
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,6 +17,7 @@ pim_common = \
|
||||||
pimd/pim_assert.c \
|
pimd/pim_assert.c \
|
||||||
pimd/pim_bfd.c \
|
pimd/pim_bfd.c \
|
||||||
pimd/pim_bsm.c \
|
pimd/pim_bsm.c \
|
||||||
|
pimd/pim_bsr_rpdb.c \
|
||||||
pimd/pim_cmd_common.c \
|
pimd/pim_cmd_common.c \
|
||||||
pimd/pim_errors.c \
|
pimd/pim_errors.c \
|
||||||
pimd/pim_hello.c \
|
pimd/pim_hello.c \
|
||||||
|
@ -162,12 +163,12 @@ clippy_scan += \
|
||||||
# end
|
# end
|
||||||
|
|
||||||
pimd_pimd_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4
|
pimd_pimd_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4
|
||||||
pimd_pimd_LDADD = lib/libfrr.la $(LIBCAP)
|
pimd_pimd_LDADD = lib/libfrr.la $(LIBCAP) -lm
|
||||||
|
|
||||||
if PIM6D
|
if PIM6D
|
||||||
sbin_PROGRAMS += pimd/pim6d
|
sbin_PROGRAMS += pimd/pim6d
|
||||||
pimd_pim6d_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=6
|
pimd_pim6d_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=6
|
||||||
pimd_pim6d_LDADD = lib/libfrr.la $(LIBCAP)
|
pimd_pim6d_LDADD = lib/libfrr.la $(LIBCAP) -lm
|
||||||
endif
|
endif
|
||||||
|
|
||||||
pimd_test_igmpv3_join_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4
|
pimd_test_igmpv3_join_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4
|
||||||
|
|
|
@ -71,6 +71,43 @@ module frr-pim-candidate {
|
||||||
/*
|
/*
|
||||||
* Groupings
|
* Groupings
|
||||||
*/
|
*/
|
||||||
|
grouping candidate-bsr-container {
|
||||||
|
description
|
||||||
|
"Grouping of Candidate BSR settings.";
|
||||||
|
|
||||||
|
container candidate-bsr {
|
||||||
|
presence
|
||||||
|
"Enable router to be a Candidate BSR.";
|
||||||
|
|
||||||
|
description
|
||||||
|
"Candidate BSR settings";
|
||||||
|
|
||||||
|
leaf bsr-priority {
|
||||||
|
type uint8;
|
||||||
|
default "64";
|
||||||
|
description
|
||||||
|
"BSR priority for this router, higher values win.";
|
||||||
|
}
|
||||||
|
|
||||||
|
choice source-address-or-interface {
|
||||||
|
description "IP address to use for BSR 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // candidate-bsr
|
||||||
|
} // candidate-bsr-container
|
||||||
|
|
||||||
grouping candidate-rp-container {
|
grouping candidate-rp-container {
|
||||||
description
|
description
|
||||||
"Grouping of Candidate RP settings.";
|
"Grouping of Candidate RP settings.";
|
||||||
|
@ -131,6 +168,7 @@ module frr-pim-candidate {
|
||||||
+ "frr-pim:address-family" {
|
+ "frr-pim:address-family" {
|
||||||
description "PIM Candidate RP augmentation.";
|
description "PIM Candidate RP augmentation.";
|
||||||
|
|
||||||
|
uses candidate-bsr-container;
|
||||||
uses candidate-rp-container;
|
uses candidate-rp-container;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue