summaryrefslogtreecommitdiff
path: root/pimd/pim_neighbor.c
diff options
context:
space:
mode:
Diffstat (limited to 'pimd/pim_neighbor.c')
-rw-r--r--pimd/pim_neighbor.c157
1 files changed, 121 insertions, 36 deletions
diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c
index 04792eb35e..c1325df260 100644
--- a/pimd/pim_neighbor.c
+++ b/pimd/pim_neighbor.c
@@ -24,6 +24,8 @@
#include "prefix.h"
#include "memory.h"
#include "if.h"
+#include "vty.h"
+#include "plist.h"
#include "pimd.h"
#include "pim_neighbor.h"
@@ -33,6 +35,10 @@
#include "pim_pim.h"
#include "pim_upstream.h"
#include "pim_ifchannel.h"
+#include "pim_rp.h"
+#include "pim_zebra.h"
+#include "pim_join.h"
+#include "pim_jp_agg.h"
static void dr_election_by_addr(struct interface *ifp)
{
@@ -125,8 +131,8 @@ int pim_if_dr_election(struct interface *ifp)
if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) {
if (PIM_DEBUG_PIM_EVENTS) {
- char dr_old_str[100];
- char dr_new_str[100];
+ char dr_old_str[INET_ADDRSTRLEN];
+ char dr_new_str[INET_ADDRSTRLEN];
pim_inet4_dump("<old_dr?>", old_dr_addr, dr_old_str, sizeof(dr_old_str));
pim_inet4_dump("<new_dr?>", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str));
zlog_debug("%s: DR was %s now is %s on interface %s",
@@ -207,20 +213,18 @@ static int on_neighbor_timer(struct thread *t)
struct interface *ifp;
char msg[100];
- zassert(t);
neigh = THREAD_ARG(t);
- zassert(neigh);
ifp = neigh->interface;
if (PIM_DEBUG_PIM_TRACE) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
zlog_debug("Expired %d sec holdtime for neighbor %s on interface %s",
neigh->holdtime, src_str, ifp->name);
}
- neigh->t_expire_timer = 0;
+ neigh->t_expire_timer = NULL;
snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime);
pim_neighbor_delete(ifp, neigh, msg);
@@ -237,26 +241,11 @@ static int on_neighbor_timer(struct thread *t)
return 0;
}
-static void neighbor_timer_off(struct pim_neighbor *neigh)
-{
- if (PIM_DEBUG_PIM_TRACE_DETAIL) {
- if (neigh->t_expire_timer) {
- char src_str[100];
- pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
- zlog_debug("%s: cancelling timer for neighbor %s on %s",
- __PRETTY_FUNCTION__,
- src_str, neigh->interface->name);
- }
- }
- THREAD_OFF(neigh->t_expire_timer);
- zassert(!neigh->t_expire_timer);
-}
-
void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime)
{
neigh->holdtime = holdtime;
- neighbor_timer_off(neigh);
+ THREAD_OFF(neigh->t_expire_timer);
/*
0xFFFF is request for no holdtime
@@ -266,7 +255,7 @@ void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime)
}
if (PIM_DEBUG_PIM_TRACE_DETAIL) {
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
zlog_debug("%s: starting %u sec timer for neighbor %s on %s",
__PRETTY_FUNCTION__,
@@ -278,6 +267,41 @@ void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime)
neigh, neigh->holdtime);
}
+static int
+on_neighbor_jp_timer (struct thread *t)
+{
+ struct pim_neighbor *neigh = THREAD_ARG(t);
+ struct pim_rpf rpf;
+
+ if (PIM_DEBUG_PIM_TRACE)
+ {
+ char src_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
+ zlog_debug("%s:Sending JP Agg to %s on %s with %d groups", __PRETTY_FUNCTION__,
+ src_str, neigh->interface->name, neigh->upstream_jp_agg->count);
+ }
+ neigh->jp_timer = NULL;
+
+ rpf.source_nexthop.interface = neigh->interface;
+ rpf.rpf_addr.u.prefix4 = neigh->source_addr;
+ pim_joinprune_send(&rpf, neigh->upstream_jp_agg);
+
+ THREAD_TIMER_ON(master, neigh->jp_timer,
+ on_neighbor_jp_timer,
+ neigh, qpim_t_periodic);
+
+ return 0;
+}
+
+static void
+pim_neighbor_start_jp_timer (struct pim_neighbor *neigh)
+{
+ THREAD_TIMER_OFF(neigh->jp_timer);
+ THREAD_TIMER_ON(master, neigh->jp_timer,
+ on_neighbor_jp_timer,
+ neigh, qpim_t_periodic);
+}
+
static struct pim_neighbor *pim_neighbor_new(struct interface *ifp,
struct in_addr source_addr,
pim_hello_options hello_options,
@@ -290,15 +314,15 @@ static struct pim_neighbor *pim_neighbor_new(struct interface *ifp,
{
struct pim_interface *pim_ifp;
struct pim_neighbor *neigh;
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
zassert(ifp);
pim_ifp = ifp->info;
zassert(pim_ifp);
- neigh = XMALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
+ neigh = XCALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
if (!neigh) {
- zlog_err("%s: PIM XMALLOC(%zu) failure",
+ zlog_err("%s: PIM XCALLOC(%zu) failure",
__PRETTY_FUNCTION__, sizeof(*neigh));
return 0;
}
@@ -311,10 +335,23 @@ static struct pim_neighbor *pim_neighbor_new(struct interface *ifp,
neigh->dr_priority = dr_priority;
neigh->generation_id = generation_id;
neigh->prefix_list = addr_list;
- neigh->t_expire_timer = 0;
+ neigh->t_expire_timer = NULL;
neigh->interface = ifp;
+ neigh->upstream_jp_agg = list_new();
+ neigh->upstream_jp_agg->cmp = pim_jp_agg_group_list_cmp;
+ neigh->upstream_jp_agg->del = (void (*)(void *))pim_jp_agg_group_list_free;
+ pim_neighbor_start_jp_timer(neigh);
+
pim_neighbor_timer_reset(neigh, holdtime);
+ /*
+ * The pim_ifstat_hello_sent variable is used to decide if
+ * we should expedite a hello out the interface. If we
+ * establish a new neighbor, we unfortunately need to
+ * reset the value so that we can know to hurry up and
+ * hello
+ */
+ pim_ifp->pim_ifstat_hello_sent = 0;
pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
@@ -380,6 +417,9 @@ void pim_neighbor_free(struct pim_neighbor *neigh)
delete_prefix_list(neigh);
+ list_delete(neigh->upstream_jp_agg);
+ THREAD_OFF(neigh->jp_timer);
+
XFREE(MTYPE_PIM_NEIGHBOR, neigh);
}
@@ -391,7 +431,8 @@ struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
struct pim_neighbor *neigh;
pim_ifp = ifp->info;
- zassert(pim_ifp);
+ if (!pim_ifp)
+ return NULL;
for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
if (source_addr.s_addr == neigh->source_addr.s_addr) {
@@ -399,7 +440,35 @@ struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
}
}
- return 0;
+ return NULL;
+}
+
+/*
+ * Find the *one* interface out
+ * this interface. If more than
+ * one return NULL
+ */
+struct pim_neighbor *
+pim_neighbor_find_if (struct interface *ifp)
+{
+ struct pim_interface *pim_ifp = ifp->info;
+
+ if (!pim_ifp || pim_ifp->pim_neighbor_list->count != 1)
+ return NULL;
+
+ return listnode_head (pim_ifp->pim_neighbor_list);
+}
+
+/* rpf info associated with an upstream entry needs to be re-evaluated
+ * when an RPF neighbor comes or goes */
+static void
+pim_neighbor_rpf_update(void)
+{
+ /* XXX: for the time being piggyback on the timer used on rib changes
+ * to scan and update the rpf nexthop. This is expensive processing
+ * and we should be able to optimize neighbor changes differently than
+ * nexthop changes. */
+ sched_rpf_cache_refresh();
}
struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
@@ -410,7 +479,8 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
uint16_t override_interval,
uint32_t dr_priority,
uint32_t generation_id,
- struct list *addr_list)
+ struct list *addr_list,
+ int send_hello_now)
{
struct pim_interface *pim_ifp;
struct pim_neighbor *neigh;
@@ -449,9 +519,22 @@ struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
message with a new GenID is received from an existing neighbor, a
new Hello message should be sent on this interface after a
randomized delay between 0 and Triggered_Hello_Delay.
+
+ This is a bit silly to do it that way. If I get a new
+ genid we need to send the hello *now* because we've
+ lined up a bunch of join/prune messages to go out the
+ interface.
*/
- pim_hello_restart_triggered(neigh->interface);
+ if (send_hello_now)
+ pim_hello_restart_now (ifp);
+ else
+ pim_hello_restart_triggered(neigh->interface);
+
+ pim_upstream_find_new_rpf();
+
+ pim_rp_setup ();
+ pim_neighbor_rpf_update();
return neigh;
}
@@ -508,7 +591,7 @@ void pim_neighbor_delete(struct interface *ifp,
const char *delete_message)
{
struct pim_interface *pim_ifp;
- char src_str[100];
+ char src_str[INET_ADDRSTRLEN];
pim_ifp = ifp->info;
zassert(pim_ifp);
@@ -517,7 +600,7 @@ void pim_neighbor_delete(struct interface *ifp,
zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s",
src_str, ifp->name, delete_message);
- neighbor_timer_off(neigh);
+ THREAD_OFF(neigh->t_expire_timer);
pim_if_assert_on_neighbor_down(ifp, neigh->source_addr);
@@ -564,6 +647,8 @@ void pim_neighbor_delete(struct interface *ifp,
listnode_delete(pim_ifp->pim_neighbor_list, neigh);
pim_neighbor_free(neigh);
+
+ pim_neighbor_rpf_update();
}
void pim_neighbor_delete_all(struct interface *ifp,
@@ -646,9 +731,9 @@ static void delete_from_neigh_addr(struct interface *ifp,
{
struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4);
if (p) {
- char addr_str[100];
- char this_neigh_str[100];
- char other_neigh_str[100];
+ char addr_str[INET_ADDRSTRLEN];
+ char this_neigh_str[INET_ADDRSTRLEN];
+ char other_neigh_str[INET_ADDRSTRLEN];
pim_inet4_dump("<addr?>", addr->u.prefix4, addr_str, sizeof(addr_str));
pim_inet4_dump("<neigh1?>", neigh_addr, this_neigh_str, sizeof(this_neigh_str));