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