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