&scope->bs_timer);
}
+static inline void pim_bs_timer_restart(struct bsm_scope *scope, int bs_timeout)
+{
+ pim_bs_timer_start(scope, bs_timeout);
+}
+
void pim_bsm_proc_init(struct pim_instance *pim)
{
memset(&pim->global_scope, 0, sizeof(struct bsm_scope));
pim_g2rp_timer_start(bsrp, hold_time);
}
+static bool pim_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr,
+ struct in_addr ip_src_addr)
+{
+ struct pim_nexthop nexthop;
+ int result;
+
+ memset(&nexthop, 0, sizeof(nexthop));
+
+ /* New BSR recived */
+ if (bsr.s_addr != pim->global_scope.current_bsr.s_addr) {
+ result = pim_nexthop_match(pim, bsr, ip_src_addr);
+
+ /* Nexthop lookup pass for the new BSR address */
+ if (result)
+ return true;
+
+ if (PIM_DEBUG_BSM) {
+ char bsr_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<bsr?>", bsr, bsr_str, sizeof(bsr_str));
+ zlog_debug("%s : No route to BSR address %s",
+ __PRETTY_FUNCTION__, bsr_str);
+ }
+ return false;
+ }
+
+ return pim_nexthop_match_nht_cache(pim, bsr, ip_src_addr);
+}
+
+static bool is_preferred_bsr(struct pim_instance *pim, struct in_addr bsr,
+ uint32_t bsr_prio)
+{
+ if (bsr.s_addr == pim->global_scope.current_bsr.s_addr)
+ return true;
+
+ if (bsr_prio > pim->global_scope.current_bsr_prio)
+ return true;
+
+ else if (bsr_prio == pim->global_scope.current_bsr_prio) {
+ if (bsr.s_addr >= pim->global_scope.current_bsr.s_addr)
+ return true;
+ else
+ return false;
+ } else
+ return false;
+}
+
+static void pim_bsm_update(struct pim_instance *pim, struct in_addr bsr,
+ uint32_t bsr_prio)
+{
+ struct pim_nexthop_cache pnc;
+
+ if (bsr.s_addr != pim->global_scope.current_bsr.s_addr) {
+ struct prefix nht_p;
+ char buf[PREFIX2STR_BUFFER];
+ bool is_bsr_tracking = true;
+
+ /* De-register old BSR and register new BSR with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+
+ if (pim->global_scope.current_bsr.s_addr != INADDR_ANY) {
+ nht_p.u.prefix4 = pim->global_scope.current_bsr;
+ if (PIM_DEBUG_BSM) {
+ prefix2str(&nht_p, buf, sizeof(buf));
+ zlog_debug(
+ "%s: Deregister BSR addr %s with Zebra NHT",
+ __PRETTY_FUNCTION__, buf);
+ }
+ pim_delete_tracked_nexthop(pim, &nht_p, NULL, NULL,
+ is_bsr_tracking);
+ }
+
+ nht_p.u.prefix4 = bsr;
+ if (PIM_DEBUG_BSM) {
+ prefix2str(&nht_p, buf, sizeof(buf));
+ zlog_debug(
+ "%s: NHT Register BSR addr %s with Zebra NHT",
+ __PRETTY_FUNCTION__, buf);
+ }
+
+ memset(&pnc, 0, sizeof(struct pim_nexthop_cache));
+ pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL,
+ is_bsr_tracking, &pnc);
+ pim->global_scope.current_bsr = bsr;
+ pim->global_scope.current_bsr_first_ts =
+ pim_time_monotonic_sec();
+ pim->global_scope.state = ACCEPT_PREFERRED;
+ }
+ pim->global_scope.current_bsr_prio = bsr_prio;
+ pim->global_scope.current_bsr_last_ts = pim_time_monotonic_sec();
+}
+
struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope,
struct prefix *grp)
{
return bsgrp;
}
+
+int pim_bsm_process(struct interface *ifp, struct ip *ip_hdr, uint8_t *buf,
+ uint32_t buf_size, bool no_fwd)
+{
+ struct bsm_hdr *bshdr;
+ struct bsmmsg_grpinfo *msg_grp;
+ struct pim_interface *pim_ifp = NULL;
+ struct pim_instance *pim;
+ char bsr_str[INET_ADDRSTRLEN];
+ uint16_t frag_tag;
+ bool empty_bsm = FALSE;
+
+ /* BSM Packet acceptance validation */
+ pim_ifp = ifp->info;
+ if (!pim_ifp) {
+ if (PIM_DEBUG_BSM)
+ zlog_debug("%s: multicast not enabled on interface %s",
+ __PRETTY_FUNCTION__, ifp->name);
+ return -1;
+ }
+
+ pim_ifp->pim_ifstat_bsm_rx++;
+ pim = pim_ifp->pim;
+ pim->bsm_rcvd++;
+
+ /* Drop if bsm processing is disabled on interface */
+ if (!pim_ifp->bsm_enable) {
+ zlog_warn("%s: BSM not enabled on interface %s",
+ __PRETTY_FUNCTION__, ifp->name);
+ pim_ifp->pim_ifstat_bsm_cfg_miss++;
+ pim->bsm_dropped++;
+ return -1;
+ }
+
+ bshdr = (struct bsm_hdr *)(buf + PIM_MSG_HEADER_LEN);
+ pim_inet4_dump("<bsr?>", bshdr->bsr_addr.addr, bsr_str,
+ sizeof(bsr_str));
+ pim->global_scope.hashMasklen = bshdr->hm_len;
+ frag_tag = ntohs(bshdr->frag_tag);
+
+ /* Identify empty BSM */
+ if ((buf_size - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN) < PIM_BSM_GRP_LEN)
+ empty_bsm = true;
+
+ if (!empty_bsm) {
+ msg_grp = (struct bsmmsg_grpinfo *)(buf + PIM_MSG_HEADER_LEN
+ + PIM_BSM_HDR_LEN);
+ /* Currently we don't support scope zoned BSM */
+ if (msg_grp->group.sz) {
+ if (PIM_DEBUG_BSM)
+ zlog_debug(
+ "%s : Administratively scoped range BSM received",
+ __PRETTY_FUNCTION__);
+ pim_ifp->pim_ifstat_bsm_invalid_sz++;
+ pim->bsm_dropped++;
+ return -1;
+ }
+ }
+
+ /* Drop if bsr is not preferred bsr */
+ if (!is_preferred_bsr(pim, bshdr->bsr_addr.addr, bshdr->bsr_prio)) {
+ if (PIM_DEBUG_BSM)
+ zlog_debug("%s : Received a non-preferred BSM",
+ __PRETTY_FUNCTION__);
+ 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 %s when accpt_nofwd_bsm false",
+ __PRETTY_FUNCTION__, bsr_str);
+ pim->bsm_dropped++;
+ pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++;
+ return -1;
+ }
+ }
+
+ /* Mulicast BSM received */
+ if (ip_hdr->ip_dst.s_addr == qpim_all_pim_routers_addr.s_addr) {
+ if (!no_fwd) {
+ if (!pim_bsr_rpf_check(pim, bshdr->bsr_addr.addr,
+ ip_hdr->ip_src)) {
+ if (PIM_DEBUG_BSM)
+ zlog_debug(
+ "%s : RPF check fail for BSR address %s",
+ __PRETTY_FUNCTION__, bsr_str);
+ pim->bsm_dropped++;
+ return -1;
+ }
+ }
+ } else if (if_lookup_exact_address(&ip_hdr->ip_dst, AF_INET,
+ pim->vrf_id)) {
+ /* Unicast BSM received - if ucast bsm not enabled on
+ * the interface, drop it
+ */
+ if (!pim_ifp->ucast_bsm_accept) {
+ if (PIM_DEBUG_BSM)
+ zlog_debug(
+ "%s : Unicast BSM not enabled on interface %s",
+ __PRETTY_FUNCTION__, ifp->name);
+ pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++;
+ pim->bsm_dropped++;
+ return -1;
+ }
+
+ } else {
+ if (PIM_DEBUG_BSM)
+ zlog_debug("%s : Invalid destination address",
+ __PRETTY_FUNCTION__);
+ pim->bsm_dropped++;
+ return -1;
+ }
+
+ if (empty_bsm) {
+ if (PIM_DEBUG_BSM)
+ zlog_debug("%s : Empty Pref BSM received",
+ __PRETTY_FUNCTION__);
+ }
+ /* Restart the bootstrap timer */
+ pim_bs_timer_restart(&pim_ifp->pim->global_scope,
+ PIM_BSR_DEFAULT_TIMEOUT);
+
+ /* If new BSM received, clear the old bsm database */
+ if (pim_ifp->pim->global_scope.bsm_frag_tag != frag_tag) {
+ if (PIM_DEBUG_BSM) {
+ zlog_debug("%s: Current frag tag: %d Frag teg rcvd: %d",
+ __PRETTY_FUNCTION__,
+ pim_ifp->pim->global_scope.bsm_frag_tag,
+ frag_tag);
+ }
+ list_delete_all_node(pim_ifp->pim->global_scope.bsm_list);
+ pim_ifp->pim->global_scope.bsm_frag_tag = frag_tag;
+ }
+
+ /* update the scope information from bsm */
+ pim_bsm_update(pim, bshdr->bsr_addr.addr, bshdr->bsr_prio);
+ return 0;
+}