#include "pim_msg.h"
/* Defines */
-#define PIM_GBL_SZ_ID 0 /* global scope zone id set to 0 */
-#define PIM_BS_TIME 60 /* RFC 5059 - Sec 5 */
+#define PIM_GBL_SZ_ID 0 /* global scope zone id set to 0 */
+#define PIM_BS_TIME 60 /* RFC 5059 - Sec 5 */
#define PIM_BSR_DEFAULT_TIMEOUT 130 /* RFC 5059 - Sec 5 */
/* These structures are only encoded IPv4 specific */
-#define PIM_BSM_HDR_LEN sizeof(struct bsm_hdr)
-#define PIM_BSM_GRP_LEN sizeof(struct bsmmsg_grpinfo)
-#define PIM_BSM_RP_LEN sizeof(struct bsmmsg_rpinfo)
+#define PIM_BSM_HDR_LEN sizeof(struct bsm_hdr)
+#define PIM_BSM_GRP_LEN sizeof(struct bsmmsg_grpinfo)
+#define PIM_BSM_RP_LEN sizeof(struct bsmmsg_rpinfo)
+
+#define PIM_MIN_BSM_LEN \
+ (PIM_HDR_LEN + PIM_BSM_HDR_LEN + PIM_BSM_GRP_LEN + PIM_BSM_RP_LEN)
-#define PIM_MIN_BSM_LEN (PIM_HDR_LEN + \
- PIM_BSM_HDR_LEN + \
- PIM_BSM_GRP_LEN + \
- PIM_BSM_RP_LEN)
/* Datastructures
* ==============
*/
/* Non candidate BSR states */
-enum ncbsr_state{
+enum ncbsr_state {
NO_INFO = 0,
ACCEPT_ANY,
ACCEPT_PREFERRED
/* BSM scope - bsm processing is per scope */
struct bsm_scope {
- int sz_id; /* scope zone id */
- enum ncbsr_state state; /* non candidate BSR state */
- bool accept_nofwd_bsm; /* no fwd bsm accepted for scope */
+ int sz_id; /* scope zone id */
+ enum ncbsr_state state; /* non candidate BSR state */
+ bool accept_nofwd_bsm; /* no fwd bsm accepted for scope */
struct in_addr current_bsr; /* current elected BSR for the sz */
uint32_t current_bsr_prio; /* current BSR priority */
int64_t current_bsr_first_ts; /* current BSR elected time */
int64_t current_bsr_last_ts; /* Last BSM received from E-BSR */
- uint16_t bsm_frag_tag; /* Last received frag tag from E-BSR */
- uint8_t hashMasklen; /* Mask in hash calc RFC 7761 4.7.2 */
+ uint16_t bsm_frag_tag; /* Last received frag tag from E-BSR */
+ uint8_t hashMasklen; /* Mask in hash calc RFC 7761 4.7.2 */
struct pim_instance *pim; /* Back pointer to pim instance */
- struct list *bsm_list; /* list of bsm frag for frowarding */
+ struct list *bsm_list; /* list of bsm frag for frowarding */
struct route_table *bsrp_table; /* group2rp mapping rcvd from BSR */
- struct thread *bs_timer; /* Boot strap timer */
+ struct thread *bs_timer; /* Boot strap timer */
struct thread *sz_timer;
};
* this node maintains the list of rp for the group.
*/
struct bsgrp_node {
- struct prefix group; /* Group range */
- struct bsm_scope *scope; /* Back ptr to scope */
- struct list *bsrp_list; /* list of RPs adv by BSR */
+ struct prefix group; /* Group range */
+ struct bsm_scope *scope; /* Back ptr to scope */
+ struct list *bsrp_list; /* list of RPs adv by BSR */
struct list *partial_bsrp_list; /* maintained until all RPs received */
- int pend_rp_cnt; /* Total RP - Received RP */
- uint16_t frag_tag; /* frag tag to identify the fragment */
+ int pend_rp_cnt; /* Total RP - Received RP */
+ uint16_t frag_tag; /* frag tag to identify the fragment */
};
/* This is the list node of bsrp_list and partial bsrp list in
uint8_t hm_len;
uint8_t bsr_prio;
struct pim_encoded_ipv4_unicast bsr_addr;
-}__attribute__((packed));
+} __attribute__((packed));
struct bsmmsg_grpinfo {
struct pim_encoded_group_ipv4 group;
uint8_t rp_count;
uint8_t frag_rp_count;
uint16_t reserved;
-}__attribute__((packed));
+} __attribute__((packed));
struct bsmmsg_rpinfo {
struct pim_encoded_ipv4_unicast rpaddr;
uint16_t rp_holdtime;
uint8_t rp_pri;
uint8_t reserved;
-}__attribute__((packed));
+} __attribute__((packed));
/* API */
void pim_bsm_proc_init(struct pim_instance *pim);
void pim_bsm_proc_free(struct pim_instance *pim);
void pim_bsm_write_config(struct vty *vty, struct interface *ifp);
+struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope,
+ struct prefix *grp);
#endif
#include "pim_mroute.h"
#include "pim_oil.h"
#include "pim_zebra.h"
+#include "pim_bsm.h"
/* Cleanup pim->rpf_hash each node data */
void pim_rp_list_hash_clean(void *data)
pim_zebra_update_all_interfaces(pim);
}
-int pim_rp_new(struct pim_instance *pim, const char *rp,
- const char *group_range, const char *plist)
+int pim_rp_new_config(struct pim_instance *pim, const char *rp,
+ const char *group_range, const char *plist)
{
int result = 0;
+ struct prefix group;
+ struct in_addr rp_addr;
+
+ if (group_range == NULL)
+ result = str2prefix("224.0.0.0/4", &group);
+ else {
+ result = str2prefix(group_range, &group);
+ if (result) {
+ struct prefix temp;
+
+ prefix_copy(&temp, &group);
+ apply_mask(&temp);
+ if (!prefix_same(&group, &temp))
+ return PIM_GROUP_BAD_ADDR_MASK_COMBO;
+ }
+ }
+
+ if (!result)
+ return PIM_GROUP_BAD_ADDRESS;
+
+ result = inet_pton(AF_INET, rp, &rp_addr);
+
+ if (result <= 0)
+ return PIM_RP_BAD_ADDRESS;
+
+ result = pim_rp_new(pim, rp_addr, group, plist, RP_SRC_STATIC);
+ return result;
+}
+
+int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr,
+ struct prefix group, const char *plist,
+ enum rp_source rp_src_flag)
+{
+ int result = 0;
+ char rp[INET_ADDRSTRLEN];
struct rp_info *rp_info;
struct rp_info *rp_all;
struct prefix group_all;
struct rp_info *tmp_rp_info;
char buffer[BUFSIZ];
struct prefix nht_p;
- struct prefix temp;
struct route_node *rn;
struct pim_upstream *up;
struct listnode *upnode;
rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info));
- if (group_range == NULL)
- result = str2prefix("224.0.0.0/4", &rp_info->group);
- else {
- result = str2prefix(group_range, &rp_info->group);
- if (result) {
- prefix_copy(&temp, &rp_info->group);
- apply_mask(&temp);
- if (!prefix_same(&rp_info->group, &temp)) {
- XFREE(MTYPE_PIM_RP, rp_info);
- return PIM_GROUP_BAD_ADDR_MASK_COMBO;
- }
- }
- }
-
- if (!result) {
- XFREE(MTYPE_PIM_RP, rp_info);
- return PIM_GROUP_BAD_ADDRESS;
- }
-
rp_info->rp.rpf_addr.family = AF_INET;
rp_info->rp.rpf_addr.prefixlen = IPV4_MAX_PREFIXLEN;
- result = inet_pton(rp_info->rp.rpf_addr.family, rp,
- &rp_info->rp.rpf_addr.u.prefix4);
+ rp_info->rp.rpf_addr.u.prefix4 = rp_addr;
+ prefix_copy(&rp_info->group, &group);
+ rp_info->rp_src = rp_src_flag;
- if (result <= 0) {
- XFREE(MTYPE_PIM_RP, rp_info);
- return PIM_RP_BAD_ADDRESS;
- }
+ inet_ntop(AF_INET, &rp_info->rp.rpf_addr.u.prefix4, rp, sizeof(rp));
if (plist) {
/*
if (rp_info->rp.rpf_addr.u.prefix4.s_addr
== tmp_rp_info->rp.rpf_addr.u.prefix4.s_addr) {
if (tmp_rp_info->plist)
- pim_rp_del(pim, rp, NULL,
- tmp_rp_info->plist);
+ pim_rp_del_config(pim, rp, NULL,
+ tmp_rp_info->plist);
else
- pim_rp_del(
+ pim_rp_del_config(
pim, rp,
prefix2str(&tmp_rp_info->group,
buffer, BUFSIZ),
&& rp_info->rp.rpf_addr.u.prefix4.s_addr
== tmp_rp_info->rp.rpf_addr.u.prefix4
.s_addr) {
- pim_rp_del(pim, rp, NULL, tmp_rp_info->plist);
+ pim_rp_del_config(pim, rp, NULL,
+ tmp_rp_info->plist);
}
}
if (prefix_same(&rp_all->group, &rp_info->group)
&& pim_rpf_addr_is_inaddr_none(&rp_all->rp)) {
rp_all->rp.rpf_addr = rp_info->rp.rpf_addr;
+ rp_all->rp_src = rp_src_flag;
XFREE(MTYPE_PIM_RP, rp_info);
/* Register addr with Zebra NHT */
grp.family = AF_INET;
grp.prefixlen = IPV4_MAX_BITLEN;
grp.u.prefix4 = up->sg.grp;
- trp_info = pim_rp_find_match_group(pim,
- &grp);
+ trp_info = pim_rp_find_match_group(
+ pim, &grp);
if (trp_info == rp_all)
pim_upstream_update(pim, up);
}
pim_rp_check_interfaces(pim, rp_all);
pim_rp_refresh_group_to_rp_mapping(pim);
-
pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_all,
false, NULL);
&rp_all->rp.source_nexthop,
&nht_p, &rp_all->group, 1))
return PIM_RP_NO_PATH;
-
return PIM_SUCCESS;
}
/*
* Return if the group is already configured for this RP
*/
- if (pim_rp_find_exact(pim, rp_info->rp.rpf_addr.u.prefix4,
- &rp_info->group)) {
+ tmp_rp_info = pim_rp_find_exact(
+ pim, rp_info->rp.rpf_addr.u.prefix4, &rp_info->group);
+ if (tmp_rp_info) {
+ if ((tmp_rp_info->rp_src != rp_src_flag)
+ && (rp_src_flag == RP_SRC_STATIC))
+ tmp_rp_info->rp_src = rp_src_flag;
XFREE(MTYPE_PIM_RP, rp_info);
- return PIM_SUCCESS;
+ return result;
}
/*
*/
if (prefix_same(&rp_info->group,
&tmp_rp_info->group)) {
+ if ((rp_src_flag == RP_SRC_STATIC)
+ && (tmp_rp_info->rp_src
+ == RP_SRC_STATIC)) {
+ XFREE(MTYPE_PIM_RP, rp_info);
+ return PIM_GROUP_OVERLAP;
+ }
+
+ result = pim_rp_change(
+ pim,
+ rp_info->rp.rpf_addr.u.prefix4,
+ tmp_rp_info->group,
+ rp_src_flag);
XFREE(MTYPE_PIM_RP, rp_info);
- return PIM_GROUP_OVERLAP;
+ return result;
}
}
}
zlog_debug("%s: NHT Register RP addr %s grp %s with Zebra ",
__PRETTY_FUNCTION__, buf, buf1);
}
-
pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, false, NULL);
if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, &nht_p,
&rp_info->group, 1))
return PIM_SUCCESS;
}
-int pim_rp_del(struct pim_instance *pim, const char *rp,
- const char *group_range, const char *plist)
+int pim_rp_del_config(struct pim_instance *pim, const char *rp,
+ const char *group_range, const char *plist)
{
struct prefix group;
struct in_addr rp_addr;
- struct prefix g_all;
- struct rp_info *rp_info;
- struct rp_info *rp_all;
int result;
- struct prefix nht_p;
- struct route_node *rn;
- bool was_plist = false;
- struct rp_info *trp_info;
- struct pim_upstream *up;
- struct listnode *upnode;
if (group_range == NULL)
result = str2prefix("224.0.0.0/4", &group);
if (result <= 0)
return PIM_RP_BAD_ADDRESS;
+ result = pim_rp_del(pim, rp_addr, group, plist, RP_SRC_STATIC);
+ return result;
+}
+
+int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr,
+ struct prefix group, const char *plist,
+ enum rp_source rp_src_flag)
+{
+ struct prefix g_all;
+ struct rp_info *rp_info;
+ struct rp_info *rp_all;
+ struct prefix nht_p;
+ struct route_node *rn;
+ bool was_plist = false;
+ struct rp_info *trp_info;
+ struct pim_upstream *up;
+ struct listnode *upnode;
+ struct bsgrp_node *bsgrp = NULL;
+ struct bsm_rpinfo *bsrp = NULL;
+ char grp_str[PREFIX2STR_BUFFER];
+ char rp_str[INET_ADDRSTRLEN];
+
+ if (!inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str)))
+ sprintf(rp_str, "<rp?>");
+ prefix2str(&group, grp_str, sizeof(grp_str));
+
if (plist)
rp_info = pim_rp_find_prefix_list(pim, rp_addr, plist);
else
was_plist = true;
}
+ if (PIM_DEBUG_TRACE)
+ zlog_debug("%s: Delete RP %s for the group %s",
+ __PRETTY_FUNCTION__, rp_str, grp_str);
+
+ /* While static RP is getting deleted, we need to check if dynamic RP
+ * present for the same group in BSM RP table, then install the dynamic
+ * RP for the group node into the main rp table
+ */
+ if (rp_src_flag == RP_SRC_STATIC) {
+ bsgrp = pim_bsm_get_bsgrp_node(&pim->global_scope, &group);
+
+ if (bsgrp) {
+ bsrp = listnode_head(bsgrp->bsrp_list);
+ if (bsrp) {
+ if (PIM_DEBUG_TRACE) {
+ char bsrp_str[INET_ADDRSTRLEN];
+
+ if (!inet_ntop(AF_INET, bsrp, bsrp_str,
+ sizeof(bsrp_str)))
+ sprintf(bsrp_str, "<bsrp?>");
+
+ zlog_debug("%s: BSM RP %s found for the group %s",
+ __PRETTY_FUNCTION__,
+ bsrp_str, grp_str);
+ }
+ return pim_rp_change(pim, bsrp->rp_address,
+ group, RP_SRC_BSR);
+ }
+ } else {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug(
+ "%s: BSM RP not found for the group %s",
+ __PRETTY_FUNCTION__, grp_str);
+ }
+ }
+
/* Deregister addr with Zebra NHT */
nht_p.family = AF_INET;
nht_p.prefixlen = IPV4_MAX_BITLEN;
/* Find the upstream (*, G) whose upstream address is
* same as the deleted RP
*/
- if ((up->upstream_addr.s_addr == rp_addr.s_addr) &&
- (up->sg.src.s_addr == INADDR_ANY)) {
+ if ((up->upstream_addr.s_addr
+ == rp_info->rp.rpf_addr.u.prefix4.s_addr)
+ && (up->sg.src.s_addr == INADDR_ANY)) {
struct prefix grp;
grp.family = AF_INET;
grp.prefixlen = IPV4_MAX_BITLEN;
/* Find the upstream (*, G) whose upstream address is same as
* the deleted RP
*/
- if ((up->upstream_addr.s_addr == rp_addr.s_addr) &&
- (up->sg.src.s_addr == INADDR_ANY)) {
+ if ((up->upstream_addr.s_addr
+ == rp_info->rp.rpf_addr.u.prefix4.s_addr)
+ && (up->sg.src.s_addr == INADDR_ANY)) {
struct prefix grp;
grp.family = AF_INET;
/* RP not found for the group grp */
if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) {
pim_upstream_rpf_clear(pim, up);
- pim_rp_set_upstream_addr(pim,
- &up->upstream_addr,
- up->sg.src, up->sg.grp);
+ pim_rp_set_upstream_addr(
+ pim, &up->upstream_addr, up->sg.src,
+ up->sg.grp);
}
/* RP found for the group grp */
return PIM_SUCCESS;
}
+int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr,
+ struct prefix group, enum rp_source rp_src_flag)
+{
+ struct prefix nht_p;
+ struct route_node *rn;
+ int result = 0;
+ struct rp_info *rp_info = NULL;
+ struct pim_upstream *up;
+ struct listnode *upnode;
+
+ rn = route_node_lookup(pim->rp_table, &group);
+ if (!rn) {
+ result = pim_rp_new(pim, new_rp_addr, group, NULL, rp_src_flag);
+ return result;
+ }
+
+ rp_info = rn->info;
+
+ if (!rp_info) {
+ route_unlock_node(rn);
+ result = pim_rp_new(pim, new_rp_addr, group, NULL, rp_src_flag);
+ return result;
+ }
+
+ if (rp_info->rp.rpf_addr.u.prefix4.s_addr == new_rp_addr.s_addr) {
+ if (rp_info->rp_src != rp_src_flag) {
+ rp_info->rp_src = rp_src_flag;
+ route_unlock_node(rn);
+ return PIM_SUCCESS;
+ }
+ }
+
+ /* Deregister old RP addr with Zebra NHT */
+ if (rp_info->rp.rpf_addr.u.prefix4.s_addr != INADDR_ANY) {
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
+ if (PIM_DEBUG_PIM_NHT_RP) {
+ char buf[PREFIX2STR_BUFFER];
+
+ prefix2str(&nht_p, buf, sizeof(buf));
+ zlog_debug("%s: Deregister RP addr %s with Zebra ",
+ __PRETTY_FUNCTION__, buf);
+ }
+ pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info, false);
+ }
+
+ pim_rp_nexthop_del(rp_info);
+ listnode_delete(pim->rp_list, rp_info);
+ /* Update the new RP address*/
+ rp_info->rp.rpf_addr.u.prefix4 = new_rp_addr;
+ rp_info->rp_src = rp_src_flag;
+ rp_info->i_am_rp = 0;
+
+ listnode_add_sort(pim->rp_list, rp_info);
+
+ for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+ if (up->sg.src.s_addr == INADDR_ANY) {
+ struct prefix grp;
+ struct rp_info *trp_info;
+
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+ trp_info = pim_rp_find_match_group(pim, &grp);
+
+ if (trp_info == rp_info)
+ pim_upstream_update(pim, up);
+ }
+ }
+
+ /* Register new RP addr with Zebra NHT */
+ nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
+ if (PIM_DEBUG_PIM_NHT_RP) {
+ char buf[PREFIX2STR_BUFFER];
+ char buf1[PREFIX2STR_BUFFER];
+
+ prefix2str(&nht_p, buf, sizeof(buf));
+ prefix2str(&rp_info->group, buf1, sizeof(buf1));
+ zlog_debug("%s: NHT Register RP addr %s grp %s with Zebra ",
+ __PRETTY_FUNCTION__, buf, buf1);
+ }
+
+ pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, false, NULL);
+ if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, &nht_p,
+ &rp_info->group, 1)) {
+ route_unlock_node(rn);
+ return PIM_RP_NO_PATH;
+ }
+
+ pim_rp_check_interfaces(pim, rp_info);
+
+ route_unlock_node(rn);
+
+ pim_rp_refresh_group_to_rp_mapping(pim);
+
+ return result;
+}
+
void pim_rp_setup(struct pim_instance *pim)
{
struct listnode *node;
if (pim_rpf_addr_is_inaddr_none(&rp_info->rp))
continue;
+ if (rp_info->rp_src == RP_SRC_BSR)
+ continue;
+
if (rp_info->plist)
vty_out(vty, "%sip pim rp %s prefix-list %s\n", spaces,
inet_ntop(AF_INET,
json_row, "group",
prefix2str(&rp_info->group, buf,
48));
- json_object_string_add(json_row,
- "source",
+ json_object_string_add(json_row, "source",
source);
json_object_array_add(json_rp_rows, json_row);