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