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