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