summaryrefslogtreecommitdiffstats
path: root/pimd/pim_nht.c
diff options
context:
space:
mode:
Diffstat (limited to 'pimd/pim_nht.c')
-rw-r--r--pimd/pim_nht.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
index 3a3a74b15..d0611a4ae 100644
--- a/pimd/pim_nht.c
+++ b/pimd/pim_nht.c
@@ -242,6 +242,169 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
}
}
+/* Given a source address and a neighbor address, check if the neighbor is one
+ * of the next hop to reach the source. search from zebra route database
+ */
+bool pim_nexthop_match(struct pim_instance *pim, struct in_addr addr,
+ struct in_addr ip_src)
+{
+ struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
+ int i = 0;
+ ifindex_t first_ifindex = 0;
+ struct interface *ifp = NULL;
+ struct pim_neighbor *nbr = NULL;
+ int num_ifindex;
+
+ if (addr.s_addr == INADDR_NONE)
+ return 0;
+
+ memset(nexthop_tab, 0,
+ sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
+ num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
+ addr, PIM_NEXTHOP_LOOKUP_MAX);
+ if (num_ifindex < 1) {
+ char addr_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
+ zlog_warn(
+ "%s %s: could not find nexthop ifindex for address %s",
+ __FILE__, __PRETTY_FUNCTION__, addr_str);
+ return 0;
+ }
+
+ while (i < num_ifindex) {
+ first_ifindex = nexthop_tab[i].ifindex;
+
+ ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
+ if (!ifp) {
+ if (PIM_DEBUG_ZEBRA) {
+ char addr_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<addr?>", addr, addr_str,
+ sizeof(addr_str));
+ zlog_debug(
+ "%s %s: could not find interface for ifindex %d (address %s)",
+ __FILE__, __PRETTY_FUNCTION__,
+ first_ifindex, addr_str);
+ }
+ i++;
+ continue;
+ }
+
+ if (!ifp->info) {
+ if (PIM_DEBUG_ZEBRA) {
+ char addr_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<addr?>", addr, addr_str,
+ sizeof(addr_str));
+ zlog_debug(
+ "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
+ __PRETTY_FUNCTION__, ifp->name,
+ first_ifindex, addr_str);
+ }
+ i++;
+ continue;
+ }
+
+ if (!pim_if_connected_to_source(ifp, addr)) {
+ nbr = pim_neighbor_find(
+ ifp, nexthop_tab[i].nexthop_addr.u.prefix4);
+ if (PIM_DEBUG_PIM_TRACE_DETAIL)
+ zlog_debug("ifp name: %s, pim nbr: %p",
+ ifp->name, nbr);
+ if (!nbr && !if_is_loopback(ifp)) {
+ i++;
+ continue;
+ }
+ }
+
+ if (nexthop_tab[i].nexthop_addr.u.prefix4.s_addr
+ == ip_src.s_addr)
+ return 1;
+
+ i++;
+ }
+
+ return 0;
+}
+
+/* Given a source address and a neighbor address, check if the neighbor is one
+ * of the next hop to reach the source. search from pim next hop cache
+ */
+bool pim_nexthop_match_nht_cache(struct pim_instance *pim, struct in_addr addr,
+ struct in_addr ip_src)
+{
+ struct pim_rpf rpf;
+ ifindex_t first_ifindex;
+ struct interface *ifp = NULL;
+ uint8_t nh_iter = 0;
+ struct pim_neighbor *nbr = NULL;
+ struct nexthop *nh_node = NULL;
+ struct pim_nexthop_cache *pnc = NULL;
+
+ memset(&rpf, 0, sizeof(struct pim_rpf));
+ rpf.rpf_addr.family = AF_INET;
+ rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN;
+ rpf.rpf_addr.u.prefix4 = addr;
+
+ pnc = pim_nexthop_cache_find(pim, &rpf);
+ if (!pnc || !pnc->nexthop_num)
+ return 0;
+
+ for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
+ first_ifindex = nh_node->ifindex;
+ ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
+ if (!ifp) {
+ if (PIM_DEBUG_PIM_NHT) {
+ char addr_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<addr?>", addr, addr_str,
+ sizeof(addr_str));
+ zlog_debug(
+ "%s %s: could not find interface for ifindex %d (address %s(%s))",
+ __FILE__, __PRETTY_FUNCTION__,
+ first_ifindex, addr_str,
+ pim->vrf->name);
+ }
+ nh_iter++;
+ continue;
+ }
+ if (!ifp->info) {
+ if (PIM_DEBUG_PIM_NHT) {
+ char addr_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<addr?>", addr, addr_str,
+ sizeof(addr_str));
+ zlog_debug(
+ "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
+ __PRETTY_FUNCTION__, ifp->name,
+ pim->vrf->name, first_ifindex,
+ addr_str);
+ }
+ nh_iter++;
+ continue;
+ }
+
+ if (!pim_if_connected_to_source(ifp, addr)) {
+ nbr = pim_neighbor_find(ifp, nh_node->gate.ipv4);
+ if (!nbr && !if_is_loopback(ifp)) {
+ if (PIM_DEBUG_PIM_NHT)
+ zlog_debug(
+ "%s: pim nbr not found on input interface %s(%s)",
+ __PRETTY_FUNCTION__, ifp->name,
+ pim->vrf->name);
+ nh_iter++;
+ continue;
+ }
+ }
+
+ if (nh_node->gate.ipv4.s_addr == ip_src.s_addr)
+ return 1;
+ }
+
+ return 0;
+}
+
void pim_rp_nexthop_del(struct rp_info *rp_info)
{
rp_info->rp.source_nexthop.interface = NULL;