summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pimd/Makefile.am4
-rw-r--r--pimd/pim_main.c3
-rw-r--r--pimd/pim_memory.c2
-rw-r--r--pimd/pim_memory.h3
-rw-r--r--pimd/pim_mroute.c2
-rw-r--r--pimd/pim_nht.c647
-rw-r--r--pimd/pim_nht.h60
-rw-r--r--pimd/pim_rp.c53
-rw-r--r--pimd/pim_rp.h15
-rw-r--r--pimd/pim_rpf.c22
-rw-r--r--pimd/pim_rpf.h2
-rw-r--r--pimd/pim_upstream.c47
-rw-r--r--pimd/pim_upstream.h1
-rw-r--r--pimd/pim_zebra.c146
-rw-r--r--pimd/pim_zebra.h6
-rw-r--r--pimd/pimd.c148
-rw-r--r--pimd/pimd.h13
17 files changed, 1020 insertions, 154 deletions
diff --git a/pimd/Makefile.am b/pimd/Makefile.am
index 59abd1aa3..7e1b451ea 100644
--- a/pimd/Makefile.am
+++ b/pimd/Makefile.am
@@ -53,7 +53,7 @@ libpim_a_SOURCES = \
pim_ssmpingd.c pim_int.c pim_rp.c \
pim_static.c pim_br.c pim_register.c pim_routemap.c \
pim_msdp.c pim_msdp_socket.c pim_msdp_packet.c \
- pim_jp_agg.c
+ pim_jp_agg.c pim_nht.c
noinst_HEADERS = \
pim_memory.h \
@@ -65,7 +65,7 @@ noinst_HEADERS = \
pim_msg.h pim_upstream.h pim_rpf.h pim_macro.h \
pim_igmp_join.h pim_ssmpingd.h pim_int.h pim_rp.h \
pim_static.h pim_br.h pim_register.h \
- pim_msdp.h pim_msdp_socket.h pim_msdp_packet.h \
+ pim_msdp.h pim_msdp_socket.h pim_msdp_packet.h pim_nht.h \
pim_jp_agg.h
pimd_SOURCES = \
diff --git a/pimd/pim_main.c b/pimd/pim_main.c
index a0e42aab5..07f281272 100644
--- a/pimd/pim_main.c
+++ b/pimd/pim_main.c
@@ -89,6 +89,7 @@ FRR_DAEMON_INFO(pimd, PIM,
.privs = &pimd_privs,
)
+
int main(int argc, char** argv, char** envp) {
frr_preinit(&pimd_di, argc, argv);
frr_opt_add("", longopts, "");
@@ -116,7 +117,7 @@ int main(int argc, char** argv, char** envp) {
/*
* Initializations
*/
- vrf_init ();
+ pim_vrf_init ();
access_list_init();
prefix_list_init ();
prefix_list_add_hook (pim_rp_prefix_list_update);
diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c
index 5af2a8203..f46cf193b 100644
--- a/pimd/pim_memory.c
+++ b/pimd/pim_memory.c
@@ -49,3 +49,5 @@ DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr")
DEFINE_MTYPE(PIMD, PIM_SEC_ADDR, "PIM secondary address")
DEFINE_MTYPE(PIMD, PIM_JP_AGG_GROUP, "PIM JP AGG Group")
DEFINE_MTYPE(PIMD, PIM_JP_AGG_SOURCE, "PIM JP AGG Source")
+DEFINE_MTYPE(PIMD, PIM_PIM_INSTANCE, "PIM global state")
+DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE, "PIM nexthop cache state")
diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h
index 0d5f131a4..bd9e12f2f 100644
--- a/pimd/pim_memory.h
+++ b/pimd/pim_memory.h
@@ -48,4 +48,7 @@ DECLARE_MTYPE(PIM_MSDP_MG_MBR)
DECLARE_MTYPE(PIM_SEC_ADDR)
DECLARE_MTYPE(PIM_JP_AGG_GROUP)
DECLARE_MTYPE(PIM_JP_AGG_SOURCE)
+DECLARE_MTYPE(PIM_PIM_INSTANCE)
+DECLARE_MTYPE(PIM_NEXTHOP_CACHE)
+
#endif /* _QUAGGA_PIM_MEMORY_H */
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index 940147581..a244534ab 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -759,7 +759,7 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name)
++qpim_mroute_add_events;
/* Do not install route if incoming interface is undefined. */
- if (c_oil->oil.mfcc_parent == MAXVIFS)
+ if (c_oil->oil.mfcc_parent >= MAXVIFS)
{
if (PIM_DEBUG_MROUTE)
{
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
new file mode 100644
index 000000000..c8cc18730
--- /dev/null
+++ b/pimd/pim_nht.c
@@ -0,0 +1,647 @@
+/*
+ * PIM for Quagga
+ * Copyright (C) 2017 Cumulus Networks, Inc.
+ * Chirag Shah
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+#include <zebra.h>
+#include "network.h"
+#include "zclient.h"
+#include "stream.h"
+#include "nexthop.h"
+#include "if.h"
+#include "hash.h"
+#include "jhash.h"
+
+#include "pimd.h"
+#include "pimd/pim_nht.h"
+#include "log.h"
+#include "pim_time.h"
+#include "pim_oil.h"
+#include "pim_ifchannel.h"
+#include "pim_mroute.h"
+#include "pim_zebra.h"
+#include "pim_upstream.h"
+#include "pim_join.h"
+#include "pim_jp_agg.h"
+#include "pim_zebra.h"
+
+/**
+ * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
+ * command to Zebra.
+ */
+static void
+pim_sendmsg_zebra_rnh (struct zclient *zclient, struct pim_nexthop_cache *pnc,
+ int command)
+{
+ struct stream *s;
+ struct prefix *p;
+ int ret;
+
+ /* Check socket. */
+ if (!zclient || zclient->sock < 0)
+ return;
+
+ p = &(pnc->rpf.rpf_addr);
+ s = zclient->obuf;
+ stream_reset (s);
+ zclient_create_header (s, command, VRF_DEFAULT);
+ /* get update for all routes for a prefix */
+ stream_putc (s, 0);
+
+ stream_putw (s, PREFIX_FAMILY (p));
+ stream_putc (s, p->prefixlen);
+ switch (PREFIX_FAMILY (p))
+ {
+ case AF_INET:
+ stream_put_in_addr (s, &p->u.prefix4);
+ break;
+ case AF_INET6:
+ stream_put (s, &(p->u.prefix6), 16);
+ break;
+ default:
+ break;
+ }
+ stream_putw_at (s, 0, stream_get_endp (s));
+
+ ret = zclient_send_message (zclient);
+ if (ret < 0)
+ zlog_warn ("sendmsg_nexthop: zclient_send_message() failed");
+
+
+ if (PIM_DEBUG_TRACE)
+ {
+ 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);
+ }
+
+ return;
+}
+
+struct pim_nexthop_cache *
+pim_nexthop_cache_find (struct pim_rpf *rpf)
+{
+ struct pim_nexthop_cache *pnc = NULL;
+ struct pim_nexthop_cache lookup;
+
+ lookup.rpf.rpf_addr.family = rpf->rpf_addr.family;
+ lookup.rpf.rpf_addr.prefixlen = rpf->rpf_addr.prefixlen;
+ lookup.rpf.rpf_addr.u.prefix4.s_addr = rpf->rpf_addr.u.prefix4.s_addr;
+
+ pnc = hash_lookup (pimg->rpf_hash, &lookup);
+
+ return pnc;
+
+}
+
+static int
+pim_rp_list_cmp (void *v1, void *v2)
+{
+ struct rp_info *rp1 = (struct rp_info *) v1;
+ struct rp_info *rp2 = (struct rp_info *) v2;
+
+ if (rp1 == rp2)
+ return 0;
+
+ if (!rp1 && rp2)
+ return -1;
+
+ if (rp1 && !rp2)
+ return 1;
+
+ /*
+ * Sort by RP IP address
+ */
+ if (rp1->rp.rpf_addr.u.prefix4.s_addr < rp2->rp.rpf_addr.u.prefix4.s_addr)
+ return -1;
+
+ if (rp1->rp.rpf_addr.u.prefix4.s_addr > rp2->rp.rpf_addr.u.prefix4.s_addr)
+ return 1;
+
+ /*
+ * Sort by group IP address
+ */
+ if (rp1->group.u.prefix4.s_addr < rp2->group.u.prefix4.s_addr)
+ return -1;
+
+ if (rp1->group.u.prefix4.s_addr > rp2->group.u.prefix4.s_addr)
+ return 1;
+
+ return -1;
+}
+
+struct pim_nexthop_cache *
+pim_nexthop_cache_add (struct pim_rpf *rpf_addr)
+{
+ struct pim_nexthop_cache *pnc;
+
+ pnc = XCALLOC (MTYPE_PIM_NEXTHOP_CACHE, sizeof (struct pim_nexthop_cache));
+ if (!pnc)
+ {
+ zlog_err ("%s: NHT PIM XCALLOC failure ", __PRETTY_FUNCTION__);
+ return NULL;
+ }
+ pnc->rpf.rpf_addr.family = rpf_addr->rpf_addr.family;
+ pnc->rpf.rpf_addr.prefixlen = rpf_addr->rpf_addr.prefixlen;
+ pnc->rpf.rpf_addr.u.prefix4.s_addr = rpf_addr->rpf_addr.u.prefix4.s_addr;
+
+ pnc = hash_get (pimg->rpf_hash, pnc, hash_alloc_intern);
+
+ pnc->rp_list = list_new ();
+ pnc->rp_list->cmp = pim_rp_list_cmp;
+
+ pnc->upstream_list = list_new ();
+ pnc->upstream_list->cmp = pim_upstream_compare;
+
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char rpf_str[PREFIX_STRLEN];
+ pim_addr_dump ("<nht?>", &rpf_addr->rpf_addr, rpf_str,
+ sizeof (rpf_str));
+ zlog_debug ("%s: NHT hash node, RP and UP lists allocated for %s ",
+ __PRETTY_FUNCTION__, rpf_str);
+ }
+
+ return pnc;
+}
+
+/* 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 pim_nexthop_cache *pnc = NULL;
+ struct pim_rpf rpf;
+ struct listnode *ch_node = NULL;
+ struct zclient *zclient = NULL;
+
+ zclient = pim_zebra_zclient_get ();
+ memset (&rpf, 0, sizeof (struct pim_rpf));
+ rpf.rpf_addr.family = addr->family;
+ rpf.rpf_addr.prefixlen = addr->prefixlen;
+ rpf.rpf_addr.u.prefix4 = addr->u.prefix4;
+
+ pnc = pim_nexthop_cache_find (&rpf);
+ if (!pnc)
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char buf[PREFIX2STR_BUFFER];
+ prefix2str (&rpf.rpf_addr, buf, sizeof (buf));
+ zlog_debug ("%s: NHT New PNC allocated for addr %s ",
+ __PRETTY_FUNCTION__, buf);
+ }
+ pnc = pim_nexthop_cache_add (&rpf);
+ if (pnc)
+ pim_sendmsg_zebra_rnh (zclient, pnc,
+ ZEBRA_NEXTHOP_REGISTER);
+ else
+ {
+ zlog_warn ("%s: pnc node allocation failed. ", __PRETTY_FUNCTION__);
+ }
+ }
+
+ if (rp != NULL)
+ {
+ ch_node = listnode_lookup (pnc->rp_list, rp);
+ if (ch_node == NULL)
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ 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",
+ __PRETTY_FUNCTION__, rp_str);
+ }
+ listnode_add_sort (pnc->rp_list, rp);
+ }
+ }
+
+ if (up != NULL)
+ {
+ ch_node = listnode_lookup (pnc->upstream_list, up);
+ if (ch_node == NULL)
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char buf[PREFIX2STR_BUFFER];
+ prefix2str (addr, buf, sizeof (buf));
+ zlog_debug
+ ("%s: NHT add upstream %s node to 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;
+
+ return 0;
+}
+
+void
+pim_delete_tracked_nexthop (struct prefix *addr, struct pim_upstream *up,
+ struct rp_info *rp)
+{
+ struct pim_nexthop_cache *pnc = NULL;
+ struct pim_nexthop_cache lookup;
+ struct zclient *zclient = NULL;
+
+ zclient = pim_zebra_zclient_get ();
+
+ /* Remove from RPF hash if it is the last entry */
+ lookup.rpf.rpf_addr = *addr;
+ pnc = hash_lookup (pimg->rpf_hash, &lookup);
+ if (pnc)
+ {
+ if (rp)
+ listnode_delete (pnc->rp_list, rp);
+ if (up)
+ listnode_delete (pnc->upstream_list, up);
+
+ if (PIM_DEBUG_ZEBRA)
+ zlog_debug ("%s: NHT rp_list count:%d upstream_list count:%d ",
+ __PRETTY_FUNCTION__, pnc->rp_list->count,
+ pnc->upstream_list->count);
+
+ if (pnc->rp_list->count == 0 && pnc->upstream_list->count == 0)
+ {
+ pim_sendmsg_zebra_rnh (zclient, pnc,
+ ZEBRA_NEXTHOP_UNREGISTER);
+
+ list_delete (pnc->rp_list);
+ list_delete (pnc->upstream_list);
+
+ hash_release (pimg->rpf_hash, pnc);
+ if (pnc->nexthop)
+ nexthops_free (pnc->nexthop);
+ XFREE (MTYPE_PIM_NEXTHOP_CACHE, pnc);
+ }
+ }
+}
+
+/* Update RP nexthop info based on Nexthop update received from Zebra.*/
+static int
+pim_update_rp_nh (struct pim_nexthop_cache *pnc)
+{
+ struct listnode *node = NULL;
+ struct rp_info *rp_info = NULL;
+ int ret = 0;
+
+ /*Traverse RP list and update each RP Nexthop info */
+ for (ALL_LIST_ELEMENTS_RO (pnc->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)
+ {
+ if (PIM_DEBUG_PIM_TRACE)
+ zlog_debug ("Unable to lookup nexthop for rp specified");
+ ret++;
+ continue;
+ }
+
+ 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 ",
+ __PRETTY_FUNCTION__, rp_str,
+ rp_info->rp.source_nexthop.interface->name);
+ }
+ }
+
+ if (ret)
+ return 0;
+
+ return 1;
+
+}
+
+/* Update Upstream nexthop info based on Nexthop update received from Zebra.*/
+static int
+pim_update_upstream_nh (struct pim_nexthop_cache *pnc)
+{
+ struct listnode *up_node;
+ struct listnode *ifnode;
+ struct listnode *up_nextnode;
+ struct listnode *node;
+ struct pim_upstream *up;
+ struct interface *ifp;
+ int vif_index = 0;
+
+ for (ALL_LIST_ELEMENTS (pnc->upstream_list, up_node, up_nextnode, up))
+ {
+ enum pim_rpf_result rpf_result;
+ struct pim_rpf old;
+
+ if (up == NULL)
+ {
+ zlog_debug ("%s: Upstream node is NULL ", __PRETTY_FUNCTION__);
+ continue;
+ }
+
+ old.source_nexthop.interface = up->rpf.source_nexthop.interface;
+ rpf_result = pim_rpf_update (up, &old, 0);
+ if (rpf_result == PIM_RPF_FAILURE)
+ continue;
+
+ if (rpf_result == PIM_RPF_CHANGED)
+ {
+
+ /*
+ * We have detected a case where we might need to rescan
+ * the inherited o_list so do it.
+ */
+ if (up->channel_oil && up->channel_oil->oil_inherited_rescan)
+ {
+ pim_upstream_inherited_olist_decide (up);
+ up->channel_oil->oil_inherited_rescan = 0;
+ }
+
+ if (up->join_state == PIM_UPSTREAM_JOINED)
+ {
+ /*
+ * If we come up real fast we can be here
+ * where the mroute has not been installed
+ * so install it.
+ */
+ if (up->channel_oil && !up->channel_oil->installed)
+ pim_mroute_add (up->channel_oil, __PRETTY_FUNCTION__);
+
+ /*
+ RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
+
+ Transitions from Joined State
+
+ RPF'(S,G) changes not due to an Assert
+
+ The upstream (S,G) state machine remains in Joined
+ state. Send Join(S,G) to the new upstream neighbor, which is
+ the new value of RPF'(S,G). Send Prune(S,G) to the old
+ upstream neighbor, which is the old value of RPF'(S,G). Set
+ the Join Timer (JT) to expire after t_periodic seconds.
+ */
+ pim_jp_agg_switch_interface (&old, &up->rpf, up);
+
+ pim_upstream_join_timer_restart (up, &old);
+ } /* up->join_state == PIM_UPSTREAM_JOINED */
+
+ /* FIXME can join_desired actually be changed by pim_rpf_update()
+ returning PIM_RPF_CHANGED ? */
+ pim_upstream_update_join_desired (up);
+
+ } /* PIM_RPF_CHANGED */
+
+ if (PIM_DEBUG_TRACE)
+ {
+ zlog_debug ("%s: NHT upstream %s old ifp %s new ifp %s",
+ __PRETTY_FUNCTION__, up->sg_str,
+ 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 (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp))
+ if (ifp->info)
+ {
+ struct pim_interface *pim_ifp = ifp->info;
+ struct pim_iface_upstream_switch *us;
+
+ for (ALL_LIST_ELEMENTS_RO (pim_ifp->upstream_switch_list, node, us))
+ {
+ struct pim_rpf rpf;
+ rpf.source_nexthop.interface = ifp;
+ rpf.rpf_addr.u.prefix4 = us->address;
+ pim_joinprune_send (&rpf, us->us);
+ pim_jp_agg_clear_group (us->us);
+ }
+ }
+
+ return 0;
+}
+
+/* This API is used to parse Registered address nexthop update coming from Zebra */
+void
+pim_parse_nexthop_update (struct zclient *zclient, int command,
+ vrf_id_t vrf_id)
+{
+ 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;
+ u_char nexthop_num = 0;
+ int i;
+ struct pim_rpf rpf;
+ struct pim_nexthop_cache *pnc = NULL;
+ struct pim_neighbor *nbr = NULL;
+ struct interface *ifp = NULL;
+
+ s = zclient->ibuf;
+ memset (&p, 0, sizeof (struct prefix));
+ p.family = stream_getw (s);
+ p.prefixlen = stream_getc (s);
+ switch (p.family)
+ {
+ case AF_INET:
+ p.u.prefix4.s_addr = stream_get_ipv4 (s);
+ break;
+ case AF_INET6:
+ stream_get (&p.u.prefix6, s, 16);
+ break;
+ default:
+ break;
+ }
+
+ if (command == ZEBRA_NEXTHOP_UPDATE)
+ {
+ rpf.rpf_addr.family = p.family;
+ rpf.rpf_addr.prefixlen = p.prefixlen;
+ rpf.rpf_addr.u.prefix4.s_addr = p.u.prefix4.s_addr;
+ pnc = pim_nexthop_cache_find (&rpf);
+ if (!pnc)
+ {
+ if (PIM_DEBUG_TRACE)
+ {
+ 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);
+ }
+ return;
+ }
+ }
+
+ pnc->last_update = pim_time_monotonic_sec ();
+ distance = stream_getc (s);
+ metric = stream_getl (s);
+ nexthop_num = stream_getc (s);
+
+ if (PIM_DEBUG_TRACE)
+ {
+ 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));
+ }
+
+ if (nexthop_num)
+ {
+ pnc->flags |= PIM_NEXTHOP_VALID;
+ pnc->distance = distance;
+ pnc->metric = metric;
+ pnc->nexthop_num = nexthop_num;
+
+ for (i = 0; i < nexthop_num; i++)
+ {
+ nexthop = nexthop_new ();
+ nexthop->type = stream_getc (s);
+ switch (nexthop->type)
+ {
+ case NEXTHOP_TYPE_IPV4:
+ nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
+ nexthop->ifindex = stream_getl (s);
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ nexthop->ifindex = stream_getl (s);
+ break;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
+ nexthop->ifindex = stream_getl (s);
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ stream_get (&nexthop->gate.ipv6, s, 16);
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ stream_get (&nexthop->gate.ipv6, s, 16);
+ nexthop->ifindex = stream_getl (s);
+ nbr =
+ pim_neighbor_find_if (if_lookup_by_index_vrf
+ (nexthop->ifindex, VRF_DEFAULT));
+ /* Overwrite with Nbr address as NH addr */
+ if (nbr)
+ nexthop->gate.ipv4 = nbr->source_addr;
+
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+
+ if (PIM_DEBUG_TRACE)
+ {
+ char p_str[PREFIX2STR_BUFFER];
+ prefix2str (&p, p_str, sizeof (p_str));
+ zlog_debug ("%s: NHT addr %s %d-nhop via %s type %d",
+ __PRETTY_FUNCTION__, p_str, i + 1,
+ inet_ntoa (nexthop->gate.ipv4), nexthop->type);
+ }
+
+ ifp = if_lookup_by_index (nexthop->ifindex);
+ if (!ifp)
+ {
+ 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)));
+ }
+ nexthop_free (nexthop);
+ continue;
+ }
+
+ if (!ifp->info)
+ {
+ if (PIM_DEBUG_ZEBRA)
+ {
+ char buf[NEXTHOP_STRLEN];
+ zlog_debug
+ ("%s: multicast not enabled on input interface %s (ifindex=%d, addr %s)",
+ __PRETTY_FUNCTION__, ifp->name, nexthop->ifindex,
+ nexthop2str (nexthop, buf, sizeof (buf)));
+ }
+ nexthop_free (nexthop);
+ continue;
+ }
+
+ if (nhlist_tail)
+ {
+ nhlist_tail->next = nexthop;
+ nhlist_tail = nexthop;
+ }
+ else
+ {
+ nhlist_tail = nexthop;
+ nhlist_head = nexthop;
+ }
+
+ for (oldnh = pnc->nexthop; oldnh; oldnh = oldnh->next)
+ if (nexthop_same_no_recurse (oldnh, nexthop))
+ break;
+ }
+ /* Reset existing pnc->nexthop before assigning new list */
+ nexthops_free (pnc->nexthop);
+ pnc->nexthop = nhlist_head;
+ }
+ else
+ {
+ pnc->flags &= ~PIM_NEXTHOP_VALID;
+ pnc->nexthop_num = nexthop_num;
+ nexthops_free (pnc->nexthop);
+ pnc->nexthop = NULL;
+ }
+
+ pim_rpf_set_refresh_time ();
+
+ if (listcount (pnc->rp_list))
+ pim_update_rp_nh (pnc);
+ if (listcount (pnc->upstream_list))
+ pim_update_upstream_nh (pnc);
+
+}
diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h
new file mode 100644
index 000000000..6e6602b3b
--- /dev/null
+++ b/pimd/pim_nht.h
@@ -0,0 +1,60 @@
+/*
+ * PIM for Quagga
+ * Copyright (C) 2017 Cumulus Networks, Inc.
+ * Chirag Shah
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+#ifndef PIM_NHT_H
+#define PIM_NHT_H
+
+#include "prefix.h"
+#include <zebra.h>
+#include "zclient.h"
+#include "vrf.h"
+
+#include "pimd.h"
+#include "pim_rp.h"
+#include "pim_rpf.h"
+
+/* PIM nexthop cache value structure. */
+struct pim_nexthop_cache
+{
+ struct pim_rpf rpf;
+ /* IGP route's metric. */
+ u_int32_t metric;
+ uint32_t distance;
+ /* Nexthop number and nexthop linked list. */
+ u_char nexthop_num;
+ struct nexthop *nexthop;
+ int64_t last_update;
+ u_int16_t flags;
+#define PIM_NEXTHOP_VALID (1 << 0)
+
+ struct list *rp_list;
+ struct list *upstream_list;
+};
+
+void pim_parse_nexthop_update (struct zclient *zclient, int command,
+ vrf_id_t vrf_id);
+int pim_find_or_track_nexthop (struct prefix *addr, struct pim_upstream *up,
+ struct rp_info *rp);
+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);
+
+#endif
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index dc19002a4..de30116ed 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -42,14 +42,8 @@
#include "pim_memory.h"
#include "pim_iface.h"
#include "pim_msdp.h"
+#include "pim_nht.h"
-struct rp_info
-{
- struct prefix group;
- struct pim_rpf rp;
- int i_am_rp;
- char *plist;
-};
static struct list *qpim_rp_list = NULL;
static struct rp_info *tail = NULL;
@@ -305,6 +299,7 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist)
struct listnode *node, *nnode;
struct rp_info *tmp_rp_info;
char buffer[BUFSIZ];
+ struct prefix nht_p;
rp_info = XCALLOC (MTYPE_PIM_RP, sizeof (*rp_info));
if (!rp_info)
@@ -401,6 +396,19 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist)
rp_all->rp.rpf_addr = rp_info->rp.rpf_addr;
XFREE (MTYPE_PIM_RP, rp_info);
+ /* 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;
+ if (PIM_DEBUG_PIM_TRACE)
+ {
+ char buf[PREFIX2STR_BUFFER];
+ prefix2str (&nht_p, buf, sizeof (buf));
+ zlog_debug ("%s: NHT Register rp_all addr %s with NHT ",
+ __PRETTY_FUNCTION__, buf);
+ }
+ 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;
@@ -448,11 +456,23 @@ pim_rp_new (const char *rp, const char *group_range, const char *plist)
listnode_add_sort (qpim_rp_list, rp_info);
+ /* 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];
+ prefix2str (&nht_p, buf, sizeof (buf));
+ zlog_debug ("%s: NHT Register RP addr %s with Zebra ", __PRETTY_FUNCTION__, buf);
+ }
+ 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;
pim_rp_check_interfaces (rp_info);
- pim_rp_refresh_group_to_rp_mapping();
+ pim_rp_refresh_group_to_rp_mapping ();
return PIM_SUCCESS;
}
@@ -465,6 +485,7 @@ pim_rp_del (const char *rp, const char *group_range, const char *plist)
struct rp_info *rp_info;
struct rp_info *rp_all;
int result;
+ struct prefix nht_p;
if (group_range == NULL)
result = str2prefix ("224.0.0.0/4", &group);
@@ -492,6 +513,18 @@ pim_rp_del (const char *rp, const char *group_range, const char *plist)
rp_info->plist = NULL;
}
+ /* Deregister 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];
+ prefix2str (&nht_p, buf, sizeof (buf));
+ zlog_debug ("%s: Deregister RP addr %s with NHT ", __PRETTY_FUNCTION__, buf);
+ }
+ pim_delete_tracked_nexthop (&nht_p, NULL, rp_info);
+
str2prefix ("224.0.0.0/4", &g_all);
rp_all = pim_rp_find_match_group (&g_all);
@@ -504,7 +537,7 @@ pim_rp_del (const char *rp, const char *group_range, const char *plist)
}
listnode_delete (qpim_rp_list, rp_info);
- pim_rp_refresh_group_to_rp_mapping();
+ pim_rp_refresh_group_to_rp_mapping ();
return PIM_SUCCESS;
}
@@ -754,7 +787,7 @@ pim_rp_check_is_my_ip_address (struct in_addr group, struct in_addr dest_addr)
if (if_lookup_exact_address (&dest_addr, AF_INET))
return 1;
-
+
return 0;
}
diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h
index b32228ed4..e5580cfa6 100644
--- a/pimd/pim_rp.h
+++ b/pimd/pim_rp.h
@@ -21,6 +21,21 @@
#ifndef PIM_RP_H
#define PIM_RP_H
+#include <zebra.h>
+#include "prefix.h"
+#include "vty.h"
+#include "plist.h"
+#include "pim_iface.h"
+#include "pim_rpf.h"
+
+struct rp_info
+{
+ struct prefix group;
+ struct pim_rpf rp;
+ int i_am_rp;
+ char *plist;
+};
+
void pim_rp_init (void);
void pim_rp_free (void);
diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c
index ff8a6054c..3d278f12a 100644
--- a/pimd/pim_rpf.c
+++ b/pimd/pim_rpf.c
@@ -34,11 +34,12 @@
#include "pim_zlookup.h"
#include "pim_ifchannel.h"
#include "pim_time.h"
+#include "pim_nht.h"
static long long last_route_change_time = -1;
long long nexthop_lookups_avoided = 0;
-static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up);
+static struct in_addr pim_rpf_find_rpf_addr (struct pim_upstream *up);
void
pim_rpf_set_refresh_time (void)
@@ -184,14 +185,31 @@ static int nexthop_mismatch(const struct pim_nexthop *nh1,
(nh1->mrib_route_metric != nh2->mrib_route_metric);
}
-enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old)
+enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old, uint8_t is_new)
{
struct pim_rpf *rpf = &up->rpf;
struct pim_rpf saved;
+ struct prefix nht_p;
saved.source_nexthop = rpf->source_nexthop;
saved.rpf_addr = rpf->rpf_addr;
+ if (is_new)
+ {
+ if (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;
+ 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) &&
diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h
index f4a987793..85fb1ed89 100644
--- a/pimd/pim_rpf.h
+++ b/pimd/pim_rpf.h
@@ -64,7 +64,7 @@ struct pim_upstream;
extern long long nexthop_lookups_avoided;
int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr, int neighbor_needed);
-enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old);
+enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct pim_rpf *old, uint8_t is_new);
int pim_rpf_addr_is_inaddr_none (struct pim_rpf *rpf);
int pim_rpf_addr_is_inaddr_any (struct pim_rpf *rpf);
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index 19f7d3336..183db532b 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -52,6 +52,7 @@
#include "pim_register.h"
#include "pim_msdp.h"
#include "pim_jp_agg.h"
+#include "pim_nht.h"
struct hash *pim_upstream_hash = NULL;
struct list *pim_upstream_list = NULL;
@@ -142,6 +143,7 @@ pim_upstream_find_parent (struct pim_upstream *child)
void pim_upstream_free(struct pim_upstream *up)
{
XFREE(MTYPE_PIM_UPSTREAM, up);
+ up = NULL;
}
static void upstream_channel_oil_detach(struct pim_upstream *up)
@@ -156,6 +158,7 @@ void
pim_upstream_del(struct pim_upstream *up, const char *name)
{
bool notify_msdp = false;
+ struct prefix nht_p;
if (PIM_DEBUG_TRACE)
zlog_debug ("%s(%s): Delete %s ref count: %d",
@@ -209,10 +212,25 @@ pim_upstream_del(struct pim_upstream *up, const char *name)
listnode_delete (pim_upstream_list, up);
hash_release (pim_upstream_hash, up);
- if (notify_msdp) {
- pim_msdp_up_del(&up->sg);
- }
- pim_upstream_free(up);
+ if (notify_msdp)
+ {
+ pim_msdp_up_del (&up->sg);
+ }
+
+ /* Deregister addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = up->upstream_addr;
+ if (PIM_DEBUG_TRACE)
+ {
+ 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);
+ }
+ pim_delete_tracked_nexthop (&nht_p, up, NULL);
+
+ pim_upstream_free (up);
}
void
@@ -517,7 +535,7 @@ pim_upstream_switch(struct pim_upstream *up,
}
}
-static int
+int
pim_upstream_compare (void *arg1, void *arg2)
{
const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
@@ -548,11 +566,12 @@ pim_upstream_new (struct prefix_sg *sg,
struct pim_upstream *up;
up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
- if (!up) {
- zlog_err("%s: PIM XCALLOC(%zu) failure",
+ if (!up)
+ {
+ zlog_err("%s: PIM XCALLOC(%zu) failure",
__PRETTY_FUNCTION__, sizeof(*up));
- return NULL;
- }
+ return NULL;
+ }
up->sg = *sg;
pim_str_sg_set (sg, up->sg_str);
@@ -600,7 +619,7 @@ pim_upstream_new (struct prefix_sg *sg,
if (up->sg.src.s_addr != INADDR_ANY)
wheel_add_item (pim_upstream_sg_wheel, up);
- rpf_result = pim_rpf_update(up, NULL);
+ rpf_result = pim_rpf_update(up, NULL, 1);
if (rpf_result == PIM_RPF_FAILURE) {
if (PIM_DEBUG_TRACE)
zlog_debug ("%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__,
@@ -631,7 +650,11 @@ pim_upstream_new (struct prefix_sg *sg,
listnode_add_sort(pim_upstream_list, up);
if (PIM_DEBUG_TRACE)
- zlog_debug ("%s: Created Upstream %s", __PRETTY_FUNCTION__, up->sg_str);
+ {
+ zlog_debug ("%s: Created Upstream %s upstream_addr %s",
+ __PRETTY_FUNCTION__, up->sg_str,
+ inet_ntoa (up->upstream_addr));
+ }
return up;
}
@@ -1403,7 +1426,7 @@ pim_upstream_find_new_rpf (void)
if (PIM_DEBUG_TRACE)
zlog_debug ("Upstream %s without a path to send join, checking",
up->sg_str);
- pim_rpf_update (up, NULL);
+ pim_rpf_update (up, NULL, 1);
}
}
}
diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h
index b191fe940..0bc4c4410 100644
--- a/pimd/pim_upstream.h
+++ b/pimd/pim_upstream.h
@@ -183,4 +183,5 @@ void pim_upstream_init (void);
void pim_upstream_terminate (void);
void join_timer_start (struct pim_upstream *up);
+int pim_upstream_compare (void *arg1, void *arg2);
#endif /* PIM_UPSTREAM_H */
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index 1db6616c5..ad4ef64ed 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -45,6 +45,7 @@
#include "pim_rp.h"
#include "pim_igmpv3.h"
#include "pim_jp_agg.h"
+#include "pim_nht.h"
#undef PIM_DEBUG_IFADDR_DUMP
#define PIM_DEBUG_IFADDR_DUMP
@@ -375,8 +376,8 @@ static void scan_upstream_rpf_cache()
old.source_nexthop.interface = up->rpf.source_nexthop.interface;
old.source_nexthop.nbr = up->rpf.source_nexthop.nbr;
- rpf_result = pim_rpf_update(up, &old);
- zlog_debug ("Looking at upstream: %s %d", up->sg_str, rpf_result);
+ rpf_result = pim_rpf_update(up, &old, 0);
+
if (rpf_result == PIM_RPF_FAILURE)
continue;
@@ -444,7 +445,7 @@ static void scan_upstream_rpf_cache()
}
void
-pim_scan_individual_oil (struct channel_oil *c_oil)
+pim_scan_individual_oil (struct channel_oil *c_oil, int in_vif_index)
{
struct in_addr vif_source;
int input_iface_vif_index;
@@ -453,7 +454,10 @@ pim_scan_individual_oil (struct channel_oil *c_oil)
if (!pim_rp_set_upstream_addr (&vif_source, c_oil->oil.mfcc_origin, c_oil->oil.mfcc_mcastgrp))
return;
- input_iface_vif_index = fib_lookup_if_vif_index (vif_source);
+ if (in_vif_index)
+ input_iface_vif_index = in_vif_index;
+ else
+ input_iface_vif_index = fib_lookup_if_vif_index (vif_source);
if (input_iface_vif_index < 1)
{
if (PIM_DEBUG_ZEBRA)
@@ -548,7 +552,7 @@ void pim_scan_oil()
++qpim_scan_oil_events;
for (ALL_LIST_ELEMENTS(pim_channel_oil_list, node, nextnode, c_oil))
- pim_scan_individual_oil (c_oil);
+ pim_scan_individual_oil (c_oil, 0);
}
static int on_rpf_cache_refresh(struct thread *t)
@@ -594,124 +598,11 @@ void sched_rpf_cache_refresh(void)
0, qpim_rpf_cache_refresh_delay_msec);
}
-static int redist_read_ipv4_route(int command, struct zclient *zclient,
- zebra_size_t length, vrf_id_t vrf_id)
+static int
+pim_zebra_nexthop_update (int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
{
- struct stream *s;
- struct zapi_ipv4 api;
- ifindex_t ifindex;
- struct in_addr nexthop;
- struct prefix_ipv4 p;
- int min_len = 4;
-
- if (length < min_len) {
- zlog_warn("%s %s: short buffer: length=%d min=%d",
- __FILE__, __PRETTY_FUNCTION__,
- length, min_len);
- return -1;
- }
-
- s = zclient->ibuf;
- ifindex = 0;
- nexthop.s_addr = 0;
-
- /* Type, flags, message. */
- api.type = stream_getc(s);
- api.instance = stream_getw (s);
- api.flags = stream_getl(s);
- api.message = stream_getc(s);
-
- /* IPv4 prefix length. */
- memset(&p, 0, sizeof(struct prefix_ipv4));
- p.family = AF_INET;
- p.prefixlen = stream_getc(s);
-
- min_len +=
- PSIZE(p.prefixlen) +
- CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 +
- CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 +
- CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 +
- CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0;
-
- if (PIM_DEBUG_ZEBRA) {
- zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
- __FILE__, __PRETTY_FUNCTION__,
- length, min_len,
- CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
- CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
- CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
- CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
- }
-
- /* IPv4 prefix. */
- stream_get(&p.prefix, s, PSIZE(p.prefixlen));
-
- /* Nexthop, ifindex, distance, metric. */
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
- api.nexthop_num = stream_getc(s);
- nexthop.s_addr = stream_get_ipv4(s);
- }
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
- api.ifindex_num = stream_getc(s);
- ifindex = stream_getl(s);
- }
-
- api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ?
- stream_getc(s) :
- 0;
-
- api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ?
- stream_getl(s) :
- 0;
-
- if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
- api.tag = stream_getl (s);
- else
- api.tag = 0;
-
- switch (command) {
- case ZEBRA_REDISTRIBUTE_IPV4_ADD:
- if (PIM_DEBUG_ZEBRA) {
- char buf[2][INET_ADDRSTRLEN];
- zlog_debug("%s: add %s %s/%d "
- "nexthop %s ifindex %d metric%s %u distance%s %u",
- __PRETTY_FUNCTION__,
- zebra_route_string(api.type),
- inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
- p.prefixlen,
- inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
- ifindex,
- CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
- api.metric,
- CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
- api.distance);
- }
- break;
- case ZEBRA_REDISTRIBUTE_IPV4_DEL:
- if (PIM_DEBUG_ZEBRA) {
- char buf[2][INET_ADDRSTRLEN];
- zlog_debug("%s: delete %s %s/%d "
- "nexthop %s ifindex %d metric%s %u distance%s %u",
- __PRETTY_FUNCTION__,
- zebra_route_string(api.type),
- inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
- p.prefixlen,
- inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
- ifindex,
- CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
- api.metric,
- CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
- api.distance);
- }
- break;
- default:
- zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command);
- return -1;
- }
-
- sched_rpf_cache_refresh();
-
- pim_rp_setup ();
+ pim_parse_nexthop_update (zclient, command, vrf_id);
return 0;
}
@@ -742,8 +633,7 @@ void pim_zebra_init(void)
zclient->interface_down = pim_zebra_if_state_down;
zclient->interface_address_add = pim_zebra_if_address_add;
zclient->interface_address_delete = pim_zebra_if_address_del;
- zclient->redistribute_route_ipv4_add = redist_read_ipv4_route;
- zclient->redistribute_route_ipv4_del = redist_read_ipv4_route;
+ zclient->nexthop_update = pim_zebra_nexthop_update;
zclient_init(zclient, ZEBRA_ROUTE_PIM, 0);
if (PIM_DEBUG_PIM_TRACE) {
@@ -1262,3 +1152,11 @@ pim_zebra_zclient_update (struct vty *vty)
vty_out(vty, "<null zclient>%s", VTY_NEWLINE);
}
}
+
+struct zclient *pim_zebra_zclient_get (void)
+{
+ if (zclient)
+ return zclient;
+ else
+ return NULL;
+}
diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h
index 751a7be25..5dc06a4a1 100644
--- a/pimd/pim_zebra.h
+++ b/pimd/pim_zebra.h
@@ -21,13 +21,16 @@
#ifndef PIM_ZEBRA_H
#define PIM_ZEBRA_H
+#include <zebra.h>
+#include "zclient.h"
+
#include "pim_igmp.h"
#include "pim_ifchannel.h"
void pim_zebra_init(void);
void pim_zebra_zclient_update (struct vty *vty);
-void pim_scan_individual_oil (struct channel_oil *c_oil);
+void pim_scan_individual_oil (struct channel_oil *c_oil, int in_vif_index);
void pim_scan_oil(void);
void igmp_anysource_forward_start(struct igmp_group *group);
@@ -40,4 +43,5 @@ void pim_forward_start(struct pim_ifchannel *ch);
void pim_forward_stop(struct pim_ifchannel *ch);
void sched_rpf_cache_refresh(void);
+struct zclient *pim_zebra_zclient_get (void);
#endif /* PIM_ZEBRA_H */
diff --git a/pimd/pimd.c b/pimd/pimd.c
index c8a0efc40..b67544b28 100644
--- a/pimd/pimd.c
+++ b/pimd/pimd.c
@@ -26,6 +26,8 @@
#include "prefix.h"
#include "vty.h"
#include "plist.h"
+#include "hash.h"
+#include "jhash.h"
#include "pimd.h"
#include "pim_cmd.h"
@@ -40,6 +42,7 @@
#include "pim_static.h"
#include "pim_rp.h"
#include "pim_zlookup.h"
+#include "pim_nht.h"
const char *const PIM_ALL_SYSTEMS = MCAST_ALL_SYSTEMS;
const char *const PIM_ALL_ROUTERS = MCAST_ALL_ROUTERS;
@@ -71,10 +74,127 @@ 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;
int32_t qpim_register_suppress_time = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT;
int32_t qpim_register_probe_time = PIM_REGISTER_PROBE_TIME_DEFAULT;
+static struct pim_instance *pim_instance_init (vrf_id_t vrf_id, afi_t afi);
+static void pim_instance_terminate (void);
+
+static int
+pim_vrf_new (struct vrf *vrf)
+{
+ zlog_debug ("VRF Created: %s(%d)", vrf->name, vrf->vrf_id);
+ return 0;
+}
+
+static int
+pim_vrf_delete (struct vrf *vrf)
+{
+ zlog_debug ("VRF Deletion: %s(%d)", vrf->name, vrf->vrf_id);
+ return 0;
+}
+
+static int
+pim_vrf_enable (struct vrf *vrf)
+{
+
+ if (!vrf) // unexpected
+ return -1;
+
+ if (vrf->vrf_id == VRF_DEFAULT)
+ {
+ pimg = pim_instance_init (VRF_DEFAULT, AFI_IP);
+ if (pimg == NULL)
+ zlog_err ("%s %s: pim class init failure ", __FILE__,
+ __PRETTY_FUNCTION__);
+ }
+ return 0;
+}
+
+static int
+pim_vrf_disable (struct vrf *vrf)
+{
+ if (vrf->vrf_id == VRF_DEFAULT)
+ return 0;
+
+ if (vrf->vrf_id == VRF_DEFAULT)
+ pim_instance_terminate ();
+
+ /* Note: This is a callback, the VRF will be deleted by the caller. */
+ return 0;
+}
+
+void
+pim_vrf_init (void)
+{
+ vrf_add_hook (VRF_NEW_HOOK, pim_vrf_new);
+ vrf_add_hook (VRF_ENABLE_HOOK, pim_vrf_enable);
+ vrf_add_hook (VRF_DISABLE_HOOK, pim_vrf_disable);
+ vrf_add_hook (VRF_DELETE_HOOK, pim_vrf_delete);
+
+ vrf_init ();
+}
+
+static void
+pim_vrf_terminate (void)
+{
+ vrf_add_hook (VRF_NEW_HOOK, NULL);
+ vrf_add_hook (VRF_ENABLE_HOOK, NULL);
+ vrf_add_hook (VRF_DISABLE_HOOK, NULL);
+ vrf_add_hook (VRF_DELETE_HOOK, NULL);
+
+ vrf_terminate ();
+}
+
+/* Key generate for pim->rpf_hash */
+static unsigned int
+pim_rpf_hash_key (void *arg)
+{
+ struct pim_nexthop_cache *r = (struct pim_nexthop_cache *) arg;
+
+ return jhash_1word (r->rpf.rpf_addr.u.prefix4.s_addr, 0);
+}
+
+/* Compare pim->rpf_hash node data */
+static int
+pim_rpf_equal (const void *arg1, const void *arg2)
+{
+ const struct pim_nexthop_cache *r1 =
+ (const struct pim_nexthop_cache *) arg1;
+ const struct pim_nexthop_cache *r2 =
+ (const struct pim_nexthop_cache *) arg2;
+
+ return prefix_same (&r1->rpf.rpf_addr, &r2->rpf.rpf_addr);
+}
+
+/* Cleanup pim->rpf_hash each node data */
+static void
+pim_rp_list_hash_clean (void *data)
+{
+ struct pim_nexthop_cache *pnc;
+
+ pnc = (struct pim_nexthop_cache *) data;
+ if (pnc->rp_list->count)
+ list_delete_all_node (pnc->rp_list);
+ if (pnc->upstream_list->count)
+ list_delete_all_node (pnc->upstream_list);
+}
+
+static void
+pim_instance_terminate (void)
+{
+ /* Traverse and cleanup rpf_hash */
+ if (pimg && pimg->rpf_hash)
+ {
+ hash_clean (pimg->rpf_hash, (void *) pim_rp_list_hash_clean);
+ hash_free (pimg->rpf_hash);
+ }
+
+ XFREE (MTYPE_PIM_PIM_INSTANCE, pimg);
+}
+
static void pim_free()
{
pim_ssmpingd_destroy();
@@ -96,6 +216,27 @@ static void pim_free()
zprivs_terminate(&pimd_privs);
}
+static struct pim_instance *
+pim_instance_init (vrf_id_t vrf_id, afi_t afi)
+{
+ struct pim_instance *pim;
+
+ pim = XCALLOC (MTYPE_PIM_PIM_INSTANCE, sizeof (struct pim_instance));
+ if (!pim)
+ return NULL;
+
+ pim->vrf_id = vrf_id;
+ pim->afi = afi;
+
+ pim->rpf_hash = hash_create_size (256, pim_rpf_hash_key, pim_rpf_equal);
+
+ if (PIM_DEBUG_ZEBRA)
+ zlog_debug ("%s: NHT rpf hash init ", __PRETTY_FUNCTION__);
+
+
+ return pim;
+}
+
void pim_init()
{
qpim_rp_keep_alive_time = PIM_RP_KEEPALIVE_PERIOD;
@@ -147,4 +288,11 @@ void pim_init()
void pim_terminate()
{
pim_free();
+
+ /* reverse prefix_list_init */
+ prefix_list_add_hook (NULL);
+ prefix_list_delete_hook (NULL);
+ prefix_list_reset ();
+
+ pim_vrf_terminate ();
}
diff --git a/pimd/pimd.h b/pimd/pimd.h
index 090601630..b3bdd9e24 100644
--- a/pimd/pimd.h
+++ b/pimd/pimd.h
@@ -22,6 +22,8 @@
#define PIMD_H
#include <stdint.h>
+#include "zebra.h"
+#include "libfrr.h"
#include "pim_str.h"
#include "pim_memory.h"
@@ -232,10 +234,21 @@ extern int32_t qpim_register_probe_time;
#define PIM_DONT_DEBUG_MSDP_PACKETS (qpim_debugs &= ~PIM_MASK_MSDP_PACKETS)
#define PIM_DONT_DEBUG_MSDP_INTERNAL (qpim_debugs &= ~PIM_MASK_MSDP_INTERNAL)
+/* Per VRF PIM DB */
+struct pim_instance
+{
+ afi_t afi;
+ vrf_id_t vrf_id;
+ struct hash *rpf_hash;
+};
+
+extern struct pim_instance *pimg; //Pim Global Instance
+
void pim_init(void);
void pim_terminate(void);
extern void pim_route_map_init (void);
extern void pim_route_map_terminate(void);
+void pim_vrf_init (void);
#endif /* PIMD_H */