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