]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_upstream.c
Merge pull request #7669 from ranjanyash54/2370
[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 if (old_state == PIM_UPSTREAM_JOINED)
753 pim_msdp_up_join_state_changed(pim, up);
754
755 if (old_state != new_state) {
756 old_use_rpt =
757 !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
758 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
759 new_use_rpt =
760 !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags);
761 if (new_use_rpt &&
762 (new_use_rpt != old_use_rpt) &&
763 up->parent)
764 /* we have decided to switch from the SPT back
765 * to the RPT which means we need to cancel
766 * any previously sent SGrpt prunes immediately
767 */
768 send_xg_jp = true;
769 }
770
771 /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards
772 RP.
773 If I am RP for G then send S,G prune to its IIF. */
774 if (pim_upstream_is_sg_rpt(up) && up->parent &&
775 !I_am_RP(pim, up->sg.grp))
776 send_xg_jp = true;
777 else
778 pim_jp_agg_single_upstream_send(&up->rpf, up,
779 0 /* prune */);
780
781 if (send_xg_jp) {
782 if (PIM_DEBUG_PIM_TRACE_DETAIL)
783 zlog_debug(
784 "re-join RPT; *,G IIF %s S,G IIF %s ",
785 up->parent->rpf.source_nexthop.interface ?
786 up->parent->rpf.source_nexthop.interface->name
787 : "Unknown",
788 up->rpf.source_nexthop.interface ?
789 up->rpf.source_nexthop.interface->name :
790 "Unknown");
791 pim_jp_agg_single_upstream_send(&up->parent->rpf,
792 up->parent,
793 1 /* (W,G) Join */);
794 }
795 join_timer_stop(up);
796 }
797 }
798
799 int pim_upstream_compare(const struct pim_upstream *up1,
800 const struct pim_upstream *up2)
801 {
802 if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr))
803 return -1;
804
805 if (ntohl(up1->sg.grp.s_addr) > ntohl(up2->sg.grp.s_addr))
806 return 1;
807
808 if (ntohl(up1->sg.src.s_addr) < ntohl(up2->sg.src.s_addr))
809 return -1;
810
811 if (ntohl(up1->sg.src.s_addr) > ntohl(up2->sg.src.s_addr))
812 return 1;
813
814 return 0;
815 }
816
817 void pim_upstream_fill_static_iif(struct pim_upstream *up,
818 struct interface *incoming)
819 {
820 up->rpf.source_nexthop.interface = incoming;
821
822 /* reset other parameters to matched a connected incoming interface */
823 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
824 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
825 PIM_NET_INADDR_ANY;
826 up->rpf.source_nexthop.mrib_metric_preference =
827 ZEBRA_CONNECT_DISTANCE_DEFAULT;
828 up->rpf.source_nexthop.mrib_route_metric = 0;
829 up->rpf.rpf_addr.family = AF_INET;
830 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
831
832 }
833
834 static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
835 struct prefix_sg *sg,
836 struct interface *incoming,
837 int flags,
838 struct pim_ifchannel *ch)
839 {
840 enum pim_rpf_result rpf_result;
841 struct pim_interface *pim_ifp;
842 struct pim_upstream *up;
843
844 up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
845
846 up->pim = pim;
847 up->sg = *sg;
848 pim_str_sg_set(sg, up->sg_str);
849 if (ch)
850 ch->upstream = up;
851
852 rb_pim_upstream_add(&pim->upstream_head, up);
853 /* Set up->upstream_addr as INADDR_ANY, if RP is not
854 * configured and retain the upstream data structure
855 */
856 if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src,
857 sg->grp)) {
858 if (PIM_DEBUG_PIM_TRACE)
859 zlog_debug("%s: Received a (*,G) with no RP configured",
860 __func__);
861 }
862
863 up->parent = pim_upstream_find_parent(pim, up);
864 if (up->sg.src.s_addr == INADDR_ANY) {
865 up->sources = list_new();
866 up->sources->cmp =
867 (int (*)(void *, void *))pim_upstream_compare;
868 } else
869 up->sources = NULL;
870
871 pim_upstream_find_new_children(pim, up);
872 up->flags = flags;
873 up->ref_count = 1;
874 up->t_join_timer = NULL;
875 up->t_ka_timer = NULL;
876 up->t_rs_timer = NULL;
877 up->t_msdp_reg_timer = NULL;
878 up->join_state = PIM_UPSTREAM_NOTJOINED;
879 up->reg_state = PIM_REG_NOINFO;
880 up->state_transition = pim_time_monotonic_sec();
881 up->channel_oil = pim_channel_oil_add(pim, &up->sg, __func__);
882 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
883
884 up->rpf.source_nexthop.interface = NULL;
885 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
886 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr =
887 PIM_NET_INADDR_ANY;
888 up->rpf.source_nexthop.mrib_metric_preference =
889 router->infinite_assert_metric.metric_preference;
890 up->rpf.source_nexthop.mrib_route_metric =
891 router->infinite_assert_metric.route_metric;
892 up->rpf.rpf_addr.family = AF_INET;
893 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
894
895 up->ifchannels = list_new();
896 up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
897
898 if (up->sg.src.s_addr != INADDR_ANY) {
899 wheel_add_item(pim->upstream_sg_wheel, up);
900
901 /* Inherit the DF role from the parent (*, G) entry for
902 * VxLAN BUM groups
903 */
904 if (up->parent
905 && PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->parent->flags)
906 && PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->parent->flags)) {
907 PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(up->flags);
908 if (PIM_DEBUG_VXLAN)
909 zlog_debug(
910 "upstream %s inherited mlag non-df flag from parent",
911 up->sg_str);
912 }
913 }
914
915 if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)
916 || PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) {
917 pim_upstream_fill_static_iif(up, incoming);
918 pim_ifp = up->rpf.source_nexthop.interface->info;
919 assert(pim_ifp);
920 pim_upstream_update_use_rpt(up,
921 false /*update_mroute*/);
922 pim_upstream_mroute_iif_update(up->channel_oil, __func__);
923
924 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags))
925 pim_upstream_keep_alive_timer_start(
926 up, pim->keep_alive_time);
927 } else if (up->upstream_addr.s_addr != INADDR_ANY) {
928 pim_upstream_update_use_rpt(up,
929 false /*update_mroute*/);
930 rpf_result = pim_rpf_update(pim, up, NULL, __func__);
931 if (rpf_result == PIM_RPF_FAILURE) {
932 if (PIM_DEBUG_PIM_TRACE)
933 zlog_debug(
934 "%s: Attempting to create upstream(%s), Unable to RPF for source",
935 __func__, up->sg_str);
936 }
937
938 if (up->rpf.source_nexthop.interface) {
939 pim_upstream_mroute_iif_update(up->channel_oil,
940 __func__);
941 }
942 }
943
944 /* send the entry to the MLAG peer */
945 /* XXX - duplicate send is possible here if pim_rpf_update
946 * successfully resolved the nexthop
947 */
948 if (pim_up_mlag_is_local(up)
949 || PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags))
950 pim_mlag_up_local_add(pim, up);
951
952 if (PIM_DEBUG_PIM_TRACE) {
953 zlog_debug(
954 "%s: Created Upstream %s upstream_addr %pI4 ref count %d increment",
955 __func__, up->sg_str, &up->upstream_addr,
956 up->ref_count);
957 }
958
959 return up;
960 }
961
962 uint32_t pim_up_mlag_local_cost(struct pim_upstream *up)
963 {
964 if (!(pim_up_mlag_is_local(up))
965 && !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
966 return router->infinite_assert_metric.route_metric;
967
968 if ((up->rpf.source_nexthop.interface ==
969 up->pim->vxlan.peerlink_rif) &&
970 (up->rpf.source_nexthop.mrib_route_metric <
971 (router->infinite_assert_metric.route_metric -
972 PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC)))
973 return up->rpf.source_nexthop.mrib_route_metric +
974 PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC;
975
976 return up->rpf.source_nexthop.mrib_route_metric;
977 }
978
979 uint32_t pim_up_mlag_peer_cost(struct pim_upstream *up)
980 {
981 if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_PEER))
982 return router->infinite_assert_metric.route_metric;
983
984 return up->mlag.peer_mrib_metric;
985 }
986
987 struct pim_upstream *pim_upstream_find(struct pim_instance *pim,
988 struct prefix_sg *sg)
989 {
990 struct pim_upstream lookup;
991 struct pim_upstream *up = NULL;
992
993 lookup.sg = *sg;
994 up = rb_pim_upstream_find(&pim->upstream_head, &lookup);
995 return up;
996 }
997
998 struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg,
999 struct interface *incoming,
1000 int flags, const char *name)
1001 {
1002 struct pim_interface *pim_ifp = incoming->info;
1003
1004 return (pim_upstream_add(pim_ifp->pim, sg, incoming, flags, name,
1005 NULL));
1006 }
1007
1008 void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name)
1009 {
1010 /* if a local MLAG reference is being created we need to send the mroute
1011 * to the peer
1012 */
1013 if (!PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->flags) &&
1014 PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(flags)) {
1015 PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(up->flags);
1016 pim_mlag_up_local_add(up->pim, up);
1017 }
1018
1019 /* when we go from non-FHR to FHR we need to re-eval traffic
1020 * forwarding path
1021 */
1022 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) &&
1023 PIM_UPSTREAM_FLAG_TEST_FHR(flags)) {
1024 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
1025 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
1026 }
1027
1028 /* re-eval joinDesired; clearing peer-msdp-sa flag can
1029 * cause JD to change
1030 */
1031 if (!PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags) &&
1032 PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags)) {
1033 PIM_UPSTREAM_FLAG_SET_SRC_MSDP(up->flags);
1034 pim_upstream_update_join_desired(up->pim, up);
1035 }
1036
1037 up->flags |= flags;
1038 ++up->ref_count;
1039 if (PIM_DEBUG_PIM_TRACE)
1040 zlog_debug("%s(%s): upstream %s ref count %d increment",
1041 __func__, name, up->sg_str, up->ref_count);
1042 }
1043
1044 struct pim_upstream *pim_upstream_add(struct pim_instance *pim,
1045 struct prefix_sg *sg,
1046 struct interface *incoming, int flags,
1047 const char *name,
1048 struct pim_ifchannel *ch)
1049 {
1050 struct pim_upstream *up = NULL;
1051 int found = 0;
1052
1053 up = pim_upstream_find(pim, sg);
1054 if (up) {
1055 pim_upstream_ref(up, flags, name);
1056 found = 1;
1057 } else {
1058 up = pim_upstream_new(pim, sg, incoming, flags, ch);
1059 }
1060
1061 if (PIM_DEBUG_PIM_TRACE) {
1062 if (up)
1063 zlog_debug("%s(%s): %s, iif %pFX (%s) found: %d: ref_count: %d",
1064 __func__, name,
1065 up->sg_str, &up->rpf.rpf_addr, up->rpf.source_nexthop.interface ?
1066 up->rpf.source_nexthop.interface->name : "Unknown" ,
1067 found, up->ref_count);
1068 else
1069 zlog_debug("%s(%s): (%s) failure to create", __func__,
1070 name, pim_str_sg_dump(sg));
1071 }
1072
1073 return up;
1074 }
1075
1076 /*
1077 * Passed in up must be the upstream for ch. starch is NULL if no
1078 * information
1079 * This function is copied over from
1080 * pim_upstream_evaluate_join_desired_interface but limited to
1081 * parent (*,G)'s includes/joins.
1082 */
1083 int pim_upstream_eval_inherit_if(struct pim_upstream *up,
1084 struct pim_ifchannel *ch,
1085 struct pim_ifchannel *starch)
1086 {
1087 /* if there is an explicit prune for this interface we cannot
1088 * add it to the OIL
1089 */
1090 if (ch) {
1091 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1092 return 0;
1093 }
1094
1095 /* Check if the OIF can be inherited fron the (*,G) entry
1096 */
1097 if (starch) {
1098 if (!pim_macro_ch_lost_assert(starch)
1099 && pim_macro_chisin_joins_or_include(starch))
1100 return 1;
1101 }
1102
1103 return 0;
1104 }
1105
1106 /*
1107 * Passed in up must be the upstream for ch. starch is NULL if no
1108 * information
1109 */
1110 int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up,
1111 struct pim_ifchannel *ch,
1112 struct pim_ifchannel *starch)
1113 {
1114 if (ch) {
1115 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1116 return 0;
1117
1118 if (!pim_macro_ch_lost_assert(ch)
1119 && pim_macro_chisin_joins_or_include(ch))
1120 return 1;
1121 }
1122
1123 /*
1124 * joins (*,G)
1125 */
1126 if (starch) {
1127 /* XXX: check on this with donald
1128 * we are looking for PIM_IF_FLAG_MASK_S_G_RPT in
1129 * upstream flags?
1130 */
1131 #if 0
1132 if (PIM_IF_FLAG_TEST_S_G_RPT(starch->upstream->flags))
1133 return 0;
1134 #endif
1135
1136 if (!pim_macro_ch_lost_assert(starch)
1137 && pim_macro_chisin_joins_or_include(starch))
1138 return 1;
1139 }
1140
1141 return 0;
1142 }
1143
1144 /* Returns true if immediate OIL is empty and is used to evaluate
1145 * JoinDesired. See pim_upstream_evaluate_join_desired.
1146 */
1147 static bool pim_upstream_empty_immediate_olist(struct pim_instance *pim,
1148 struct pim_upstream *up)
1149 {
1150 struct interface *ifp;
1151 struct pim_ifchannel *ch;
1152
1153 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1154 if (!ifp->info)
1155 continue;
1156
1157 ch = pim_ifchannel_find(ifp, &up->sg);
1158 if (!ch)
1159 continue;
1160
1161 /* If we have even one immediate OIF we can return with
1162 * not-empty
1163 */
1164 if (pim_upstream_evaluate_join_desired_interface(up, ch,
1165 NULL /* starch */))
1166 return false;
1167 } /* scan iface channel list */
1168
1169 /* immediate_oil is empty */
1170 return true;
1171 }
1172
1173
1174 static inline bool pim_upstream_is_msdp_peer_sa(struct pim_upstream *up)
1175 {
1176 return PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags);
1177 }
1178
1179 /*
1180 * bool JoinDesired(*,G) {
1181 * if (immediate_olist(*,G) != NULL)
1182 * return TRUE
1183 * else
1184 * return FALSE
1185 * }
1186 *
1187 * bool JoinDesired(S,G) {
1188 * return( immediate_olist(S,G) != NULL
1189 * OR ( KeepaliveTimer(S,G) is running
1190 * AND inherited_olist(S,G) != NULL ) )
1191 * }
1192 */
1193 bool pim_upstream_evaluate_join_desired(struct pim_instance *pim,
1194 struct pim_upstream *up)
1195 {
1196 bool empty_imm_oil;
1197 bool empty_inh_oil;
1198
1199 empty_imm_oil = pim_upstream_empty_immediate_olist(pim, up);
1200
1201 /* (*,G) */
1202 if (up->sg.src.s_addr == INADDR_ANY)
1203 return !empty_imm_oil;
1204
1205 /* (S,G) */
1206 if (!empty_imm_oil)
1207 return true;
1208 empty_inh_oil = pim_upstream_empty_inherited_olist(up);
1209 if (!empty_inh_oil &&
1210 (pim_upstream_is_kat_running(up) ||
1211 pim_upstream_is_msdp_peer_sa(up)))
1212 return true;
1213
1214 return false;
1215 }
1216
1217 /*
1218 See also pim_upstream_evaluate_join_desired() above.
1219 */
1220 void pim_upstream_update_join_desired(struct pim_instance *pim,
1221 struct pim_upstream *up)
1222 {
1223 int was_join_desired; /* boolean */
1224 int is_join_desired; /* boolean */
1225
1226 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
1227
1228 is_join_desired = pim_upstream_evaluate_join_desired(pim, up);
1229 if (is_join_desired)
1230 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
1231 else
1232 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
1233
1234 /* switched from false to true */
1235 if (is_join_desired && (up->join_state == PIM_UPSTREAM_NOTJOINED)) {
1236 pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED);
1237 return;
1238 }
1239
1240 /* switched from true to false */
1241 if (!is_join_desired && was_join_desired) {
1242 pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED);
1243 return;
1244 }
1245 }
1246
1247 /*
1248 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
1249 Transitions from Joined State
1250 RPF'(S,G) GenID changes
1251
1252 The upstream (S,G) state machine remains in Joined state. If the
1253 Join Timer is set to expire in more than t_override seconds, reset
1254 it so that it expires after t_override seconds.
1255 */
1256 void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
1257 struct in_addr neigh_addr)
1258 {
1259 struct pim_upstream *up;
1260
1261 /*
1262 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1263 */
1264 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1265 if (PIM_DEBUG_PIM_TRACE) {
1266 char neigh_str[INET_ADDRSTRLEN];
1267 char rpf_addr_str[PREFIX_STRLEN];
1268 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str,
1269 sizeof(neigh_str));
1270 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str,
1271 sizeof(rpf_addr_str));
1272 zlog_debug(
1273 "%s: matching neigh=%s against upstream (S,G)=%s[%s] joined=%d rpf_addr=%s",
1274 __func__, neigh_str, up->sg_str, pim->vrf->name,
1275 up->join_state == PIM_UPSTREAM_JOINED,
1276 rpf_addr_str);
1277 }
1278
1279 /* consider only (S,G) upstream in Joined state */
1280 if (up->join_state != PIM_UPSTREAM_JOINED)
1281 continue;
1282
1283 /* match RPF'(S,G)=neigh_addr */
1284 if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr)
1285 continue;
1286
1287 pim_upstream_join_timer_decrease_to_t_override(
1288 "RPF'(S,G) GenID change", up);
1289 }
1290 }
1291
1292
1293 void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
1294 struct interface *old_rpf_ifp)
1295 {
1296 struct listnode *chnode;
1297 struct listnode *chnextnode;
1298 struct pim_ifchannel *ch;
1299
1300 /* search all ifchannels */
1301 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1302 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
1303 if (
1304 /* RPF_interface(S) was NOT I */
1305 (old_rpf_ifp == ch->interface) &&
1306 /* RPF_interface(S) stopped being I */
1307 (ch->upstream->rpf.source_nexthop
1308 .interface) &&
1309 (ch->upstream->rpf.source_nexthop
1310 .interface != ch->interface)) {
1311 assert_action_a5(ch);
1312 }
1313 } /* PIM_IFASSERT_I_AM_LOSER */
1314
1315 pim_ifchannel_update_assert_tracking_desired(ch);
1316 }
1317 }
1318
1319 void pim_upstream_update_could_assert(struct pim_upstream *up)
1320 {
1321 struct listnode *chnode;
1322 struct listnode *chnextnode;
1323 struct pim_ifchannel *ch;
1324
1325 /* scan per-interface (S,G) state */
1326 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1327 pim_ifchannel_update_could_assert(ch);
1328 } /* scan iface channel list */
1329 }
1330
1331 void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
1332 {
1333 struct listnode *chnode;
1334 struct listnode *chnextnode;
1335 struct pim_ifchannel *ch;
1336
1337 /* scan per-interface (S,G) state */
1338 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1339 pim_ifchannel_update_my_assert_metric(ch);
1340
1341 } /* scan iface channel list */
1342 }
1343
1344 static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
1345 {
1346 struct listnode *chnode;
1347 struct listnode *chnextnode;
1348 struct pim_interface *pim_ifp;
1349 struct pim_ifchannel *ch;
1350
1351 /* scan per-interface (S,G) state */
1352 for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
1353 if (!ch->interface)
1354 continue;
1355 pim_ifp = ch->interface->info;
1356 if (!pim_ifp)
1357 continue;
1358
1359 pim_ifchannel_update_assert_tracking_desired(ch);
1360
1361 } /* scan iface channel list */
1362 }
1363
1364 /* When kat is stopped CouldRegister goes to false so we need to
1365 * transition the (S, G) on FHR to NI state and remove reg tunnel
1366 * from the OIL */
1367 static void pim_upstream_fhr_kat_expiry(struct pim_instance *pim,
1368 struct pim_upstream *up)
1369 {
1370 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
1371 return;
1372
1373 if (PIM_DEBUG_PIM_TRACE)
1374 zlog_debug("kat expired on %s; clear fhr reg state",
1375 up->sg_str);
1376
1377 /* stop reg-stop timer */
1378 THREAD_OFF(up->t_rs_timer);
1379 /* remove regiface from the OIL if it is there*/
1380 pim_channel_del_oif(up->channel_oil, pim->regiface,
1381 PIM_OIF_FLAG_PROTO_PIM, __func__);
1382 /* clear the register state */
1383 up->reg_state = PIM_REG_NOINFO;
1384 PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags);
1385 }
1386
1387 /* When kat is started CouldRegister can go to true. And if it does we
1388 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
1389 * to the OIL */
1390 static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
1391 {
1392 if (pim_upstream_could_register(up)) {
1393 if (PIM_DEBUG_PIM_TRACE)
1394 zlog_debug(
1395 "kat started on %s; set fhr reg state to joined",
1396 up->sg_str);
1397
1398 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
1399 if (up->reg_state == PIM_REG_NOINFO)
1400 pim_register_join(up);
1401 pim_upstream_update_use_rpt(up, true /*update_mroute*/);
1402 }
1403 }
1404
1405 /*
1406 * On an RP, the PMBR value must be cleared when the
1407 * Keepalive Timer expires
1408 * KAT expiry indicates that flow is inactive. If the flow was created or
1409 * maintained by activity now is the time to deref it.
1410 */
1411 struct pim_upstream *pim_upstream_keep_alive_timer_proc(
1412 struct pim_upstream *up)
1413 {
1414 struct pim_instance *pim;
1415
1416 pim = up->channel_oil->pim;
1417
1418 if (PIM_UPSTREAM_FLAG_TEST_DISABLE_KAT_EXPIRY(up->flags)) {
1419 /* if the router is a PIM vxlan encapsulator we prevent expiry
1420 * of KAT as the mroute is pre-setup without any traffic
1421 */
1422 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
1423 return up;
1424 }
1425
1426 if (I_am_RP(pim, up->sg.grp)) {
1427 pim_br_clear_pmbr(&up->sg);
1428 /*
1429 * We need to do more here :)
1430 * But this is the start.
1431 */
1432 }
1433
1434 /* source is no longer active - pull the SA from MSDP's cache */
1435 pim_msdp_sa_local_del(pim, &up->sg);
1436
1437 /* JoinDesired can change when KAT is started or stopped */
1438 pim_upstream_update_join_desired(pim, up);
1439
1440 /* if entry was created because of activity we need to deref it */
1441 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1442 pim_upstream_fhr_kat_expiry(pim, up);
1443 if (PIM_DEBUG_PIM_TRACE)
1444 zlog_debug(
1445 "kat expired on %s[%s]; remove stream reference",
1446 up->sg_str, pim->vrf->name);
1447 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
1448
1449 /* Return if upstream entry got deleted.*/
1450 if (!pim_upstream_del(pim, up, __func__))
1451 return NULL;
1452 }
1453 if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) {
1454 PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(up->flags);
1455
1456 if (!pim_upstream_del(pim, up, __func__))
1457 return NULL;
1458 }
1459
1460 /* upstream reference would have been added to track the local
1461 * membership if it is LHR. We have to clear it when KAT expires.
1462 * Otherwise would result in stale entry with uncleared ref count.
1463 */
1464 if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
1465 struct pim_upstream *parent = up->parent;
1466
1467 PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
1468 up = pim_upstream_del(pim, up, __func__);
1469
1470 if (parent) {
1471 pim_jp_agg_single_upstream_send(&parent->rpf, parent,
1472 true);
1473 }
1474 }
1475
1476 return up;
1477 }
1478 static int pim_upstream_keep_alive_timer(struct thread *t)
1479 {
1480 struct pim_upstream *up;
1481
1482 up = THREAD_ARG(t);
1483
1484 /* pull the stats and re-check */
1485 if (pim_upstream_sg_running_proc(up))
1486 /* kat was restarted because of new activity */
1487 return 0;
1488
1489 pim_upstream_keep_alive_timer_proc(up);
1490 return 0;
1491 }
1492
1493 void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time)
1494 {
1495 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
1496 if (PIM_DEBUG_PIM_TRACE)
1497 zlog_debug("kat start on %s with no stream reference",
1498 up->sg_str);
1499 }
1500 THREAD_OFF(up->t_ka_timer);
1501 thread_add_timer(router->master, pim_upstream_keep_alive_timer, up,
1502 time, &up->t_ka_timer);
1503
1504 /* any time keepalive is started against a SG we will have to
1505 * re-evaluate our active source database */
1506 pim_msdp_sa_local_update(up);
1507 /* JoinDesired can change when KAT is started or stopped */
1508 pim_upstream_update_join_desired(up->pim, up);
1509 }
1510
1511 /* MSDP on RP needs to know if a source is registerable to this RP */
1512 static int pim_upstream_msdp_reg_timer(struct thread *t)
1513 {
1514 struct pim_upstream *up = THREAD_ARG(t);
1515 struct pim_instance *pim = up->channel_oil->pim;
1516
1517 /* source is no longer active - pull the SA from MSDP's cache */
1518 pim_msdp_sa_local_del(pim, &up->sg);
1519 return 1;
1520 }
1521 void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
1522 {
1523 THREAD_OFF(up->t_msdp_reg_timer);
1524 thread_add_timer(router->master, pim_upstream_msdp_reg_timer, up,
1525 PIM_MSDP_REG_RXED_PERIOD, &up->t_msdp_reg_timer);
1526
1527 pim_msdp_sa_local_update(up);
1528 }
1529
1530 /*
1531 * 4.2.1 Last-Hop Switchover to the SPT
1532 *
1533 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1534 * RP. Once traffic from sources to joined groups arrives at a last-hop
1535 * router, it has the option of switching to receive the traffic on a
1536 * shortest path tree (SPT).
1537 *
1538 * The decision for a router to switch to the SPT is controlled as
1539 * follows:
1540 *
1541 * void
1542 * CheckSwitchToSpt(S,G) {
1543 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1544 * (+) pim_include(S,G) != NULL )
1545 * AND SwitchToSptDesired(S,G) ) {
1546 * # Note: Restarting the KAT will result in the SPT switch
1547 * set KeepaliveTimer(S,G) to Keepalive_Period
1548 * }
1549 * }
1550 *
1551 * SwitchToSptDesired(S,G) is a policy function that is implementation
1552 * defined. An "infinite threshold" policy can be implemented by making
1553 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1554 * first packet" policy can be implemented by making
1555 * SwitchToSptDesired(S,G) return true once a single packet has been
1556 * received for the source and group.
1557 */
1558 int pim_upstream_switch_to_spt_desired_on_rp(struct pim_instance *pim,
1559 struct prefix_sg *sg)
1560 {
1561 if (I_am_RP(pim, sg->grp))
1562 return 1;
1563
1564 return 0;
1565 }
1566
1567 int pim_upstream_is_sg_rpt(struct pim_upstream *up)
1568 {
1569 struct listnode *chnode;
1570 struct pim_ifchannel *ch;
1571
1572 for (ALL_LIST_ELEMENTS_RO(up->ifchannels, chnode, ch)) {
1573 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
1574 return 1;
1575 }
1576
1577 return 0;
1578 }
1579 /*
1580 * After receiving a packet set SPTbit:
1581 * void
1582 * Update_SPTbit(S,G,iif) {
1583 * if ( iif == RPF_interface(S)
1584 * AND JoinDesired(S,G) == true
1585 * AND ( DirectlyConnected(S) == true
1586 * OR RPF_interface(S) != RPF_interface(RP(G))
1587 * OR inherited_olist(S,G,rpt) == NULL
1588 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1589 * ( RPF'(S,G) != NULL ) )
1590 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1591 * Set SPTbit(S,G) to true
1592 * }
1593 * }
1594 */
1595 void pim_upstream_set_sptbit(struct pim_upstream *up,
1596 struct interface *incoming)
1597 {
1598 struct pim_upstream *starup = up->parent;
1599
1600 // iif == RPF_interfvace(S)
1601 if (up->rpf.source_nexthop.interface != incoming) {
1602 if (PIM_DEBUG_PIM_TRACE)
1603 zlog_debug(
1604 "%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1605 __func__, incoming->name,
1606 up->rpf.source_nexthop.interface->name);
1607 return;
1608 }
1609
1610 // AND JoinDesired(S,G) == true
1611 if (!pim_upstream_evaluate_join_desired(up->channel_oil->pim, up)) {
1612 if (PIM_DEBUG_PIM_TRACE)
1613 zlog_debug("%s: %s Join is not Desired", __func__,
1614 up->sg_str);
1615 return;
1616 }
1617
1618 // DirectlyConnected(S) == true
1619 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1620 up->sg.src)) {
1621 if (PIM_DEBUG_PIM_TRACE)
1622 zlog_debug("%s: %s is directly connected to the source",
1623 __func__, up->sg_str);
1624 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1625 return;
1626 }
1627
1628 // OR RPF_interface(S) != RPF_interface(RP(G))
1629 if (!starup
1630 || up->rpf.source_nexthop
1631 .interface != starup->rpf.source_nexthop.interface) {
1632 struct pim_upstream *starup = up->parent;
1633
1634 if (PIM_DEBUG_PIM_TRACE)
1635 zlog_debug(
1636 "%s: %s RPF_interface(S) != RPF_interface(RP(G))",
1637 __func__, up->sg_str);
1638 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1639
1640 pim_jp_agg_single_upstream_send(&starup->rpf, starup, true);
1641 return;
1642 }
1643
1644 // OR inherited_olist(S,G,rpt) == NULL
1645 if (pim_upstream_is_sg_rpt(up)
1646 && pim_upstream_empty_inherited_olist(up)) {
1647 if (PIM_DEBUG_PIM_TRACE)
1648 zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL",
1649 __func__, up->sg_str);
1650 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1651 return;
1652 }
1653
1654 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1655 // ( RPF'(S,G) != NULL ) )
1656 if (up->parent && pim_rpf_is_same(&up->rpf, &up->parent->rpf)) {
1657 if (PIM_DEBUG_PIM_TRACE)
1658 zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)",
1659 __func__, up->sg_str);
1660 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1661 return;
1662 }
1663
1664 return;
1665 }
1666
1667 const char *pim_upstream_state2str(enum pim_upstream_state join_state)
1668 {
1669 switch (join_state) {
1670 case PIM_UPSTREAM_NOTJOINED:
1671 return "NotJoined";
1672 case PIM_UPSTREAM_JOINED:
1673 return "Joined";
1674 }
1675 return "Unknown";
1676 }
1677
1678 const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str,
1679 size_t state_str_len)
1680 {
1681 switch (reg_state) {
1682 case PIM_REG_NOINFO:
1683 strlcpy(state_str, "RegNoInfo", state_str_len);
1684 break;
1685 case PIM_REG_JOIN:
1686 strlcpy(state_str, "RegJoined", state_str_len);
1687 break;
1688 case PIM_REG_JOIN_PENDING:
1689 strlcpy(state_str, "RegJoinPend", state_str_len);
1690 break;
1691 case PIM_REG_PRUNE:
1692 strlcpy(state_str, "RegPrune", state_str_len);
1693 break;
1694 default:
1695 strlcpy(state_str, "RegUnknown", state_str_len);
1696 }
1697 return state_str;
1698 }
1699
1700 static int pim_upstream_register_stop_timer(struct thread *t)
1701 {
1702 struct pim_interface *pim_ifp;
1703 struct pim_instance *pim;
1704 struct pim_upstream *up;
1705 up = THREAD_ARG(t);
1706 pim = up->channel_oil->pim;
1707
1708 if (PIM_DEBUG_PIM_TRACE) {
1709 char state_str[PIM_REG_STATE_STR_LEN];
1710 zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
1711 __func__, up->sg_str, pim->vrf->name,
1712 pim_reg_state2str(up->reg_state, state_str,
1713 sizeof(state_str)));
1714 }
1715
1716 switch (up->reg_state) {
1717 case PIM_REG_JOIN_PENDING:
1718 up->reg_state = PIM_REG_JOIN;
1719 pim_channel_add_oif(up->channel_oil, pim->regiface,
1720 PIM_OIF_FLAG_PROTO_PIM,
1721 __func__);
1722 pim_vxlan_update_sg_reg_state(pim, up, true /*reg_join*/);
1723 break;
1724 case PIM_REG_JOIN:
1725 break;
1726 case PIM_REG_PRUNE:
1727 /* This is equalent to Couldreg -> False */
1728 if (!up->rpf.source_nexthop.interface) {
1729 if (PIM_DEBUG_PIM_TRACE)
1730 zlog_debug("%s: up %s RPF is not present",
1731 __func__, up->sg_str);
1732 up->reg_state = PIM_REG_NOINFO;
1733 return 0;
1734 }
1735
1736 pim_ifp = up->rpf.source_nexthop.interface->info;
1737 if (!pim_ifp) {
1738 if (PIM_DEBUG_PIM_TRACE)
1739 zlog_debug(
1740 "%s: Interface: %s is not configured for pim",
1741 __func__,
1742 up->rpf.source_nexthop.interface->name);
1743 return 0;
1744 }
1745 up->reg_state = PIM_REG_JOIN_PENDING;
1746 pim_upstream_start_register_stop_timer(up, 1);
1747
1748 if (((up->channel_oil->cc.lastused / 100)
1749 > pim->keep_alive_time)
1750 && (I_am_RP(pim_ifp->pim, up->sg.grp))) {
1751 if (PIM_DEBUG_PIM_TRACE)
1752 zlog_debug(
1753 "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while",
1754 __func__);
1755 return 0;
1756 }
1757 pim_null_register_send(up);
1758 break;
1759 default:
1760 break;
1761 }
1762
1763 return 0;
1764 }
1765
1766 void pim_upstream_start_register_stop_timer(struct pim_upstream *up,
1767 int null_register)
1768 {
1769 uint32_t time;
1770
1771 THREAD_OFF(up->t_rs_timer);
1772
1773 if (!null_register) {
1774 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1775 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1776 time = lower + (frr_weak_random() % (upper - lower + 1))
1777 - PIM_REGISTER_PROBE_PERIOD;
1778 } else
1779 time = PIM_REGISTER_PROBE_PERIOD;
1780
1781 if (PIM_DEBUG_PIM_TRACE) {
1782 zlog_debug(
1783 "%s: (S,G)=%s Starting upstream register stop timer %d",
1784 __func__, up->sg_str, time);
1785 }
1786 thread_add_timer(router->master, pim_upstream_register_stop_timer, up,
1787 time, &up->t_rs_timer);
1788 }
1789
1790 int pim_upstream_inherited_olist_decide(struct pim_instance *pim,
1791 struct pim_upstream *up)
1792 {
1793 struct interface *ifp;
1794 struct pim_ifchannel *ch, *starch;
1795 struct pim_upstream *starup = up->parent;
1796 int output_intf = 0;
1797
1798 if (!up->rpf.source_nexthop.interface)
1799 if (PIM_DEBUG_PIM_TRACE)
1800 zlog_debug("%s: up %s RPF is not present", __func__,
1801 up->sg_str);
1802
1803 FOR_ALL_INTERFACES (pim->vrf, ifp) {
1804 struct pim_interface *pim_ifp;
1805 if (!ifp->info)
1806 continue;
1807
1808 ch = pim_ifchannel_find(ifp, &up->sg);
1809
1810 if (starup)
1811 starch = pim_ifchannel_find(ifp, &starup->sg);
1812 else
1813 starch = NULL;
1814
1815 if (!ch && !starch)
1816 continue;
1817
1818 pim_ifp = ifp->info;
1819 if (PIM_I_am_DualActive(pim_ifp)
1820 && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)
1821 && (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)
1822 || !PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up->flags)))
1823 continue;
1824 if (pim_upstream_evaluate_join_desired_interface(up, ch,
1825 starch)) {
1826 int flag = 0;
1827
1828 if (!ch)
1829 flag = PIM_OIF_FLAG_PROTO_STAR;
1830 else {
1831 if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
1832 flag = PIM_OIF_FLAG_PROTO_IGMP;
1833 if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
1834 flag |= PIM_OIF_FLAG_PROTO_PIM;
1835 }
1836
1837 pim_channel_add_oif(up->channel_oil, ifp, flag,
1838 __func__);
1839 output_intf++;
1840 }
1841 }
1842
1843 return output_intf;
1844 }
1845
1846 /*
1847 * For a given upstream, determine the inherited_olist
1848 * and apply it.
1849 *
1850 * inherited_olist(S,G,rpt) =
1851 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1852 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1853 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1854 *
1855 * inherited_olist(S,G) =
1856 * inherited_olist(S,G,rpt) (+)
1857 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1858 *
1859 * return 1 if there are any output interfaces
1860 * return 0 if there are not any output interfaces
1861 */
1862 int pim_upstream_inherited_olist(struct pim_instance *pim,
1863 struct pim_upstream *up)
1864 {
1865 int output_intf = pim_upstream_inherited_olist_decide(pim, up);
1866
1867 /*
1868 * If we have output_intf switch state to Join and work like normal
1869 * If we don't have an output_intf that means we are probably a
1870 * switch on a stick so turn on forwarding to just accept the
1871 * incoming packets so we don't bother the other stuff!
1872 */
1873 pim_upstream_update_join_desired(pim, up);
1874
1875 if (!output_intf)
1876 forward_on(up);
1877
1878 return output_intf;
1879 }
1880
1881 int pim_upstream_empty_inherited_olist(struct pim_upstream *up)
1882 {
1883 return pim_channel_oil_empty(up->channel_oil);
1884 }
1885
1886 /*
1887 * When we have a new neighbor,
1888 * find upstreams that don't have their rpf_addr
1889 * set and see if the new neighbor allows
1890 * the join to be sent
1891 */
1892 void pim_upstream_find_new_rpf(struct pim_instance *pim)
1893 {
1894 struct pim_upstream *up;
1895 struct pim_rpf old;
1896 enum pim_rpf_result rpf_result;
1897
1898 /*
1899 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1900 */
1901 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
1902 if (up->upstream_addr.s_addr == INADDR_ANY) {
1903 if (PIM_DEBUG_PIM_TRACE)
1904 zlog_debug(
1905 "%s: RP not configured for Upstream %s",
1906 __func__, up->sg_str);
1907 continue;
1908 }
1909
1910 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
1911 if (PIM_DEBUG_PIM_TRACE)
1912 zlog_debug(
1913 "%s: Upstream %s without a path to send join, checking",
1914 __func__, up->sg_str);
1915 old.source_nexthop.interface =
1916 up->rpf.source_nexthop.interface;
1917 rpf_result = pim_rpf_update(pim, up, &old, __func__);
1918 if (rpf_result == PIM_RPF_CHANGED ||
1919 (rpf_result == PIM_RPF_FAILURE &&
1920 old.source_nexthop.interface))
1921 pim_zebra_upstream_rpf_changed(pim, up, &old);
1922 /* update kernel multicast forwarding cache (MFC) */
1923 pim_upstream_mroute_iif_update(up->channel_oil,
1924 __func__);
1925 }
1926 }
1927 pim_zebra_update_all_interfaces(pim);
1928 }
1929
1930 unsigned int pim_upstream_hash_key(const void *arg)
1931 {
1932 const struct pim_upstream *up = arg;
1933
1934 return jhash_2words(up->sg.src.s_addr, up->sg.grp.s_addr, 0);
1935 }
1936
1937 void pim_upstream_terminate(struct pim_instance *pim)
1938 {
1939 struct pim_upstream *up;
1940
1941 while ((up = rb_pim_upstream_first(&pim->upstream_head))) {
1942 pim_upstream_del(pim, up, __func__);
1943 }
1944
1945 rb_pim_upstream_fini(&pim->upstream_head);
1946
1947 if (pim->upstream_sg_wheel)
1948 wheel_delete(pim->upstream_sg_wheel);
1949 pim->upstream_sg_wheel = NULL;
1950 }
1951
1952 bool pim_upstream_equal(const void *arg1, const void *arg2)
1953 {
1954 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1955 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
1956
1957 if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr)
1958 && (up1->sg.src.s_addr == up2->sg.src.s_addr))
1959 return true;
1960
1961 return false;
1962 }
1963
1964 /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1965 * the cases where kat has to be restarted on rxing traffic -
1966 *
1967 * if( DirectlyConnected(S) == true AND iif == RPF_interface(S) ) {
1968 * set KeepaliveTimer(S,G) to Keepalive_Period
1969 * # Note: a register state transition or UpstreamJPState(S,G)
1970 * # transition may happen as a result of restarting
1971 * # KeepaliveTimer, and must be dealt with here.
1972 * }
1973 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1974 * inherited_olist(S,G) != NULL ) {
1975 * set KeepaliveTimer(S,G) to Keepalive_Period
1976 * }
1977 */
1978 static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
1979 {
1980 struct channel_oil *c_oil = up->channel_oil;
1981 struct interface *ifp = up->rpf.source_nexthop.interface;
1982 struct pim_interface *pim_ifp;
1983
1984 /* "iif == RPF_interface(S)" check is not easy to do as the info
1985 * we get from the kernel/ASIC is really a "lookup/key hit".
1986 * So we will do an approximate check here to avoid starting KAT
1987 * because of (S,G,rpt) forwarding on a non-LHR.
1988 */
1989 if (!ifp)
1990 return false;
1991
1992 pim_ifp = ifp->info;
1993 if (pim_ifp->mroute_vif_index != c_oil->oil.mfcc_parent)
1994 return false;
1995
1996 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1997 up->sg.src)) {
1998 return true;
1999 }
2000
2001 if ((up->join_state == PIM_UPSTREAM_JOINED)
2002 && !pim_upstream_empty_inherited_olist(up)) {
2003 return true;
2004 }
2005
2006 return false;
2007 }
2008
2009 static bool pim_upstream_sg_running_proc(struct pim_upstream *up)
2010 {
2011 bool rv = false;
2012 struct pim_instance *pim = up->pim;
2013
2014 if (!up->channel_oil->installed)
2015 return rv;
2016
2017 pim_mroute_update_counters(up->channel_oil);
2018
2019 // Have we seen packets?
2020 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt)
2021 && (up->channel_oil->cc.lastused / 100 > 30)) {
2022 if (PIM_DEBUG_PIM_TRACE) {
2023 zlog_debug(
2024 "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
2025 __func__, up->sg_str, pim->vrf->name,
2026 up->channel_oil->cc.oldpktcnt,
2027 up->channel_oil->cc.pktcnt,
2028 up->channel_oil->cc.lastused / 100);
2029 }
2030 return rv;
2031 }
2032
2033 if (pim_upstream_kat_start_ok(up)) {
2034 /* Add a source reference to the stream if
2035 * one doesn't already exist */
2036 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
2037 if (PIM_DEBUG_PIM_TRACE)
2038 zlog_debug(
2039 "source reference created on kat restart %s[%s]",
2040 up->sg_str, pim->vrf->name);
2041
2042 pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM,
2043 __func__);
2044 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
2045 pim_upstream_fhr_kat_start(up);
2046 }
2047 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
2048 rv = true;
2049 } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) {
2050 pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time);
2051 rv = true;
2052 }
2053
2054 if ((up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) &&
2055 (up->rpf.source_nexthop.interface)) {
2056 pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
2057 }
2058
2059 return rv;
2060 }
2061
2062 /*
2063 * Code to check and see if we've received packets on a S,G mroute
2064 * and if so to set the SPT bit appropriately
2065 */
2066 static void pim_upstream_sg_running(void *arg)
2067 {
2068 struct pim_upstream *up = (struct pim_upstream *)arg;
2069 struct pim_instance *pim = up->channel_oil->pim;
2070
2071 // No packet can have arrived here if this is the case
2072 if (!up->channel_oil->installed) {
2073 if (PIM_DEBUG_TRACE)
2074 zlog_debug("%s: %s%s is not installed in mroute",
2075 __func__, up->sg_str, pim->vrf->name);
2076 return;
2077 }
2078
2079 /*
2080 * This is a bit of a hack
2081 * We've noted that we should rescan but
2082 * we've missed the window for doing so in
2083 * pim_zebra.c for some reason. I am
2084 * only doing this at this point in time
2085 * to get us up and working for the moment
2086 */
2087 if (up->channel_oil->oil_inherited_rescan) {
2088 if (PIM_DEBUG_TRACE)
2089 zlog_debug(
2090 "%s: Handling unscanned inherited_olist for %s[%s]",
2091 __func__, up->sg_str, pim->vrf->name);
2092 pim_upstream_inherited_olist_decide(pim, up);
2093 up->channel_oil->oil_inherited_rescan = 0;
2094 }
2095
2096 pim_upstream_sg_running_proc(up);
2097 }
2098
2099 void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim)
2100 {
2101 struct pim_upstream *up;
2102
2103 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2104 if (up->sg.src.s_addr != INADDR_ANY)
2105 continue;
2106
2107 if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags))
2108 continue;
2109
2110 pim_channel_add_oif(up->channel_oil, pim->regiface,
2111 PIM_OIF_FLAG_PROTO_IGMP, __func__);
2112 }
2113 }
2114
2115 void pim_upstream_spt_prefix_list_update(struct pim_instance *pim,
2116 struct prefix_list *pl)
2117 {
2118 const char *pname = prefix_list_name(pl);
2119
2120 if (pim->spt.plist && strcmp(pim->spt.plist, pname) == 0) {
2121 pim_upstream_remove_lhr_star_pimreg(pim, pname);
2122 }
2123 }
2124
2125 /*
2126 * nlist -> The new prefix list
2127 *
2128 * Per Group Application of pimreg to the OIL
2129 * If the prefix list tells us DENY then
2130 * we need to Switchover to SPT immediate
2131 * so add the pimreg.
2132 * If the prefix list tells us to ACCEPT than
2133 * we need to Never do the SPT so remove
2134 * the interface
2135 *
2136 */
2137 void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim,
2138 const char *nlist)
2139 {
2140 struct pim_upstream *up;
2141 struct prefix_list *np;
2142 struct prefix g;
2143 enum prefix_list_type apply_new;
2144
2145 np = prefix_list_lookup(AFI_IP, nlist);
2146
2147 g.family = AF_INET;
2148 g.prefixlen = IPV4_MAX_PREFIXLEN;
2149
2150 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
2151 if (up->sg.src.s_addr != INADDR_ANY)
2152 continue;
2153
2154 if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags))
2155 continue;
2156
2157 if (!nlist) {
2158 pim_channel_del_oif(up->channel_oil, pim->regiface,
2159 PIM_OIF_FLAG_PROTO_IGMP, __func__);
2160 continue;
2161 }
2162 g.u.prefix4 = up->sg.grp;
2163 apply_new = prefix_list_apply(np, &g);
2164 if (apply_new == PREFIX_DENY)
2165 pim_channel_add_oif(up->channel_oil, pim->regiface,
2166 PIM_OIF_FLAG_PROTO_IGMP,
2167 __func__);
2168 else
2169 pim_channel_del_oif(up->channel_oil, pim->regiface,
2170 PIM_OIF_FLAG_PROTO_IGMP, __func__);
2171 }
2172 }
2173
2174 void pim_upstream_init(struct pim_instance *pim)
2175 {
2176 char name[64];
2177
2178 snprintf(name, sizeof(name), "PIM %s Timer Wheel", pim->vrf->name);
2179 pim->upstream_sg_wheel =
2180 wheel_init(router->master, 31000, 100, pim_upstream_hash_key,
2181 pim_upstream_sg_running, name);
2182
2183 rb_pim_upstream_init(&pim->upstream_head);
2184 }