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