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