]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_upstream.c
03ca3b6edcc14957012d88f305c826a7ff1c3f31
[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
22 #include <zebra.h>
23
24 #include "zebra/rib.h"
25
26 #include "log.h"
27 #include "zclient.h"
28 #include "memory.h"
29 #include "thread.h"
30 #include "linklist.h"
31
32 #include "pimd.h"
33 #include "pim_pim.h"
34 #include "pim_str.h"
35 #include "pim_time.h"
36 #include "pim_iface.h"
37 #include "pim_join.h"
38 #include "pim_zlookup.h"
39 #include "pim_upstream.h"
40 #include "pim_ifchannel.h"
41 #include "pim_neighbor.h"
42 #include "pim_rpf.h"
43 #include "pim_zebra.h"
44 #include "pim_oil.h"
45 #include "pim_macro.h"
46 #include "pim_rp.h"
47 #include "pim_br.h"
48 #include "pim_register.h"
49
50 static void join_timer_start(struct pim_upstream *up);
51 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
52
53 /*
54 * A (*,G) or a (*,*) is going away
55 * remove the parent pointer from
56 * those pointing at us
57 */
58 static void
59 pim_upstream_remove_children (struct pim_upstream *up)
60 {
61 struct listnode *ch_node;
62 struct pim_upstream *child;
63
64 // Basic sanity, (*,*) not currently supported
65 if ((up->sg.src.s_addr == INADDR_ANY) &&
66 (up->sg.grp.s_addr == INADDR_ANY))
67 return;
68
69 // Basic sanity (S,G) have no children
70 if ((up->sg.src.s_addr != INADDR_ANY) &&
71 (up->sg.grp.s_addr != INADDR_ANY))
72 return;
73
74 for (ALL_LIST_ELEMENTS_RO (qpim_upstream_list, ch_node, child))
75 {
76 if (child->parent == up)
77 child->parent = NULL;
78 }
79 }
80
81 /*
82 * A (*,G) or a (*,*) is being created
83 * Find the children that would point
84 * at us.
85 */
86 static void
87 pim_upstream_find_new_children (struct pim_upstream *up)
88 {
89 struct pim_upstream *child;
90 struct listnode *ch_node;
91
92 if ((up->sg.src.s_addr != INADDR_ANY) &&
93 (up->sg.grp.s_addr != INADDR_ANY))
94 return;
95
96 if ((up->sg.src.s_addr == INADDR_ANY) &&
97 (up->sg.grp.s_addr == INADDR_ANY))
98 return;
99
100 for (ALL_LIST_ELEMENTS_RO (qpim_upstream_list, ch_node, child))
101 {
102 if ((up->sg.grp.s_addr != INADDR_ANY) &&
103 (child->sg.grp.s_addr == up->sg.grp.s_addr) &&
104 (child != up))
105 child->parent = up;
106 }
107 }
108
109 /*
110 * If we have a (*,*) || (S,*) there is no parent
111 * If we have a (S,G), find the (*,G)
112 * If we have a (*,G), find the (*,*)
113 */
114 static struct pim_upstream *
115 pim_upstream_find_parent (struct prefix_sg *sg)
116 {
117 struct prefix_sg any = *sg;
118
119 // (*,*) || (S,*)
120 if (((sg->src.s_addr == INADDR_ANY) &&
121 (sg->grp.s_addr == INADDR_ANY)) ||
122 ((sg->src.s_addr != INADDR_ANY) &&
123 (sg->grp.s_addr == INADDR_ANY)))
124 return NULL;
125
126 // (S,G)
127 if ((sg->src.s_addr != INADDR_ANY) &&
128 (sg->grp.s_addr != INADDR_ANY))
129 {
130 any.src.s_addr = INADDR_ANY;
131 return pim_upstream_find (&any);
132 }
133
134 // (*,G)
135 any.grp.s_addr = INADDR_ANY;
136 return pim_upstream_find (&any);
137 }
138
139 void pim_upstream_free(struct pim_upstream *up)
140 {
141 XFREE(MTYPE_PIM_UPSTREAM, up);
142 }
143
144 static void upstream_channel_oil_detach(struct pim_upstream *up)
145 {
146 if (up->channel_oil) {
147 pim_channel_oil_del(up->channel_oil);
148 up->channel_oil = NULL;
149 }
150 }
151
152 void pim_upstream_delete(struct pim_upstream *up)
153 {
154 THREAD_OFF(up->t_join_timer);
155 THREAD_OFF(up->t_ka_timer);
156 THREAD_OFF(up->t_rs_timer);
157
158 pim_upstream_remove_children (up);
159 pim_mroute_del (up->channel_oil);
160 upstream_channel_oil_detach(up);
161
162 /*
163 notice that listnode_delete() can't be moved
164 into pim_upstream_free() because the later is
165 called by list_delete_all_node()
166 */
167 listnode_delete(qpim_upstream_list, up);
168
169 pim_upstream_free(up);
170 }
171
172 void
173 pim_upstream_send_join (struct pim_upstream *up)
174 {
175 if (PIM_DEBUG_PIM_TRACE) {
176 char rpf_str[100];
177 pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
178 zlog_debug ("%s: RPF'%s=%s(%s) for Interface %s", __PRETTY_FUNCTION__,
179 pim_str_sg_dump (&up->sg), rpf_str, pim_upstream_state2str (up->join_state),
180 up->rpf.source_nexthop.interface->name);
181 if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) {
182 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
183 __PRETTY_FUNCTION__,
184 pim_str_sg_dump (&up->sg), rpf_str);
185 /* warning only */
186 }
187 }
188
189 /* send Join(S,G) to the current upstream neighbor */
190 pim_joinprune_send(up->rpf.source_nexthop.interface,
191 up->rpf.rpf_addr,
192 &up->sg,
193 1 /* join */);
194 }
195
196 static int on_join_timer(struct thread *t)
197 {
198 struct pim_upstream *up;
199
200 zassert(t);
201 up = THREAD_ARG(t);
202 zassert(up);
203
204 up->t_join_timer = NULL;
205
206 /*
207 * In the case of a HFR we will not ahve anyone to send this to.
208 */
209 if (up->fhr)
210 return 0;
211
212 pim_upstream_send_join (up);
213
214 join_timer_start(up);
215
216 return 0;
217 }
218
219 static void join_timer_start(struct pim_upstream *up)
220 {
221 if (PIM_DEBUG_PIM_EVENTS) {
222 zlog_debug("%s: starting %d sec timer for upstream (S,G)=%s",
223 __PRETTY_FUNCTION__,
224 qpim_t_periodic,
225 pim_str_sg_dump (&up->sg));
226 }
227
228 THREAD_OFF (up->t_join_timer);
229 THREAD_TIMER_ON(master, up->t_join_timer,
230 on_join_timer,
231 up, qpim_t_periodic);
232 }
233
234 void pim_upstream_join_timer_restart(struct pim_upstream *up)
235 {
236 THREAD_OFF(up->t_join_timer);
237 join_timer_start(up);
238 }
239
240 static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
241 int interval_msec)
242 {
243 if (PIM_DEBUG_PIM_EVENTS) {
244 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
245 __PRETTY_FUNCTION__,
246 interval_msec,
247 pim_str_sg_dump (&up->sg));
248 }
249
250 THREAD_OFF(up->t_join_timer);
251 THREAD_TIMER_MSEC_ON(master, up->t_join_timer,
252 on_join_timer,
253 up, interval_msec);
254 }
255
256 void pim_upstream_join_suppress(struct pim_upstream *up,
257 struct in_addr rpf_addr,
258 int holdtime)
259 {
260 long t_joinsuppress_msec;
261 long join_timer_remain_msec;
262
263 t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
264 1000 * holdtime);
265
266 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
267
268 if (PIM_DEBUG_PIM_TRACE) {
269 char rpf_str[100];
270 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
271 zlog_debug("%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
272 __FILE__, __PRETTY_FUNCTION__,
273 pim_str_sg_dump (&up->sg),
274 rpf_str,
275 join_timer_remain_msec, t_joinsuppress_msec);
276 }
277
278 if (join_timer_remain_msec < t_joinsuppress_msec) {
279 if (PIM_DEBUG_PIM_TRACE) {
280 zlog_debug("%s %s: suppressing Join(S,G)=%s for %ld msec",
281 __FILE__, __PRETTY_FUNCTION__,
282 pim_str_sg_dump (&up->sg), t_joinsuppress_msec);
283 }
284
285 pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
286 }
287 }
288
289 void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
290 struct pim_upstream *up,
291 struct in_addr rpf_addr)
292 {
293 long join_timer_remain_msec;
294 int t_override_msec;
295
296 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
297 t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface);
298
299 if (PIM_DEBUG_PIM_TRACE) {
300 char rpf_str[100];
301 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
302 zlog_debug("%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
303 debug_label,
304 pim_str_sg_dump (&up->sg), rpf_str,
305 join_timer_remain_msec, t_override_msec);
306 }
307
308 if (join_timer_remain_msec > t_override_msec) {
309 if (PIM_DEBUG_PIM_TRACE) {
310 zlog_debug("%s: decreasing (S,G)=%s join timer to t_override=%d msec",
311 debug_label,
312 pim_str_sg_dump (&up->sg),
313 t_override_msec);
314 }
315
316 pim_upstream_join_timer_restart_msec(up, t_override_msec);
317 }
318 }
319
320 static void forward_on(struct pim_upstream *up)
321 {
322 struct listnode *ifnode;
323 struct listnode *ifnextnode;
324 struct listnode *chnode;
325 struct listnode *chnextnode;
326 struct interface *ifp;
327 struct pim_interface *pim_ifp;
328 struct pim_ifchannel *ch;
329
330 /* scan all interfaces */
331 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
332 pim_ifp = ifp->info;
333 if (!pim_ifp)
334 continue;
335
336 /* scan per-interface (S,G) state */
337 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
338
339 if (ch->upstream != up)
340 continue;
341
342 if (pim_macro_chisin_oiflist(ch))
343 pim_forward_start(ch);
344
345 } /* scan iface channel list */
346 } /* scan iflist */
347 }
348
349 static void forward_off(struct pim_upstream *up)
350 {
351 struct listnode *ifnode;
352 struct listnode *ifnextnode;
353 struct listnode *chnode;
354 struct listnode *chnextnode;
355 struct interface *ifp;
356 struct pim_interface *pim_ifp;
357 struct pim_ifchannel *ch;
358
359 /* scan all interfaces */
360 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
361 pim_ifp = ifp->info;
362 if (!pim_ifp)
363 continue;
364
365 /* scan per-interface (S,G) state */
366 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
367
368 if (ch->upstream != up)
369 continue;
370
371 pim_forward_stop(ch);
372
373 } /* scan iface channel list */
374 } /* scan iflist */
375 }
376
377 static int
378 pim_upstream_could_register (struct pim_upstream *up)
379 {
380 struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info;
381
382 if (PIM_I_am_DR (pim_ifp) &&
383 pim_if_connected_to_source (up->rpf.source_nexthop.interface, up->sg.src))
384 return 1;
385
386 return 0;
387 }
388
389 void
390 pim_upstream_switch(struct pim_upstream *up,
391 enum pim_upstream_state new_state)
392 {
393 enum pim_upstream_state old_state = up->join_state;
394
395 if (PIM_DEBUG_PIM_EVENTS) {
396 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
397 __PRETTY_FUNCTION__,
398 pim_str_sg_dump (&up->sg),
399 pim_upstream_state2str (up->join_state),
400 pim_upstream_state2str (new_state));
401 }
402
403 /*
404 * This code still needs work.
405 */
406 switch (up->join_state)
407 {
408 case PIM_UPSTREAM_PRUNE:
409 if (!up->fhr)
410 {
411 up->join_state = new_state;
412 up->state_transition = pim_time_monotonic_sec ();
413 }
414 break;
415 case PIM_UPSTREAM_JOIN_PENDING:
416 break;
417 case PIM_UPSTREAM_NOTJOINED:
418 case PIM_UPSTREAM_JOINED:
419 up->join_state = new_state;
420 up->state_transition = pim_time_monotonic_sec();
421
422 break;
423 }
424
425 pim_upstream_update_assert_tracking_desired(up);
426
427 if (new_state == PIM_UPSTREAM_JOINED) {
428 if (old_state != PIM_UPSTREAM_JOINED)
429 {
430 int old_fhr = up->fhr;
431 forward_on(up);
432 up->fhr = pim_upstream_could_register (up);
433 if (up->fhr)
434 {
435 if (!old_fhr)
436 {
437 pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
438 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
439 }
440 }
441 else
442 {
443 pim_upstream_send_join (up);
444 join_timer_start (up);
445 }
446 }
447 else
448 {
449 forward_on (up);
450 }
451 }
452 else {
453 forward_off(up);
454 pim_joinprune_send(up->rpf.source_nexthop.interface,
455 up->rpf.rpf_addr,
456 &up->sg,
457 0 /* prune */);
458 if (up->t_join_timer)
459 THREAD_OFF(up->t_join_timer);
460 }
461 }
462
463 static struct pim_upstream *pim_upstream_new(struct prefix_sg *sg,
464 struct interface *incoming)
465 {
466 struct pim_upstream *up;
467 enum pim_rpf_result rpf_result;
468
469 up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
470 if (!up) {
471 zlog_err("%s: PIM XCALLOC(%zu) failure",
472 __PRETTY_FUNCTION__, sizeof(*up));
473 return NULL;
474 }
475
476 up->sg = *sg;
477 if (!pim_rp_set_upstream_addr (&up->upstream_addr, sg->src, sg->grp))
478 {
479 if (PIM_DEBUG_PIM_TRACE)
480 zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
481
482 XFREE (MTYPE_PIM_UPSTREAM, up);
483 return NULL;
484 }
485
486 up->parent = pim_upstream_find_parent (sg);
487 pim_upstream_find_new_children (up);
488 up->flags = 0;
489 up->ref_count = 1;
490 up->t_join_timer = NULL;
491 up->t_ka_timer = NULL;
492 up->t_rs_timer = NULL;
493 up->join_state = 0;
494 up->state_transition = pim_time_monotonic_sec();
495 up->channel_oil = NULL;
496 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
497
498 up->rpf.source_nexthop.interface = NULL;
499 up->rpf.source_nexthop.mrib_nexthop_addr.s_addr = PIM_NET_INADDR_ANY;
500 up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference;
501 up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric;
502 up->rpf.rpf_addr.s_addr = PIM_NET_INADDR_ANY;
503
504 rpf_result = pim_rpf_update(up, 0);
505 if (rpf_result == PIM_RPF_FAILURE) {
506 XFREE(MTYPE_PIM_UPSTREAM, up);
507 return NULL;
508 }
509
510 listnode_add(qpim_upstream_list, up);
511
512 return up;
513 }
514
515 /*
516 * For a given sg, find any non * source
517 */
518 struct pim_upstream *pim_upstream_find_non_any (struct prefix_sg *sg)
519 {
520 struct listnode *up_node;
521 struct prefix_sg any = *sg;
522 struct pim_upstream *up;
523
524 any.src.s_addr = INADDR_ANY;
525
526 for (ALL_LIST_ELEMENTS_RO (qpim_upstream_list, up_node, up))
527 {
528 if ((any.grp.s_addr == up->sg.grp.s_addr) &&
529 (up->sg.src.s_addr != any.src.s_addr))
530 return up;
531 }
532
533 return NULL;
534 }
535
536 struct pim_upstream *pim_upstream_find(struct prefix_sg *sg)
537 {
538 struct listnode *up_node;
539 struct pim_upstream *up;
540
541 for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) {
542 if ((sg->grp.s_addr == up->sg.grp.s_addr) &&
543 (sg->src.s_addr == up->sg.src.s_addr))
544 return up;
545 }
546
547 return NULL;
548 }
549
550 struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
551 struct interface *incoming)
552 {
553 struct pim_upstream *up;
554
555 up = pim_upstream_find(sg);
556 if (up) {
557 ++up->ref_count;
558 }
559 else {
560 up = pim_upstream_new(sg, incoming);
561 }
562
563 return up;
564 }
565
566 void pim_upstream_del(struct pim_upstream *up)
567 {
568 --up->ref_count;
569
570 if (up->ref_count < 1) {
571 pim_upstream_delete(up);
572 }
573 }
574
575 static int
576 pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up,
577 struct pim_ifchannel *ch)
578 {
579 struct pim_upstream *parent = up->parent;
580
581 if (ch->upstream == up)
582 {
583 if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch))
584 return 1;
585 }
586 /*
587 * joins (*,G)
588 */
589 if (parent && ch->upstream == parent)
590 {
591 if (!pim_macro_ch_lost_assert (ch) && pim_macro_chisin_joins_or_include (ch))
592 return 1;
593 }
594
595 return 0;
596 }
597
598 /*
599 Evaluate JoinDesired(S,G):
600
601 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
602 in the set:
603
604 inherited_olist(S,G) =
605 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
606
607 JoinDesired(S,G) may be affected by changes in the following:
608
609 pim_ifp->primary_address
610 pim_ifp->pim_dr_addr
611 ch->ifassert_winner_metric
612 ch->ifassert_winner
613 ch->local_ifmembership
614 ch->ifjoin_state
615 ch->upstream->rpf.source_nexthop.mrib_metric_preference
616 ch->upstream->rpf.source_nexthop.mrib_route_metric
617 ch->upstream->rpf.source_nexthop.interface
618
619 See also pim_upstream_update_join_desired() below.
620 */
621 int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
622 {
623 struct listnode *ifnode;
624 struct listnode *ifnextnode;
625 struct listnode *chnode;
626 struct listnode *chnextnode;
627 struct interface *ifp;
628 struct pim_interface *pim_ifp;
629 struct pim_ifchannel *ch;
630 int ret = 0;
631
632 /* scan all interfaces */
633 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
634 pim_ifp = ifp->info;
635 if (!pim_ifp)
636 continue;
637
638 /* scan per-interface (S,G) state */
639 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch))
640 {
641 ret += pim_upstream_evaluate_join_desired_interface (up, ch);
642 } /* scan iface channel list */
643 } /* scan iflist */
644
645 return ret; /* false */
646 }
647
648 /*
649 See also pim_upstream_evaluate_join_desired() above.
650 */
651 void pim_upstream_update_join_desired(struct pim_upstream *up)
652 {
653 int was_join_desired; /* boolean */
654 int is_join_desired; /* boolean */
655
656 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
657
658 is_join_desired = pim_upstream_evaluate_join_desired(up);
659 if (is_join_desired)
660 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
661 else
662 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
663
664 /* switched from false to true */
665 if (is_join_desired && !was_join_desired) {
666 pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
667 return;
668 }
669
670 /* switched from true to false */
671 if (!is_join_desired && was_join_desired) {
672 pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
673 return;
674 }
675 }
676
677 /*
678 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
679 Transitions from Joined State
680 RPF'(S,G) GenID changes
681
682 The upstream (S,G) state machine remains in Joined state. If the
683 Join Timer is set to expire in more than t_override seconds, reset
684 it so that it expires after t_override seconds.
685 */
686 void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
687 {
688 struct listnode *up_node;
689 struct listnode *up_nextnode;
690 struct pim_upstream *up;
691
692 /*
693 Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
694 */
695 for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
696
697 if (PIM_DEBUG_PIM_TRACE) {
698 char neigh_str[100];
699 char rpf_addr_str[100];
700 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
701 pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
702 zlog_debug("%s: matching neigh=%s against upstream (S,G)=%s joined=%d rpf_addr=%s",
703 __PRETTY_FUNCTION__,
704 neigh_str, pim_str_sg_dump (&up->sg),
705 up->join_state == PIM_UPSTREAM_JOINED,
706 rpf_addr_str);
707 }
708
709 /* consider only (S,G) upstream in Joined state */
710 if (up->join_state != PIM_UPSTREAM_JOINED)
711 continue;
712
713 /* match RPF'(S,G)=neigh_addr */
714 if (up->rpf.rpf_addr.s_addr != neigh_addr.s_addr)
715 continue;
716
717 pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
718 up, neigh_addr);
719 }
720 }
721
722
723 void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
724 struct interface *old_rpf_ifp)
725 {
726 struct listnode *ifnode;
727 struct listnode *ifnextnode;
728 struct interface *ifp;
729
730 /* scan all interfaces */
731 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
732 struct listnode *chnode;
733 struct listnode *chnextnode;
734 struct pim_ifchannel *ch;
735 struct pim_interface *pim_ifp;
736
737 pim_ifp = ifp->info;
738 if (!pim_ifp)
739 continue;
740
741 /* search all ifchannels */
742 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
743 if (ch->upstream != up)
744 continue;
745
746 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
747 if (
748 /* RPF_interface(S) was NOT I */
749 (old_rpf_ifp == ch->interface)
750 &&
751 /* RPF_interface(S) stopped being I */
752 (ch->upstream->rpf.source_nexthop.interface != ch->interface)
753 ) {
754 assert_action_a5(ch);
755 }
756 } /* PIM_IFASSERT_I_AM_LOSER */
757
758 pim_ifchannel_update_assert_tracking_desired(ch);
759 }
760 }
761 }
762
763 void pim_upstream_update_could_assert(struct pim_upstream *up)
764 {
765 struct listnode *ifnode;
766 struct listnode *ifnextnode;
767 struct listnode *chnode;
768 struct listnode *chnextnode;
769 struct interface *ifp;
770 struct pim_interface *pim_ifp;
771 struct pim_ifchannel *ch;
772
773 /* scan all interfaces */
774 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
775 pim_ifp = ifp->info;
776 if (!pim_ifp)
777 continue;
778
779 /* scan per-interface (S,G) state */
780 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
781
782 if (ch->upstream != up)
783 continue;
784
785 pim_ifchannel_update_could_assert(ch);
786
787 } /* scan iface channel list */
788 } /* scan iflist */
789 }
790
791 void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
792 {
793 struct listnode *ifnode;
794 struct listnode *ifnextnode;
795 struct listnode *chnode;
796 struct listnode *chnextnode;
797 struct interface *ifp;
798 struct pim_interface *pim_ifp;
799 struct pim_ifchannel *ch;
800
801 /* scan all interfaces */
802 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
803 pim_ifp = ifp->info;
804 if (!pim_ifp)
805 continue;
806
807 /* scan per-interface (S,G) state */
808 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
809
810 if (ch->upstream != up)
811 continue;
812
813 pim_ifchannel_update_my_assert_metric(ch);
814
815 } /* scan iface channel list */
816 } /* scan iflist */
817 }
818
819 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
820 {
821 struct listnode *ifnode;
822 struct listnode *ifnextnode;
823 struct listnode *chnode;
824 struct listnode *chnextnode;
825 struct interface *ifp;
826 struct pim_interface *pim_ifp;
827 struct pim_ifchannel *ch;
828
829 /* scan all interfaces */
830 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
831 pim_ifp = ifp->info;
832 if (!pim_ifp)
833 continue;
834
835 /* scan per-interface (S,G) state */
836 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
837
838 if (ch->upstream != up)
839 continue;
840
841 pim_ifchannel_update_assert_tracking_desired(ch);
842
843 } /* scan iface channel list */
844 } /* scan iflist */
845 }
846
847 /*
848 * On an RP, the PMBR value must be cleared when the
849 * Keepalive Timer expires
850 */
851 static int
852 pim_upstream_keep_alive_timer (struct thread *t)
853 {
854 struct pim_upstream *up;
855
856 up = THREAD_ARG(t);
857
858 if (I_am_RP (up->sg.grp))
859 {
860 pim_br_clear_pmbr (&up->sg);
861 /*
862 * We need to do more here :)
863 * But this is the start.
864 */
865 }
866
867 pim_mroute_update_counters (up->channel_oil);
868
869 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt) &&
870 (up->channel_oil->cc.oldlastused >= up->channel_oil->cc.lastused))
871 {
872 pim_mroute_del (up->channel_oil);
873 THREAD_OFF (up->t_ka_timer);
874 THREAD_OFF (up->t_rs_timer);
875 THREAD_OFF (up->t_join_timer);
876 pim_joinprune_send (up->rpf.source_nexthop.interface, up->rpf.rpf_addr,
877 &up->sg, 0);
878 pim_upstream_del (up);
879 }
880 else
881 {
882 up->t_ka_timer = NULL;
883 pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
884 }
885
886 return 1;
887 }
888
889 void
890 pim_upstream_keep_alive_timer_start (struct pim_upstream *up,
891 uint32_t time)
892 {
893 THREAD_OFF (up->t_ka_timer);
894 THREAD_TIMER_ON (master,
895 up->t_ka_timer,
896 pim_upstream_keep_alive_timer,
897 up, time);
898 }
899
900 /*
901 * 4.2.1 Last-Hop Switchover to the SPT
902 *
903 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
904 * RP. Once traffic from sources to joined groups arrives at a last-hop
905 * router, it has the option of switching to receive the traffic on a
906 * shortest path tree (SPT).
907 *
908 * The decision for a router to switch to the SPT is controlled as
909 * follows:
910 *
911 * void
912 * CheckSwitchToSpt(S,G) {
913 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
914 * (+) pim_include(S,G) != NULL )
915 * AND SwitchToSptDesired(S,G) ) {
916 * # Note: Restarting the KAT will result in the SPT switch
917 * set KeepaliveTimer(S,G) to Keepalive_Period
918 * }
919 * }
920 *
921 * SwitchToSptDesired(S,G) is a policy function that is implementation
922 * defined. An "infinite threshold" policy can be implemented by making
923 * SwitchToSptDesired(S,G) return false all the time. A "switch on
924 * first packet" policy can be implemented by making
925 * SwitchToSptDesired(S,G) return true once a single packet has been
926 * received for the source and group.
927 */
928 int
929 pim_upstream_switch_to_spt_desired (struct prefix_sg *sg)
930 {
931 if (I_am_RP (sg->grp))
932 return 1;
933
934 return 0;
935 }
936
937 const char *
938 pim_upstream_state2str (enum pim_upstream_state join_state)
939 {
940 switch (join_state)
941 {
942 case PIM_UPSTREAM_NOTJOINED:
943 return "NtJnd";
944 break;
945 case PIM_UPSTREAM_JOINED:
946 return "Jnd";
947 break;
948 case PIM_UPSTREAM_JOIN_PENDING:
949 return "JPend";
950 break;
951 case PIM_UPSTREAM_PRUNE:
952 return "Prune";
953 break;
954 }
955 return "Unkwn";
956 }
957
958 static int
959 pim_upstream_register_stop_timer (struct thread *t)
960 {
961 struct pim_interface *pim_ifp;
962 struct pim_upstream *up;
963 struct pim_rpf *rpg;
964 struct ip ip_hdr;
965 up = THREAD_ARG (t);
966
967 THREAD_TIMER_OFF (up->t_rs_timer);
968 up->t_rs_timer = NULL;
969
970 if (PIM_DEBUG_TRACE)
971 {
972 zlog_debug ("%s: (S,G)=%s upstream register stop timer %s",
973 __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg),
974 pim_upstream_state2str(up->join_state));
975 }
976
977 switch (up->join_state)
978 {
979 case PIM_UPSTREAM_JOIN_PENDING:
980 up->join_state = PIM_UPSTREAM_JOINED;
981 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
982 break;
983 case PIM_UPSTREAM_JOINED:
984 break;
985 case PIM_UPSTREAM_PRUNE:
986 pim_ifp = up->rpf.source_nexthop.interface->info;
987 up->join_state = PIM_UPSTREAM_JOIN_PENDING;
988 pim_upstream_start_register_stop_timer (up, 1);
989
990 rpg = RP (up->sg.grp);
991 memset (&ip_hdr, 0, sizeof (struct ip));
992 ip_hdr.ip_p = PIM_IP_PROTO_PIM;
993 ip_hdr.ip_hl = 5;
994 ip_hdr.ip_v = 4;
995 ip_hdr.ip_src = up->sg.src;
996 ip_hdr.ip_dst = up->sg.grp;
997 ip_hdr.ip_len = htons (20);
998 // checksum is broken
999 pim_register_send ((uint8_t *)&ip_hdr, sizeof (struct ip),
1000 pim_ifp->primary_address, rpg, 1);
1001 break;
1002 default:
1003 break;
1004 }
1005
1006 return 0;
1007 }
1008
1009 void
1010 pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_register)
1011 {
1012 uint32_t time;
1013
1014 if (up->t_rs_timer)
1015 {
1016 THREAD_TIMER_OFF (up->t_rs_timer);
1017 up->t_rs_timer = NULL;
1018 }
1019
1020 if (!null_register)
1021 {
1022 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1023 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1024 time = lower + (random () % (upper - lower + 1)) - PIM_REGISTER_PROBE_PERIOD;
1025 }
1026 else
1027 time = PIM_REGISTER_PROBE_PERIOD;
1028
1029 if (PIM_DEBUG_TRACE)
1030 {
1031 zlog_debug ("%s: (S,G)=%s Starting upstream register stop timer %d",
1032 __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg), time);
1033 }
1034 THREAD_TIMER_ON (master, up->t_rs_timer,
1035 pim_upstream_register_stop_timer,
1036 up, time);
1037 }
1038
1039 /*
1040 * For a given upstream, determine the inherited_olist
1041 * and apply it.
1042 *
1043 * inherited_olist(S,G,rpt) =
1044 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1045 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1046 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1047 *
1048 * inherited_olist(S,G) =
1049 * inherited_olist(S,G,rpt) (+)
1050 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1051 *
1052 * return 1 if there are any output interfaces
1053 * return 0 if there are not any output interfaces
1054 */
1055 int
1056 pim_upstream_inherited_olist (struct pim_upstream *up)
1057 {
1058 struct pim_interface *pim_ifp;
1059 struct listnode *ifnextnode;
1060 struct listnode *chnextnode;
1061 struct pim_ifchannel *ch;
1062 struct listnode *chnode;
1063 struct listnode *ifnode;
1064 struct interface *ifp;
1065 int output_intf = 0;
1066
1067 pim_ifp = up->rpf.source_nexthop.interface->info;
1068 if (!up->channel_oil)
1069 up->channel_oil = pim_channel_oil_add (&up->sg, pim_ifp->mroute_vif_index);
1070
1071 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp))
1072 {
1073 pim_ifp = ifp->info;
1074 if (!pim_ifp)
1075 continue;
1076
1077 for (ALL_LIST_ELEMENTS (pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch))
1078 {
1079 if (pim_upstream_evaluate_join_desired_interface (up, ch))
1080 {
1081 pim_channel_add_oif (up->channel_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
1082 output_intf++;
1083 }
1084 }
1085 }
1086
1087 pim_upstream_switch (up, PIM_UPSTREAM_JOINED);
1088
1089 return output_intf;
1090 }