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