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