]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_upstream.c
pimd: Carefully Reconstruct FHR state when interface bounces
[mirror_frr.git] / pimd / pim_upstream.c
CommitLineData
12e41d03
DL
1/*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
18 MA 02110-1301 USA
12e41d03
DL
19*/
20
21#include <zebra.h>
22
23#include "zebra/rib.h"
24
25#include "log.h"
26#include "zclient.h"
27#include "memory.h"
28#include "thread.h"
29#include "linklist.h"
dfe43e25
DW
30#include "vty.h"
31#include "plist.h"
0f588989
DS
32#include "hash.h"
33#include "jhash.h"
9c5e4d62 34#include "wheel.h"
12e41d03
DL
35
36#include "pimd.h"
37#include "pim_pim.h"
38#include "pim_str.h"
39#include "pim_time.h"
40#include "pim_iface.h"
41#include "pim_join.h"
42#include "pim_zlookup.h"
43#include "pim_upstream.h"
44#include "pim_ifchannel.h"
45#include "pim_neighbor.h"
46#include "pim_rpf.h"
47#include "pim_zebra.h"
48#include "pim_oil.h"
49#include "pim_macro.h"
8f5f5e91 50#include "pim_rp.h"
f14248dd 51#include "pim_br.h"
627ed2a3 52#include "pim_register.h"
3c72d654 53#include "pim_msdp.h"
982bff89 54#include "pim_jp_agg.h"
1bc98276 55#include "pim_nht.h"
12e41d03 56
0f588989
DS
57struct hash *pim_upstream_hash = NULL;
58struct list *pim_upstream_list = NULL;
9c5e4d62 59struct timer_wheel *pim_upstream_sg_wheel = NULL;
0f588989 60
982bff89 61static void join_timer_stop(struct pim_upstream *up);
12e41d03
DL
62static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
63
cfa91a87
DS
64/*
65 * A (*,G) or a (*,*) is going away
66 * remove the parent pointer from
67 * those pointing at us
68 */
69static void
70pim_upstream_remove_children (struct pim_upstream *up)
71{
cfa91a87
DS
72 struct pim_upstream *child;
73
03417ccd 74 if (!up->sources)
cfa91a87
DS
75 return;
76
03417ccd 77 while (!list_isempty (up->sources))
cfa91a87 78 {
03417ccd
DS
79 child = listnode_head (up->sources);
80 child->parent = NULL;
81 listnode_delete (up->sources, child);
cfa91a87
DS
82 }
83}
84
85/*
86 * A (*,G) or a (*,*) is being created
87 * Find the children that would point
88 * at us.
89 */
90static void
91pim_upstream_find_new_children (struct pim_upstream *up)
92{
93 struct pim_upstream *child;
94 struct listnode *ch_node;
95
4ed0af70
DS
96 if ((up->sg.src.s_addr != INADDR_ANY) &&
97 (up->sg.grp.s_addr != INADDR_ANY))
cfa91a87
DS
98 return;
99
4ed0af70
DS
100 if ((up->sg.src.s_addr == INADDR_ANY) &&
101 (up->sg.grp.s_addr == INADDR_ANY))
cfa91a87
DS
102 return;
103
0f588989 104 for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, ch_node, child))
cfa91a87 105 {
4ed0af70 106 if ((up->sg.grp.s_addr != INADDR_ANY) &&
0f588989 107 (child->sg.grp.s_addr == up->sg.grp.s_addr) &&
cfa91a87 108 (child != up))
03417ccd
DS
109 {
110 child->parent = up;
111 listnode_add_sort (up->sources, child);
112 }
cfa91a87
DS
113 }
114}
115
4d99418b
DS
116/*
117 * If we have a (*,*) || (S,*) there is no parent
118 * If we have a (S,G), find the (*,G)
119 * If we have a (*,G), find the (*,*)
120 */
121static struct pim_upstream *
03417ccd 122pim_upstream_find_parent (struct pim_upstream *child)
4d99418b 123{
03417ccd
DS
124 struct prefix_sg any = child->sg;
125 struct pim_upstream *up = NULL;
4d99418b
DS
126
127 // (S,G)
03417ccd
DS
128 if ((child->sg.src.s_addr != INADDR_ANY) &&
129 (child->sg.grp.s_addr != INADDR_ANY))
4d99418b 130 {
4ed0af70 131 any.src.s_addr = INADDR_ANY;
03417ccd
DS
132 up = pim_upstream_find (&any);
133
134 if (up)
135 listnode_add (up->sources, child);
136
137 return up;
4d99418b
DS
138 }
139
03417ccd 140 return NULL;
4d99418b
DS
141}
142
12e41d03
DL
143void pim_upstream_free(struct pim_upstream *up)
144{
145 XFREE(MTYPE_PIM_UPSTREAM, up);
1bc98276 146 up = NULL;
12e41d03
DL
147}
148
149static void upstream_channel_oil_detach(struct pim_upstream *up)
150{
151 if (up->channel_oil) {
152 pim_channel_oil_del(up->channel_oil);
25a335e0 153 up->channel_oil = NULL;
12e41d03
DL
154 }
155}
156
e5905a3b
DS
157void
158pim_upstream_del(struct pim_upstream *up, const char *name)
12e41d03 159{
7667c556 160 bool notify_msdp = false;
1bc98276 161 struct prefix nht_p;
7667c556 162
3197cb1e
DS
163 if (PIM_DEBUG_TRACE)
164 zlog_debug ("%s(%s): Delete %s ref count: %d",
165 __PRETTY_FUNCTION__, name, up->sg_str, up->ref_count);
166
e5905a3b
DS
167 --up->ref_count;
168
169 if (up->ref_count >= 1)
170 return;
171
f14248dd 172 THREAD_OFF(up->t_ka_timer);
792f4d29 173 THREAD_OFF(up->t_rs_timer);
1bf16443 174 THREAD_OFF(up->t_msdp_reg_timer);
12e41d03 175
7667c556 176 if (up->join_state == PIM_UPSTREAM_JOINED) {
982bff89
DS
177 pim_jp_agg_single_upstream_send (&up->rpf, up, 0);
178
7667c556 179 if (up->sg.src.s_addr == INADDR_ANY) {
180 /* if a (*, G) entry in the joined state is being deleted we
181 * need to notify MSDP */
182 notify_msdp = true;
183 }
184 }
185
fc9d070d
DS
186 join_timer_stop(up);
187 up->rpf.source_nexthop.interface = NULL;
188
36e466fe 189 if (up->sg.src.s_addr != INADDR_ANY) {
9c5e4d62 190 wheel_remove_item (pim_upstream_sg_wheel, up);
36e466fe 191 notify_msdp = true;
192 }
9c5e4d62 193
cfa91a87 194 pim_upstream_remove_children (up);
6a78764e 195 pim_mroute_del (up->channel_oil, __PRETTY_FUNCTION__);
12e41d03
DL
196 upstream_channel_oil_detach(up);
197
03417ccd
DS
198 if (up->sources)
199 list_delete (up->sources);
200 up->sources = NULL;
201
12e41d03
DL
202 /*
203 notice that listnode_delete() can't be moved
204 into pim_upstream_free() because the later is
205 called by list_delete_all_node()
206 */
03417ccd
DS
207 if (up->parent)
208 {
209 listnode_delete (up->parent->sources, up);
210 up->parent = NULL;
211 }
0f588989
DS
212 listnode_delete (pim_upstream_list, up);
213 hash_release (pim_upstream_hash, up);
12e41d03 214
1bc98276
CS
215 if (notify_msdp)
216 {
217 pim_msdp_up_del (&up->sg);
218 }
219
220 /* Deregister addr with Zebra NHT */
221 nht_p.family = AF_INET;
222 nht_p.prefixlen = IPV4_MAX_BITLEN;
223 nht_p.u.prefix4 = up->upstream_addr;
224 if (PIM_DEBUG_TRACE)
225 {
226 char buf[PREFIX2STR_BUFFER];
227 prefix2str (&nht_p, buf, sizeof (buf));
228 zlog_debug ("%s: Deregister upstream %s upstream addr %s with NHT ",
229 __PRETTY_FUNCTION__, up->sg_str, buf);
230 }
231 pim_delete_tracked_nexthop (&nht_p, up, NULL);
232
233 pim_upstream_free (up);
12e41d03
DL
234}
235
56638739
DS
236void
237pim_upstream_send_join (struct pim_upstream *up)
12e41d03 238{
3197cb1e 239 if (PIM_DEBUG_TRACE) {
eaa54bdb 240 char rpf_str[PREFIX_STRLEN];
63c59d0c 241 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
05e451f8 242 zlog_debug ("%s: RPF'%s=%s(%s) for Interface %s", __PRETTY_FUNCTION__,
8bfb8b67 243 up->sg_str, rpf_str, pim_upstream_state2str (up->join_state),
56638739 244 up->rpf.source_nexthop.interface->name);
63c59d0c 245 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
05e451f8 246 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
56638739 247 __PRETTY_FUNCTION__,
8bfb8b67 248 up->sg_str, rpf_str);
12e41d03
DL
249 /* warning only */
250 }
251 }
56638739 252
12e41d03 253 /* send Join(S,G) to the current upstream neighbor */
982bff89 254 pim_jp_agg_single_upstream_send(&up->rpf, up, 1 /* join */);
12e41d03
DL
255}
256
257static int on_join_timer(struct thread *t)
258{
259 struct pim_upstream *up;
260
12e41d03 261 up = THREAD_ARG(t);
12e41d03 262
bb6e291f
DS
263 up->t_join_timer = NULL;
264
265 /*
266 * In the case of a HFR we will not ahve anyone to send this to.
267 */
0bf27c5c 268 if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
bb6e291f
DS
269 return 0;
270
eb345962
DS
271 /*
272 * Don't send the join if the outgoing interface is a loopback
273 * But since this might change leave the join timer running
274 */
fc9d070d
DS
275 if (up->rpf.source_nexthop.interface &&
276 !if_is_loopback (up->rpf.source_nexthop.interface))
eb345962 277 pim_upstream_send_join (up);
12e41d03 278
12e41d03
DL
279 join_timer_start(up);
280
281 return 0;
282}
283
982bff89 284static void join_timer_stop(struct pim_upstream *up)
12e41d03 285{
982bff89
DS
286 struct pim_neighbor *nbr;
287
288 nbr = pim_neighbor_find (up->rpf.source_nexthop.interface,
289 up->rpf.rpf_addr.u.prefix4);
290
291 if (nbr)
292 pim_jp_agg_remove_group (nbr->upstream_jp_agg, up);
293
294 THREAD_OFF (up->t_join_timer);
295}
296
297void
298join_timer_start(struct pim_upstream *up)
299{
fc9d070d 300 struct pim_neighbor *nbr = NULL;
982bff89 301
fc9d070d
DS
302 if (up->rpf.source_nexthop.interface)
303 {
304 nbr = pim_neighbor_find (up->rpf.source_nexthop.interface,
305 up->rpf.rpf_addr.u.prefix4);
306
307 if (PIM_DEBUG_PIM_EVENTS) {
308 zlog_debug("%s: starting %d sec timer for upstream (S,G)=%s",
309 __PRETTY_FUNCTION__,
310 qpim_t_periodic,
311 up->sg_str);
312 }
313 }
12e41d03 314
982bff89
DS
315 if (nbr)
316 pim_jp_agg_add_group (nbr->upstream_jp_agg, up, 1);
317 else
318 {
319 THREAD_OFF (up->t_join_timer);
320 THREAD_TIMER_ON(master, up->t_join_timer,
321 on_join_timer,
322 up, qpim_t_periodic);
323 }
12e41d03
DL
324}
325
982bff89
DS
326/*
327 * This is only called when we are switching the upstream
328 * J/P from one neighbor to another
329 *
330 * As such we need to remove from the old list and
331 * add to the new list.
332 */
333void pim_upstream_join_timer_restart(struct pim_upstream *up, struct pim_rpf *old)
12e41d03 334{
982bff89
DS
335 struct pim_neighbor *nbr;
336
337 nbr = pim_neighbor_find (old->source_nexthop.interface,
338 old->rpf_addr.u.prefix4);
339 if (nbr)
340 pim_jp_agg_remove_group (nbr->upstream_jp_agg, up);
341
342 //THREAD_OFF(up->t_join_timer);
12e41d03
DL
343 join_timer_start(up);
344}
345
346static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
347 int interval_msec)
348{
349 if (PIM_DEBUG_PIM_EVENTS) {
05e451f8 350 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
12e41d03
DL
351 __PRETTY_FUNCTION__,
352 interval_msec,
8bfb8b67 353 up->sg_str);
12e41d03
DL
354 }
355
356 THREAD_OFF(up->t_join_timer);
357 THREAD_TIMER_MSEC_ON(master, up->t_join_timer,
358 on_join_timer,
359 up, interval_msec);
360}
361
362void pim_upstream_join_suppress(struct pim_upstream *up,
363 struct in_addr rpf_addr,
364 int holdtime)
365{
366 long t_joinsuppress_msec;
367 long join_timer_remain_msec;
368
369 t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
370 1000 * holdtime);
371
372 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
373
3197cb1e 374 if (PIM_DEBUG_TRACE) {
eaa54bdb 375 char rpf_str[INET_ADDRSTRLEN];
12e41d03 376 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
05e451f8 377 zlog_debug("%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
12e41d03 378 __FILE__, __PRETTY_FUNCTION__,
8bfb8b67 379 up->sg_str,
12e41d03
DL
380 rpf_str,
381 join_timer_remain_msec, t_joinsuppress_msec);
382 }
383
384 if (join_timer_remain_msec < t_joinsuppress_msec) {
3197cb1e 385 if (PIM_DEBUG_TRACE) {
05e451f8 386 zlog_debug("%s %s: suppressing Join(S,G)=%s for %ld msec",
12e41d03 387 __FILE__, __PRETTY_FUNCTION__,
8bfb8b67 388 up->sg_str, t_joinsuppress_msec);
12e41d03
DL
389 }
390
391 pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
392 }
393}
394
395void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
c48a612c 396 struct pim_upstream *up)
12e41d03
DL
397{
398 long join_timer_remain_msec;
399 int t_override_msec;
400
401 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
402 t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface);
403
3197cb1e 404 if (PIM_DEBUG_TRACE) {
eaa54bdb 405 char rpf_str[INET_ADDRSTRLEN];
c48a612c 406 pim_inet4_dump("<rpf?>", up->rpf.rpf_addr.u.prefix4, rpf_str, sizeof(rpf_str));
05e451f8 407 zlog_debug("%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
12e41d03 408 debug_label,
8bfb8b67 409 up->sg_str, rpf_str,
12e41d03
DL
410 join_timer_remain_msec, t_override_msec);
411 }
412
413 if (join_timer_remain_msec > t_override_msec) {
3197cb1e 414 if (PIM_DEBUG_TRACE) {
05e451f8 415 zlog_debug("%s: decreasing (S,G)=%s join timer to t_override=%d msec",
12e41d03 416 debug_label,
8bfb8b67 417 up->sg_str,
12e41d03
DL
418 t_override_msec);
419 }
420
421 pim_upstream_join_timer_restart_msec(up, t_override_msec);
422 }
423}
424
425static void forward_on(struct pim_upstream *up)
426{
12e41d03
DL
427 struct listnode *chnode;
428 struct listnode *chnextnode;
12e41d03
DL
429 struct pim_interface *pim_ifp;
430 struct pim_ifchannel *ch;
431
ea4a71fc
DS
432 /* scan (S,G) state */
433 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
434 pim_ifp = ch->interface->info;
12e41d03
DL
435 if (!pim_ifp)
436 continue;
437
ea4a71fc
DS
438 if (ch->upstream != up)
439 continue;
12e41d03 440
ea4a71fc
DS
441 if (pim_macro_chisin_oiflist(ch))
442 pim_forward_start(ch);
12e41d03 443
ea4a71fc 444 } /* scan iface channel list */
12e41d03
DL
445}
446
447static void forward_off(struct pim_upstream *up)
448{
12e41d03
DL
449 struct listnode *chnode;
450 struct listnode *chnextnode;
12e41d03
DL
451 struct pim_interface *pim_ifp;
452 struct pim_ifchannel *ch;
453
ea4a71fc
DS
454 /* scan per-interface (S,G) state */
455 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
456 pim_ifp = ch->interface->info;
12e41d03
DL
457 if (!pim_ifp)
458 continue;
459
ea4a71fc
DS
460 if (ch->upstream != up)
461 continue;
12e41d03 462
ea4a71fc 463 pim_forward_stop(ch);
12e41d03 464
ea4a71fc 465 } /* scan iface channel list */
12e41d03
DL
466}
467
bb6e291f
DS
468static int
469pim_upstream_could_register (struct pim_upstream *up)
470{
471 struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info;
472
35917570 473 if (pim_ifp && PIM_I_am_DR (pim_ifp) &&
bb6e291f
DS
474 pim_if_connected_to_source (up->rpf.source_nexthop.interface, up->sg.src))
475 return 1;
476
477 return 0;
478}
479
7fcdfb34
DS
480void
481pim_upstream_switch(struct pim_upstream *up,
482 enum pim_upstream_state new_state)
12e41d03
DL
483{
484 enum pim_upstream_state old_state = up->join_state;
485
12e41d03 486 if (PIM_DEBUG_PIM_EVENTS) {
c9802954 487 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
12e41d03 488 __PRETTY_FUNCTION__,
8bfb8b67 489 up->sg_str,
c9802954
DS
490 pim_upstream_state2str (up->join_state),
491 pim_upstream_state2str (new_state));
12e41d03
DL
492 }
493
b4786acd 494 up->join_state = new_state;
495 if (old_state != new_state)
496 up->state_transition = pim_time_monotonic_sec();
bb027ee8 497
12e41d03
DL
498 pim_upstream_update_assert_tracking_desired(up);
499
500 if (new_state == PIM_UPSTREAM_JOINED) {
81900c5a
DS
501 if (old_state != PIM_UPSTREAM_JOINED)
502 {
0bf27c5c 503 int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags);
81900c5a 504 forward_on(up);
7667c556 505 pim_msdp_up_join_state_changed(up);
0bf27c5c 506 if (pim_upstream_could_register (up))
bb6e291f 507 {
0bf27c5c 508 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
a9b59879 509 if (!old_fhr && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
bb6e291f 510 {
0c2ebf00 511 up->reg_state = PIM_REG_JOIN;
bb6e291f
DS
512 pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
513 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
514 }
515 }
516 else
517 {
518 pim_upstream_send_join (up);
519 join_timer_start (up);
520 }
81900c5a
DS
521 }
522 else
523 {
524 forward_on (up);
525 }
12e41d03
DL
526 }
527 else {
982bff89 528
12e41d03 529 forward_off(up);
7667c556 530 if (old_state == PIM_UPSTREAM_JOINED)
531 pim_msdp_up_join_state_changed(up);
982bff89
DS
532
533 pim_jp_agg_single_upstream_send(&up->rpf, up, 0 /* prune */);
534 join_timer_stop(up);
12e41d03 535 }
12e41d03
DL
536}
537
1bc98276 538int
03417ccd
DS
539pim_upstream_compare (void *arg1, void *arg2)
540{
541 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
542 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
543
544 if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr))
545 return -1;
546
547 if (ntohl(up1->sg.grp.s_addr) > ntohl(up2->sg.grp.s_addr))
548 return 1;
549
550 if (ntohl(up1->sg.src.s_addr) < ntohl(up2->sg.src.s_addr))
551 return -1;
552
553 if (ntohl(up1->sg.src.s_addr) > ntohl(up2->sg.src.s_addr))
554 return 1;
555
556 return 0;
557}
558
07335c8d
DS
559static struct pim_upstream *
560pim_upstream_new (struct prefix_sg *sg,
561 struct interface *incoming,
562 int flags)
12e41d03 563{
2f702571 564 enum pim_rpf_result rpf_result;
07335c8d
DS
565 struct pim_interface *pim_ifp;
566 struct pim_upstream *up;
12e41d03 567
36d9e7dc 568 up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
1bc98276
CS
569 if (!up)
570 {
571 zlog_err("%s: PIM XCALLOC(%zu) failure",
12e41d03 572 __PRETTY_FUNCTION__, sizeof(*up));
1bc98276
CS
573 return NULL;
574 }
12e41d03 575
5074a423 576 up->sg = *sg;
8bfb8b67 577 pim_str_sg_set (sg, up->sg_str);
0f588989 578 up = hash_get (pim_upstream_hash, up, hash_alloc_intern);
36d6bd7d 579 if (!pim_rp_set_upstream_addr (&up->upstream_addr, sg->src, sg->grp))
8f5f5e91 580 {
3197cb1e 581 if (PIM_DEBUG_TRACE)
8f5f5e91
DS
582 zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
583
03417ccd 584 hash_release (pim_upstream_hash, up);
8f5f5e91
DS
585 XFREE (MTYPE_PIM_UPSTREAM, up);
586 return NULL;
587 }
588
03417ccd
DS
589 up->parent = pim_upstream_find_parent (up);
590 if (up->sg.src.s_addr == INADDR_ANY)
591 {
592 up->sources = list_new ();
593 up->sources->cmp = pim_upstream_compare;
594 }
595 else
596 up->sources = NULL;
597
cfa91a87 598 pim_upstream_find_new_children (up);
4a40c37a 599 up->flags = flags;
12e41d03 600 up->ref_count = 1;
4a4c4a07
DS
601 up->t_join_timer = NULL;
602 up->t_ka_timer = NULL;
792f4d29 603 up->t_rs_timer = NULL;
1bf16443 604 up->t_msdp_reg_timer = NULL;
b4786acd 605 up->join_state = PIM_UPSTREAM_NOTJOINED;
0c2ebf00 606 up->reg_state = PIM_REG_NOINFO;
12e41d03 607 up->state_transition = pim_time_monotonic_sec();
4a4c4a07 608 up->channel_oil = NULL;
f9e0ab5b 609 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
12e41d03 610
f24405b1 611 up->rpf.source_nexthop.interface = NULL;
63c59d0c
DS
612 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
613 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
12e41d03
DL
614 up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference;
615 up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric;
63c59d0c
DS
616 up->rpf.rpf_addr.family = AF_INET;
617 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
12e41d03 618
9c5e4d62
DS
619 if (up->sg.src.s_addr != INADDR_ANY)
620 wheel_add_item (pim_upstream_sg_wheel, up);
621
1bc98276 622 rpf_result = pim_rpf_update(up, NULL, 1);
2f702571 623 if (rpf_result == PIM_RPF_FAILURE) {
3197cb1e 624 if (PIM_DEBUG_TRACE)
4a40c37a 625 zlog_debug ("%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__,
8bfb8b67 626 up->sg_str);
03417ccd
DS
627
628 if (up->parent)
629 {
630 listnode_delete (up->parent->sources, up);
631 up->parent = NULL;
632 }
9c5e4d62
DS
633
634 if (up->sg.src.s_addr != INADDR_ANY)
635 wheel_remove_item (pim_upstream_sg_wheel, up);
636
03417ccd
DS
637 pim_upstream_remove_children (up);
638 if (up->sources)
639 list_delete (up->sources);
640
641 hash_release (pim_upstream_hash, up);
2f702571
DS
642 XFREE(MTYPE_PIM_UPSTREAM, up);
643 return NULL;
644 }
12e41d03 645
07335c8d
DS
646 pim_ifp = up->rpf.source_nexthop.interface->info;
647 if (pim_ifp)
648 up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index);
649
0f588989 650 listnode_add_sort(pim_upstream_list, up);
12e41d03 651
3197cb1e 652 if (PIM_DEBUG_TRACE)
1bc98276
CS
653 {
654 zlog_debug ("%s: Created Upstream %s upstream_addr %s",
655 __PRETTY_FUNCTION__, up->sg_str,
656 inet_ntoa (up->upstream_addr));
657 }
03417ccd 658
12e41d03
DL
659 return up;
660}
661
4ed0af70 662struct pim_upstream *pim_upstream_find(struct prefix_sg *sg)
12e41d03 663{
0f588989
DS
664 struct pim_upstream lookup;
665 struct pim_upstream *up = NULL;
12e41d03 666
0f588989
DS
667 lookup.sg = *sg;
668 up = hash_lookup (pim_upstream_hash, &lookup);
669 return up;
12e41d03
DL
670}
671
e711cd3c
DS
672struct pim_upstream *
673pim_upstream_find_or_add(struct prefix_sg *sg,
674 struct interface *incoming,
675 int flags, const char *name)
676{
677 struct pim_upstream *up;
678
679 up = pim_upstream_find(sg);
680
681 if (up)
682 {
683 if (!(up->flags & flags))
684 {
685 up->flags |= flags;
686 up->ref_count++;
687 }
688 }
689 else
690 up = pim_upstream_add (sg, incoming, flags, name);
691
692 return up;
693}
694
1bf16443 695static void pim_upstream_ref(struct pim_upstream *up, int flags)
696{
697 up->flags |= flags;
698 ++up->ref_count;
699}
700
4ed0af70 701struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
4a40c37a 702 struct interface *incoming,
e5905a3b 703 int flags, const char *name)
12e41d03 704{
594a78cc 705 struct pim_upstream *up = NULL;
e5905a3b 706 int found = 0;
5074a423 707 up = pim_upstream_find(sg);
12e41d03 708 if (up) {
1bf16443 709 pim_upstream_ref(up, flags);
e5905a3b 710 found = 1;
12e41d03
DL
711 }
712 else {
4a40c37a 713 up = pim_upstream_new(sg, incoming, flags);
12e41d03
DL
714 }
715
e5905a3b 716 if (PIM_DEBUG_TRACE)
f4075cb4
DS
717 {
718 if (up)
3197cb1e 719 zlog_debug("%s(%s): %s, found: %d: ref_count: %d",
f4075cb4 720 __PRETTY_FUNCTION__, name,
8bfb8b67 721 up->sg_str, found,
f4075cb4
DS
722 up->ref_count);
723 else
724 zlog_debug("%s(%s): (%s) failure to create",
725 __PRETTY_FUNCTION__, name,
726 pim_str_sg_dump (sg));
727 }
12e41d03 728
e5905a3b 729 return up;
12e41d03
DL
730}
731
9f44d042 732int
7a3ddda5
DS
733pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up,
734 struct pim_ifchannel *ch)
735{
736 struct pim_upstream *parent = up->parent;
737
738 if (ch->upstream == up)
739 {
740 if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch))
741 return 1;
46c8aab8
DS
742
743 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
744 return 0;
7a3ddda5 745 }
46c8aab8 746
7a3ddda5
DS
747 /*
748 * joins (*,G)
749 */
750 if (parent && ch->upstream == parent)
751 {
752 if (!pim_macro_ch_lost_assert (ch) && pim_macro_chisin_joins_or_include (ch))
753 return 1;
754 }
755
756 return 0;
757}
758
12e41d03
DL
759/*
760 Evaluate JoinDesired(S,G):
761
762 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
763 in the set:
764
765 inherited_olist(S,G) =
766 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
767
768 JoinDesired(S,G) may be affected by changes in the following:
769
770 pim_ifp->primary_address
771 pim_ifp->pim_dr_addr
772 ch->ifassert_winner_metric
773 ch->ifassert_winner
774 ch->local_ifmembership
775 ch->ifjoin_state
776 ch->upstream->rpf.source_nexthop.mrib_metric_preference
777 ch->upstream->rpf.source_nexthop.mrib_route_metric
778 ch->upstream->rpf.source_nexthop.interface
779
780 See also pim_upstream_update_join_desired() below.
781 */
782int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
783{
12e41d03
DL
784 struct listnode *chnode;
785 struct listnode *chnextnode;
12e41d03
DL
786 struct pim_interface *pim_ifp;
787 struct pim_ifchannel *ch;
7a3ddda5 788 int ret = 0;
12e41d03 789
ea4a71fc
DS
790 /* scan per-interface (S,G) state */
791 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch))
792 {
793 pim_ifp = ch->interface->info;
794 if (!pim_ifp)
795 continue;
12e41d03 796
ea4a71fc
DS
797 ret += pim_upstream_evaluate_join_desired_interface (up, ch);
798 } /* scan iface channel list */
12e41d03 799
7a3ddda5 800 return ret; /* false */
12e41d03
DL
801}
802
803/*
804 See also pim_upstream_evaluate_join_desired() above.
805*/
806void pim_upstream_update_join_desired(struct pim_upstream *up)
807{
808 int was_join_desired; /* boolean */
809 int is_join_desired; /* boolean */
810
811 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
812
813 is_join_desired = pim_upstream_evaluate_join_desired(up);
814 if (is_join_desired)
815 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
816 else
817 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
818
819 /* switched from false to true */
820 if (is_join_desired && !was_join_desired) {
12e41d03
DL
821 pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
822 return;
823 }
824
825 /* switched from true to false */
826 if (!is_join_desired && was_join_desired) {
12e41d03
DL
827 pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
828 return;
829 }
830}
831
832/*
833 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
834 Transitions from Joined State
835 RPF'(S,G) GenID changes
836
837 The upstream (S,G) state machine remains in Joined state. If the
838 Join Timer is set to expire in more than t_override seconds, reset
839 it so that it expires after t_override seconds.
840*/
841void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
842{
843 struct listnode *up_node;
844 struct listnode *up_nextnode;
845 struct pim_upstream *up;
846
847 /*
0f588989
DS
848 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
849 */
850 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
12e41d03 851
3197cb1e 852 if (PIM_DEBUG_TRACE) {
eaa54bdb
DW
853 char neigh_str[INET_ADDRSTRLEN];
854 char rpf_addr_str[PREFIX_STRLEN];
12e41d03 855 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
63c59d0c 856 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
05e451f8 857 zlog_debug("%s: matching neigh=%s against upstream (S,G)=%s joined=%d rpf_addr=%s",
12e41d03 858 __PRETTY_FUNCTION__,
8bfb8b67 859 neigh_str, up->sg_str,
12e41d03
DL
860 up->join_state == PIM_UPSTREAM_JOINED,
861 rpf_addr_str);
862 }
863
864 /* consider only (S,G) upstream in Joined state */
865 if (up->join_state != PIM_UPSTREAM_JOINED)
866 continue;
867
868 /* match RPF'(S,G)=neigh_addr */
63c59d0c 869 if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr)
12e41d03
DL
870 continue;
871
872 pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
c48a612c 873 up);
12e41d03
DL
874 }
875}
876
877
878void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
879 struct interface *old_rpf_ifp)
880{
ea4a71fc
DS
881 struct listnode *chnode;
882 struct listnode *chnextnode;
883 struct pim_ifchannel *ch;
884 struct pim_interface *pim_ifp;
885
886 /* search all ifchannels */
887 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
888
889 pim_ifp = ch->interface->info;
12e41d03
DL
890 if (!pim_ifp)
891 continue;
892
ea4a71fc
DS
893 if (ch->upstream != up)
894 continue;
12e41d03 895
ea4a71fc
DS
896 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
897 if (
898 /* RPF_interface(S) was NOT I */
899 (old_rpf_ifp == ch->interface)
900 &&
901 /* RPF_interface(S) stopped being I */
902 (ch->upstream->rpf.source_nexthop.interface != ch->interface)
903 ) {
904 assert_action_a5(ch);
905 }
906 } /* PIM_IFASSERT_I_AM_LOSER */
12e41d03 907
ea4a71fc 908 pim_ifchannel_update_assert_tracking_desired(ch);
12e41d03
DL
909 }
910}
911
912void pim_upstream_update_could_assert(struct pim_upstream *up)
913{
12e41d03
DL
914 struct listnode *chnode;
915 struct listnode *chnextnode;
12e41d03
DL
916 struct pim_interface *pim_ifp;
917 struct pim_ifchannel *ch;
918
ea4a71fc
DS
919 /* scan per-interface (S,G) state */
920 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
921 pim_ifp = ch->interface->info;
12e41d03
DL
922 if (!pim_ifp)
923 continue;
924
ea4a71fc
DS
925 if (ch->upstream != up)
926 continue;
12e41d03 927
ea4a71fc
DS
928 pim_ifchannel_update_could_assert(ch);
929 } /* scan iface channel list */
12e41d03
DL
930}
931
932void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
933{
12e41d03
DL
934 struct listnode *chnode;
935 struct listnode *chnextnode;
12e41d03
DL
936 struct pim_interface *pim_ifp;
937 struct pim_ifchannel *ch;
938
ea4a71fc
DS
939 /* scan per-interface (S,G) state */
940 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
941 pim_ifp = ch->interface->info;
12e41d03
DL
942 if (!pim_ifp)
943 continue;
944
ea4a71fc
DS
945 if (ch->upstream != up)
946 continue;
12e41d03 947
ea4a71fc 948 pim_ifchannel_update_my_assert_metric(ch);
12e41d03 949
ea4a71fc 950 } /* scan iface channel list */
12e41d03
DL
951}
952
953static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
954{
12e41d03
DL
955 struct listnode *chnode;
956 struct listnode *chnextnode;
12e41d03
DL
957 struct pim_interface *pim_ifp;
958 struct pim_ifchannel *ch;
959
ea4a71fc
DS
960 /* scan per-interface (S,G) state */
961 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
962 pim_ifp = ch->interface->info;
12e41d03
DL
963 if (!pim_ifp)
964 continue;
965
ea4a71fc
DS
966 if (ch->upstream != up)
967 continue;
12e41d03 968
ea4a71fc 969 pim_ifchannel_update_assert_tracking_desired(ch);
12e41d03 970
ea4a71fc 971 } /* scan iface channel list */
12e41d03 972}
f14248dd 973
1bf16443 974/* When kat is stopped CouldRegister goes to false so we need to
975 * transition the (S, G) on FHR to NI state and remove reg tunnel
976 * from the OIL */
977static void pim_upstream_fhr_kat_expiry(struct pim_upstream *up)
978{
979 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
980 return;
981
982 if (PIM_DEBUG_TRACE)
8bfb8b67
DS
983 zlog_debug ("kat expired on %s; clear fhr reg state", up->sg_str);
984
1bf16443 985 /* stop reg-stop timer */
986 THREAD_OFF(up->t_rs_timer);
987 /* remove regiface from the OIL if it is there*/
988 pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
0c2ebf00 989 /* clear the register state */
990 up->reg_state = PIM_REG_NOINFO;
1bf16443 991 PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags);
992}
993
994/* When kat is started CouldRegister can go to true. And if it does we
995 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
996 * to the OIL */
997static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
998{
999 if (pim_upstream_could_register(up)) {
1000 if (PIM_DEBUG_TRACE)
8bfb8b67
DS
1001 zlog_debug ("kat started on %s; set fhr reg state to joined", up->sg_str);
1002
1bf16443 1003 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
0c2ebf00 1004 if (up->reg_state == PIM_REG_NOINFO) {
1bf16443 1005 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
0c2ebf00 1006 up->reg_state = PIM_REG_JOIN;
1bf16443 1007 }
1008 }
1009}
1010
f14248dd
DS
1011/*
1012 * On an RP, the PMBR value must be cleared when the
1013 * Keepalive Timer expires
1bf16443 1014 * KAT expiry indicates that flow is inactive. If the flow was created or
1015 * maintained by activity now is the time to deref it.
f14248dd
DS
1016 */
1017static int
1018pim_upstream_keep_alive_timer (struct thread *t)
1019{
1020 struct pim_upstream *up;
1021
1022 up = THREAD_ARG(t);
1bf16443 1023 up->t_ka_timer = NULL;
f14248dd 1024
4ed0af70 1025 if (I_am_RP (up->sg.grp))
1bf16443 1026 {
1027 pim_br_clear_pmbr (&up->sg);
1028 /*
1029 * We need to do more here :)
1030 * But this is the start.
1031 */
1032 }
14315ea8 1033
1bf16443 1034 /* source is no longer active - pull the SA from MSDP's cache */
1035 pim_msdp_sa_local_del(&up->sg);
14315ea8 1036
1bf16443 1037 /* if entry was created because of activity we need to deref it */
1038 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
1039 {
1040 pim_upstream_fhr_kat_expiry(up);
1041 if (PIM_DEBUG_TRACE)
8bfb8b67 1042 zlog_debug ("kat expired on %s; remove stream reference", up->sg_str);
1bf16443 1043 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
1044 pim_upstream_del(up, __PRETTY_FUNCTION__);
1045 }
14315ea8 1046
1bf16443 1047 return 0;
f14248dd
DS
1048}
1049
f14248dd
DS
1050void
1051pim_upstream_keep_alive_timer_start (struct pim_upstream *up,
1052 uint32_t time)
1053{
1bf16443 1054 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1055 if (PIM_DEBUG_TRACE)
8bfb8b67 1056 zlog_debug ("kat start on %s with no stream reference", up->sg_str);
1bf16443 1057 }
00d2f9e4 1058 THREAD_OFF (up->t_ka_timer);
f14248dd
DS
1059 THREAD_TIMER_ON (master,
1060 up->t_ka_timer,
1061 pim_upstream_keep_alive_timer,
1062 up, time);
1bf16443 1063
1064 /* any time keepalive is started against a SG we will have to
1065 * re-evaluate our active source database */
1066 pim_msdp_sa_local_update(up);
1067}
1068
1069/* MSDP on RP needs to know if a source is registerable to this RP */
1070static int
1071pim_upstream_msdp_reg_timer(struct thread *t)
1072{
1073 struct pim_upstream *up;
1074
1075 up = THREAD_ARG(t);
1076 up->t_msdp_reg_timer = NULL;
1077
1078 /* source is no longer active - pull the SA from MSDP's cache */
1079 pim_msdp_sa_local_del(&up->sg);
1080 return 1;
1081}
1082void
1083pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
1084{
1085 THREAD_OFF(up->t_msdp_reg_timer);
1086 THREAD_TIMER_ON(master, up->t_msdp_reg_timer,
1087 pim_upstream_msdp_reg_timer, up, PIM_MSDP_REG_RXED_PERIOD);
1088
1089 pim_msdp_sa_local_update(up);
f14248dd 1090}
cb40b272
DS
1091
1092/*
1093 * 4.2.1 Last-Hop Switchover to the SPT
1094 *
1095 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1096 * RP. Once traffic from sources to joined groups arrives at a last-hop
1097 * router, it has the option of switching to receive the traffic on a
1098 * shortest path tree (SPT).
1099 *
1100 * The decision for a router to switch to the SPT is controlled as
1101 * follows:
1102 *
1103 * void
1104 * CheckSwitchToSpt(S,G) {
1105 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1106 * (+) pim_include(S,G) != NULL )
1107 * AND SwitchToSptDesired(S,G) ) {
1108 * # Note: Restarting the KAT will result in the SPT switch
1109 * set KeepaliveTimer(S,G) to Keepalive_Period
1110 * }
1111 * }
1112 *
1113 * SwitchToSptDesired(S,G) is a policy function that is implementation
1114 * defined. An "infinite threshold" policy can be implemented by making
1115 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1116 * first packet" policy can be implemented by making
1117 * SwitchToSptDesired(S,G) return true once a single packet has been
1118 * received for the source and group.
1119 */
1120int
4ed0af70 1121pim_upstream_switch_to_spt_desired (struct prefix_sg *sg)
cb40b272 1122{
4ed0af70 1123 if (I_am_RP (sg->grp))
a3b58b4a
DS
1124 return 1;
1125
cb40b272
DS
1126 return 0;
1127}
d7259eac 1128
80d9c3a0
DS
1129int
1130pim_upstream_is_sg_rpt (struct pim_upstream *up)
1131{
f21597f0
DS
1132 struct listnode *chnode;
1133 struct pim_ifchannel *ch;
1134
1135 for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, chnode, ch))
1136 {
1137 if ((ch->upstream == up) &&
1138 (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)))
1139 return 1;
1140 }
e43b8697 1141
80d9c3a0
DS
1142 return 0;
1143}
3a66b17b
DS
1144/*
1145 * After receiving a packet set SPTbit:
1146 * void
1147 * Update_SPTbit(S,G,iif) {
1148 * if ( iif == RPF_interface(S)
1149 * AND JoinDesired(S,G) == TRUE
1150 * AND ( DirectlyConnected(S) == TRUE
1151 * OR RPF_interface(S) != RPF_interface(RP(G))
1152 * OR inherited_olist(S,G,rpt) == NULL
1153 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1154 * ( RPF'(S,G) != NULL ) )
1155 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1156 * Set SPTbit(S,G) to TRUE
1157 * }
1158 * }
1159 */
1160void
1161pim_upstream_set_sptbit (struct pim_upstream *up, struct interface *incoming)
1162{
1163 struct pim_rpf *grpf = NULL;
1164
1165 // iif == RPF_interfvace(S)
1166 if (up->rpf.source_nexthop.interface != incoming)
1167 {
1168 if (PIM_DEBUG_TRACE)
1169 zlog_debug ("%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1170 __PRETTY_FUNCTION__, incoming->name, up->rpf.source_nexthop.interface->name);
1171 return;
1172 }
1173
1174 // AND JoinDesired(S,G) == TRUE
1175 // FIXME
1176
1177 // DirectlyConnected(S) == TRUE
1178 if (pim_if_connected_to_source (up->rpf.source_nexthop.interface, up->sg.src))
1179 {
1180 if (PIM_DEBUG_TRACE)
1181 zlog_debug ("%s: %s is directly connected to the source", __PRETTY_FUNCTION__,
8bfb8b67 1182 up->sg_str);
3a66b17b
DS
1183 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1184 return;
1185 }
1186
1187 // OR RPF_interface(S) != RPF_interface(RP(G))
1188 grpf = RP(up->sg.grp);
1189 if (!grpf || up->rpf.source_nexthop.interface != grpf->source_nexthop.interface)
1190 {
1191 if (PIM_DEBUG_TRACE)
1192 zlog_debug ("%s: %s RPF_interface(S) != RPF_interface(RP(G))",
8bfb8b67 1193 __PRETTY_FUNCTION__, up->sg_str);
3a66b17b
DS
1194 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1195 return;
1196 }
1197
1198 // OR inherited_olist(S,G,rpt) == NULL
1199 if (pim_upstream_is_sg_rpt(up) && pim_upstream_empty_inherited_olist(up))
1200 {
1201 if (PIM_DEBUG_TRACE)
1202 zlog_debug ("%s: %s OR inherited_olist(S,G,rpt) == NULL", __PRETTY_FUNCTION__,
8bfb8b67 1203 up->sg_str);
3a66b17b
DS
1204 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1205 return;
1206 }
1207
1208 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1209 // ( RPF'(S,G) != NULL ) )
1210 if (up->parent && pim_rpf_is_same (&up->rpf, &up->parent->rpf))
1211 {
1212 if (PIM_DEBUG_TRACE)
1213 zlog_debug ("%s: %s RPF'(S,G) is the same as RPF'(*,G)", __PRETTY_FUNCTION__,
8bfb8b67 1214 up->sg_str);
3a66b17b
DS
1215 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1216 return;
1217 }
1218
1219 return;
1220}
80d9c3a0 1221
d7259eac 1222const char *
c9802954 1223pim_upstream_state2str (enum pim_upstream_state join_state)
d7259eac 1224{
c9802954 1225 switch (join_state)
d7259eac
DS
1226 {
1227 case PIM_UPSTREAM_NOTJOINED:
e775c0a4 1228 return "NotJoined";
d7259eac
DS
1229 break;
1230 case PIM_UPSTREAM_JOINED:
e775c0a4 1231 return "Joined";
d7259eac 1232 break;
d7259eac 1233 }
e775c0a4 1234 return "Unknown";
d7259eac 1235}
627ed2a3 1236
e0e127b0 1237const char *
0c2ebf00 1238pim_reg_state2str (enum pim_reg_state reg_state, char *state_str)
e0e127b0 1239{
0c2ebf00 1240 switch (reg_state)
e0e127b0 1241 {
0c2ebf00 1242 case PIM_REG_NOINFO:
1243 strcpy (state_str, "RegNoInfo");
e0e127b0 1244 break;
0c2ebf00 1245 case PIM_REG_JOIN:
1246 strcpy (state_str, "RegJoined");
e0e127b0 1247 break;
0c2ebf00 1248 case PIM_REG_JOIN_PENDING:
1249 strcpy (state_str, "RegJoinPend");
e0e127b0 1250 break;
0c2ebf00 1251 case PIM_REG_PRUNE:
1252 strcpy (state_str, "RegPrune");
e0e127b0 1253 break;
1254 default:
0c2ebf00 1255 strcpy (state_str, "RegUnknown");
e0e127b0 1256 }
1257 return state_str;
1258}
1259
627ed2a3
DS
1260static int
1261pim_upstream_register_stop_timer (struct thread *t)
1262{
4df01a4e 1263 struct pim_interface *pim_ifp;
627ed2a3
DS
1264 struct pim_upstream *up;
1265 struct pim_rpf *rpg;
1266 struct ip ip_hdr;
627ed2a3
DS
1267 up = THREAD_ARG (t);
1268
1269 up->t_rs_timer = NULL;
1270
1271 if (PIM_DEBUG_TRACE)
1272 {
0c2ebf00 1273 char state_str[PIM_REG_STATE_STR_LEN];
d5ed8a9c 1274 zlog_debug ("%s: (S,G)=%s upstream register stop timer %s",
8bfb8b67 1275 __PRETTY_FUNCTION__, up->sg_str,
0c2ebf00 1276 pim_reg_state2str(up->reg_state, state_str));
627ed2a3
DS
1277 }
1278
e0e127b0 1279 switch (up->reg_state)
627ed2a3 1280 {
0c2ebf00 1281 case PIM_REG_JOIN_PENDING:
1282 up->reg_state = PIM_REG_JOIN;
bb027ee8
DS
1283 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
1284 break;
0c2ebf00 1285 case PIM_REG_JOIN:
627ed2a3 1286 break;
0c2ebf00 1287 case PIM_REG_PRUNE:
4df01a4e 1288 pim_ifp = up->rpf.source_nexthop.interface->info;
7ef66046
DS
1289 if (!pim_ifp)
1290 {
1291 if (PIM_DEBUG_TRACE)
1292 zlog_debug ("%s: Interface: %s is not configured for pim",
1293 __PRETTY_FUNCTION__, up->rpf.source_nexthop.interface->name);
1294 return 0;
1295 }
0c2ebf00 1296 up->reg_state = PIM_REG_JOIN_PENDING;
627ed2a3
DS
1297 pim_upstream_start_register_stop_timer (up, 1);
1298
70e7fda8
DS
1299 if (((up->channel_oil->cc.lastused/100) > PIM_KEEPALIVE_PERIOD) &&
1300 (I_am_RP (up->sg.grp)))
1301 {
1302 if (PIM_DEBUG_TRACE)
1303 zlog_debug ("%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while", __PRETTY_FUNCTION__);
1304 return 0;
1305 }
4ed0af70 1306 rpg = RP (up->sg.grp);
627ed2a3
DS
1307 memset (&ip_hdr, 0, sizeof (struct ip));
1308 ip_hdr.ip_p = PIM_IP_PROTO_PIM;
1309 ip_hdr.ip_hl = 5;
1310 ip_hdr.ip_v = 4;
4ed0af70
DS
1311 ip_hdr.ip_src = up->sg.src;
1312 ip_hdr.ip_dst = up->sg.grp;
dc686f82 1313 ip_hdr.ip_len = htons (20);
627ed2a3 1314 // checksum is broken
4df01a4e 1315 pim_register_send ((uint8_t *)&ip_hdr, sizeof (struct ip),
0e3b3d5d 1316 pim_ifp->primary_address, rpg, 1, up);
627ed2a3
DS
1317 break;
1318 default:
1319 break;
1320 }
1321
1322 return 0;
1323}
1324
1325void
1326pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_register)
1327{
1328 uint32_t time;
1329
1330 if (up->t_rs_timer)
1331 {
1332 THREAD_TIMER_OFF (up->t_rs_timer);
1333 up->t_rs_timer = NULL;
1334 }
1335
1336 if (!null_register)
1337 {
1338 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1339 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1340 time = lower + (random () % (upper - lower + 1)) - PIM_REGISTER_PROBE_PERIOD;
1341 }
1342 else
1343 time = PIM_REGISTER_PROBE_PERIOD;
1344
1345 if (PIM_DEBUG_TRACE)
1346 {
05e451f8 1347 zlog_debug ("%s: (S,G)=%s Starting upstream register stop timer %d",
8bfb8b67 1348 __PRETTY_FUNCTION__, up->sg_str, time);
627ed2a3
DS
1349 }
1350 THREAD_TIMER_ON (master, up->t_rs_timer,
1351 pim_upstream_register_stop_timer,
1352 up, time);
1353}
4fdc8f36 1354
4fdc8f36 1355int
b5183fd1 1356pim_upstream_inherited_olist_decide (struct pim_upstream *up)
4fdc8f36 1357{
219e0013 1358 struct pim_interface *pim_ifp;
219e0013
DS
1359 struct listnode *chnextnode;
1360 struct pim_ifchannel *ch;
1361 struct listnode *chnode;
219e0013
DS
1362 int output_intf = 0;
1363
3667b0bc 1364 pim_ifp = up->rpf.source_nexthop.interface->info;
da55afba 1365 if (pim_ifp && !up->channel_oil)
3667b0bc 1366 up->channel_oil = pim_channel_oil_add (&up->sg, pim_ifp->mroute_vif_index);
219e0013 1367
ea4a71fc 1368 for (ALL_LIST_ELEMENTS (pim_ifchannel_list, chnode, chnextnode, ch))
219e0013 1369 {
ea4a71fc 1370 pim_ifp = ch->interface->info;
7a3ddda5
DS
1371 if (!pim_ifp)
1372 continue;
219e0013 1373
ea4a71fc 1374 if (pim_upstream_evaluate_join_desired_interface (up, ch))
7a3ddda5 1375 {
781a1745
DS
1376 int flag = PIM_OIF_FLAG_PROTO_PIM;
1377
1378 if (ch->sg.src.s_addr == INADDR_ANY && ch->upstream != up)
1379 flag = PIM_OIF_FLAG_PROTO_STAR;
1380 pim_channel_add_oif (up->channel_oil, ch->interface, flag);
ea4a71fc 1381 output_intf++;
219e0013
DS
1382 }
1383 }
1384
b5183fd1
DS
1385 return output_intf;
1386}
1387
1388/*
1389 * For a given upstream, determine the inherited_olist
1390 * and apply it.
1391 *
1392 * inherited_olist(S,G,rpt) =
1393 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1394 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1395 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1396 *
1397 * inherited_olist(S,G) =
1398 * inherited_olist(S,G,rpt) (+)
1399 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1400 *
1401 * return 1 if there are any output interfaces
1402 * return 0 if there are not any output interfaces
1403 */
1404int
1405pim_upstream_inherited_olist (struct pim_upstream *up)
1406{
1407 int output_intf = pim_upstream_inherited_olist_decide (up);
1408
483eef9d
DS
1409 /*
1410 * If we have output_intf switch state to Join and work like normal
1411 * If we don't have an output_intf that means we are probably a
1412 * switch on a stick so turn on forwarding to just accept the
1413 * incoming packets so we don't bother the other stuff!
1414 */
1415 if (output_intf)
1416 pim_upstream_switch (up, PIM_UPSTREAM_JOINED);
1417 else
1418 forward_on (up);
219e0013
DS
1419
1420 return output_intf;
4fdc8f36 1421}
d3dd1804 1422
80d9c3a0
DS
1423int
1424pim_upstream_empty_inherited_olist (struct pim_upstream *up)
1425{
ce0ddb4e 1426 return pim_channel_oil_empty (up->channel_oil);
80d9c3a0
DS
1427}
1428
d3dd1804
DS
1429/*
1430 * When we have a new neighbor,
1431 * find upstreams that don't have their rpf_addr
1432 * set and see if the new neighbor allows
1433 * the join to be sent
1434 */
1435void
1436pim_upstream_find_new_rpf (void)
1437{
1438 struct listnode *up_node;
1439 struct listnode *up_nextnode;
1440 struct pim_upstream *up;
1441
1442 /*
0f588989
DS
1443 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1444 */
1445 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up))
d3dd1804 1446 {
63c59d0c 1447 if (pim_rpf_addr_is_inaddr_any(&up->rpf))
d3dd1804 1448 {
3197cb1e 1449 if (PIM_DEBUG_TRACE)
d3dd1804 1450 zlog_debug ("Upstream %s without a path to send join, checking",
8bfb8b67 1451 up->sg_str);
1bc98276 1452 pim_rpf_update (up, NULL, 1);
d3dd1804
DS
1453 }
1454 }
1455}
0f588989 1456
0f588989
DS
1457static unsigned int
1458pim_upstream_hash_key (void *arg)
1459{
1460 struct pim_upstream *up = (struct pim_upstream *)arg;
1461
1462 return jhash_2words (up->sg.src.s_addr, up->sg.grp.s_addr, 0);
1463}
1464
1465void pim_upstream_terminate (void)
1466{
1467 if (pim_upstream_list)
693c9259 1468 list_delete (pim_upstream_list);
0f588989
DS
1469 pim_upstream_list = NULL;
1470
1471 if (pim_upstream_hash)
1472 hash_free (pim_upstream_hash);
693c9259 1473 pim_upstream_hash = NULL;
0f588989
DS
1474}
1475
1476static int
1477pim_upstream_equal (const void *arg1, const void *arg2)
1478{
1479 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1480 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
1481
1482 if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr) &&
1483 (up1->sg.src.s_addr == up2->sg.src.s_addr))
1484 return 1;
1485
1486 return 0;
1487}
1488
1bf16443 1489/* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1490 * the cases where kat has to be restarted on rxing traffic -
1491 *
1492 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1493 * set KeepaliveTimer(S,G) to Keepalive_Period
1494 * # Note: a register state transition or UpstreamJPState(S,G)
1495 * # transition may happen as a result of restarting
1496 * # KeepaliveTimer, and must be dealt with here.
1497 * }
1498 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1499 * inherited_olist(S,G) != NULL ) {
1500 * set KeepaliveTimer(S,G) to Keepalive_Period
1501 * }
1502 */
1503static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
1504{
1505 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1506 * so we will skip that here */
1507 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1508 up->sg.src)) {
1509 return true;
1510 }
1511
1512 if ((up->join_state == PIM_UPSTREAM_JOINED) &&
1513 !pim_upstream_empty_inherited_olist(up)) {
1514 /* XXX: I have added this RP check just for 3.2 and it's a digression from
1515 * what rfc-4601 says. Till now we were only running KAT on FHR and RP and
1516 * there is some angst around making the change to run it all routers that
1517 * maintain the (S, G) state. This is tracked via CM-13601 and MUST be
1518 * removed to handle spt turn-arounds correctly in a 3-tier clos */
1519 if (I_am_RP (up->sg.grp))
1520 return true;
1521 }
1522
1523 return false;
1524}
1525
9c5e4d62
DS
1526/*
1527 * Code to check and see if we've received packets on a S,G mroute
1528 * and if so to set the SPT bit appropriately
1529 */
1530static void
1531pim_upstream_sg_running (void *arg)
1532{
1533 struct pim_upstream *up = (struct pim_upstream *)arg;
e43b8697
DS
1534
1535 // No packet can have arrived here if this is the case
1536 if (!up->channel_oil || !up->channel_oil->installed)
1537 {
1538 if (PIM_DEBUG_TRACE)
1539 zlog_debug ("%s: %s is not installed in mroute",
8bfb8b67 1540 __PRETTY_FUNCTION__, up->sg_str);
e43b8697
DS
1541 return;
1542 }
1543
bfdf4096
DS
1544 /*
1545 * This is a bit of a hack
1546 * We've noted that we should rescan but
1547 * we've missed the window for doing so in
1548 * pim_zebra.c for some reason. I am
1549 * only doing this at this point in time
1550 * to get us up and working for the moment
1551 */
1552 if (up->channel_oil->oil_inherited_rescan)
1553 {
1554 if (PIM_DEBUG_TRACE)
1555 zlog_debug ("%s: Handling unscanned inherited_olist for %s", __PRETTY_FUNCTION__, up->sg_str);
1556 pim_upstream_inherited_olist_decide (up);
1557 up->channel_oil->oil_inherited_rescan = 0;
1558 }
e43b8697
DS
1559 pim_mroute_update_counters (up->channel_oil);
1560
1561 // Have we seen packets?
1bf16443 1562 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt) &&
e43b8697
DS
1563 (up->channel_oil->cc.lastused/100 > 30))
1564 {
1565 if (PIM_DEBUG_TRACE)
1566 {
eeedae06
DS
1567 zlog_debug ("%s: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1568 __PRETTY_FUNCTION__, up->sg_str,
1569 up->channel_oil->cc.oldpktcnt,
1570 up->channel_oil->cc.pktcnt,
1571 up->channel_oil->cc.lastused/100);
e43b8697
DS
1572 }
1573 return;
1574 }
1575
1bf16443 1576 if (pim_upstream_kat_start_ok(up)) {
1577 /* Add a source reference to the stream if
1578 * one doesn't already exist */
1579 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
1580 {
1581 if (PIM_DEBUG_TRACE)
8bfb8b67
DS
1582 zlog_debug ("source reference created on kat restart %s", up->sg_str);
1583
1bf16443 1584 pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM);
1585 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
1586 pim_upstream_fhr_kat_start(up);
1587 }
1588 pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
1589 }
1590
1591 if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE)
1592 {
1593 pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
1594 }
e43b8697 1595 return;
9c5e4d62
DS
1596}
1597
040d86ad
DS
1598void
1599pim_upstream_init (void)
0f588989 1600{
9c5e4d62
DS
1601 pim_upstream_sg_wheel = wheel_init (master, 31000, 100,
1602 pim_upstream_hash_key,
1603 pim_upstream_sg_running);
0f588989
DS
1604 pim_upstream_hash = hash_create_size (8192, pim_upstream_hash_key,
1605 pim_upstream_equal);
1606
1607 pim_upstream_list = list_new ();
1608 pim_upstream_list->del = (void (*)(void *)) pim_upstream_free;
03417ccd 1609 pim_upstream_list->cmp = pim_upstream_compare;
0f588989
DS
1610
1611}