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