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