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