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