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