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