]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_upstream.c
pimd: Fix various ifdown/ifup scenarios w/ J/P Agg
[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 /*
477 * This code still needs work.
478 */
479 switch (up->join_state)
480 {
481 case PIM_UPSTREAM_PRUNE:
482 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
483 {
484 up->join_state = new_state;
485 up->state_transition = pim_time_monotonic_sec ();
486 }
487 break;
488 case PIM_UPSTREAM_JOIN_PENDING:
489 break;
490 case PIM_UPSTREAM_NOTJOINED:
491 case PIM_UPSTREAM_JOINED:
492 up->join_state = new_state;
493 if (old_state != new_state)
494 up->state_transition = pim_time_monotonic_sec();
495
496 break;
497 }
498
499 pim_upstream_update_assert_tracking_desired(up);
500
501 if (new_state == PIM_UPSTREAM_JOINED) {
502 if (old_state != PIM_UPSTREAM_JOINED)
503 {
504 int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags);
505 forward_on(up);
506 pim_msdp_up_join_state_changed(up);
507 if (pim_upstream_could_register (up))
508 {
509 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
510 if (!old_fhr && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
511 {
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 static 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 zlog_err("%s: PIM XCALLOC(%zu) failure",
571 __PRETTY_FUNCTION__, sizeof(*up));
572 return NULL;
573 }
574
575 up->sg = *sg;
576 pim_str_sg_set (sg, up->sg_str);
577 up = hash_get (pim_upstream_hash, up, hash_alloc_intern);
578 if (!pim_rp_set_upstream_addr (&up->upstream_addr, sg->src, sg->grp))
579 {
580 if (PIM_DEBUG_TRACE)
581 zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
582
583 hash_release (pim_upstream_hash, up);
584 XFREE (MTYPE_PIM_UPSTREAM, up);
585 return NULL;
586 }
587
588 up->parent = pim_upstream_find_parent (up);
589 if (up->sg.src.s_addr == INADDR_ANY)
590 {
591 up->sources = list_new ();
592 up->sources->cmp = pim_upstream_compare;
593 }
594 else
595 up->sources = NULL;
596
597 pim_upstream_find_new_children (up);
598 up->flags = flags;
599 up->ref_count = 1;
600 up->t_join_timer = NULL;
601 up->t_ka_timer = NULL;
602 up->t_rs_timer = NULL;
603 up->t_msdp_reg_timer = NULL;
604 up->join_state = 0;
605 up->state_transition = pim_time_monotonic_sec();
606 up->channel_oil = NULL;
607 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
608
609 up->rpf.source_nexthop.interface = NULL;
610 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
611 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
612 up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference;
613 up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric;
614 up->rpf.rpf_addr.family = AF_INET;
615 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
616
617 if (up->sg.src.s_addr != INADDR_ANY)
618 wheel_add_item (pim_upstream_sg_wheel, up);
619
620 rpf_result = pim_rpf_update(up, NULL);
621 if (rpf_result == PIM_RPF_FAILURE) {
622 if (PIM_DEBUG_TRACE)
623 zlog_debug ("%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__,
624 up->sg_str);
625
626 if (up->parent)
627 {
628 listnode_delete (up->parent->sources, up);
629 up->parent = NULL;
630 }
631
632 if (up->sg.src.s_addr != INADDR_ANY)
633 wheel_remove_item (pim_upstream_sg_wheel, up);
634
635 pim_upstream_remove_children (up);
636 if (up->sources)
637 list_delete (up->sources);
638
639 hash_release (pim_upstream_hash, up);
640 XFREE(MTYPE_PIM_UPSTREAM, up);
641 return NULL;
642 }
643
644 pim_ifp = up->rpf.source_nexthop.interface->info;
645 if (pim_ifp)
646 up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index);
647
648 listnode_add_sort(pim_upstream_list, up);
649
650 if (PIM_DEBUG_TRACE)
651 zlog_debug ("%s: Created Upstream %s", __PRETTY_FUNCTION__, up->sg_str);
652
653 return up;
654 }
655
656 struct pim_upstream *pim_upstream_find(struct prefix_sg *sg)
657 {
658 struct pim_upstream lookup;
659 struct pim_upstream *up = NULL;
660
661 lookup.sg = *sg;
662 up = hash_lookup (pim_upstream_hash, &lookup);
663 return up;
664 }
665
666 static void pim_upstream_ref(struct pim_upstream *up, int flags)
667 {
668 up->flags |= flags;
669 ++up->ref_count;
670 }
671
672 struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
673 struct interface *incoming,
674 int flags, const char *name)
675 {
676 struct pim_upstream *up = NULL;
677 int found = 0;
678 up = pim_upstream_find(sg);
679 if (up) {
680 pim_upstream_ref(up, flags);
681 found = 1;
682 }
683 else {
684 up = pim_upstream_new(sg, incoming, flags);
685 }
686
687 if (PIM_DEBUG_TRACE)
688 {
689 if (up)
690 zlog_debug("%s(%s): %s, found: %d: ref_count: %d",
691 __PRETTY_FUNCTION__, name,
692 up->sg_str, found,
693 up->ref_count);
694 else
695 zlog_debug("%s(%s): (%s) failure to create",
696 __PRETTY_FUNCTION__, name,
697 pim_str_sg_dump (sg));
698 }
699
700 return up;
701 }
702
703 int
704 pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up,
705 struct pim_ifchannel *ch)
706 {
707 struct pim_upstream *parent = up->parent;
708
709 if (ch->upstream == up)
710 {
711 if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch))
712 return 1;
713
714 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
715 return 0;
716 }
717
718 /*
719 * joins (*,G)
720 */
721 if (parent && ch->upstream == parent)
722 {
723 if (!pim_macro_ch_lost_assert (ch) && pim_macro_chisin_joins_or_include (ch))
724 return 1;
725 }
726
727 return 0;
728 }
729
730 /*
731 Evaluate JoinDesired(S,G):
732
733 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
734 in the set:
735
736 inherited_olist(S,G) =
737 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
738
739 JoinDesired(S,G) may be affected by changes in the following:
740
741 pim_ifp->primary_address
742 pim_ifp->pim_dr_addr
743 ch->ifassert_winner_metric
744 ch->ifassert_winner
745 ch->local_ifmembership
746 ch->ifjoin_state
747 ch->upstream->rpf.source_nexthop.mrib_metric_preference
748 ch->upstream->rpf.source_nexthop.mrib_route_metric
749 ch->upstream->rpf.source_nexthop.interface
750
751 See also pim_upstream_update_join_desired() below.
752 */
753 int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
754 {
755 struct listnode *chnode;
756 struct listnode *chnextnode;
757 struct pim_interface *pim_ifp;
758 struct pim_ifchannel *ch;
759 int ret = 0;
760
761 /* scan per-interface (S,G) state */
762 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch))
763 {
764 pim_ifp = ch->interface->info;
765 if (!pim_ifp)
766 continue;
767
768 ret += pim_upstream_evaluate_join_desired_interface (up, ch);
769 } /* scan iface channel list */
770
771 return ret; /* false */
772 }
773
774 /*
775 See also pim_upstream_evaluate_join_desired() above.
776 */
777 void pim_upstream_update_join_desired(struct pim_upstream *up)
778 {
779 int was_join_desired; /* boolean */
780 int is_join_desired; /* boolean */
781
782 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
783
784 is_join_desired = pim_upstream_evaluate_join_desired(up);
785 if (is_join_desired)
786 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
787 else
788 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
789
790 /* switched from false to true */
791 if (is_join_desired && !was_join_desired) {
792 pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
793 return;
794 }
795
796 /* switched from true to false */
797 if (!is_join_desired && was_join_desired) {
798 pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
799 return;
800 }
801 }
802
803 /*
804 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
805 Transitions from Joined State
806 RPF'(S,G) GenID changes
807
808 The upstream (S,G) state machine remains in Joined state. If the
809 Join Timer is set to expire in more than t_override seconds, reset
810 it so that it expires after t_override seconds.
811 */
812 void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
813 {
814 struct listnode *up_node;
815 struct listnode *up_nextnode;
816 struct pim_upstream *up;
817
818 /*
819 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
820 */
821 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
822
823 if (PIM_DEBUG_TRACE) {
824 char neigh_str[INET_ADDRSTRLEN];
825 char rpf_addr_str[PREFIX_STRLEN];
826 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
827 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
828 zlog_debug("%s: matching neigh=%s against upstream (S,G)=%s joined=%d rpf_addr=%s",
829 __PRETTY_FUNCTION__,
830 neigh_str, up->sg_str,
831 up->join_state == PIM_UPSTREAM_JOINED,
832 rpf_addr_str);
833 }
834
835 /* consider only (S,G) upstream in Joined state */
836 if (up->join_state != PIM_UPSTREAM_JOINED)
837 continue;
838
839 /* match RPF'(S,G)=neigh_addr */
840 if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr)
841 continue;
842
843 pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
844 up);
845 }
846 }
847
848
849 void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
850 struct interface *old_rpf_ifp)
851 {
852 struct listnode *chnode;
853 struct listnode *chnextnode;
854 struct pim_ifchannel *ch;
855 struct pim_interface *pim_ifp;
856
857 /* search all ifchannels */
858 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
859
860 pim_ifp = ch->interface->info;
861 if (!pim_ifp)
862 continue;
863
864 if (ch->upstream != up)
865 continue;
866
867 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
868 if (
869 /* RPF_interface(S) was NOT I */
870 (old_rpf_ifp == ch->interface)
871 &&
872 /* RPF_interface(S) stopped being I */
873 (ch->upstream->rpf.source_nexthop.interface != ch->interface)
874 ) {
875 assert_action_a5(ch);
876 }
877 } /* PIM_IFASSERT_I_AM_LOSER */
878
879 pim_ifchannel_update_assert_tracking_desired(ch);
880 }
881 }
882
883 void pim_upstream_update_could_assert(struct pim_upstream *up)
884 {
885 struct listnode *chnode;
886 struct listnode *chnextnode;
887 struct pim_interface *pim_ifp;
888 struct pim_ifchannel *ch;
889
890 /* scan per-interface (S,G) state */
891 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
892 pim_ifp = ch->interface->info;
893 if (!pim_ifp)
894 continue;
895
896 if (ch->upstream != up)
897 continue;
898
899 pim_ifchannel_update_could_assert(ch);
900 } /* scan iface channel list */
901 }
902
903 void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
904 {
905 struct listnode *chnode;
906 struct listnode *chnextnode;
907 struct pim_interface *pim_ifp;
908 struct pim_ifchannel *ch;
909
910 /* scan per-interface (S,G) state */
911 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
912 pim_ifp = ch->interface->info;
913 if (!pim_ifp)
914 continue;
915
916 if (ch->upstream != up)
917 continue;
918
919 pim_ifchannel_update_my_assert_metric(ch);
920
921 } /* scan iface channel list */
922 }
923
924 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
925 {
926 struct listnode *chnode;
927 struct listnode *chnextnode;
928 struct pim_interface *pim_ifp;
929 struct pim_ifchannel *ch;
930
931 /* scan per-interface (S,G) state */
932 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
933 pim_ifp = ch->interface->info;
934 if (!pim_ifp)
935 continue;
936
937 if (ch->upstream != up)
938 continue;
939
940 pim_ifchannel_update_assert_tracking_desired(ch);
941
942 } /* scan iface channel list */
943 }
944
945 /* When kat is stopped CouldRegister goes to false so we need to
946 * transition the (S, G) on FHR to NI state and remove reg tunnel
947 * from the OIL */
948 static void pim_upstream_fhr_kat_expiry(struct pim_upstream *up)
949 {
950 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
951 return;
952
953 if (PIM_DEBUG_TRACE)
954 zlog_debug ("kat expired on %s; clear fhr reg state", up->sg_str);
955
956 /* stop reg-stop timer */
957 THREAD_OFF(up->t_rs_timer);
958 /* remove regiface from the OIL if it is there*/
959 pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
960 /* move to "not-joined" */
961 up->join_state = PIM_UPSTREAM_NOTJOINED;
962 PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags);
963 }
964
965 /* When kat is started CouldRegister can go to true. And if it does we
966 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
967 * to the OIL */
968 static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
969 {
970 if (pim_upstream_could_register(up)) {
971 if (PIM_DEBUG_TRACE)
972 zlog_debug ("kat started on %s; set fhr reg state to joined", up->sg_str);
973
974 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
975 if (up->join_state == PIM_UPSTREAM_NOTJOINED) {
976 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
977 up->join_state = PIM_UPSTREAM_JOINED;
978 }
979 }
980 }
981
982 /*
983 * On an RP, the PMBR value must be cleared when the
984 * Keepalive Timer expires
985 * KAT expiry indicates that flow is inactive. If the flow was created or
986 * maintained by activity now is the time to deref it.
987 */
988 static int
989 pim_upstream_keep_alive_timer (struct thread *t)
990 {
991 struct pim_upstream *up;
992
993 up = THREAD_ARG(t);
994 up->t_ka_timer = NULL;
995
996 if (I_am_RP (up->sg.grp))
997 {
998 pim_br_clear_pmbr (&up->sg);
999 /*
1000 * We need to do more here :)
1001 * But this is the start.
1002 */
1003 }
1004
1005 /* source is no longer active - pull the SA from MSDP's cache */
1006 pim_msdp_sa_local_del(&up->sg);
1007
1008 /* if entry was created because of activity we need to deref it */
1009 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
1010 {
1011 pim_upstream_fhr_kat_expiry(up);
1012 if (PIM_DEBUG_TRACE)
1013 zlog_debug ("kat expired on %s; remove stream reference", up->sg_str);
1014 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
1015 pim_upstream_del(up, __PRETTY_FUNCTION__);
1016 }
1017
1018 return 0;
1019 }
1020
1021 void
1022 pim_upstream_keep_alive_timer_start (struct pim_upstream *up,
1023 uint32_t time)
1024 {
1025 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1026 if (PIM_DEBUG_TRACE)
1027 zlog_debug ("kat start on %s with no stream reference", up->sg_str);
1028 }
1029 THREAD_OFF (up->t_ka_timer);
1030 THREAD_TIMER_ON (master,
1031 up->t_ka_timer,
1032 pim_upstream_keep_alive_timer,
1033 up, time);
1034
1035 /* any time keepalive is started against a SG we will have to
1036 * re-evaluate our active source database */
1037 pim_msdp_sa_local_update(up);
1038 }
1039
1040 /* MSDP on RP needs to know if a source is registerable to this RP */
1041 static int
1042 pim_upstream_msdp_reg_timer(struct thread *t)
1043 {
1044 struct pim_upstream *up;
1045
1046 up = THREAD_ARG(t);
1047 up->t_msdp_reg_timer = NULL;
1048
1049 /* source is no longer active - pull the SA from MSDP's cache */
1050 pim_msdp_sa_local_del(&up->sg);
1051 return 1;
1052 }
1053 void
1054 pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
1055 {
1056 THREAD_OFF(up->t_msdp_reg_timer);
1057 THREAD_TIMER_ON(master, up->t_msdp_reg_timer,
1058 pim_upstream_msdp_reg_timer, up, PIM_MSDP_REG_RXED_PERIOD);
1059
1060 pim_msdp_sa_local_update(up);
1061 }
1062
1063 /*
1064 * 4.2.1 Last-Hop Switchover to the SPT
1065 *
1066 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1067 * RP. Once traffic from sources to joined groups arrives at a last-hop
1068 * router, it has the option of switching to receive the traffic on a
1069 * shortest path tree (SPT).
1070 *
1071 * The decision for a router to switch to the SPT is controlled as
1072 * follows:
1073 *
1074 * void
1075 * CheckSwitchToSpt(S,G) {
1076 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1077 * (+) pim_include(S,G) != NULL )
1078 * AND SwitchToSptDesired(S,G) ) {
1079 * # Note: Restarting the KAT will result in the SPT switch
1080 * set KeepaliveTimer(S,G) to Keepalive_Period
1081 * }
1082 * }
1083 *
1084 * SwitchToSptDesired(S,G) is a policy function that is implementation
1085 * defined. An "infinite threshold" policy can be implemented by making
1086 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1087 * first packet" policy can be implemented by making
1088 * SwitchToSptDesired(S,G) return true once a single packet has been
1089 * received for the source and group.
1090 */
1091 int
1092 pim_upstream_switch_to_spt_desired (struct prefix_sg *sg)
1093 {
1094 if (I_am_RP (sg->grp))
1095 return 1;
1096
1097 return 0;
1098 }
1099
1100 int
1101 pim_upstream_is_sg_rpt (struct pim_upstream *up)
1102 {
1103 struct listnode *chnode;
1104 struct pim_ifchannel *ch;
1105
1106 for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, chnode, ch))
1107 {
1108 if ((ch->upstream == up) &&
1109 (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)))
1110 return 1;
1111 }
1112
1113 return 0;
1114 }
1115 /*
1116 * After receiving a packet set SPTbit:
1117 * void
1118 * Update_SPTbit(S,G,iif) {
1119 * if ( iif == RPF_interface(S)
1120 * AND JoinDesired(S,G) == TRUE
1121 * AND ( DirectlyConnected(S) == TRUE
1122 * OR RPF_interface(S) != RPF_interface(RP(G))
1123 * OR inherited_olist(S,G,rpt) == NULL
1124 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1125 * ( RPF'(S,G) != NULL ) )
1126 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1127 * Set SPTbit(S,G) to TRUE
1128 * }
1129 * }
1130 */
1131 void
1132 pim_upstream_set_sptbit (struct pim_upstream *up, struct interface *incoming)
1133 {
1134 struct pim_rpf *grpf = NULL;
1135
1136 // iif == RPF_interfvace(S)
1137 if (up->rpf.source_nexthop.interface != incoming)
1138 {
1139 if (PIM_DEBUG_TRACE)
1140 zlog_debug ("%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1141 __PRETTY_FUNCTION__, incoming->name, up->rpf.source_nexthop.interface->name);
1142 return;
1143 }
1144
1145 // AND JoinDesired(S,G) == TRUE
1146 // FIXME
1147
1148 // DirectlyConnected(S) == TRUE
1149 if (pim_if_connected_to_source (up->rpf.source_nexthop.interface, up->sg.src))
1150 {
1151 if (PIM_DEBUG_TRACE)
1152 zlog_debug ("%s: %s is directly connected to the source", __PRETTY_FUNCTION__,
1153 up->sg_str);
1154 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1155 return;
1156 }
1157
1158 // OR RPF_interface(S) != RPF_interface(RP(G))
1159 grpf = RP(up->sg.grp);
1160 if (!grpf || up->rpf.source_nexthop.interface != grpf->source_nexthop.interface)
1161 {
1162 if (PIM_DEBUG_TRACE)
1163 zlog_debug ("%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1164 __PRETTY_FUNCTION__, up->sg_str);
1165 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1166 return;
1167 }
1168
1169 // OR inherited_olist(S,G,rpt) == NULL
1170 if (pim_upstream_is_sg_rpt(up) && pim_upstream_empty_inherited_olist(up))
1171 {
1172 if (PIM_DEBUG_TRACE)
1173 zlog_debug ("%s: %s OR inherited_olist(S,G,rpt) == NULL", __PRETTY_FUNCTION__,
1174 up->sg_str);
1175 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1176 return;
1177 }
1178
1179 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1180 // ( RPF'(S,G) != NULL ) )
1181 if (up->parent && pim_rpf_is_same (&up->rpf, &up->parent->rpf))
1182 {
1183 if (PIM_DEBUG_TRACE)
1184 zlog_debug ("%s: %s RPF'(S,G) is the same as RPF'(*,G)", __PRETTY_FUNCTION__,
1185 up->sg_str);
1186 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1187 return;
1188 }
1189
1190 return;
1191 }
1192
1193 const char *
1194 pim_upstream_state2str (enum pim_upstream_state join_state)
1195 {
1196 switch (join_state)
1197 {
1198 case PIM_UPSTREAM_NOTJOINED:
1199 return "NotJoined";
1200 break;
1201 case PIM_UPSTREAM_JOINED:
1202 return "Joined";
1203 break;
1204 case PIM_UPSTREAM_JOIN_PENDING:
1205 return "JoinPending";
1206 break;
1207 case PIM_UPSTREAM_PRUNE:
1208 return "Prune";
1209 break;
1210 }
1211 return "Unknown";
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 zlog_debug ("%s: (S,G)=%s upstream register stop timer %s",
1228 __PRETTY_FUNCTION__, up->sg_str,
1229 pim_upstream_state2str(up->join_state));
1230 }
1231
1232 switch (up->join_state)
1233 {
1234 case PIM_UPSTREAM_JOIN_PENDING:
1235 up->join_state = PIM_UPSTREAM_JOINED;
1236 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
1237 break;
1238 case PIM_UPSTREAM_JOINED:
1239 break;
1240 case PIM_UPSTREAM_PRUNE:
1241 pim_ifp = up->rpf.source_nexthop.interface->info;
1242 if (!pim_ifp)
1243 {
1244 if (PIM_DEBUG_TRACE)
1245 zlog_debug ("%s: Interface: %s is not configured for pim",
1246 __PRETTY_FUNCTION__, up->rpf.source_nexthop.interface->name);
1247 return 0;
1248 }
1249 up->join_state = PIM_UPSTREAM_JOIN_PENDING;
1250 pim_upstream_start_register_stop_timer (up, 1);
1251
1252 if (((up->channel_oil->cc.lastused/100) > PIM_KEEPALIVE_PERIOD) &&
1253 (I_am_RP (up->sg.grp)))
1254 {
1255 if (PIM_DEBUG_TRACE)
1256 zlog_debug ("%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while", __PRETTY_FUNCTION__);
1257 return 0;
1258 }
1259 rpg = RP (up->sg.grp);
1260 memset (&ip_hdr, 0, sizeof (struct ip));
1261 ip_hdr.ip_p = PIM_IP_PROTO_PIM;
1262 ip_hdr.ip_hl = 5;
1263 ip_hdr.ip_v = 4;
1264 ip_hdr.ip_src = up->sg.src;
1265 ip_hdr.ip_dst = up->sg.grp;
1266 ip_hdr.ip_len = htons (20);
1267 // checksum is broken
1268 pim_register_send ((uint8_t *)&ip_hdr, sizeof (struct ip),
1269 pim_ifp->primary_address, rpg, 1, up);
1270 break;
1271 default:
1272 break;
1273 }
1274
1275 return 0;
1276 }
1277
1278 void
1279 pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_register)
1280 {
1281 uint32_t time;
1282
1283 if (up->t_rs_timer)
1284 {
1285 THREAD_TIMER_OFF (up->t_rs_timer);
1286 up->t_rs_timer = NULL;
1287 }
1288
1289 if (!null_register)
1290 {
1291 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1292 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1293 time = lower + (random () % (upper - lower + 1)) - PIM_REGISTER_PROBE_PERIOD;
1294 }
1295 else
1296 time = PIM_REGISTER_PROBE_PERIOD;
1297
1298 if (PIM_DEBUG_TRACE)
1299 {
1300 zlog_debug ("%s: (S,G)=%s Starting upstream register stop timer %d",
1301 __PRETTY_FUNCTION__, up->sg_str, time);
1302 }
1303 THREAD_TIMER_ON (master, up->t_rs_timer,
1304 pim_upstream_register_stop_timer,
1305 up, time);
1306 }
1307
1308 int
1309 pim_upstream_inherited_olist_decide (struct pim_upstream *up)
1310 {
1311 struct pim_interface *pim_ifp;
1312 struct listnode *chnextnode;
1313 struct pim_ifchannel *ch;
1314 struct listnode *chnode;
1315 int output_intf = 0;
1316
1317 pim_ifp = up->rpf.source_nexthop.interface->info;
1318 if (pim_ifp && !up->channel_oil)
1319 up->channel_oil = pim_channel_oil_add (&up->sg, pim_ifp->mroute_vif_index);
1320
1321 for (ALL_LIST_ELEMENTS (pim_ifchannel_list, chnode, chnextnode, ch))
1322 {
1323 pim_ifp = ch->interface->info;
1324 if (!pim_ifp)
1325 continue;
1326
1327 if (pim_upstream_evaluate_join_desired_interface (up, ch))
1328 {
1329 int flag = PIM_OIF_FLAG_PROTO_PIM;
1330
1331 if (ch->sg.src.s_addr == INADDR_ANY && ch->upstream != up)
1332 flag = PIM_OIF_FLAG_PROTO_STAR;
1333 pim_channel_add_oif (up->channel_oil, ch->interface, flag);
1334 output_intf++;
1335 }
1336 }
1337
1338 return output_intf;
1339 }
1340
1341 /*
1342 * For a given upstream, determine the inherited_olist
1343 * and apply it.
1344 *
1345 * inherited_olist(S,G,rpt) =
1346 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1347 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1348 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1349 *
1350 * inherited_olist(S,G) =
1351 * inherited_olist(S,G,rpt) (+)
1352 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1353 *
1354 * return 1 if there are any output interfaces
1355 * return 0 if there are not any output interfaces
1356 */
1357 int
1358 pim_upstream_inherited_olist (struct pim_upstream *up)
1359 {
1360 int output_intf = pim_upstream_inherited_olist_decide (up);
1361
1362 /*
1363 * If we have output_intf switch state to Join and work like normal
1364 * If we don't have an output_intf that means we are probably a
1365 * switch on a stick so turn on forwarding to just accept the
1366 * incoming packets so we don't bother the other stuff!
1367 */
1368 if (output_intf)
1369 pim_upstream_switch (up, PIM_UPSTREAM_JOINED);
1370 else
1371 forward_on (up);
1372
1373 return output_intf;
1374 }
1375
1376 int
1377 pim_upstream_empty_inherited_olist (struct pim_upstream *up)
1378 {
1379 return pim_channel_oil_empty (up->channel_oil);
1380 }
1381
1382 /*
1383 * When we have a new neighbor,
1384 * find upstreams that don't have their rpf_addr
1385 * set and see if the new neighbor allows
1386 * the join to be sent
1387 */
1388 void
1389 pim_upstream_find_new_rpf (void)
1390 {
1391 struct listnode *up_node;
1392 struct listnode *up_nextnode;
1393 struct pim_upstream *up;
1394
1395 /*
1396 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1397 */
1398 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up))
1399 {
1400 if (pim_rpf_addr_is_inaddr_any(&up->rpf))
1401 {
1402 if (PIM_DEBUG_TRACE)
1403 zlog_debug ("Upstream %s without a path to send join, checking",
1404 up->sg_str);
1405 pim_rpf_update (up, NULL);
1406 }
1407 }
1408 }
1409
1410 static unsigned int
1411 pim_upstream_hash_key (void *arg)
1412 {
1413 struct pim_upstream *up = (struct pim_upstream *)arg;
1414
1415 return jhash_2words (up->sg.src.s_addr, up->sg.grp.s_addr, 0);
1416 }
1417
1418 void pim_upstream_terminate (void)
1419 {
1420 if (pim_upstream_list)
1421 list_delete (pim_upstream_list);
1422 pim_upstream_list = NULL;
1423
1424 if (pim_upstream_hash)
1425 hash_free (pim_upstream_hash);
1426 pim_upstream_hash = NULL;
1427 }
1428
1429 static int
1430 pim_upstream_equal (const void *arg1, const void *arg2)
1431 {
1432 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1433 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
1434
1435 if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr) &&
1436 (up1->sg.src.s_addr == up2->sg.src.s_addr))
1437 return 1;
1438
1439 return 0;
1440 }
1441
1442 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1443 * the cases where kat has to be restarted on rxing traffic -
1444 *
1445 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1446 * set KeepaliveTimer(S,G) to Keepalive_Period
1447 * # Note: a register state transition or UpstreamJPState(S,G)
1448 * # transition may happen as a result of restarting
1449 * # KeepaliveTimer, and must be dealt with here.
1450 * }
1451 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1452 * inherited_olist(S,G) != NULL ) {
1453 * set KeepaliveTimer(S,G) to Keepalive_Period
1454 * }
1455 */
1456 static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
1457 {
1458 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1459 * so we will skip that here */
1460 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1461 up->sg.src)) {
1462 return true;
1463 }
1464
1465 if ((up->join_state == PIM_UPSTREAM_JOINED) &&
1466 !pim_upstream_empty_inherited_olist(up)) {
1467 /* XXX: I have added this RP check just for 3.2 and it's a digression from
1468 * what rfc-4601 says. Till now we were only running KAT on FHR and RP and
1469 * there is some angst around making the change to run it all routers that
1470 * maintain the (S, G) state. This is tracked via CM-13601 and MUST be
1471 * removed to handle spt turn-arounds correctly in a 3-tier clos */
1472 if (I_am_RP (up->sg.grp))
1473 return true;
1474 }
1475
1476 return false;
1477 }
1478
1479 /*
1480 * Code to check and see if we've received packets on a S,G mroute
1481 * and if so to set the SPT bit appropriately
1482 */
1483 static void
1484 pim_upstream_sg_running (void *arg)
1485 {
1486 struct pim_upstream *up = (struct pim_upstream *)arg;
1487
1488 // No packet can have arrived here if this is the case
1489 if (!up->channel_oil || !up->channel_oil->installed)
1490 {
1491 if (PIM_DEBUG_TRACE)
1492 zlog_debug ("%s: %s is not installed in mroute",
1493 __PRETTY_FUNCTION__, up->sg_str);
1494 return;
1495 }
1496
1497 /*
1498 * This is a bit of a hack
1499 * We've noted that we should rescan but
1500 * we've missed the window for doing so in
1501 * pim_zebra.c for some reason. I am
1502 * only doing this at this point in time
1503 * to get us up and working for the moment
1504 */
1505 if (up->channel_oil->oil_inherited_rescan)
1506 {
1507 if (PIM_DEBUG_TRACE)
1508 zlog_debug ("%s: Handling unscanned inherited_olist for %s", __PRETTY_FUNCTION__, up->sg_str);
1509 pim_upstream_inherited_olist_decide (up);
1510 up->channel_oil->oil_inherited_rescan = 0;
1511 }
1512 pim_mroute_update_counters (up->channel_oil);
1513
1514 // Have we seen packets?
1515 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt) &&
1516 (up->channel_oil->cc.lastused/100 > 30))
1517 {
1518 if (PIM_DEBUG_TRACE)
1519 {
1520 zlog_debug ("%s: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1521 __PRETTY_FUNCTION__, up->sg_str,
1522 up->channel_oil->cc.oldpktcnt,
1523 up->channel_oil->cc.pktcnt,
1524 up->channel_oil->cc.lastused/100);
1525 }
1526 return;
1527 }
1528
1529 if (pim_upstream_kat_start_ok(up)) {
1530 /* Add a source reference to the stream if
1531 * one doesn't already exist */
1532 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
1533 {
1534 if (PIM_DEBUG_TRACE)
1535 zlog_debug ("source reference created on kat restart %s", up->sg_str);
1536
1537 pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM);
1538 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
1539 pim_upstream_fhr_kat_start(up);
1540 }
1541 pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
1542 }
1543
1544 if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE)
1545 {
1546 pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
1547 }
1548 return;
1549 }
1550
1551 void
1552 pim_upstream_init (void)
1553 {
1554 pim_upstream_sg_wheel = wheel_init (master, 31000, 100,
1555 pim_upstream_hash_key,
1556 pim_upstream_sg_running);
1557 pim_upstream_hash = hash_create_size (8192, pim_upstream_hash_key,
1558 pim_upstream_equal);
1559
1560 pim_upstream_list = list_new ();
1561 pim_upstream_list->del = (void (*)(void *)) pim_upstream_free;
1562 pim_upstream_list->cmp = pim_upstream_compare;
1563
1564 }