summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pimd/pim_cmd.c216
-rw-r--r--pimd/pim_iface.c49
-rw-r--r--pimd/pim_mroute.c12
-rw-r--r--pimd/pim_neighbor.c14
-rw-r--r--pimd/pim_nht.c561
-rw-r--r--pimd/pim_nht.h13
-rw-r--r--pimd/pim_oil.c4
-rw-r--r--pimd/pim_register.c9
-rw-r--r--pimd/pim_rp.c174
-rw-r--r--pimd/pim_rp.h2
-rw-r--r--pimd/pim_rpf.c67
-rw-r--r--pimd/pim_upstream.c22
-rw-r--r--pimd/pim_zebra.c168
-rw-r--r--pimd/pimd.c4
-rw-r--r--pimd/pimd.h3
15 files changed, 1144 insertions, 174 deletions
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 3c5a16ec6..6af072f32 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -26,6 +26,8 @@
#include "prefix.h"
#include "zclient.h"
#include "plist.h"
+#include "hash.h"
+#include "nexthop.h"
#include "pimd.h"
#include "pim_mroute.h"
@@ -55,6 +57,7 @@
#include "pim_zlookup.h"
#include "pim_msdp.h"
#include "pim_ssm.h"
+#include "pim_nht.h"
static struct cmd_node pim_global_node = {
PIM_NODE,
@@ -2059,6 +2062,50 @@ static void pim_show_rpf(struct vty *vty, u_char uj)
}
}
+static int
+pim_print_pnc_cache_walkcb (struct hash_backet *backet, void *arg)
+{
+ struct pim_nexthop_cache *pnc = backet->data;
+ struct vty *vty = arg;
+ struct nexthop *nh_node = NULL;
+ ifindex_t first_ifindex;
+ struct interface *ifp = NULL;
+
+ if (!pnc)
+ return CMD_SUCCESS;
+
+ for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next)
+ {
+ first_ifindex = nh_node->ifindex;
+ ifp = if_lookup_by_index (first_ifindex, VRF_DEFAULT);
+
+ vty_out (vty, "%-15s ", inet_ntoa (pnc->rpf.rpf_addr.u.prefix4));
+ vty_out (vty, "%-14s ", ifp ? ifp->name : "NULL");
+ vty_out (vty, "%s ", inet_ntoa (nh_node->gate.ipv4));
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
+static void
+pim_show_nexthop (struct vty *vty)
+{
+
+ if (pimg && !pimg->rpf_hash)
+ {
+ vty_out (vty, "no nexthop cache %s", VTY_NEWLINE);
+ return;
+ }
+
+ vty_out (vty, "Number of registered addresses: %lu %s",
+ pimg->rpf_hash->count, VTY_NEWLINE);
+ vty_out (vty, "Address Interface Nexthop%s", VTY_NEWLINE);
+ vty_out (vty, "-------------------------------------------%s", VTY_NEWLINE);
+
+ hash_walk (pimg->rpf_hash, pim_print_pnc_cache_walkcb, vty);
+
+}
+
static void igmp_show_groups(struct vty *vty, u_char uj)
{
struct listnode *ifnode;
@@ -2793,6 +2840,99 @@ DEFUN (show_ip_pim_rpf,
return CMD_SUCCESS;
}
+DEFUN (show_ip_pim_nexthop,
+ show_ip_pim_nexthop_cmd,
+ "show ip pim nexthop",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ "PIM cached nexthop rpf information\n")
+{
+ pim_show_nexthop (vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_pim_nexthop_lookup,
+ show_ip_pim_nexthop_lookup_cmd,
+ "show ip pim nexthop-lookup A.B.C.D A.B.C.D",
+ SHOW_STR
+ IP_STR
+ PIM_STR
+ "PIM cached nexthop rpf lookup\n"
+ "Source/RP address\n"
+ "Multicast Group address\n")
+{
+ struct pim_nexthop_cache pnc;
+ struct prefix nht_p;
+ int result = 0;
+ struct in_addr src_addr, grp_addr;
+ struct in_addr vif_source;
+ const char *addr_str, *addr_str1;
+ struct prefix grp;
+ struct pim_nexthop nexthop;
+ char nexthop_addr_str[PREFIX_STRLEN];
+ char grp_str[PREFIX_STRLEN];
+
+ addr_str = (const char *)argv[0];
+ result = inet_pton (AF_INET, addr_str, &src_addr);
+ if (result <= 0)
+ {
+ vty_out (vty, "Bad unicast address %s: errno=%d: %s%s",
+ addr_str, errno, safe_strerror (errno), VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (pim_is_group_224_4 (src_addr))
+ {
+ vty_out (vty, "Invalid argument. Expected Valid Source Address.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ addr_str1 = (const char *)argv[1];
+ result = inet_pton (AF_INET, addr_str1, &grp_addr);
+ if (result <= 0)
+ {
+ vty_out (vty, "Bad unicast address %s: errno=%d: %s%s",
+ addr_str, errno, safe_strerror (errno), VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!pim_is_group_224_4 (grp_addr))
+ {
+ vty_out (vty, "Invalid argument. Expected Valid Multicast Group Address.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!pim_rp_set_upstream_addr (&vif_source, src_addr, grp_addr))
+ return CMD_SUCCESS;
+
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = vif_source;
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = grp_addr;
+ memset (&nexthop, 0, sizeof (nexthop));
+
+ if ((pim_find_or_track_nexthop (&nht_p, NULL, NULL, &pnc)) == 1)
+ {
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&pnc, &nexthop, &nht_p, &grp, 0);
+ }
+ else
+ pim_ecmp_nexthop_lookup (&nexthop, vif_source, &nht_p, &grp, 0);
+
+ pim_addr_dump ("<grp?>", &grp, grp_str, sizeof (grp_str));
+ pim_addr_dump ("<nexthop?>", &nexthop.mrib_nexthop_addr,
+ nexthop_addr_str, sizeof (nexthop_addr_str));
+ vty_out (vty, "Group %s --- Nexthop %s Interface %s %s", grp_str,
+ nexthop_addr_str, nexthop.interface->name, VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
static void show_multicast_interfaces(struct vty *vty)
{
struct listnode *node;
@@ -2871,15 +3011,17 @@ DEFUN (show_ip_multicast,
PIM_MAX_USABLE_VIFS,
VTY_NEWLINE);
- vty_out(vty, "%s", VTY_NEWLINE);
- vty_out(vty, "Upstream Join Timer: %d secs%s",
- qpim_t_periodic,
- VTY_NEWLINE);
- vty_out(vty, "Join/Prune Holdtime: %d secs%s",
- PIM_JP_HOLDTIME,
- VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "Upstream Join Timer: %d secs%s",
+ qpim_t_periodic, VTY_NEWLINE);
+ vty_out (vty, "Join/Prune Holdtime: %d secs%s",
+ PIM_JP_HOLDTIME, VTY_NEWLINE);
+ vty_out (vty, "PIM ECMP: %s%s",
+ qpim_ecmp_enable ? "Enable" : "Disable", VTY_NEWLINE);
+ vty_out (vty, "PIM ECMP Rebalance: %s%s",
+ qpim_ecmp_rebalance_enable ? "Enable" : "Disable", VTY_NEWLINE);
- vty_out(vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
show_rpf_refresh_stats(vty, now, NULL);
@@ -3826,6 +3968,58 @@ DEFUN (no_ip_ssmpingd,
return CMD_SUCCESS;
}
+DEFUN (ip_pim_ecmp,
+ ip_pim_ecmp_cmd,
+ "ip pim ecmp",
+ IP_STR
+ "pim multicast routing\n"
+ "Enable PIM ECMP \n")
+{
+ qpim_ecmp_enable = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_ecmp,
+ no_ip_pim_ecmp_cmd,
+ "no ip pim ecmp",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Disable PIM ECMP \n")
+{
+ qpim_ecmp_enable = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ip_pim_ecmp_rebalance,
+ ip_pim_ecmp_rebalance_cmd,
+ "ip pim ecmp rebalance",
+ IP_STR
+ "pim multicast routing\n"
+ "Enable PIM ECMP \n"
+ "Enable PIM ECMP Rebalance\n")
+{
+ qpim_ecmp_rebalance_enable = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_ecmp_rebalance,
+ no_ip_pim_ecmp_rebalance_cmd,
+ "no ip pim ecmp rebalance",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Disable PIM ECMP \n"
+ "Disable PIM ECMP Rebalance\n")
+{
+ qpim_ecmp_rebalance_enable = 0;
+
+ return CMD_SUCCESS;
+}
+
static int
pim_cmd_igmp_start (struct vty *vty, struct interface *ifp)
{
@@ -6191,6 +6385,10 @@ void pim_cmd_init()
install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd);
install_element (CONFIG_NODE, &ip_msdp_peer_cmd);
install_element (CONFIG_NODE, &no_ip_msdp_peer_cmd);
+ install_element (CONFIG_NODE, &ip_pim_ecmp_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_ecmp_cmd);
+ install_element (CONFIG_NODE, &ip_pim_ecmp_rebalance_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_ecmp_rebalance_cmd);
install_element (INTERFACE_NODE, &interface_ip_igmp_cmd);
install_element (INTERFACE_NODE, &interface_no_ip_igmp_cmd);
@@ -6246,6 +6444,8 @@ void pim_cmd_init()
install_element (VIEW_NODE, &show_ip_rib_cmd);
install_element (VIEW_NODE, &show_ip_ssmpingd_cmd);
install_element (VIEW_NODE, &show_debugging_pim_cmd);
+ install_element (VIEW_NODE, &show_ip_pim_nexthop_cmd);
+ install_element (VIEW_NODE, &show_ip_pim_nexthop_lookup_cmd);
install_element (ENABLE_NODE, &clear_ip_interfaces_cmd);
install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd);
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index 086479643..bdad1c531 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -30,6 +30,7 @@
#include "hash.h"
#include "pimd.h"
+#include "pim_zebra.h"
#include "pim_iface.h"
#include "pim_igmp.h"
#include "pim_mroute.h"
@@ -42,6 +43,7 @@
#include "pim_time.h"
#include "pim_ssmpingd.h"
#include "pim_rp.h"
+#include "pim_nht.h"
struct interface *pim_regiface = NULL;
struct list *pim_ifchannel_list = NULL;
@@ -583,21 +585,40 @@ void pim_if_addr_add(struct connected *ifc)
}
} /* igmp */
- if (PIM_IF_TEST_PIM(pim_ifp->options)) {
-
- /* Interface has a valid primary address ? */
- if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
-
- /* Interface has a valid socket ? */
- if (pim_ifp->pim_sock_fd < 0) {
- if (pim_sock_add(ifp)) {
- zlog_warn("Failure creating PIM socket for interface %s",
- ifp->name);
- }
- }
+ if (PIM_IF_TEST_PIM(pim_ifp->options))
+ {
- }
- } /* pim */
+ if (PIM_INADDR_ISNOT_ANY (pim_ifp->primary_address))
+ {
+
+ /* Interface has a valid socket ? */
+ if (pim_ifp->pim_sock_fd < 0)
+ {
+ if (pim_sock_add (ifp))
+ {
+ zlog_warn ("Failure creating PIM socket for interface %s",
+ ifp->name);
+ }
+ }
+ struct pim_nexthop_cache *pnc = NULL;
+ struct pim_rpf rpf;
+ struct zclient *zclient = NULL;
+
+ zclient = pim_zebra_zclient_get ();
+ /* RP config might come prior to (local RP's interface) IF UP event.
+ In this case, pnc would not have pim enabled nexthops.
+ Once Interface is UP and pim info is available, reregister
+ with RNH address to receive update and add the interface as nexthop. */
+ 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 = ifc->address->u.prefix4;
+ pnc = pim_nexthop_cache_find (&rpf);
+ if (pnc)
+ pim_sendmsg_zebra_rnh (zclient, pnc,
+ ZEBRA_NEXTHOP_REGISTER);
+ }
+ } /* pim */
/*
PIM or IGMP is enabled on interface, and there is at least one
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index 2fb243b9b..23f08efc0 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -178,6 +178,15 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg
up->channel_oil->cc.pktcnt++;
PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
+ // resolve mfcc_parent prior to mroute_add in channel_add_oif
+ if (up->channel_oil->oil.mfcc_parent >= MAXVIFS)
+ {
+ int vif_index = 0;
+ vif_index =
+ pim_if_find_vifindex_by_ifindex (up->rpf.source_nexthop.
+ interface->ifindex);
+ up->channel_oil->oil.mfcc_parent = vif_index;
+ }
pim_register_join (up);
return 0;
@@ -858,9 +867,8 @@ int pim_mroute_del (struct channel_oil *c_oil, const char *name)
pim_channel_oil_dump (c_oil, buf, sizeof(buf)));
}
- /*reset incoming vifi and kernel installed flags*/
+ //Reset kernel installed flag
c_oil->installed = 0;
- c_oil->oil.mfcc_parent = MAXVIFS;
return 0;
}
diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c
index c1325df26..71d7ac414 100644
--- a/pimd/pim_neighbor.c
+++ b/pimd/pim_neighbor.c
@@ -502,6 +502,12 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
listnode_add(pim_ifp->pim_neighbor_list, neigh);
+ if (PIM_DEBUG_PIM_TRACE_DETAIL)
+ {
+ char str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<nht_nbr?>", source_addr, str, sizeof (str));
+ zlog_debug ("%s: neighbor %s added ", __PRETTY_FUNCTION__, str);
+ }
/*
RFC 4601: 4.3.2. DR Election
@@ -532,6 +538,14 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
pim_upstream_find_new_rpf();
+ /* RNH can send nexthop update prior to PIM neibhor UP
+ in that case nexthop cache would not consider this neighbor
+ as RPF.
+ Upon PIM neighbor UP, iterate all RPs and update
+ nexthop cache with this neighbor.
+ */
+ pim_resolve_rp_nh ();
+
pim_rp_setup ();
pim_neighbor_rpf_update();
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
index fe96d01a0..23efd554e 100644
--- a/pimd/pim_nht.c
+++ b/pimd/pim_nht.c
@@ -39,12 +39,13 @@
#include "pim_join.h"
#include "pim_jp_agg.h"
#include "pim_zebra.h"
+#include "pim_zlookup.h"
/**
* pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
* command to Zebra.
*/
-static void
+void
pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc,
int command)
{
@@ -87,9 +88,9 @@ pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc,
{
char buf[PREFIX2STR_BUFFER];
prefix2str (p, buf, sizeof (buf));
- zlog_debug ("%s: NHT Addr %s %sregistered with Zebra ret:%d ",
- __PRETTY_FUNCTION__, buf,
- (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", ret);
+ zlog_debug ("%s: NHT %sregistered addr %s with Zebra ret:%d ",
+ __PRETTY_FUNCTION__,
+ (command == ZEBRA_NEXTHOP_REGISTER) ? " " : "de", buf, ret);
}
return;
@@ -149,7 +150,8 @@ pim_nexthop_cache_add (struct pim_rpf *rpf_addr)
/* This API is used to Register an address with Zebra */
int
pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up,
- struct rp_info *rp)
+ struct rp_info *rp,
+ struct pim_nexthop_cache *out_pnc)
{
struct pim_nexthop_cache *pnc = NULL;
struct pim_rpf rpf;
@@ -174,11 +176,14 @@ pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up,
}
pnc = pim_nexthop_cache_add (&rpf);
if (pnc)
- pim_sendmsg_zebra_rnh (zclient, pnc,
- ZEBRA_NEXTHOP_REGISTER);
+ pim_sendmsg_zebra_rnh (zclient, pnc, ZEBRA_NEXTHOP_REGISTER);
else
{
- zlog_warn ("%s: pnc node allocation failed. ", __PRETTY_FUNCTION__);
+ char rpf_str[PREFIX_STRLEN];
+ pim_addr_dump ("<nht-pnc?>", addr, rpf_str, sizeof (rpf_str));
+ zlog_warn ("%s: pnc node allocation failed. addr %s ",
+ __PRETTY_FUNCTION__, rpf_str);
+ return -1;
}
}
@@ -192,7 +197,7 @@ pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up,
char rp_str[PREFIX_STRLEN];
pim_addr_dump ("<rp?>", &rp->rp.rpf_addr, rp_str,
sizeof (rp_str));
- zlog_debug ("%s: NHT add RP %s node to cached list",
+ zlog_debug ("%s: Add RP %s node to pnc cached list",
__PRETTY_FUNCTION__, rp_str);
}
listnode_add_sort (pnc->rp_list, rp);
@@ -209,15 +214,18 @@ pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up,
char buf[PREFIX2STR_BUFFER];
prefix2str (addr, buf, sizeof (buf));
zlog_debug
- ("%s: NHT add upstream %s node to cached list, rpf %s",
+ ("%s: Add upstream %s node to pnc cached list, rpf %s",
__PRETTY_FUNCTION__, up->sg_str, buf);
}
listnode_add_sort (pnc->upstream_list, up);
}
}
- if (CHECK_FLAG (pnc->flags, PIM_NEXTHOP_VALID))
- return 1;
+ if (pnc && CHECK_FLAG (pnc->flags, PIM_NEXTHOP_VALID))
+ {
+ memcpy (out_pnc, pnc, sizeof (struct pim_nexthop_cache));
+ return 1;
+ }
return 0;
}
@@ -249,8 +257,7 @@ pim_delete_tracked_nexthop (struct prefix *addr, struct pim_upstream *up,
if (pnc->rp_list->count == 0 && pnc->upstream_list->count == 0)
{
- pim_sendmsg_zebra_rnh (zclient, pnc,
- ZEBRA_NEXTHOP_UNREGISTER);
+ pim_sendmsg_zebra_rnh (zclient, pnc, ZEBRA_NEXTHOP_UNREGISTER);
list_delete (pnc->rp_list);
list_delete (pnc->upstream_list);
@@ -277,21 +284,16 @@ pim_update_rp_nh (struct pim_nexthop_cache *pnc)
if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
continue;
- if (pim_nexthop_lookup (&rp_info->rp.source_nexthop,
- rp_info->rp.rpf_addr.u.prefix4, 1) != 0)
- {
- if (PIM_DEBUG_PIM_TRACE)
- zlog_debug ("Unable to lookup nexthop for rp specified");
- ret++;
- continue;
- }
+ //Compute PIM RPF using cached nexthop
+ pim_ecmp_nexthop_search (pnc, &rp_info->rp.source_nexthop,
+ &rp_info->rp.rpf_addr, &rp_info->group, 1);
if (PIM_DEBUG_TRACE)
{
char rp_str[PREFIX_STRLEN];
pim_addr_dump ("<rp?>", &rp_info->rp.rpf_addr, rp_str,
sizeof (rp_str));
- zlog_debug ("%s: NHT update nexthop for RP %s to interface %s ",
+ zlog_debug ("%s: NHT update, nexthop for RP %s is interface %s ",
__PRETTY_FUNCTION__, rp_str,
rp_info->rp.source_nexthop.interface->name);
}
@@ -304,6 +306,48 @@ pim_update_rp_nh (struct pim_nexthop_cache *pnc)
}
+/* This API is used to traverse nexthop cache of RPF addr
+ of upstream entry whose IPv4 nexthop address is in
+ unresolved state and due to event like pim neighbor
+ UP event if it can be resolved.
+*/
+void
+pim_resolve_upstream_nh (struct prefix *nht_p)
+{
+ struct nexthop *nh_node = NULL;
+ struct pim_nexthop_cache pnc;
+ struct pim_neighbor *nbr = NULL;
+
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ if ((pim_find_or_track_nexthop (nht_p, NULL, NULL, &pnc)) == 1)
+ {
+ for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next)
+ {
+ if (nh_node->gate.ipv4.s_addr == 0)
+ {
+ nbr =
+ pim_neighbor_find_if (if_lookup_by_index
+ (nh_node->ifindex, VRF_DEFAULT));
+ if (nbr)
+ {
+ nh_node->gate.ipv4 = nbr->source_addr;
+ if (PIM_DEBUG_TRACE)
+ {
+ char str[PREFIX_STRLEN];
+ char str1[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<nht_nbr?>", nbr->source_addr, str1,
+ sizeof (str1));
+ pim_addr_dump ("<nht_addr?>", nht_p, str, sizeof (str));
+ zlog_debug
+ ("%s: addr %s new nexthop addr %s ifindex %d ",
+ __PRETTY_FUNCTION__, str, str1, nh_node->ifindex);
+ }
+ }
+ }
+ }
+ }
+}
+
/* Update Upstream nexthop info based on Nexthop update received from Zebra.*/
static int
pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
@@ -312,8 +356,8 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
struct listnode *ifnode;
struct listnode *up_nextnode;
struct listnode *node;
- struct pim_upstream *up;
- struct interface *ifp;
+ struct pim_upstream *up = NULL;
+ struct interface *ifp = NULL;
int vif_index = 0;
for (ALL_LIST_ELEMENTS (pnc->upstream_list, up_node, up_nextnode, up))
@@ -326,6 +370,26 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
if (rpf_result == PIM_RPF_FAILURE)
continue;
+ /* update kernel multicast forwarding cache (MFC) */
+ if (up->channel_oil)
+ {
+ vif_index =
+ pim_if_find_vifindex_by_ifindex (up->rpf.
+ source_nexthop.interface->
+ ifindex);
+ /* Pass Current selected NH vif index to mroute download */
+ if (vif_index)
+ pim_scan_individual_oil (up->channel_oil, vif_index);
+ else
+ {
+ if (PIM_DEBUG_ZEBRA)
+ zlog_debug
+ ("%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
+ __PRETTY_FUNCTION__, up->sg_str,
+ up->rpf.source_nexthop.interface->name);
+ }
+ }
+
if (rpf_result == PIM_RPF_CHANGED)
{
struct pim_neighbor *nbr;
@@ -377,7 +441,7 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
returning PIM_RPF_CHANGED ? */
pim_upstream_update_join_desired (up);
- } /* PIM_RPF_CHANGED */
+ } /* PIM_RPF_CHANGED */
if (PIM_DEBUG_TRACE)
{
@@ -386,26 +450,7 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
old.source_nexthop.interface->name,
up->rpf.source_nexthop.interface->name);
}
- /* update kernel multicast forwarding cache (MFC) */
- if (up->channel_oil)
- {
- vif_index =
- pim_if_find_vifindex_by_ifindex (up->rpf.
- source_nexthop.interface->
- ifindex);
- /* Pass Current selected NH vif index to mroute download */
- if (vif_index)
- pim_scan_individual_oil (up->channel_oil, vif_index);
- else
- {
- if (PIM_DEBUG_ZEBRA)
- zlog_debug ("%s: NHT upstream %s channel_oil IIF %s vif_index is not valid",
- __PRETTY_FUNCTION__, up->sg_str,
- up->rpf.source_nexthop.interface->name);
- }
- }
-
- } /* for (pnc->upstream_list) */
+ } /* for (pnc->upstream_list) */
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp))
if (ifp->info)
@@ -426,10 +471,209 @@ pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
return 0;
}
-/*
- * This API is used to parse Registered address nexthop update
- * coming from Zebra
- */
+uint32_t
+pim_compute_ecmp_hash (struct prefix * src, struct prefix * grp)
+{
+ uint32_t hash_val;
+ uint32_t s = 0, g = 0;
+
+ if ((!src))
+ return 0;
+
+ switch (src->family)
+ {
+ case AF_INET:
+ {
+ s = src->u.prefix4.s_addr;
+ s = s == 0 ? 1 : s;
+ if (grp)
+ g = grp->u.prefix4.s_addr;
+ }
+ break;
+ default:
+ break;
+ }
+
+ hash_val = jhash_2words (g, s, 101);
+ if (PIM_DEBUG_TRACE)
+ {
+ char buf[PREFIX2STR_BUFFER];
+ char bufg[PREFIX2STR_BUFFER];
+ prefix2str (src, buf, sizeof (buf));
+ if (grp)
+ prefix2str (grp, bufg, sizeof (bufg));
+ zlog_debug ("%s: addr %s %s hash_val %u", __PRETTY_FUNCTION__, buf,
+ grp ? bufg : "", hash_val);
+
+ }
+ return hash_val;
+}
+
+int
+pim_ecmp_nexthop_search (struct pim_nexthop_cache *pnc,
+ struct pim_nexthop *nexthop, struct prefix *src,
+ struct prefix *grp, int neighbor_needed)
+{
+ struct pim_neighbor *nbr = NULL;
+ struct nexthop *nh_node = NULL;
+ ifindex_t first_ifindex;
+ struct interface *ifp = NULL;
+ uint32_t hash_val = 0, mod_val = 0;
+ uint8_t nh_iter = 0, found = 0;
+
+ if (!pnc || !pnc->nexthop_num || !nexthop)
+ return -1;
+
+ if (qpim_ecmp_enable)
+ {
+ //User configured knob to explicitly switch to new path.
+ if (qpim_ecmp_rebalance_enable == 0)
+ {
+ //Current Nexthop is VALID then stay on the current path.
+ if (nexthop->interface && nexthop->interface->info &&
+ nexthop->mrib_nexthop_addr.u.prefix4.s_addr !=
+ PIM_NET_INADDR_ANY)
+ {
+ if (neighbor_needed
+ && !pim_if_connected_to_source (nexthop->interface,
+ src->u.prefix4))
+ {
+ nbr = pim_neighbor_find (nexthop->interface,
+ nexthop->mrib_nexthop_addr.
+ u.prefix4);
+ if (!nbr && !if_is_loopback (nexthop->interface))
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: current nexthop does not have nbr ",
+ __PRETTY_FUNCTION__);
+ }
+ else
+ {
+ if (PIM_DEBUG_TRACE)
+ {
+ char src_str[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<addr?>", src->u.prefix4, src_str,
+ sizeof (src_str));
+ char grp_str[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<addr?>", grp->u.prefix4, grp_str,
+ sizeof (grp_str));
+ zlog_debug
+ ("%s: %s %s current nexthop %d is valid, not choosing new path",
+ __PRETTY_FUNCTION__, src_str, grp_str,
+ nexthop->interface->ifindex);
+ }
+ return 0;
+ }
+ }
+ }
+ }
+ //PIM ECMP flag is enable then choose ECMP path.
+ hash_val = pim_compute_ecmp_hash (src, grp);
+ mod_val = hash_val % pnc->nexthop_num;
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: hash_val %u mod_val %u ",
+ __PRETTY_FUNCTION__, hash_val, mod_val);
+ }
+
+ for (nh_node = pnc->nexthop; nh_node && (found == 0);
+ nh_node = nh_node->next)
+ {
+ first_ifindex = nh_node->ifindex;
+ ifp = if_lookup_by_index (first_ifindex, VRF_DEFAULT);
+ if (!ifp)
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char addr_str[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<addr?>", src->u.prefix4, 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);
+ }
+ if (nh_iter == mod_val)
+ mod_val++; //Select nexthpath
+ nh_iter++;
+ continue;
+ }
+ if (!ifp->info)
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char addr_str[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<addr?>", src->u.prefix4, 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);
+ }
+ if (nh_iter == mod_val)
+ mod_val++; //Select nexthpath
+ nh_iter++;
+ continue;
+ }
+
+ if (neighbor_needed
+ && !pim_if_connected_to_source (ifp, src->u.prefix4))
+ {
+ nbr = pim_neighbor_find (ifp, nh_node->gate.ipv4);
+ if (PIM_DEBUG_PIM_TRACE_DETAIL)
+ zlog_debug ("ifp name: %s, pim nbr: %p", ifp->name, nbr);
+ if (!nbr && !if_is_loopback (ifp))
+ {
+ if (PIM_DEBUG_ZEBRA)
+ zlog_debug
+ ("%s: pim nbr not found on input interface %s",
+ __PRETTY_FUNCTION__, ifp->name);
+ if (nh_iter == mod_val)
+ mod_val++; //Select nexthpath
+ nh_iter++;
+ continue;
+ }
+ }
+
+ if (nh_iter == mod_val)
+ {
+ nexthop->interface = ifp;
+ nexthop->mrib_nexthop_addr.family = AF_INET;
+ nexthop->mrib_nexthop_addr.prefixlen = IPV4_MAX_BITLEN;
+ nexthop->mrib_nexthop_addr.u.prefix4 = nh_node->gate.ipv4;
+ nexthop->mrib_metric_preference = pnc->distance;
+ nexthop->mrib_route_metric = pnc->metric;
+ nexthop->last_lookup = src->u.prefix4;
+ nexthop->last_lookup_time = pim_time_monotonic_usec ();
+ nexthop->nbr = nbr;
+ found = 1;
+
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char buf[NEXTHOP_STRLEN];
+ char buf2[PREFIX2STR_BUFFER];
+ char buf3[PREFIX2STR_BUFFER];
+ char buf4[PREFIX2STR_BUFFER];
+ pim_inet4_dump ("<src?>", src->u.prefix4, buf2, sizeof (buf2));
+ if (grp)
+ pim_inet4_dump ("<src?>", grp->u.prefix4, buf3,
+ sizeof (buf3));
+ pim_inet4_dump ("<rpf?>",
+ nexthop->mrib_nexthop_addr.u.prefix4, buf4,
+ sizeof (buf4));
+ snprintf (buf, sizeof (buf), "%s if %u",
+ inet_ntoa (nh_node->gate.ipv4), nh_node->ifindex);
+ zlog_debug
+ ("%s: NHT %s %s selected nhop interface %s nhop %s (%s) mod_val:%u iter:%d ecmp_enable:%d",
+ __PRETTY_FUNCTION__, buf2, grp ? buf3 : " ", ifp->name,
+ buf, buf4, mod_val, nh_iter, qpim_ecmp_enable);
+ }
+ }
+ nh_iter++;
+
+ }
+
+ return 0;
+}
+
+/* This API is used to parse Registered address nexthop update coming from Zebra */
int
pim_parse_nexthop_update (int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
@@ -437,7 +681,6 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
struct stream *s;
struct prefix p;
struct nexthop *nexthop;
- struct nexthop *oldnh;
struct nexthop *nhlist_head = NULL;
struct nexthop *nhlist_tail = NULL;
uint32_t metric, distance;
@@ -476,8 +719,9 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
{
char buf[PREFIX2STR_BUFFER];
prefix2str (&rpf.rpf_addr, buf, sizeof (buf));
- zlog_debug ("%s: NHT addr %s is not in local cached DB.",
- __PRETTY_FUNCTION__, buf);
+ zlog_debug
+ ("%s: Skipping NHT update, addr %s is not in local cached DB.",
+ __PRETTY_FUNCTION__, buf);
}
return 0;
}
@@ -490,7 +734,7 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
return 0;
}
- pnc->last_update = pim_time_monotonic_sec ();
+ pnc->last_update = pim_time_monotonic_usec ();
distance = stream_getc (s);
metric = stream_getl (s);
nexthop_num = stream_getc (s);
@@ -499,17 +743,15 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
{
char buf[PREFIX2STR_BUFFER];
prefix2str (&p, buf, sizeof (buf));
- zlog_debug ("%s: NHT Update for %s nexthop_num %d vrf:%d upcount %d rpcount %d",
- __PRETTY_FUNCTION__, buf, nexthop_num, vrf_id,
- listcount (pnc->upstream_list), listcount (pnc->rp_list));
+ zlog_debug
+ ("%s: NHT Update for %s nexthop_num %d vrf:%d upcount %d rpcount %d",
+ __PRETTY_FUNCTION__, buf, nexthop_num, vrf_id,
+ listcount (pnc->upstream_list), listcount (pnc->rp_list));
}
if (nexthop_num)
{
- pnc->flags |= PIM_NEXTHOP_VALID;
- pnc->distance = distance;
- pnc->metric = metric;
- pnc->nexthop_num = nexthop_num;
+ pnc->nexthop_num = 0; //Only increment for pim enabled rpf.
for (i = 0; i < nexthop_num; i++)
{
@@ -539,7 +781,34 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
(nexthop->ifindex, VRF_DEFAULT));
/* Overwrite with Nbr address as NH addr */
if (nbr)
- nexthop->gate.ipv4 = nbr->source_addr;
+ {
+ nexthop->gate.ipv4 = nbr->source_addr;
+ if (PIM_DEBUG_TRACE)
+ {
+ char str[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<nht_nbr?>", nbr->source_addr, str,
+ sizeof (str));
+ zlog_debug
+ ("%s: NHT using pim nbr addr %s ifindex %d as rpf",
+ __PRETTY_FUNCTION__, str, nexthop->ifindex);
+ }
+ }
+ else
+ {
+ if (PIM_DEBUG_TRACE)
+ {
+ struct interface *ifp1 =
+ if_lookup_by_index (nexthop->ifindex,
+ VRF_DEFAULT);
+ struct pim_interface *pim_ifp = ifp1->info;
+ zlog_debug
+ ("%s: NHT pim nbr not found on interface %s nbr count:%d ",
+ __PRETTY_FUNCTION__, ifp1->name,
+ pim_ifp->pim_neighbor_list->count);
+ }
+ //Mark nexthop address to 0 until PIM Nbr is resolved.
+ nexthop->gate.ipv4.s_addr = PIM_NET_INADDR_ANY;
+ }
break;
default:
@@ -562,9 +831,10 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
if (PIM_DEBUG_ZEBRA)
{
char buf[NEXTHOP_STRLEN];
- zlog_debug("%s: could not find interface for ifindex %d (addr %s)",
- __PRETTY_FUNCTION__,
- nexthop->ifindex, nexthop2str (nexthop, buf, sizeof (buf)));
+ zlog_debug
+ ("%s: could not find interface for ifindex %d (addr %s)",
+ __PRETTY_FUNCTION__, nexthop->ifindex,
+ nexthop2str (nexthop, buf, sizeof (buf)));
}
nexthop_free (nexthop);
continue;
@@ -594,14 +864,18 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
nhlist_tail = nexthop;
nhlist_head = nexthop;
}
-
- for (oldnh = pnc->nexthop; oldnh; oldnh = oldnh->next)
- if (nexthop_same_no_recurse (oldnh, nexthop))
- break;
+ //Only keep track of nexthops which are PIM enabled.
+ pnc->nexthop_num++;
}
/* Reset existing pnc->nexthop before assigning new list */
nexthops_free (pnc->nexthop);
pnc->nexthop = nhlist_head;
+ if (pnc->nexthop_num)
+ {
+ pnc->flags |= PIM_NEXTHOP_VALID;
+ pnc->distance = distance;
+ pnc->metric = metric;
+ }
}
else
{
@@ -611,6 +885,16 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
pnc->nexthop = NULL;
}
+ if (PIM_DEBUG_TRACE)
+ {
+ char buf[PREFIX2STR_BUFFER];
+ prefix2str (&p, buf, sizeof (buf));
+ zlog_debug
+ ("%s: NHT Update for %s nexthop_num:%d pim nexthop_num %d vrf:%d up %d rp %d",
+ __PRETTY_FUNCTION__, buf, nexthop_num, pnc->nexthop_num, vrf_id,
+ listcount (pnc->upstream_list), listcount (pnc->rp_list));
+ }
+
pim_rpf_set_refresh_time ();
if (listcount (pnc->rp_list))
@@ -620,3 +904,142 @@ pim_parse_nexthop_update (int command, struct zclient *zclient,
return 0;
}
+
+int
+pim_ecmp_nexthop_lookup (struct pim_nexthop *nexthop, struct in_addr addr,
+ struct prefix *src, struct prefix *grp,
+ int neighbor_needed)
+{
+ struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
+ struct pim_neighbor *nbr = NULL;
+ int num_ifindex;
+ struct interface *ifp;
+ int first_ifindex;
+ int found = 0;
+ uint8_t i = 0;
+ uint32_t hash_val = 0, mod_val = 0;
+
+ if (PIM_DEBUG_TRACE)
+ {
+ char addr_str[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<addr?>", addr, addr_str, sizeof (addr_str));
+ zlog_debug ("%s: Looking up: %s, last lookup time: %lld",
+ __PRETTY_FUNCTION__, addr_str, nexthop->last_lookup_time);
+ }
+
+ memset (nexthop_tab, 0,
+ sizeof (struct pim_zlookup_nexthop) * MULTIPATH_NUM);
+ num_ifindex =
+ zclient_lookup_nexthop (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 -1;
+ }
+
+ //If PIM ECMP enable then choose ECMP path
+ if (qpim_ecmp_enable)
+ {
+ hash_val = pim_compute_ecmp_hash (src, grp);
+ mod_val = hash_val % num_ifindex;
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: hash_val %u mod_val %u ",
+ __PRETTY_FUNCTION__, hash_val, mod_val);
+ }
+
+ while (!found && (i < num_ifindex))
+ {
+ first_ifindex = nexthop_tab[i].ifindex;
+
+ ifp = if_lookup_by_index (first_ifindex, VRF_DEFAULT);
+ 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);
+ }
+ if (i == mod_val)
+ mod_val++;
+ 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);
+ }
+ if (i == mod_val)
+ mod_val++;
+ i++;
+ continue;
+ }
+ if (neighbor_needed && !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))
+ {
+ if (i == mod_val)
+ mod_val++;
+ i++;
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char addr_str[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<addr?>", addr, addr_str,
+ sizeof (addr_str));
+ zlog_debug
+ ("%s: NBR not found on input interface %s (RPF for source %s)",
+ __PRETTY_FUNCTION__, ifp->name, addr_str);
+ }
+ continue;
+ }
+ }
+
+ if (i == mod_val)
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char nexthop_str[PREFIX_STRLEN];
+ char addr_str[INET_ADDRSTRLEN];
+ pim_addr_dump ("<nexthop?>", &nexthop_tab[i].nexthop_addr,
+ nexthop_str, sizeof (nexthop_str));
+ pim_inet4_dump ("<addr?>", addr, addr_str, sizeof (addr_str));
+ zlog_debug
+ ("%s %s: found nexthop %s for addr %s interface %s metric=%d pref=%d",
+ __FILE__, __PRETTY_FUNCTION__, nexthop_str, addr_str,
+ ifp->name, nexthop_tab[i].route_metric,
+ nexthop_tab[i].protocol_distance);
+ }
+ /* update nextop data */
+ nexthop->interface = ifp;
+ nexthop->mrib_nexthop_addr = nexthop_tab[i].nexthop_addr;
+ nexthop->mrib_metric_preference = nexthop_tab[i].protocol_distance;
+ nexthop->mrib_route_metric = nexthop_tab[i].route_metric;
+ nexthop->last_lookup = addr;
+ nexthop->last_lookup_time = pim_time_monotonic_usec();
+ nexthop->nbr = nbr;
+ found = 1;
+ }
+ i++;
+ }
+ if (found)
+ return 0;
+ else
+ return -1;
+}
diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h
index 5348ec370..b4b2d91e4 100644
--- a/pimd/pim_nht.h
+++ b/pimd/pim_nht.h
@@ -51,10 +51,19 @@ struct pim_nexthop_cache
int pim_parse_nexthop_update (int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id);
int pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up,
- struct rp_info *rp);
+ struct rp_info *rp, struct pim_nexthop_cache *out_pnc);
void pim_delete_tracked_nexthop (struct prefix *addr, struct pim_upstream *up,
struct rp_info *rp);
struct pim_nexthop_cache *pim_nexthop_cache_add (struct pim_rpf *rpf_addr);
struct pim_nexthop_cache *pim_nexthop_cache_find (struct pim_rpf *rpf);
-
+uint32_t pim_compute_ecmp_hash (struct prefix *src, struct prefix *grp);
+int pim_ecmp_nexthop_search (struct pim_nexthop_cache * pnc,
+ struct pim_nexthop *nexthop, struct prefix *src,
+ struct prefix *grp, int neighbor_needed);
+int pim_ecmp_nexthop_lookup (struct pim_nexthop *nexthop, struct in_addr addr,
+ struct prefix *src, struct prefix *grp,
+ int neighbor_needed);
+void pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc,
+ int command);
+void pim_resolve_upstream_nh (struct prefix *nht_p);
#endif
diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c
index 270107905..2d4aa3feb 100644
--- a/pimd/pim_oil.c
+++ b/pimd/pim_oil.c
@@ -289,10 +289,10 @@ pim_channel_del_oif (struct channel_oil *channel_oil,
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
- zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
+ zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u IIF:%d OIF=%s vif_index=%d",
__FILE__, __PRETTY_FUNCTION__,
source_str, group_str,
- proto_mask, oif->name, pim_ifp->mroute_vif_index);
+ proto_mask, channel_oil->oil.mfcc_parent ,oif->name, pim_ifp->mroute_vif_index);
}
return 0;
diff --git a/pimd/pim_register.c b/pimd/pim_register.c
index 65a3e8714..12f8dd53f 100644
--- a/pimd/pim_register.c
+++ b/pimd/pim_register.c
@@ -187,6 +187,15 @@ pim_register_send (const uint8_t *buf, int buf_size, struct in_addr src, struct
return;
}
+ if (PIM_DEBUG_PIM_REG)
+ {
+ char rp_str[INET_ADDRSTRLEN];
+ strcpy (rp_str, inet_ntoa (rpg->rpf_addr.u.prefix4));
+ zlog_debug ("%s: Sending %s %sRegister Packet to %s on %s",
+ __PRETTY_FUNCTION__, up->sg_str,
+ null_register ? "NULL " : "", rp_str, ifp->name);
+ }
+
memset(buffer, 0, 10000);
b1 = buffer + PIM_MSG_HEADER_LEN;
*b1 |= null_register << 6;
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index 78bbd1440..ec31069eb 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -30,6 +30,7 @@
#include "vty.h"
#include "vrf.h"
#include "plist.h"
+#include "nexthop.h"
#include "pimd.h"
#include "pim_vty.h"
@@ -280,7 +281,7 @@ pim_rp_check_interfaces (struct rp_info *rp_info)
int
pim_rp_new (const char *rp, const char *group_range, const char *plist)
{
- int result;
+ int result, ret = 0;
struct rp_info *rp_info;
struct rp_info *rp_all;
struct prefix group_all;
@@ -288,6 +289,7 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist)
struct rp_info *tmp_rp_info;
char buffer[BUFSIZ];
struct prefix nht_p;
+ struct pim_nexthop_cache pnc;
rp_info = XCALLOC (MTYPE_PIM_RP, sizeof (*rp_info));
if (!rp_info)
@@ -387,21 +389,31 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist)
/* Register addr with Zebra NHT */
nht_p.family = AF_INET;
nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4 = rp_all->rp.rpf_addr.u.prefix4;
+ nht_p.u.prefix4 = rp_all->rp.rpf_addr.u.prefix4; //RP address
if (PIM_DEBUG_PIM_TRACE)
{
char buf[PREFIX2STR_BUFFER];
+ char buf1[PREFIX2STR_BUFFER];
prefix2str (&nht_p, buf, sizeof (buf));
- zlog_debug ("%s: NHT Register rp_all addr %s with NHT ",
- __PRETTY_FUNCTION__, buf);
+ prefix2str (&rp_all->group, buf1, sizeof (buf1));
+ zlog_debug ("%s: NHT Register rp_all addr %s grp %s ",
+ __PRETTY_FUNCTION__, buf, buf1);
+ }
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ if ((ret =
+ pim_find_or_track_nexthop (&nht_p, NULL, rp_all, &pnc)) == 1)
+ {
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&pnc, &rp_all->rp.source_nexthop,
+ &nht_p, &rp_all->group, 1);
+ }
+ else
+ {
+ if (pim_nexthop_lookup (&rp_all->rp.source_nexthop, rp_all->rp.rpf_addr.u.prefix4, 1) != 0)
+ return PIM_RP_NO_PATH;
}
- pim_find_or_track_nexthop (&nht_p, NULL, rp_all);
-
- if (pim_nexthop_lookup (&rp_all->rp.source_nexthop, rp_all->rp.rpf_addr.u.prefix4, 1) != 0)
- return PIM_RP_NO_PATH;
-
pim_rp_check_interfaces (rp_all);
- pim_rp_refresh_group_to_rp_mapping();
+ pim_rp_refresh_group_to_rp_mapping ();
return PIM_SUCCESS;
}
@@ -451,13 +463,25 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist)
if (PIM_DEBUG_PIM_TRACE)
{
char buf[PREFIX2STR_BUFFER];
+ char buf1[PREFIX2STR_BUFFER];
prefix2str (&nht_p, buf, sizeof (buf));
- zlog_debug ("%s: NHT Register RP addr %s with Zebra ", __PRETTY_FUNCTION__, 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 (&nht_p, NULL, rp_info);
- if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0)
- return PIM_RP_NO_PATH;
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ if ((ret = pim_find_or_track_nexthop (&nht_p, NULL, rp_info, &pnc)) == 1)
+ {
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&pnc, &rp_info->rp.source_nexthop,
+ &nht_p, &rp_info->group, 1);
+ }
+ else
+ {
+ if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0)
+ return PIM_RP_NO_PATH;
+ }
pim_rp_check_interfaces (rp_info);
pim_rp_refresh_group_to_rp_mapping ();
@@ -509,7 +533,8 @@ pim_rp_del (const char *rp, const char *group_range, const char *plist)
{
char buf[PREFIX2STR_BUFFER];
prefix2str (&nht_p, buf, sizeof (buf));
- zlog_debug ("%s: Deregister RP addr %s with NHT ", __PRETTY_FUNCTION__, buf);
+ zlog_debug ("%s: Deregister RP addr %s with Zebra ", __PRETTY_FUNCTION__,
+ buf);
}
pim_delete_tracked_nexthop (&nht_p, NULL, rp_info);
@@ -535,17 +560,39 @@ pim_rp_setup (void)
struct listnode *node;
struct rp_info *rp_info;
int ret = 0;
+ struct prefix nht_p;
+ struct pim_nexthop_cache pnc;
for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
{
if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
continue;
- if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0)
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ if ((pim_find_or_track_nexthop (&nht_p, NULL, rp_info, &pnc)) == 1)
{
- if (PIM_DEBUG_PIM_TRACE)
- zlog_debug ("Unable to lookup nexthop for rp specified");
- ret++;
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&pnc, &rp_info->rp.source_nexthop,
+ &nht_p, &rp_info->group, 1);
+ }
+ else
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char buf[PREFIX2STR_BUFFER];
+ prefix2str (&nht_p, buf, sizeof (buf));
+ zlog_debug ("%s: NHT Local Nexthop not found for RP %s ",
+ __PRETTY_FUNCTION__, buf);
+ }
+ if (pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1) != 0)
+ {
+ if (PIM_DEBUG_PIM_TRACE)
+ zlog_debug ("Unable to lookup nexthop for rp specified");
+ ret++;
+ }
}
}
@@ -680,7 +727,43 @@ pim_rp_g (struct in_addr group)
if (rp_info)
{
- pim_nexthop_lookup(&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1);
+ int ret = 0;
+ struct prefix nht_p;
+ struct pim_nexthop_cache pnc;
+ /* Register addr with Zebra NHT */
+ 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_TRACE)
+ {
+ 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);
+ }
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ if ((ret = pim_find_or_track_nexthop (&nht_p, NULL, rp_info, &pnc)) == 1)
+ {
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&pnc, &rp_info->rp.source_nexthop,
+ &nht_p, &rp_info->group, 1);
+ }
+ else
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char buf[PREFIX2STR_BUFFER];
+ char buf1[PREFIX2STR_BUFFER];
+ prefix2str (&nht_p, buf, sizeof (buf));
+ prefix2str (&g, buf1, sizeof (buf1));
+ zlog_debug ("%s: NHT nexthop cache not found for RP %s grp %s",
+ __PRETTY_FUNCTION__, buf, buf1);
+ }
+ pim_rpf_set_refresh_time ();
+ pim_nexthop_lookup (&rp_info->rp.source_nexthop, rp_info->rp.rpf_addr.u.prefix4, 1);
+ }
return (&rp_info->rp);
}
@@ -862,3 +945,54 @@ pim_rp_show_information (struct vty *vty, u_char uj)
json_object_free(json);
}
}
+
+void
+pim_resolve_rp_nh (void)
+{
+ struct listnode *node = NULL;
+ struct rp_info *rp_info = NULL;
+ struct nexthop *nh_node = NULL;
+ struct prefix nht_p;
+ struct pim_nexthop_cache pnc;
+ struct pim_neighbor *nbr = NULL;
+
+ for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
+ {
+ if (rp_info->rp.rpf_addr.u.prefix4.s_addr == INADDR_NONE)
+ continue;
+
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4;
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ if ((pim_find_or_track_nexthop (&nht_p, NULL, rp_info, &pnc)) == 1)
+ {
+ for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next)
+ {
+ if (nh_node->gate.ipv4.s_addr == 0)
+ {
+ nbr =
+ pim_neighbor_find_if (if_lookup_by_index
+ (nh_node->ifindex, VRF_DEFAULT));
+ if (nbr)
+ {
+ nh_node->gate.ipv4 = nbr->source_addr;
+ if (PIM_DEBUG_TRACE)
+ {
+ char str[PREFIX_STRLEN];
+ char str1[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<nht_nbr?>", nbr->source_addr,
+ str1, sizeof (str1));
+ pim_addr_dump ("<nht_addr?>", &nht_p, str,
+ sizeof (str));
+ zlog_debug
+ ("%s: addr %s new nexthop addr %s ifindex %d ",
+ __PRETTY_FUNCTION__, str, str1,
+ nh_node->ifindex);
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h
index 84ab9be48..df18c998d 100644
--- a/pimd/pim_rp.h
+++ b/pimd/pim_rp.h
@@ -61,6 +61,6 @@ struct pim_rpf *pim_rp_g (struct in_addr group);
#define RP(G) pim_rp_g ((G))
void pim_rp_show_information (struct vty *vty, u_char uj);
-
+void pim_resolve_rp_nh (void);
int pim_rp_list_cmp (void *v1, void *v2);
#endif
diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c
index 400048738..0f5fab0d9 100644
--- a/pimd/pim_rpf.c
+++ b/pimd/pim_rpf.c
@@ -67,11 +67,14 @@ int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, int nei
{
char addr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
- zlog_debug ("%s: Using last lookup for %s at %lld, %lld",
+ char nexthop_str[PREFIX_STRLEN];
+ pim_addr_dump("<nexthop?>", &nexthop->mrib_nexthop_addr,
+ nexthop_str, sizeof(nexthop_str));
+ zlog_debug ("%s: Using last lookup for %s at %lld, %lld addr%s",
__PRETTY_FUNCTION__,
addr_str,
nexthop->last_lookup_time,
- last_route_change_time);
+ last_route_change_time, nexthop_str);
}
nexthop_lookups_avoided++;
return 0;
@@ -190,32 +193,56 @@ enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old,
struct pim_rpf *rpf = &up->rpf;
struct pim_rpf saved;
struct prefix nht_p;
+ struct pim_nexthop_cache pnc;
+ int ret = 0;
+ struct prefix src, grp;
saved.source_nexthop = rpf->source_nexthop;
saved.rpf_addr = rpf->rpf_addr;
- if (is_new)
+ if (is_new && PIM_DEBUG_ZEBRA)
+ {
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump ("<source?>", up->upstream_addr, source_str,
+ sizeof (source_str));
+ zlog_debug ("%s: NHT Register upstream %s addr %s with Zebra.",
+ __PRETTY_FUNCTION__, up->sg_str, source_str);
+ }
+ /* Register addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
+
+ src.family = AF_INET;
+ src.prefixlen = IPV4_MAX_BITLEN;
+ src.u.prefix4 = up->upstream_addr; //RP or Src address
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+ memset (&pnc, 0, sizeof (struct pim_nexthop_cache));
+ if ((ret = pim_find_or_track_nexthop (&nht_p, up, NULL, &pnc)) == 1)
{
- if (PIM_DEBUG_ZEBRA)
+ if (pnc.nexthop_num)
{
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>", up->upstream_addr, source_str, sizeof(source_str));
- zlog_debug ("%s: NHT Register upstream %s addr %s with Zebra.",
- __PRETTY_FUNCTION__, up->sg_str, source_str);
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&pnc, &up->rpf.source_nexthop,
+ &src, &grp,
+ !PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) &&
+ !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->
+ flags));
}
- /* Register addr with Zebra NHT */
- nht_p.family = AF_INET;
- nht_p.prefixlen = IPV4_MAX_BITLEN;
- nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
- pim_find_or_track_nexthop (&nht_p, up, NULL);
}
-
- if (pim_nexthop_lookup(&rpf->source_nexthop,
- up->upstream_addr,
- !PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) &&
- !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))) {
- return PIM_RPF_FAILURE;
- }
+ else
+ {
+ if (pim_ecmp_nexthop_lookup (&rpf->source_nexthop,
+ up->upstream_addr, &src, &grp,
+ !PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) &&
+ !PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->
+ flags)))
+ {
+ return PIM_RPF_FAILURE;
+ }
+ }
rpf->rpf_addr.family = AF_INET;
rpf->rpf_addr.u.prefix4 = pim_rpf_find_rpf_addr(up);
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index 172d0d21c..c9c279576 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -227,8 +227,8 @@ pim_upstream_del(struct pim_upstream *up, const char *name)
{
char buf[PREFIX2STR_BUFFER];
prefix2str (&nht_p, buf, sizeof (buf));
- zlog_debug ("%s: Deregister upstream %s upstream addr %s with NHT ",
- __PRETTY_FUNCTION__, up->sg_str, buf);
+ zlog_debug ("%s: Deregister upstream %s addr %s with Zebra",
+ __PRETTY_FUNCTION__, up->sg_str, buf);
}
pim_delete_tracked_nexthop (&nht_p, up, NULL);
@@ -694,10 +694,12 @@ pim_upstream_new (struct prefix_sg *sg,
return NULL;
}
- pim_ifp = up->rpf.source_nexthop.interface->info;
- if (pim_ifp)
- up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index);
-
+ if (up->rpf.source_nexthop.interface)
+ {
+ pim_ifp = up->rpf.source_nexthop.interface->info;
+ if (pim_ifp)
+ up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index);
+ }
listnode_add_sort(pim_upstream_list, up);
if (PIM_DEBUG_TRACE)
@@ -768,10 +770,14 @@ struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
if (PIM_DEBUG_TRACE)
{
if (up)
- zlog_debug("%s(%s): %s, found: %d: ref_count: %d",
+ {
+ char buf[PREFIX2STR_BUFFER];
+ prefix2str (&up->rpf.rpf_addr, buf, sizeof (buf));
+ zlog_debug("%s(%s): %s, iif %s found: %d: ref_count: %d",
__PRETTY_FUNCTION__, name,
- up->sg_str, found,
+ up->sg_str, buf, found,
up->ref_count);
+ }
else
zlog_debug("%s(%s): (%s) failure to create",
__PRETTY_FUNCTION__, name,
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index 4e18c478d..80e7d7764 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -372,6 +372,12 @@ static void scan_upstream_rpf_cache()
for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
enum pim_rpf_result rpf_result;
struct pim_rpf old;
+ struct prefix nht_p;
+
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
+ pim_resolve_upstream_nh (&nht_p);
old.source_nexthop.interface = up->rpf.source_nexthop.interface;
old.source_nexthop.nbr = up->rpf.source_nexthop.nbr;
@@ -574,7 +580,8 @@ static int on_rpf_cache_refresh(struct thread *t)
qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
++qpim_rpf_cache_refresh_events;
- pim_rp_setup ();
+ //It is called as part of pim_neighbor_add
+ //pim_rp_setup ();
return 0;
}
@@ -836,6 +843,7 @@ void igmp_source_forward_start(struct igmp_source *source)
struct igmp_group *group;
struct prefix_sg sg;
int result;
+ int input_iface_vif_index = 0;
memset (&sg, 0, sizeof (struct prefix_sg));
sg.src = source->source_addr;
@@ -861,11 +869,61 @@ void igmp_source_forward_start(struct igmp_source *source)
if (!source->source_channel_oil) {
struct in_addr vif_source;
struct pim_interface *pim_oif;
+ struct prefix nht_p, src, grp;
+ int ret = 0;
+ struct pim_nexthop_cache out_pnc;
+ struct pim_nexthop nexthop;
if (!pim_rp_set_upstream_addr (&vif_source, source->source_addr, sg.grp))
return;
- int input_iface_vif_index = fib_lookup_if_vif_index(vif_source);
+ /* Register addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = vif_source;
+ memset (&out_pnc, 0, sizeof (struct pim_nexthop_cache));
+
+ if ((ret = pim_find_or_track_nexthop (&nht_p, NULL, NULL, &out_pnc)) == 1)
+ {
+ if (out_pnc.nexthop_num)
+ {
+ src.family = AF_INET;
+ src.prefixlen = IPV4_MAX_BITLEN;
+ src.u.prefix4 = vif_source; //RP or Src address
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = sg.grp;
+ memset (&nexthop, 0, sizeof (nexthop));
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&out_pnc, &nexthop,
+ &src, &grp, 0);
+ if (nexthop.interface)
+ input_iface_vif_index = pim_if_find_vifindex_by_ifindex (nexthop.interface->ifindex);
+ }
+ else
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char buf1[INET_ADDRSTRLEN];
+ char buf2[INET_ADDRSTRLEN];
+ pim_inet4_dump("<source?>", nht_p.u.prefix4, buf1, sizeof(buf1));
+ pim_inet4_dump("<source?>", grp.u.prefix4, buf2, sizeof(buf2));
+ zlog_debug ("%s: NHT Nexthop not found for addr %s grp %s" ,
+ __PRETTY_FUNCTION__, buf1, buf2);
+ }
+ }
+ }
+ else
+ input_iface_vif_index = fib_lookup_if_vif_index(vif_source);
+
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char buf2[INET_ADDRSTRLEN];
+ pim_inet4_dump("<source?>", vif_source, buf2, sizeof(buf2));
+ zlog_debug ("%s: NHT %s vif_source %s vif_index:%d ", __PRETTY_FUNCTION__,
+ pim_str_sg_dump (&sg), buf2, input_iface_vif_index);
+ }
+
if (input_iface_vif_index < 1) {
if (PIM_DEBUG_IGMP_TRACE)
{
@@ -1013,49 +1071,105 @@ void pim_forward_start(struct pim_ifchannel *ch)
{
struct pim_upstream *up = ch->upstream;
uint32_t mask = PIM_OIF_FLAG_PROTO_PIM;
+ int input_iface_vif_index = 0;
if (PIM_DEBUG_PIM_TRACE) {
char source_str[INET_ADDRSTRLEN];
- char group_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
char upstream_str[INET_ADDRSTRLEN];
pim_inet4_dump("<source?>", ch->sg.src, source_str, sizeof(source_str));
pim_inet4_dump("<group?>", ch->sg.grp, group_str, sizeof(group_str));
pim_inet4_dump("<upstream?>", up->upstream_addr, upstream_str, sizeof(upstream_str));
- zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)",
+ zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%s)",
__PRETTY_FUNCTION__,
source_str, group_str, ch->interface->name, upstream_str);
}
- if (!up->channel_oil) {
- int input_iface_vif_index = fib_lookup_if_vif_index(up->upstream_addr);
- if (input_iface_vif_index < 1) {
- if (PIM_DEBUG_PIM_TRACE)
- {
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>", up->sg.src, source_str, sizeof(source_str));
- zlog_debug("%s %s: could not find input interface for source %s",
- __FILE__, __PRETTY_FUNCTION__,
- source_str);
- }
- return;
- }
+ /* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS,
+ as part of mroute_del called by pim_forward_stop.
+ */
+ if (!up->channel_oil ||
+ (up->channel_oil && up->channel_oil->oil.mfcc_parent >= MAXVIFS))
+ {
+ struct prefix nht_p, src, grp;
+ int ret = 0;
+ struct pim_nexthop_cache out_pnc;
+ struct pim_nexthop nexthop;
+
+ /* Register addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr;
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+ memset (&out_pnc, 0, sizeof (struct pim_nexthop_cache));
+
+ if ((ret =
+ pim_find_or_track_nexthop (&nht_p, NULL, NULL, &out_pnc)) == 1)
+ {
+ if (out_pnc.nexthop_num)
+ {
+ src.family = AF_INET;
+ src.prefixlen = IPV4_MAX_BITLEN;
+ src.u.prefix4 = up->upstream_addr; //RP or Src address
+ grp.family = AF_INET;
+ grp.prefixlen = IPV4_MAX_BITLEN;
+ grp.u.prefix4 = up->sg.grp;
+ memset (&nexthop, 0, sizeof (nexthop));
+ //Compute PIM RPF using Cached nexthop
+ pim_ecmp_nexthop_search (&out_pnc, &nexthop, &src, &grp, 0);
+ input_iface_vif_index =
+ pim_if_find_vifindex_by_ifindex (nexthop.interface->ifindex);
+ }
+ else
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char buf1[INET_ADDRSTRLEN];
+ char buf2[INET_ADDRSTRLEN];
+ pim_inet4_dump("<source?>", nht_p.u.prefix4, buf1, sizeof(buf1));
+ pim_inet4_dump("<source?>", grp.u.prefix4, buf2, sizeof(buf2));
+ zlog_debug ("%s: NHT pnc is NULL for addr %s grp %s" ,
+ __PRETTY_FUNCTION__, buf1, buf2);
+ }
+ }
+ }
+ else
+ input_iface_vif_index = fib_lookup_if_vif_index (up->upstream_addr);
- up->channel_oil = pim_channel_oil_add(&up->sg,
- input_iface_vif_index);
- if (!up->channel_oil) {
- if (PIM_DEBUG_PIM_TRACE)
- zlog_debug("%s %s: could not create OIL for channel (S,G)=%s",
- __FILE__, __PRETTY_FUNCTION__,
- up->sg_str);
- return;
+ if (input_iface_vif_index < 1)
+ {
+ if (PIM_DEBUG_PIM_TRACE)
+ {
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<source?>", up->sg.src, source_str, sizeof(source_str));
+ zlog_debug("%s %s: could not find input interface for source %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ source_str);
+ }
+ return;
+ }
+ if (PIM_DEBUG_TRACE)
+ {
+ zlog_debug ("%s: NHT entry %s update channel_oil vif_index %d ",
+ __PRETTY_FUNCTION__, up->sg_str, input_iface_vif_index);
+ }
+ up->channel_oil = pim_channel_oil_add (&up->sg, input_iface_vif_index);
+ if (!up->channel_oil)
+ {
+ if (PIM_DEBUG_PIM_TRACE)
+ zlog_debug ("%s %s: could not create OIL for channel (S,G)=%s",
+ __FILE__, __PRETTY_FUNCTION__, up->sg_str);
+ return;
+ }
}
- }
if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
mask = PIM_OIF_FLAG_PROTO_IGMP;
- pim_channel_add_oif(up->channel_oil, ch->interface, mask);
+ pim_channel_add_oif (up->channel_oil, ch->interface, mask);
}
void pim_forward_stop(struct pim_ifchannel *ch)
diff --git a/pimd/pimd.c b/pimd/pimd.c
index bdbd251e2..653856665 100644
--- a/pimd/pimd.c
+++ b/pimd/pimd.c
@@ -75,7 +75,9 @@ unsigned int qpim_keep_alive_time = PIM_KEEPALIVE_PERIOD;
signed int qpim_rp_keep_alive_time = 0;
int64_t qpim_nexthop_lookups = 0;
int qpim_packet_process = PIM_DEFAULT_PACKET_PROCESS;
-struct pim_instance *pimg = NULL;
+uint8_t qpim_ecmp_enable = 0;
+uint8_t qpim_ecmp_rebalance_enable = 0;
+struct pim_instance *pimg = NULL;
int32_t qpim_register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT;
int32_t qpim_register_probe_time = PIM_REGISTER_PROBE_TIME_DEFAULT;
diff --git a/pimd/pimd.h b/pimd/pimd.h
index 69aee28f8..d1ada0220 100644
--- a/pimd/pimd.h
+++ b/pimd/pimd.h
@@ -155,6 +155,9 @@ struct list *qpim_static_route_list; /* list of routes added static
extern unsigned int qpim_keep_alive_time;
extern signed int qpim_rp_keep_alive_time;
extern int qpim_packet_process;
+extern uint8_t qpim_ecmp_enable;
+extern uint8_t qpim_ecmp_rebalance_enable;
+
#define PIM_DEFAULT_PACKET_PROCESS 3
#define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2)