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