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