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