]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_upstream.c
pimd: Add more vrf debugging to pim_upstream.c
[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[%s] ref count: %d , flags: %d c_oil ref count %d (Pre decrement)",
171 __PRETTY_FUNCTION__, name, up->sg_str,
172 pim->vrf->name, up->ref_count,
173 up->flags, up->channel_oil->oil_ref_count);
174
175 --up->ref_count;
176
177 if (up->ref_count >= 1)
178 return up;
179
180 THREAD_OFF(up->t_ka_timer);
181 THREAD_OFF(up->t_rs_timer);
182 THREAD_OFF(up->t_msdp_reg_timer);
183
184 if (up->join_state == PIM_UPSTREAM_JOINED) {
185 pim_jp_agg_single_upstream_send(&up->rpf, up, 0);
186
187 if (up->sg.src.s_addr == INADDR_ANY) {
188 /* if a (*, G) entry in the joined state is being
189 * deleted we
190 * need to notify MSDP */
191 notify_msdp = true;
192 }
193 }
194
195 join_timer_stop(up);
196 pim_jp_agg_upstream_verification(up, false);
197 up->rpf.source_nexthop.interface = NULL;
198
199 if (up->sg.src.s_addr != INADDR_ANY) {
200 wheel_remove_item(pim->upstream_sg_wheel, up);
201 notify_msdp = true;
202 }
203
204 pim_upstream_remove_children(pim, up);
205 if (up->sources)
206 list_delete(up->sources);
207 up->sources = NULL;
208 pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__);
209 upstream_channel_oil_detach(up);
210
211 list_delete(up->ifchannels);
212 up->ifchannels = NULL;
213
214 /*
215 notice that listnode_delete() can't be moved
216 into pim_upstream_free() because the later is
217 called by list_delete_all_node()
218 */
219 if (up->parent && up->parent->sources)
220 listnode_delete(up->parent->sources, up);
221 up->parent = NULL;
222
223 listnode_delete(pim->upstream_list, up);
224 hash_release(pim->upstream_hash, up);
225
226 if (notify_msdp) {
227 pim_msdp_up_del(pim, &up->sg);
228 }
229
230 /* Deregister addr with Zebra NHT */
231 nht_p.family = AF_INET;
232 nht_p.prefixlen = IPV4_MAX_BITLEN;
233 nht_p.u.prefix4 = up->upstream_addr;
234 if (PIM_DEBUG_TRACE) {
235 char buf[PREFIX2STR_BUFFER];
236 prefix2str(&nht_p, buf, sizeof(buf));
237 zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT",
238 __PRETTY_FUNCTION__, up->sg_str, buf);
239 }
240 pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
241
242 pim_upstream_free(up);
243
244 return NULL;
245 }
246
247 void pim_upstream_send_join(struct pim_upstream *up)
248 {
249 if (PIM_DEBUG_TRACE) {
250 char rpf_str[PREFIX_STRLEN];
251 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str,
252 sizeof(rpf_str));
253 zlog_debug("%s: RPF'%s=%s(%s) for Interface %s",
254 __PRETTY_FUNCTION__, up->sg_str, rpf_str,
255 pim_upstream_state2str(up->join_state),
256 up->rpf.source_nexthop.interface->name);
257 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
258 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
259 __PRETTY_FUNCTION__, up->sg_str, rpf_str);
260 /* warning only */
261 }
262 }
263
264 /* send Join(S,G) to the current upstream neighbor */
265 pim_jp_agg_single_upstream_send(&up->rpf, up, 1 /* join */);
266 }
267
268 static int on_join_timer(struct thread *t)
269 {
270 struct pim_upstream *up;
271
272 up = THREAD_ARG(t);
273
274 /*
275 * In the case of a HFR we will not ahve anyone to send this to.
276 */
277 if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
278 return 0;
279
280 /*
281 * Don't send the join if the outgoing interface is a loopback
282 * But since this might change leave the join timer running
283 */
284 if (up->rpf.source_nexthop
285 .interface && !if_is_loopback(up->rpf.source_nexthop.interface))
286 pim_upstream_send_join(up);
287
288 join_timer_start(up);
289
290 return 0;
291 }
292
293 static void join_timer_stop(struct pim_upstream *up)
294 {
295 struct pim_neighbor *nbr;
296
297 THREAD_OFF(up->t_join_timer);
298
299 nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
300 up->rpf.rpf_addr.u.prefix4);
301
302 if (nbr)
303 pim_jp_agg_remove_group(nbr->upstream_jp_agg, up);
304
305 pim_jp_agg_upstream_verification(up, false);
306 }
307
308 void join_timer_start(struct pim_upstream *up)
309 {
310 struct pim_neighbor *nbr = NULL;
311
312 if (up->rpf.source_nexthop.interface) {
313 nbr = pim_neighbor_find(up->rpf.source_nexthop.interface,
314 up->rpf.rpf_addr.u.prefix4);
315
316 if (PIM_DEBUG_PIM_EVENTS) {
317 zlog_debug(
318 "%s: starting %d sec timer for upstream (S,G)=%s",
319 __PRETTY_FUNCTION__, qpim_t_periodic,
320 up->sg_str);
321 }
322 }
323
324 if (nbr)
325 pim_jp_agg_add_group(nbr->upstream_jp_agg, up, 1);
326 else {
327 THREAD_OFF(up->t_join_timer);
328 thread_add_timer(master, on_join_timer, up, qpim_t_periodic,
329 &up->t_join_timer);
330 }
331 pim_jp_agg_upstream_verification(up, true);
332 }
333
334 /*
335 * This is only called when we are switching the upstream
336 * J/P from one neighbor to another
337 *
338 * As such we need to remove from the old list and
339 * add to the new list.
340 */
341 void pim_upstream_join_timer_restart(struct pim_upstream *up,
342 struct pim_rpf *old)
343 {
344 // THREAD_OFF(up->t_join_timer);
345 join_timer_start(up);
346 }
347
348 static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
349 int interval_msec)
350 {
351 if (PIM_DEBUG_PIM_EVENTS) {
352 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
353 __PRETTY_FUNCTION__, interval_msec, up->sg_str);
354 }
355
356 THREAD_OFF(up->t_join_timer);
357 thread_add_timer_msec(master, on_join_timer, up, interval_msec,
358 &up->t_join_timer);
359 }
360
361 void pim_upstream_join_suppress(struct pim_upstream *up,
362 struct in_addr rpf_addr, int holdtime)
363 {
364 long t_joinsuppress_msec;
365 long join_timer_remain_msec;
366
367 t_joinsuppress_msec =
368 MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
369 1000 * holdtime);
370
371 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
372
373 if (PIM_DEBUG_TRACE) {
374 char rpf_str[INET_ADDRSTRLEN];
375 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
376 zlog_debug(
377 "%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
378 __FILE__, __PRETTY_FUNCTION__, up->sg_str, rpf_str,
379 join_timer_remain_msec, t_joinsuppress_msec);
380 }
381
382 if (join_timer_remain_msec < t_joinsuppress_msec) {
383 if (PIM_DEBUG_TRACE) {
384 zlog_debug(
385 "%s %s: suppressing Join(S,G)=%s for %ld msec",
386 __FILE__, __PRETTY_FUNCTION__, up->sg_str,
387 t_joinsuppress_msec);
388 }
389
390 pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
391 }
392 }
393
394 void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
395 struct pim_upstream *up)
396 {
397 long join_timer_remain_msec;
398 int t_override_msec;
399
400 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
401 t_override_msec =
402 pim_if_t_override_msec(up->rpf.source_nexthop.interface);
403
404 if (PIM_DEBUG_TRACE) {
405 char rpf_str[INET_ADDRSTRLEN];
406 pim_inet4_dump("<rpf?>", up->rpf.rpf_addr.u.prefix4, rpf_str,
407 sizeof(rpf_str));
408 zlog_debug(
409 "%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
410 debug_label, up->sg_str, rpf_str,
411 join_timer_remain_msec, t_override_msec);
412 }
413
414 if (join_timer_remain_msec > t_override_msec) {
415 if (PIM_DEBUG_TRACE) {
416 zlog_debug(
417 "%s: decreasing (S,G)=%s join timer to t_override=%d msec",
418 debug_label, up->sg_str, t_override_msec);
419 }
420
421 pim_upstream_join_timer_restart_msec(up, t_override_msec);
422 }
423 }
424
425 static void forward_on(struct pim_upstream *up)
426 {
427 struct listnode *chnode;
428 struct listnode *chnextnode;
429 struct pim_ifchannel *ch = NULL;
430
431 /* scan (S,G) state */
432 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
433 if (pim_macro_chisin_oiflist(ch))
434 pim_forward_start(ch);
435
436 } /* scan iface channel list */
437 }
438
439 static void forward_off(struct pim_upstream *up)
440 {
441 struct listnode *chnode;
442 struct listnode *chnextnode;
443 struct pim_ifchannel *ch;
444
445 /* scan per-interface (S,G) state */
446 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
447
448 pim_forward_stop(ch, false);
449
450 } /* scan iface channel list */
451 }
452
453 static int pim_upstream_could_register(struct pim_upstream *up)
454 {
455 struct pim_interface *pim_ifp = NULL;
456
457 if (up->rpf.source_nexthop.interface)
458 pim_ifp = up->rpf.source_nexthop.interface->info;
459 else {
460 if (PIM_DEBUG_TRACE)
461 zlog_debug("%s: up %s RPF is not present",
462 __PRETTY_FUNCTION__, up->sg_str);
463 }
464
465 if (pim_ifp && PIM_I_am_DR(pim_ifp)
466 && pim_if_connected_to_source(up->rpf.source_nexthop.interface,
467 up->sg.src))
468 return 1;
469
470 return 0;
471 }
472
473 /* Source registration is supressed for SSM groups. When the SSM range changes
474 * we re-revaluate register setup for existing upstream entries */
475 void pim_upstream_register_reevaluate(struct pim_instance *pim)
476 {
477 struct listnode *upnode;
478 struct pim_upstream *up;
479
480 for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
481 /* If FHR is set CouldRegister is True. Also check if the flow
482 * is actually active; if it is not kat setup will trigger
483 * source
484 * registration whenever the flow becomes active. */
485 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) || !up->t_ka_timer)
486 continue;
487
488 if (pim_is_grp_ssm(pim, up->sg.grp)) {
489 /* clear the register state for SSM groups */
490 if (up->reg_state != PIM_REG_NOINFO) {
491 if (PIM_DEBUG_PIM_EVENTS)
492 zlog_debug(
493 "Clear register for %s as G is now SSM",
494 up->sg_str);
495 /* remove regiface from the OIL if it is there*/
496 pim_channel_del_oif(up->channel_oil,
497 pim->regiface,
498 PIM_OIF_FLAG_PROTO_PIM);
499 up->reg_state = PIM_REG_NOINFO;
500 }
501 } else {
502 /* register ASM sources with the RP */
503 if (up->reg_state == PIM_REG_NOINFO) {
504 if (PIM_DEBUG_PIM_EVENTS)
505 zlog_debug(
506 "Register %s as G is now ASM",
507 up->sg_str);
508 pim_channel_add_oif(up->channel_oil,
509 pim->regiface,
510 PIM_OIF_FLAG_PROTO_PIM);
511 up->reg_state = PIM_REG_JOIN;
512 }
513 }
514 }
515 }
516
517 void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
518 enum pim_upstream_state new_state)
519 {
520 enum pim_upstream_state old_state = up->join_state;
521
522 if (PIM_DEBUG_PIM_EVENTS) {
523 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
524 __PRETTY_FUNCTION__, up->sg_str,
525 pim_upstream_state2str(up->join_state),
526 pim_upstream_state2str(new_state));
527 }
528
529 up->join_state = new_state;
530 if (old_state != new_state)
531 up->state_transition = pim_time_monotonic_sec();
532
533 pim_upstream_update_assert_tracking_desired(up);
534
535 if (new_state == PIM_UPSTREAM_JOINED) {
536 if (old_state != PIM_UPSTREAM_JOINED) {
537 int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags);
538 forward_on(up);
539 pim_msdp_up_join_state_changed(pim, up);
540 if (pim_upstream_could_register(up)) {
541 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
542 if (!old_fhr
543 && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(
544 up->flags)) {
545 pim_upstream_keep_alive_timer_start(
546 up, pim->keep_alive_time);
547 pim_register_join(up);
548 }
549 } else {
550 pim_upstream_send_join(up);
551 join_timer_start(up);
552 }
553 } else {
554 forward_on(up);
555 }
556 } else {
557
558 forward_off(up);
559 if (old_state == PIM_UPSTREAM_JOINED)
560 pim_msdp_up_join_state_changed(pim, up);
561
562 /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
563 RP.
564 If I am RP for G then send S,G prune to its IIF. */
565 if (pim_upstream_is_sg_rpt(up) && up->parent
566 && !I_am_RP(pim, up->sg.grp)) {
567 if (PIM_DEBUG_PIM_TRACE_DETAIL)
568 zlog_debug(
569 "%s: *,G IIF %s S,G IIF %s ",
570 __PRETTY_FUNCTION__,
571 up->parent->rpf.source_nexthop
572 .interface->name,
573 up->rpf.source_nexthop.interface->name);
574 pim_jp_agg_single_upstream_send(&up->parent->rpf,
575 up->parent,
576 1 /* (W,G) Join */);
577 } else
578 pim_jp_agg_single_upstream_send(&up->rpf, up,
579 0 /* prune */);
580 join_timer_stop(up);
581 }
582 }
583
584 int pim_upstream_compare(void *arg1, void *arg2)
585 {
586 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
587 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
588
589 if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr))
590 return -1;
591
592 if (ntohl(up1->sg.grp.s_addr) > ntohl(up2->sg.grp.s_addr))
593 return 1;
594
595 if (ntohl(up1->sg.src.s_addr) < ntohl(up2->sg.src.s_addr))
596 return -1;
597
598 if (ntohl(up1->sg.src.s_addr) > ntohl(up2->sg.src.s_addr))
599 return 1;
600
601 return 0;
602 }
603
604 static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
605 struct prefix_sg *sg,
606 struct interface *incoming,
607 int flags,
608 struct pim_ifchannel *ch)
609 {
610 enum pim_rpf_result rpf_result;
611 struct pim_interface *pim_ifp;
612 struct pim_upstream *up;
613
614 up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
615 if (!up) {
616 zlog_err("%s: PIM XCALLOC(%zu) failure", __PRETTY_FUNCTION__,
617 sizeof(*up));
618 return NULL;
619 }
620
621 up->sg = *sg;
622 pim_str_sg_set(sg, up->sg_str);
623 if (ch)
624 ch->upstream = up;
625
626 up = hash_get(pim->upstream_hash, up, hash_alloc_intern);
627 if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src,
628 sg->grp)) {
629 if (PIM_DEBUG_TRACE)
630 zlog_debug("%s: Received a (*,G) with no RP configured",
631 __PRETTY_FUNCTION__);
632
633 hash_release(pim->upstream_hash, up);
634 XFREE(MTYPE_PIM_UPSTREAM, up);
635 return NULL;
636 }
637
638 up->parent = pim_upstream_find_parent(pim, up);
639 if (up->sg.src.s_addr == INADDR_ANY) {
640 up->sources = list_new();
641 up->sources->cmp = pim_upstream_compare;
642 } else
643 up->sources = NULL;
644
645 pim_upstream_find_new_children(pim, up);
646 up->flags = flags;
647 up->ref_count = 1;
648 up->t_join_timer = NULL;
649 up->t_ka_timer = NULL;
650 up->t_rs_timer = NULL;
651 up->t_msdp_reg_timer = NULL;
652 up->join_state = PIM_UPSTREAM_NOTJOINED;
653 up->reg_state = PIM_REG_NOINFO;
654 up->state_transition = pim_time_monotonic_sec();
655 up->channel_oil = NULL;
656 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
657
658 up->rpf.source_nexthop.interface = NULL;
659 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
660 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
661 PIM_NET_INADDR_ANY;
662 up->rpf.source_nexthop.mrib_metric_preference =
663 qpim_infinite_assert_metric.metric_preference;
664 up->rpf.source_nexthop.mrib_route_metric =
665 qpim_infinite_assert_metric.route_metric;
666 up->rpf.rpf_addr.family = AF_INET;
667 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
668
669 up->ifchannels = list_new();
670 up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
671
672 if (up->sg.src.s_addr != INADDR_ANY)
673 wheel_add_item(pim->upstream_sg_wheel, up);
674
675 rpf_result = pim_rpf_update(pim, up, NULL, 1);
676 if (rpf_result == PIM_RPF_FAILURE) {
677 struct prefix nht_p;
678
679 if (PIM_DEBUG_TRACE)
680 zlog_debug(
681 "%s: Attempting to create upstream(%s), Unable to RPF for source",
682 __PRETTY_FUNCTION__, up->sg_str);
683
684 nht_p.family = AF_INET;
685 nht_p.prefixlen = IPV4_MAX_BITLEN;
686 nht_p.u.prefix4 = up->upstream_addr;
687 pim_delete_tracked_nexthop(pim, &nht_p, up, NULL);
688
689 if (up->parent) {
690 listnode_delete(up->parent->sources, up);
691 up->parent = NULL;
692 }
693
694 if (up->sg.src.s_addr != INADDR_ANY)
695 wheel_remove_item(pim->upstream_sg_wheel, up);
696
697 pim_upstream_remove_children(pim, up);
698 if (up->sources)
699 list_delete(up->sources);
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 listnode *node;
868 struct pim_ifchannel *ch, *starch;
869 struct pim_upstream *starup = up->parent;
870 int ret = 0;
871
872 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, ifp)) {
873 if (!ifp->info)
874 continue;
875
876 ch = pim_ifchannel_find(ifp, &up->sg);
877
878 if (starup)
879 starch = pim_ifchannel_find(ifp, &starup->sg);
880 else
881 starch = NULL;
882
883 if (!ch && !starch)
884 continue;
885
886 ret += pim_upstream_evaluate_join_desired_interface(up, ch,
887 starch);
888 } /* scan iface channel list */
889
890 return ret; /* false */
891 }
892
893 /*
894 See also pim_upstream_evaluate_join_desired() above.
895 */
896 void pim_upstream_update_join_desired(struct pim_instance *pim,
897 struct pim_upstream *up)
898 {
899 int was_join_desired; /* boolean */
900 int is_join_desired; /* boolean */
901
902 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
903
904 is_join_desired = pim_upstream_evaluate_join_desired(pim, up);
905 if (is_join_desired)
906 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
907 else
908 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
909
910 /* switched from false to true */
911 if (is_join_desired && !was_join_desired) {
912 pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
913 return;
914 }
915
916 /* switched from true to false */
917 if (!is_join_desired && was_join_desired) {
918 pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
919 return;
920 }
921 }
922
923 /*
924 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
925 Transitions from Joined State
926 RPF'(S,G) GenID changes
927
928 The upstream (S,G) state machine remains in Joined state. If the
929 Join Timer is set to expire in more than t_override seconds, reset
930 it so that it expires after t_override seconds.
931 */
932 void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
933 struct in_addr neigh_addr)
934 {
935 struct listnode *up_node;
936 struct listnode *up_nextnode;
937 struct pim_upstream *up;
938
939 /*
940 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
941 */
942 for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
943
944 if (PIM_DEBUG_TRACE) {
945 char neigh_str[INET_ADDRSTRLEN];
946 char rpf_addr_str[PREFIX_STRLEN];
947 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str,
948 sizeof(neigh_str));
949 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str,
950 sizeof(rpf_addr_str));
951 zlog_debug(
952 "%s: matching neigh=%s against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s",
953 __PRETTY_FUNCTION__, neigh_str, up->sg_str, 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("kat expired on %s[%s]; remove stream reference",
1111 up->sg_str, pim->vrf->name);
1112 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
1113 pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
1114 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
1115 struct pim_upstream *parent = up->parent;
1116
1117 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
1118 pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
1119
1120 if (parent) {
1121 pim_jp_agg_single_upstream_send(&parent->rpf,
1122 parent, true);
1123 }
1124 }
1125
1126 return 0;
1127 }
1128
1129 void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time)
1130 {
1131 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1132 if (PIM_DEBUG_TRACE)
1133 zlog_debug("kat start on %s with no stream reference",
1134 up->sg_str);
1135 }
1136 THREAD_OFF(up->t_ka_timer);
1137 thread_add_timer(master, pim_upstream_keep_alive_timer, up, time,
1138 &up->t_ka_timer);
1139
1140 /* any time keepalive is started against a SG we will have to
1141 * re-evaluate our active source database */
1142 pim_msdp_sa_local_update(up);
1143 }
1144
1145 /* MSDP on RP needs to know if a source is registerable to this RP */
1146 static int pim_upstream_msdp_reg_timer(struct thread *t)
1147 {
1148 struct pim_upstream *up = THREAD_ARG(t);
1149 struct pim_instance *pim = up->channel_oil->pim;
1150
1151 /* source is no longer active - pull the SA from MSDP's cache */
1152 pim_msdp_sa_local_del(pim, &up->sg);
1153 return 1;
1154 }
1155 void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
1156 {
1157 THREAD_OFF(up->t_msdp_reg_timer);
1158 thread_add_timer(master, pim_upstream_msdp_reg_timer, up,
1159 PIM_MSDP_REG_RXED_PERIOD, &up->t_msdp_reg_timer);
1160
1161 pim_msdp_sa_local_update(up);
1162 }
1163
1164 /*
1165 * 4.2.1 Last-Hop Switchover to the SPT
1166 *
1167 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1168 * RP. Once traffic from sources to joined groups arrives at a last-hop
1169 * router, it has the option of switching to receive the traffic on a
1170 * shortest path tree (SPT).
1171 *
1172 * The decision for a router to switch to the SPT is controlled as
1173 * follows:
1174 *
1175 * void
1176 * CheckSwitchToSpt(S,G) {
1177 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1178 * (+) pim_include(S,G) != NULL )
1179 * AND SwitchToSptDesired(S,G) ) {
1180 * # Note: Restarting the KAT will result in the SPT switch
1181 * set KeepaliveTimer(S,G) to Keepalive_Period
1182 * }
1183 * }
1184 *
1185 * SwitchToSptDesired(S,G) is a policy function that is implementation
1186 * defined. An "infinite threshold" policy can be implemented by making
1187 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1188 * first packet" policy can be implemented by making
1189 * SwitchToSptDesired(S,G) return true once a single packet has been
1190 * received for the source and group.
1191 */
1192 int pim_upstream_switch_to_spt_desired(struct pim_instance *pim,
1193 struct prefix_sg *sg)
1194 {
1195 if (I_am_RP(pim, sg->grp))
1196 return 1;
1197
1198 return 0;
1199 }
1200
1201 int pim_upstream_is_sg_rpt(struct pim_upstream *up)
1202 {
1203 struct listnode *chnode;
1204 struct pim_ifchannel *ch;
1205
1206 for (ALL_LIST_ELEMENTS_RO(up->ifchannels, chnode, ch)) {
1207 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1208 return 1;
1209 }
1210
1211 return 0;
1212 }
1213 /*
1214 * After receiving a packet set SPTbit:
1215 * void
1216 * Update_SPTbit(S,G,iif) {
1217 * if ( iif == RPF_interface(S)
1218 * AND JoinDesired(S,G) == TRUE
1219 * AND ( DirectlyConnected(S) == TRUE
1220 * OR RPF_interface(S) != RPF_interface(RP(G))
1221 * OR inherited_olist(S,G,rpt) == NULL
1222 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1223 * ( RPF'(S,G) != NULL ) )
1224 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1225 * Set SPTbit(S,G) to TRUE
1226 * }
1227 * }
1228 */
1229 void pim_upstream_set_sptbit(struct pim_upstream *up,
1230 struct interface *incoming)
1231 {
1232 struct pim_upstream *starup = up->parent;
1233
1234 // iif == RPF_interfvace(S)
1235 if (up->rpf.source_nexthop.interface != incoming) {
1236 if (PIM_DEBUG_TRACE)
1237 zlog_debug(
1238 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1239 __PRETTY_FUNCTION__, incoming->name,
1240 up->rpf.source_nexthop.interface->name);
1241 return;
1242 }
1243
1244 // AND JoinDesired(S,G) == TRUE
1245 // FIXME
1246
1247 // DirectlyConnected(S) == TRUE
1248 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1249 up->sg.src)) {
1250 if (PIM_DEBUG_TRACE)
1251 zlog_debug("%s: %s is directly connected to the source",
1252 __PRETTY_FUNCTION__, up->sg_str);
1253 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1254 return;
1255 }
1256
1257 // OR RPF_interface(S) != RPF_interface(RP(G))
1258 if (!starup
1259 || up->rpf.source_nexthop
1260 .interface != starup->rpf.source_nexthop.interface) {
1261 if (PIM_DEBUG_TRACE)
1262 zlog_debug(
1263 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1264 __PRETTY_FUNCTION__, up->sg_str);
1265 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1266 return;
1267 }
1268
1269 // OR inherited_olist(S,G,rpt) == NULL
1270 if (pim_upstream_is_sg_rpt(up)
1271 && pim_upstream_empty_inherited_olist(up)) {
1272 if (PIM_DEBUG_TRACE)
1273 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1274 __PRETTY_FUNCTION__, up->sg_str);
1275 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1276 return;
1277 }
1278
1279 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1280 // ( RPF'(S,G) != NULL ) )
1281 if (up->parent && pim_rpf_is_same(&up->rpf, &up->parent->rpf)) {
1282 if (PIM_DEBUG_TRACE)
1283 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1284 __PRETTY_FUNCTION__, up->sg_str);
1285 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1286 return;
1287 }
1288
1289 return;
1290 }
1291
1292 const char *pim_upstream_state2str(enum pim_upstream_state join_state)
1293 {
1294 switch (join_state) {
1295 case PIM_UPSTREAM_NOTJOINED:
1296 return "NotJoined";
1297 break;
1298 case PIM_UPSTREAM_JOINED:
1299 return "Joined";
1300 break;
1301 }
1302 return "Unknown";
1303 }
1304
1305 const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str)
1306 {
1307 switch (reg_state) {
1308 case PIM_REG_NOINFO:
1309 strcpy(state_str, "RegNoInfo");
1310 break;
1311 case PIM_REG_JOIN:
1312 strcpy(state_str, "RegJoined");
1313 break;
1314 case PIM_REG_JOIN_PENDING:
1315 strcpy(state_str, "RegJoinPend");
1316 break;
1317 case PIM_REG_PRUNE:
1318 strcpy(state_str, "RegPrune");
1319 break;
1320 default:
1321 strcpy(state_str, "RegUnknown");
1322 }
1323 return state_str;
1324 }
1325
1326 static int pim_upstream_register_stop_timer(struct thread *t)
1327 {
1328 struct pim_interface *pim_ifp;
1329 struct pim_instance *pim;
1330 struct pim_upstream *up;
1331 struct pim_rpf *rpg;
1332 struct ip ip_hdr;
1333 up = THREAD_ARG(t);
1334 pim = up->channel_oil->pim;
1335
1336 if (PIM_DEBUG_TRACE) {
1337 char state_str[PIM_REG_STATE_STR_LEN];
1338 zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
1339 __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
1340 pim_reg_state2str(up->reg_state, state_str));
1341 }
1342
1343 switch (up->reg_state) {
1344 case PIM_REG_JOIN_PENDING:
1345 up->reg_state = PIM_REG_JOIN;
1346 pim_channel_add_oif(up->channel_oil, pim->regiface,
1347 PIM_OIF_FLAG_PROTO_PIM);
1348 break;
1349 case PIM_REG_JOIN:
1350 break;
1351 case PIM_REG_PRUNE:
1352 pim_ifp = up->rpf.source_nexthop.interface->info;
1353 if (!pim_ifp) {
1354 if (PIM_DEBUG_TRACE)
1355 zlog_debug(
1356 "%s: Interface: %s is not configured for pim",
1357 __PRETTY_FUNCTION__,
1358 up->rpf.source_nexthop.interface->name);
1359 return 0;
1360 }
1361 up->reg_state = PIM_REG_JOIN_PENDING;
1362 pim_upstream_start_register_stop_timer(up, 1);
1363
1364 if (((up->channel_oil->cc.lastused / 100)
1365 > PIM_KEEPALIVE_PERIOD)
1366 && (I_am_RP(pim_ifp->pim, up->sg.grp))) {
1367 if (PIM_DEBUG_TRACE)
1368 zlog_debug(
1369 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1370 __PRETTY_FUNCTION__);
1371 return 0;
1372 }
1373 rpg = RP(pim_ifp->pim, up->sg.grp);
1374 if (!rpg) {
1375 if (PIM_DEBUG_TRACE)
1376 zlog_debug(
1377 "%s: Cannot send register for %s no RPF to the RP",
1378 __PRETTY_FUNCTION__, up->sg_str);
1379 return 0;
1380 }
1381 memset(&ip_hdr, 0, sizeof(struct ip));
1382 ip_hdr.ip_p = PIM_IP_PROTO_PIM;
1383 ip_hdr.ip_hl = 5;
1384 ip_hdr.ip_v = 4;
1385 ip_hdr.ip_src = up->sg.src;
1386 ip_hdr.ip_dst = up->sg.grp;
1387 ip_hdr.ip_len = htons(20);
1388 // checksum is broken
1389 pim_register_send((uint8_t *)&ip_hdr, sizeof(struct ip),
1390 pim_ifp->primary_address, rpg, 1, up);
1391 break;
1392 default:
1393 break;
1394 }
1395
1396 return 0;
1397 }
1398
1399 void pim_upstream_start_register_stop_timer(struct pim_upstream *up,
1400 int null_register)
1401 {
1402 uint32_t time;
1403
1404 THREAD_TIMER_OFF(up->t_rs_timer);
1405
1406 if (!null_register) {
1407 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1408 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1409 time = lower + (random() % (upper - lower + 1))
1410 - PIM_REGISTER_PROBE_PERIOD;
1411 } else
1412 time = PIM_REGISTER_PROBE_PERIOD;
1413
1414 if (PIM_DEBUG_TRACE) {
1415 zlog_debug(
1416 "%s: (S,G)=%s Starting upstream register stop timer %d",
1417 __PRETTY_FUNCTION__, up->sg_str, time);
1418 }
1419 thread_add_timer(master, pim_upstream_register_stop_timer, up, time,
1420 &up->t_rs_timer);
1421 }
1422
1423 int pim_upstream_inherited_olist_decide(struct pim_instance *pim,
1424 struct pim_upstream *up)
1425 {
1426 struct interface *ifp;
1427 struct pim_interface *pim_ifp = NULL;
1428 struct pim_ifchannel *ch, *starch;
1429 struct listnode *node;
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_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), node, 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(pim->upstream_list);
1550 pim->upstream_list = NULL;
1551
1552 if (pim->upstream_hash)
1553 hash_free(pim->upstream_hash);
1554 pim->upstream_hash = NULL;
1555 }
1556
1557 int pim_upstream_equal(const void *arg1, const void *arg2)
1558 {
1559 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1560 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
1561
1562 if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr)
1563 && (up1->sg.src.s_addr == up2->sg.src.s_addr))
1564 return 1;
1565
1566 return 0;
1567 }
1568
1569 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1570 * the cases where kat has to be restarted on rxing traffic -
1571 *
1572 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1573 * set KeepaliveTimer(S,G) to Keepalive_Period
1574 * # Note: a register state transition or UpstreamJPState(S,G)
1575 * # transition may happen as a result of restarting
1576 * # KeepaliveTimer, and must be dealt with here.
1577 * }
1578 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1579 * inherited_olist(S,G) != NULL ) {
1580 * set KeepaliveTimer(S,G) to Keepalive_Period
1581 * }
1582 */
1583 static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
1584 {
1585 struct pim_instance *pim = up->channel_oil->pim;
1586
1587 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1588 * so we will skip that here */
1589 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1590 up->sg.src)) {
1591 return true;
1592 }
1593
1594 if ((up->join_state == PIM_UPSTREAM_JOINED)
1595 && !pim_upstream_empty_inherited_olist(up)) {
1596 /* XXX: I have added this RP check just for 3.2 and it's a
1597 * digression from
1598 * what rfc-4601 says. Till now we were only running KAT on FHR
1599 * and RP and
1600 * there is some angst around making the change to run it all
1601 * routers that
1602 * maintain the (S, G) state. This is tracked via CM-13601 and
1603 * MUST be
1604 * removed to handle spt turn-arounds correctly in a 3-tier clos
1605 */
1606 if (I_am_RP(pim, up->sg.grp))
1607 return true;
1608 }
1609
1610 return false;
1611 }
1612
1613 /*
1614 * Code to check and see if we've received packets on a S,G mroute
1615 * and if so to set the SPT bit appropriately
1616 */
1617 static void pim_upstream_sg_running(void *arg)
1618 {
1619 struct pim_upstream *up = (struct pim_upstream *)arg;
1620 struct pim_instance *pim = up->channel_oil->pim;
1621
1622 // No packet can have arrived here if this is the case
1623 if (!up->channel_oil->installed) {
1624 if (PIM_DEBUG_TRACE)
1625 zlog_debug("%s: %s is not installed in mroute",
1626 __PRETTY_FUNCTION__, up->sg_str);
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, pim->vrf->name);
1643 pim_upstream_inherited_olist_decide(pim, up);
1644 up->channel_oil->oil_inherited_rescan = 0;
1645 }
1646 pim_mroute_update_counters(up->channel_oil);
1647
1648 // Have we seen packets?
1649 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt)
1650 && (up->channel_oil->cc.lastused / 100 > 30)) {
1651 if (PIM_DEBUG_TRACE) {
1652 zlog_debug(
1653 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1654 __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
1655 up->channel_oil->cc.oldpktcnt,
1656 up->channel_oil->cc.pktcnt,
1657 up->channel_oil->cc.lastused / 100);
1658 }
1659 return;
1660 }
1661
1662 if (pim_upstream_kat_start_ok(up)) {
1663 /* Add a source reference to the stream if
1664 * one doesn't already exist */
1665 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1666 if (PIM_DEBUG_TRACE)
1667 zlog_debug(
1668 "source reference created on kat restart %s[%s]",
1669 up->sg_str, pim->vrf->name);
1670
1671 pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
1672 __PRETTY_FUNCTION__);
1673 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
1674 pim_upstream_fhr_kat_start(up);
1675 }
1676 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
1677 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
1678 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
1679
1680 if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) {
1681 pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
1682 }
1683 return;
1684 }
1685
1686 void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim)
1687 {
1688 struct pim_upstream *up;
1689 struct listnode *node;
1690
1691 for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
1692 if (up->sg.src.s_addr != INADDR_ANY)
1693 continue;
1694
1695 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags))
1696 continue;
1697
1698 pim_channel_add_oif(up->channel_oil, pim->regiface,
1699 PIM_OIF_FLAG_PROTO_IGMP);
1700 }
1701 }
1702
1703 void pim_upstream_spt_prefix_list_update(struct pim_instance *pim,
1704 struct prefix_list *pl)
1705 {
1706 const char *pname = prefix_list_name(pl);
1707
1708 if (pim->spt.plist && strcmp(pim->spt.plist, pname) == 0) {
1709 pim_upstream_remove_lhr_star_pimreg(pim, pname);
1710 }
1711 }
1712
1713 /*
1714 * nlist -> The new prefix list
1715 *
1716 * Per Group Application of pimreg to the OIL
1717 * If the prefix list tells us DENY then
1718 * we need to Switchover to SPT immediate
1719 * so add the pimreg.
1720 * If the prefix list tells us to ACCEPT than
1721 * we need to Never do the SPT so remove
1722 * the interface
1723 *
1724 */
1725 void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim,
1726 const char *nlist)
1727 {
1728 struct pim_upstream *up;
1729 struct listnode *node;
1730 struct prefix_list *np;
1731 struct prefix g;
1732 enum prefix_list_type apply_new;
1733
1734 np = prefix_list_lookup(AFI_IP, nlist);
1735
1736 g.family = AF_INET;
1737 g.prefixlen = IPV4_MAX_PREFIXLEN;
1738
1739 for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
1740 if (up->sg.src.s_addr != INADDR_ANY)
1741 continue;
1742
1743 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags))
1744 continue;
1745
1746 if (!nlist) {
1747 pim_channel_del_oif(up->channel_oil, pim->regiface,
1748 PIM_OIF_FLAG_PROTO_IGMP);
1749 continue;
1750 }
1751 g.u.prefix4 = up->sg.grp;
1752 apply_new = prefix_list_apply(np, &g);
1753 if (apply_new == PREFIX_DENY)
1754 pim_channel_add_oif(up->channel_oil, pim->regiface,
1755 PIM_OIF_FLAG_PROTO_IGMP);
1756 else
1757 pim_channel_del_oif(up->channel_oil, pim->regiface,
1758 PIM_OIF_FLAG_PROTO_IGMP);
1759 }
1760 }
1761
1762 void pim_upstream_init(struct pim_instance *pim)
1763 {
1764 char hash_name[64];
1765
1766 pim->upstream_sg_wheel =
1767 wheel_init(master, 31000, 100, pim_upstream_hash_key,
1768 pim_upstream_sg_running);
1769
1770 snprintf(hash_name, 64, "PIM %s Upstream Hash",
1771 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 }