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