]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_upstream.c
pimd: pim_rp.c -> convert pimg to pim
[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(pimg, &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 pimg->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 pimg->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 pim_ifp = incoming->info;
675 nht_p.family = AF_INET;
676 nht_p.prefixlen = IPV4_MAX_BITLEN;
677 nht_p.u.prefix4 = up->upstream_addr;
678 pim_delete_tracked_nexthop(pim_ifp->pim, &nht_p, up, NULL);
679
680 if (up->parent) {
681 listnode_delete(up->parent->sources, up);
682 up->parent = NULL;
683 }
684
685 if (up->sg.src.s_addr != INADDR_ANY)
686 wheel_remove_item(pim_upstream_sg_wheel, up);
687
688 pim_upstream_remove_children(up);
689 if (up->sources)
690 list_delete(up->sources);
691
692 hash_release(pim_upstream_hash, up);
693 XFREE(MTYPE_PIM_UPSTREAM, up);
694 return NULL;
695 }
696
697 if (up->rpf.source_nexthop.interface) {
698 pim_ifp = up->rpf.source_nexthop.interface->info;
699 if (pim_ifp)
700 up->channel_oil = pim_channel_oil_add(
701 &up->sg, pim_ifp->mroute_vif_index);
702 }
703 listnode_add_sort(pim_upstream_list, up);
704
705 if (PIM_DEBUG_TRACE) {
706 zlog_debug(
707 "%s: Created Upstream %s upstream_addr %s ref count %d increment",
708 __PRETTY_FUNCTION__, up->sg_str,
709 inet_ntoa(up->upstream_addr), up->ref_count);
710 }
711
712 return up;
713 }
714
715 struct pim_upstream *pim_upstream_find(struct prefix_sg *sg)
716 {
717 struct pim_upstream lookup;
718 struct pim_upstream *up = NULL;
719
720 lookup.sg = *sg;
721 up = hash_lookup(pim_upstream_hash, &lookup);
722 return up;
723 }
724
725 struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg,
726 struct interface *incoming,
727 int flags, const char *name)
728 {
729 struct pim_upstream *up;
730
731 up = pim_upstream_find(sg);
732
733 if (up) {
734 if (!(up->flags & flags)) {
735 up->flags |= flags;
736 up->ref_count++;
737 if (PIM_DEBUG_TRACE)
738 zlog_debug(
739 "%s(%s): upstream %s ref count %d increment",
740 __PRETTY_FUNCTION__, name, up->sg_str,
741 up->ref_count);
742 }
743 } else
744 up = pim_upstream_add(sg, incoming, flags, name);
745
746 return up;
747 }
748
749 void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name)
750 {
751 up->flags |= flags;
752 ++up->ref_count;
753 if (PIM_DEBUG_TRACE)
754 zlog_debug("%s(%s): upstream %s ref count %d increment",
755 __PRETTY_FUNCTION__, name, up->sg_str,
756 up->ref_count);
757 }
758
759 struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
760 struct interface *incoming, int flags,
761 const char *name)
762 {
763 struct pim_upstream *up = NULL;
764 int found = 0;
765 up = pim_upstream_find(sg);
766 if (up) {
767 pim_upstream_ref(up, flags, name);
768 found = 1;
769 } else {
770 up = pim_upstream_new(sg, incoming, flags);
771 }
772
773 if (PIM_DEBUG_TRACE) {
774 if (up) {
775 char buf[PREFIX2STR_BUFFER];
776 prefix2str(&up->rpf.rpf_addr, buf, sizeof(buf));
777 zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d",
778 __PRETTY_FUNCTION__, name,
779 up->sg_str, buf, up->rpf.source_nexthop.interface ?
780 up->rpf.source_nexthop.interface->name : "NIL" ,
781 found, up->ref_count);
782 } else
783 zlog_debug("%s(%s): (%s) failure to create",
784 __PRETTY_FUNCTION__, name,
785 pim_str_sg_dump(sg));
786 }
787
788 return up;
789 }
790
791 /*
792 * Passed in up must be the upstream for ch. starch is NULL if no
793 * information
794 */
795 int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
796 struct pim_ifchannel *ch,
797 struct pim_ifchannel *starch)
798 {
799 if (ch) {
800 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
801 return 0;
802
803 if (!pim_macro_ch_lost_assert(ch)
804 && pim_macro_chisin_joins_or_include(ch))
805 return 1;
806 }
807
808 /*
809 * joins (*,G)
810 */
811 if (starch) {
812 if (PIM_IF_FLAG_TEST_S_G_RPT(starch->upstream->flags))
813 return 0;
814
815 if (!pim_macro_ch_lost_assert(starch)
816 && pim_macro_chisin_joins_or_include(starch))
817 return 1;
818 }
819
820 return 0;
821 }
822
823 /*
824 Evaluate JoinDesired(S,G):
825
826 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
827 in the set:
828
829 inherited_olist(S,G) =
830 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
831
832 JoinDesired(S,G) may be affected by changes in the following:
833
834 pim_ifp->primary_address
835 pim_ifp->pim_dr_addr
836 ch->ifassert_winner_metric
837 ch->ifassert_winner
838 ch->local_ifmembership
839 ch->ifjoin_state
840 ch->upstream->rpf.source_nexthop.mrib_metric_preference
841 ch->upstream->rpf.source_nexthop.mrib_route_metric
842 ch->upstream->rpf.source_nexthop.interface
843
844 See also pim_upstream_update_join_desired() below.
845 */
846 int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
847 {
848 struct interface *ifp;
849 struct listnode *node;
850 struct pim_ifchannel *ch, *starch;
851 struct pim_upstream *starup = up->parent;
852 int ret = 0;
853
854 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pimg->vrf_id), node, ifp)) {
855 if (!ifp->info)
856 continue;
857
858 ch = pim_ifchannel_find(ifp, &up->sg);
859
860 if (starup)
861 starch = pim_ifchannel_find(ifp, &starup->sg);
862 else
863 starch = NULL;
864
865 if (!ch && !starch)
866 continue;
867
868 ret += pim_upstream_evaluate_join_desired_interface(up, ch,
869 starch);
870 } /* scan iface channel list */
871
872 return ret; /* false */
873 }
874
875 /*
876 See also pim_upstream_evaluate_join_desired() above.
877 */
878 void pim_upstream_update_join_desired(struct pim_upstream *up)
879 {
880 int was_join_desired; /* boolean */
881 int is_join_desired; /* boolean */
882
883 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
884
885 is_join_desired = pim_upstream_evaluate_join_desired(up);
886 if (is_join_desired)
887 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
888 else
889 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
890
891 /* switched from false to true */
892 if (is_join_desired && !was_join_desired) {
893 pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
894 return;
895 }
896
897 /* switched from true to false */
898 if (!is_join_desired && was_join_desired) {
899 pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
900 return;
901 }
902 }
903
904 /*
905 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
906 Transitions from Joined State
907 RPF'(S,G) GenID changes
908
909 The upstream (S,G) state machine remains in Joined state. If the
910 Join Timer is set to expire in more than t_override seconds, reset
911 it so that it expires after t_override seconds.
912 */
913 void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
914 {
915 struct listnode *up_node;
916 struct listnode *up_nextnode;
917 struct pim_upstream *up;
918
919 /*
920 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
921 */
922 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
923
924 if (PIM_DEBUG_TRACE) {
925 char neigh_str[INET_ADDRSTRLEN];
926 char rpf_addr_str[PREFIX_STRLEN];
927 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str,
928 sizeof(neigh_str));
929 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str,
930 sizeof(rpf_addr_str));
931 zlog_debug(
932 "%s: matching neigh=%s against upstream (S,G)=%s joined=%d rpf_addr=%s",
933 __PRETTY_FUNCTION__, neigh_str, up->sg_str,
934 up->join_state == PIM_UPSTREAM_JOINED,
935 rpf_addr_str);
936 }
937
938 /* consider only (S,G) upstream in Joined state */
939 if (up->join_state != PIM_UPSTREAM_JOINED)
940 continue;
941
942 /* match RPF'(S,G)=neigh_addr */
943 if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr)
944 continue;
945
946 pim_upstream_join_timer_decrease_to_t_override(
947 "RPF'(S,G) GenID change", up);
948 }
949 }
950
951
952 void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
953 struct interface *old_rpf_ifp)
954 {
955 struct listnode *chnode;
956 struct listnode *chnextnode;
957 struct pim_ifchannel *ch;
958
959 /* search all ifchannels */
960 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
961 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
962 if (
963 /* RPF_interface(S) was NOT I */
964 (old_rpf_ifp == ch->interface) &&
965 /* RPF_interface(S) stopped being I */
966 (ch->upstream->rpf.source_nexthop
967 .interface != ch->interface)) {
968 assert_action_a5(ch);
969 }
970 } /* PIM_IFASSERT_I_AM_LOSER */
971
972 pim_ifchannel_update_assert_tracking_desired(ch);
973 }
974 }
975
976 void pim_upstream_update_could_assert(struct pim_upstream *up)
977 {
978 struct listnode *chnode;
979 struct listnode *chnextnode;
980 struct pim_ifchannel *ch;
981
982 /* scan per-interface (S,G) state */
983 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
984 pim_ifchannel_update_could_assert(ch);
985 } /* scan iface channel list */
986 }
987
988 void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
989 {
990 struct listnode *chnode;
991 struct listnode *chnextnode;
992 struct pim_ifchannel *ch;
993
994 /* scan per-interface (S,G) state */
995 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
996 pim_ifchannel_update_my_assert_metric(ch);
997
998 } /* scan iface channel list */
999 }
1000
1001 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
1002 {
1003 struct listnode *chnode;
1004 struct listnode *chnextnode;
1005 struct pim_interface *pim_ifp;
1006 struct pim_ifchannel *ch;
1007
1008 /* scan per-interface (S,G) state */
1009 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1010 if (!ch->interface)
1011 continue;
1012 pim_ifp = ch->interface->info;
1013 if (!pim_ifp)
1014 continue;
1015
1016 pim_ifchannel_update_assert_tracking_desired(ch);
1017
1018 } /* scan iface channel list */
1019 }
1020
1021 /* When kat is stopped CouldRegister goes to false so we need to
1022 * transition the (S, G) on FHR to NI state and remove reg tunnel
1023 * from the OIL */
1024 static void pim_upstream_fhr_kat_expiry(struct pim_upstream *up)
1025 {
1026 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
1027 return;
1028
1029 if (PIM_DEBUG_TRACE)
1030 zlog_debug("kat expired on %s; clear fhr reg state",
1031 up->sg_str);
1032
1033 /* stop reg-stop timer */
1034 THREAD_OFF(up->t_rs_timer);
1035 /* remove regiface from the OIL if it is there*/
1036 pim_channel_del_oif(up->channel_oil, pimg->regiface,
1037 PIM_OIF_FLAG_PROTO_PIM);
1038 /* clear the register state */
1039 up->reg_state = PIM_REG_NOINFO;
1040 PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags);
1041 }
1042
1043 /* When kat is started CouldRegister can go to true. And if it does we
1044 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1045 * to the OIL */
1046 static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
1047 {
1048 if (pim_upstream_could_register(up)) {
1049 if (PIM_DEBUG_TRACE)
1050 zlog_debug(
1051 "kat started on %s; set fhr reg state to joined",
1052 up->sg_str);
1053
1054 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
1055 if (up->reg_state == PIM_REG_NOINFO)
1056 pim_register_join(up);
1057 }
1058 }
1059
1060 /*
1061 * On an RP, the PMBR value must be cleared when the
1062 * Keepalive Timer expires
1063 * KAT expiry indicates that flow is inactive. If the flow was created or
1064 * maintained by activity now is the time to deref it.
1065 */
1066 static int pim_upstream_keep_alive_timer(struct thread *t)
1067 {
1068 struct pim_upstream *up;
1069
1070 up = THREAD_ARG(t);
1071
1072 if (I_am_RP(up->sg.grp)) {
1073 pim_br_clear_pmbr(&up->sg);
1074 /*
1075 * We need to do more here :)
1076 * But this is the start.
1077 */
1078 }
1079
1080 /* source is no longer active - pull the SA from MSDP's cache */
1081 pim_msdp_sa_local_del(&up->sg);
1082
1083 /* if entry was created because of activity we need to deref it */
1084 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1085 pim_upstream_fhr_kat_expiry(up);
1086 if (PIM_DEBUG_TRACE)
1087 zlog_debug("kat expired on %s; remove stream reference",
1088 up->sg_str);
1089 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
1090 pim_upstream_del(up, __PRETTY_FUNCTION__);
1091 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
1092 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
1093 pim_upstream_del(up, __PRETTY_FUNCTION__);
1094 }
1095
1096 return 0;
1097 }
1098
1099 void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time)
1100 {
1101 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1102 if (PIM_DEBUG_TRACE)
1103 zlog_debug("kat start on %s with no stream reference",
1104 up->sg_str);
1105 }
1106 THREAD_OFF(up->t_ka_timer);
1107 thread_add_timer(master, pim_upstream_keep_alive_timer, up, time,
1108 &up->t_ka_timer);
1109
1110 /* any time keepalive is started against a SG we will have to
1111 * re-evaluate our active source database */
1112 pim_msdp_sa_local_update(up);
1113 }
1114
1115 /* MSDP on RP needs to know if a source is registerable to this RP */
1116 static int pim_upstream_msdp_reg_timer(struct thread *t)
1117 {
1118 struct pim_upstream *up;
1119
1120 up = THREAD_ARG(t);
1121
1122 /* source is no longer active - pull the SA from MSDP's cache */
1123 pim_msdp_sa_local_del(&up->sg);
1124 return 1;
1125 }
1126 void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
1127 {
1128 THREAD_OFF(up->t_msdp_reg_timer);
1129 thread_add_timer(master, pim_upstream_msdp_reg_timer, up,
1130 PIM_MSDP_REG_RXED_PERIOD, &up->t_msdp_reg_timer);
1131
1132 pim_msdp_sa_local_update(up);
1133 }
1134
1135 /*
1136 * 4.2.1 Last-Hop Switchover to the SPT
1137 *
1138 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1139 * RP. Once traffic from sources to joined groups arrives at a last-hop
1140 * router, it has the option of switching to receive the traffic on a
1141 * shortest path tree (SPT).
1142 *
1143 * The decision for a router to switch to the SPT is controlled as
1144 * follows:
1145 *
1146 * void
1147 * CheckSwitchToSpt(S,G) {
1148 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1149 * (+) pim_include(S,G) != NULL )
1150 * AND SwitchToSptDesired(S,G) ) {
1151 * # Note: Restarting the KAT will result in the SPT switch
1152 * set KeepaliveTimer(S,G) to Keepalive_Period
1153 * }
1154 * }
1155 *
1156 * SwitchToSptDesired(S,G) is a policy function that is implementation
1157 * defined. An "infinite threshold" policy can be implemented by making
1158 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1159 * first packet" policy can be implemented by making
1160 * SwitchToSptDesired(S,G) return true once a single packet has been
1161 * received for the source and group.
1162 */
1163 int pim_upstream_switch_to_spt_desired(struct prefix_sg *sg)
1164 {
1165 if (I_am_RP(sg->grp))
1166 return 1;
1167
1168 return 0;
1169 }
1170
1171 int pim_upstream_is_sg_rpt(struct pim_upstream *up)
1172 {
1173 struct listnode *chnode;
1174 struct pim_ifchannel *ch;
1175
1176 for (ALL_LIST_ELEMENTS_RO(up->ifchannels, chnode, ch)) {
1177 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1178 return 1;
1179 }
1180
1181 return 0;
1182 }
1183 /*
1184 * After receiving a packet set SPTbit:
1185 * void
1186 * Update_SPTbit(S,G,iif) {
1187 * if ( iif == RPF_interface(S)
1188 * AND JoinDesired(S,G) == TRUE
1189 * AND ( DirectlyConnected(S) == TRUE
1190 * OR RPF_interface(S) != RPF_interface(RP(G))
1191 * OR inherited_olist(S,G,rpt) == NULL
1192 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1193 * ( RPF'(S,G) != NULL ) )
1194 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1195 * Set SPTbit(S,G) to TRUE
1196 * }
1197 * }
1198 */
1199 void pim_upstream_set_sptbit(struct pim_upstream *up,
1200 struct interface *incoming)
1201 {
1202 struct pim_upstream *starup = up->parent;
1203
1204 // iif == RPF_interfvace(S)
1205 if (up->rpf.source_nexthop.interface != incoming) {
1206 if (PIM_DEBUG_TRACE)
1207 zlog_debug(
1208 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1209 __PRETTY_FUNCTION__, incoming->name,
1210 up->rpf.source_nexthop.interface->name);
1211 return;
1212 }
1213
1214 // AND JoinDesired(S,G) == TRUE
1215 // FIXME
1216
1217 // DirectlyConnected(S) == TRUE
1218 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1219 up->sg.src)) {
1220 if (PIM_DEBUG_TRACE)
1221 zlog_debug("%s: %s is directly connected to the source",
1222 __PRETTY_FUNCTION__, up->sg_str);
1223 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1224 return;
1225 }
1226
1227 // OR RPF_interface(S) != RPF_interface(RP(G))
1228 if (!starup
1229 || up->rpf.source_nexthop
1230 .interface != starup->rpf.source_nexthop.interface) {
1231 if (PIM_DEBUG_TRACE)
1232 zlog_debug(
1233 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1234 __PRETTY_FUNCTION__, up->sg_str);
1235 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1236 return;
1237 }
1238
1239 // OR inherited_olist(S,G,rpt) == NULL
1240 if (pim_upstream_is_sg_rpt(up)
1241 && pim_upstream_empty_inherited_olist(up)) {
1242 if (PIM_DEBUG_TRACE)
1243 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1244 __PRETTY_FUNCTION__, up->sg_str);
1245 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1246 return;
1247 }
1248
1249 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1250 // ( RPF'(S,G) != NULL ) )
1251 if (up->parent && pim_rpf_is_same(&up->rpf, &up->parent->rpf)) {
1252 if (PIM_DEBUG_TRACE)
1253 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1254 __PRETTY_FUNCTION__, up->sg_str);
1255 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1256 return;
1257 }
1258
1259 return;
1260 }
1261
1262 const char *pim_upstream_state2str(enum pim_upstream_state join_state)
1263 {
1264 switch (join_state) {
1265 case PIM_UPSTREAM_NOTJOINED:
1266 return "NotJoined";
1267 break;
1268 case PIM_UPSTREAM_JOINED:
1269 return "Joined";
1270 break;
1271 }
1272 return "Unknown";
1273 }
1274
1275 const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str)
1276 {
1277 switch (reg_state) {
1278 case PIM_REG_NOINFO:
1279 strcpy(state_str, "RegNoInfo");
1280 break;
1281 case PIM_REG_JOIN:
1282 strcpy(state_str, "RegJoined");
1283 break;
1284 case PIM_REG_JOIN_PENDING:
1285 strcpy(state_str, "RegJoinPend");
1286 break;
1287 case PIM_REG_PRUNE:
1288 strcpy(state_str, "RegPrune");
1289 break;
1290 default:
1291 strcpy(state_str, "RegUnknown");
1292 }
1293 return state_str;
1294 }
1295
1296 static int pim_upstream_register_stop_timer(struct thread *t)
1297 {
1298 struct pim_interface *pim_ifp;
1299 struct pim_upstream *up;
1300 struct pim_rpf *rpg;
1301 struct ip ip_hdr;
1302 up = THREAD_ARG(t);
1303
1304 if (PIM_DEBUG_TRACE) {
1305 char state_str[PIM_REG_STATE_STR_LEN];
1306 zlog_debug("%s: (S,G)=%s upstream register stop timer %s",
1307 __PRETTY_FUNCTION__, up->sg_str,
1308 pim_reg_state2str(up->reg_state, state_str));
1309 }
1310
1311 switch (up->reg_state) {
1312 case PIM_REG_JOIN_PENDING:
1313 up->reg_state = PIM_REG_JOIN;
1314 pim_channel_add_oif(up->channel_oil, pimg->regiface,
1315 PIM_OIF_FLAG_PROTO_PIM);
1316 break;
1317 case PIM_REG_JOIN:
1318 break;
1319 case PIM_REG_PRUNE:
1320 pim_ifp = up->rpf.source_nexthop.interface->info;
1321 if (!pim_ifp) {
1322 if (PIM_DEBUG_TRACE)
1323 zlog_debug(
1324 "%s: Interface: %s is not configured for pim",
1325 __PRETTY_FUNCTION__,
1326 up->rpf.source_nexthop.interface->name);
1327 return 0;
1328 }
1329 up->reg_state = PIM_REG_JOIN_PENDING;
1330 pim_upstream_start_register_stop_timer(up, 1);
1331
1332 if (((up->channel_oil->cc.lastused / 100)
1333 > PIM_KEEPALIVE_PERIOD)
1334 && (I_am_RP(up->sg.grp))) {
1335 if (PIM_DEBUG_TRACE)
1336 zlog_debug(
1337 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1338 __PRETTY_FUNCTION__);
1339 return 0;
1340 }
1341 rpg = RP(pimg, up->sg.grp);
1342 memset(&ip_hdr, 0, sizeof(struct ip));
1343 ip_hdr.ip_p = PIM_IP_PROTO_PIM;
1344 ip_hdr.ip_hl = 5;
1345 ip_hdr.ip_v = 4;
1346 ip_hdr.ip_src = up->sg.src;
1347 ip_hdr.ip_dst = up->sg.grp;
1348 ip_hdr.ip_len = htons(20);
1349 // checksum is broken
1350 pim_register_send((uint8_t *)&ip_hdr, sizeof(struct ip),
1351 pim_ifp->primary_address, rpg, 1, up);
1352 break;
1353 default:
1354 break;
1355 }
1356
1357 return 0;
1358 }
1359
1360 void pim_upstream_start_register_stop_timer(struct pim_upstream *up,
1361 int null_register)
1362 {
1363 uint32_t time;
1364
1365 THREAD_TIMER_OFF(up->t_rs_timer);
1366
1367 if (!null_register) {
1368 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1369 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1370 time = lower + (random() % (upper - lower + 1))
1371 - PIM_REGISTER_PROBE_PERIOD;
1372 } else
1373 time = PIM_REGISTER_PROBE_PERIOD;
1374
1375 if (PIM_DEBUG_TRACE) {
1376 zlog_debug(
1377 "%s: (S,G)=%s Starting upstream register stop timer %d",
1378 __PRETTY_FUNCTION__, up->sg_str, time);
1379 }
1380 thread_add_timer(master, pim_upstream_register_stop_timer, up, time,
1381 &up->t_rs_timer);
1382 }
1383
1384 int pim_upstream_inherited_olist_decide(struct pim_upstream *up)
1385 {
1386 struct interface *ifp;
1387 struct pim_interface *pim_ifp = NULL;
1388 struct pim_ifchannel *ch, *starch;
1389 struct listnode *node;
1390 struct pim_upstream *starup = up->parent;
1391 int output_intf = 0;
1392
1393 if (up->rpf.source_nexthop.interface)
1394 pim_ifp = up->rpf.source_nexthop.interface->info;
1395 else {
1396 if (PIM_DEBUG_TRACE)
1397 zlog_debug("%s: up %s RPF is not present",
1398 __PRETTY_FUNCTION__, up->sg_str);
1399 }
1400 if (pim_ifp && !up->channel_oil)
1401 up->channel_oil =
1402 pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index);
1403
1404 for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pimg->vrf_id), node, ifp)) {
1405 if (!ifp->info)
1406 continue;
1407
1408 ch = pim_ifchannel_find(ifp, &up->sg);
1409
1410 if (starup)
1411 starch = pim_ifchannel_find(ifp, &starup->sg);
1412 else
1413 starch = NULL;
1414
1415 if (!ch && !starch)
1416 continue;
1417
1418 if (pim_upstream_evaluate_join_desired_interface(up, ch,
1419 starch)) {
1420 int flag = PIM_OIF_FLAG_PROTO_PIM;
1421
1422 if (!ch)
1423 flag = PIM_OIF_FLAG_PROTO_STAR;
1424
1425 pim_channel_add_oif(up->channel_oil, ifp, flag);
1426 output_intf++;
1427 }
1428 }
1429
1430 return output_intf;
1431 }
1432
1433 /*
1434 * For a given upstream, determine the inherited_olist
1435 * and apply it.
1436 *
1437 * inherited_olist(S,G,rpt) =
1438 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1439 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1440 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1441 *
1442 * inherited_olist(S,G) =
1443 * inherited_olist(S,G,rpt) (+)
1444 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1445 *
1446 * return 1 if there are any output interfaces
1447 * return 0 if there are not any output interfaces
1448 */
1449 int pim_upstream_inherited_olist(struct pim_upstream *up)
1450 {
1451 int output_intf = pim_upstream_inherited_olist_decide(up);
1452
1453 /*
1454 * If we have output_intf switch state to Join and work like normal
1455 * If we don't have an output_intf that means we are probably a
1456 * switch on a stick so turn on forwarding to just accept the
1457 * incoming packets so we don't bother the other stuff!
1458 */
1459 if (output_intf)
1460 pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
1461 else
1462 forward_on(up);
1463
1464 return output_intf;
1465 }
1466
1467 int pim_upstream_empty_inherited_olist(struct pim_upstream *up)
1468 {
1469 return pim_channel_oil_empty(up->channel_oil);
1470 }
1471
1472 /*
1473 * When we have a new neighbor,
1474 * find upstreams that don't have their rpf_addr
1475 * set and see if the new neighbor allows
1476 * the join to be sent
1477 */
1478 void pim_upstream_find_new_rpf(void)
1479 {
1480 struct listnode *up_node;
1481 struct listnode *up_nextnode;
1482 struct pim_upstream *up;
1483
1484 /*
1485 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1486 */
1487 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
1488 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
1489 if (PIM_DEBUG_TRACE)
1490 zlog_debug(
1491 "Upstream %s without a path to send join, checking",
1492 up->sg_str);
1493 pim_rpf_update(up, NULL, 1);
1494 }
1495 }
1496 }
1497
1498 static unsigned int pim_upstream_hash_key(void *arg)
1499 {
1500 struct pim_upstream *up = (struct pim_upstream *)arg;
1501
1502 return jhash_2words(up->sg.src.s_addr, up->sg.grp.s_addr, 0);
1503 }
1504
1505 void pim_upstream_terminate(void)
1506 {
1507 if (pim_upstream_list)
1508 list_delete(pim_upstream_list);
1509 pim_upstream_list = NULL;
1510
1511 if (pim_upstream_hash)
1512 hash_free(pim_upstream_hash);
1513 pim_upstream_hash = NULL;
1514 }
1515
1516 static int pim_upstream_equal(const void *arg1, const void *arg2)
1517 {
1518 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1519 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
1520
1521 if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr)
1522 && (up1->sg.src.s_addr == up2->sg.src.s_addr))
1523 return 1;
1524
1525 return 0;
1526 }
1527
1528 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1529 * the cases where kat has to be restarted on rxing traffic -
1530 *
1531 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1532 * set KeepaliveTimer(S,G) to Keepalive_Period
1533 * # Note: a register state transition or UpstreamJPState(S,G)
1534 * # transition may happen as a result of restarting
1535 * # KeepaliveTimer, and must be dealt with here.
1536 * }
1537 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1538 * inherited_olist(S,G) != NULL ) {
1539 * set KeepaliveTimer(S,G) to Keepalive_Period
1540 * }
1541 */
1542 static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
1543 {
1544 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1545 * so we will skip that here */
1546 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1547 up->sg.src)) {
1548 return true;
1549 }
1550
1551 if ((up->join_state == PIM_UPSTREAM_JOINED)
1552 && !pim_upstream_empty_inherited_olist(up)) {
1553 /* XXX: I have added this RP check just for 3.2 and it's a
1554 * digression from
1555 * what rfc-4601 says. Till now we were only running KAT on FHR
1556 * and RP and
1557 * there is some angst around making the change to run it all
1558 * routers that
1559 * maintain the (S, G) state. This is tracked via CM-13601 and
1560 * MUST be
1561 * removed to handle spt turn-arounds correctly in a 3-tier clos
1562 */
1563 if (I_am_RP(up->sg.grp))
1564 return true;
1565 }
1566
1567 return false;
1568 }
1569
1570 /*
1571 * Code to check and see if we've received packets on a S,G mroute
1572 * and if so to set the SPT bit appropriately
1573 */
1574 static void pim_upstream_sg_running(void *arg)
1575 {
1576 struct pim_upstream *up = (struct pim_upstream *)arg;
1577
1578 // No packet can have arrived here if this is the case
1579 if (!up->channel_oil || !up->channel_oil->installed) {
1580 if (PIM_DEBUG_TRACE)
1581 zlog_debug("%s: %s is not installed in mroute",
1582 __PRETTY_FUNCTION__, up->sg_str);
1583 return;
1584 }
1585
1586 /*
1587 * This is a bit of a hack
1588 * We've noted that we should rescan but
1589 * we've missed the window for doing so in
1590 * pim_zebra.c for some reason. I am
1591 * only doing this at this point in time
1592 * to get us up and working for the moment
1593 */
1594 if (up->channel_oil->oil_inherited_rescan) {
1595 if (PIM_DEBUG_TRACE)
1596 zlog_debug(
1597 "%s: Handling unscanned inherited_olist for %s",
1598 __PRETTY_FUNCTION__, up->sg_str);
1599 pim_upstream_inherited_olist_decide(up);
1600 up->channel_oil->oil_inherited_rescan = 0;
1601 }
1602 pim_mroute_update_counters(up->channel_oil);
1603
1604 // Have we seen packets?
1605 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt)
1606 && (up->channel_oil->cc.lastused / 100 > 30)) {
1607 if (PIM_DEBUG_TRACE) {
1608 zlog_debug(
1609 "%s: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1610 __PRETTY_FUNCTION__, up->sg_str,
1611 up->channel_oil->cc.oldpktcnt,
1612 up->channel_oil->cc.pktcnt,
1613 up->channel_oil->cc.lastused / 100);
1614 }
1615 return;
1616 }
1617
1618 if (pim_upstream_kat_start_ok(up)) {
1619 /* Add a source reference to the stream if
1620 * one doesn't already exist */
1621 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1622 if (PIM_DEBUG_TRACE)
1623 zlog_debug(
1624 "source reference created on kat restart %s",
1625 up->sg_str);
1626
1627 pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
1628 __PRETTY_FUNCTION__);
1629 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
1630 pim_upstream_fhr_kat_start(up);
1631 }
1632 pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
1633 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
1634 pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
1635
1636 if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) {
1637 pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
1638 }
1639 return;
1640 }
1641
1642 void pim_upstream_add_lhr_star_pimreg(void)
1643 {
1644 struct pim_upstream *up;
1645 struct listnode *node;
1646
1647 for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, node, up)) {
1648 if (up->sg.src.s_addr != INADDR_ANY)
1649 continue;
1650
1651 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags))
1652 continue;
1653
1654 pim_channel_add_oif(up->channel_oil, pimg->regiface,
1655 PIM_OIF_FLAG_PROTO_IGMP);
1656 }
1657 }
1658
1659 void pim_upstream_spt_prefix_list_update(struct prefix_list *pl)
1660 {
1661 const char *pname = prefix_list_name(pl);
1662
1663 if (pimg->spt.plist && strcmp(pimg->spt.plist, pname) == 0) {
1664 pim_upstream_remove_lhr_star_pimreg(pname);
1665 }
1666 }
1667
1668 /*
1669 * nlist -> The new prefix list
1670 *
1671 * Per Group Application of pimreg to the OIL
1672 * If the prefix list tells us DENY then
1673 * we need to Switchover to SPT immediate
1674 * so add the pimreg.
1675 * If the prefix list tells us to ACCEPT than
1676 * we need to Never do the SPT so remove
1677 * the interface
1678 *
1679 */
1680 void pim_upstream_remove_lhr_star_pimreg(const char *nlist)
1681 {
1682 struct pim_upstream *up;
1683 struct listnode *node;
1684 struct prefix_list *np;
1685 struct prefix g;
1686 enum prefix_list_type apply_new;
1687
1688 np = prefix_list_lookup(AFI_IP, nlist);
1689
1690 g.family = AF_INET;
1691 g.prefixlen = IPV4_MAX_PREFIXLEN;
1692
1693 for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, node, up)) {
1694 if (up->sg.src.s_addr != INADDR_ANY)
1695 continue;
1696
1697 if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags))
1698 continue;
1699
1700 if (!nlist) {
1701 pim_channel_del_oif(up->channel_oil, pimg->regiface,
1702 PIM_OIF_FLAG_PROTO_IGMP);
1703 continue;
1704 }
1705 g.u.prefix4 = up->sg.grp;
1706 apply_new = prefix_list_apply(np, &g);
1707 if (apply_new == PREFIX_DENY)
1708 pim_channel_add_oif(up->channel_oil, pimg->regiface,
1709 PIM_OIF_FLAG_PROTO_IGMP);
1710 else
1711 pim_channel_del_oif(up->channel_oil, pimg->regiface,
1712 PIM_OIF_FLAG_PROTO_IGMP);
1713 }
1714 }
1715
1716 void pim_upstream_init(void)
1717 {
1718 pim_upstream_sg_wheel =
1719 wheel_init(master, 31000, 100, pim_upstream_hash_key,
1720 pim_upstream_sg_running);
1721 pim_upstream_hash = hash_create_size(8192, pim_upstream_hash_key,
1722 pim_upstream_equal, NULL);
1723
1724 pim_upstream_list = list_new();
1725 pim_upstream_list->del = (void (*)(void *))pim_upstream_free;
1726 pim_upstream_list->cmp = pim_upstream_compare;
1727 }