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