]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_upstream.c
lib, pimd: Fix borked up prefix code
[mirror_frr.git] / pimd / pim_upstream.c
CommitLineData
12e41d03
DL
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
12e41d03
DL
20*/
21
22#include <zebra.h>
23
24#include "zebra/rib.h"
25
26#include "log.h"
27#include "zclient.h"
28#include "memory.h"
29#include "thread.h"
30#include "linklist.h"
31
32#include "pimd.h"
33#include "pim_pim.h"
34#include "pim_str.h"
35#include "pim_time.h"
36#include "pim_iface.h"
37#include "pim_join.h"
38#include "pim_zlookup.h"
39#include "pim_upstream.h"
40#include "pim_ifchannel.h"
41#include "pim_neighbor.h"
42#include "pim_rpf.h"
43#include "pim_zebra.h"
44#include "pim_oil.h"
45#include "pim_macro.h"
8f5f5e91 46#include "pim_rp.h"
f14248dd 47#include "pim_br.h"
627ed2a3 48#include "pim_register.h"
12e41d03
DL
49
50static void join_timer_start(struct pim_upstream *up);
51static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
52
cfa91a87
DS
53/*
54 * A (*,G) or a (*,*) is going away
55 * remove the parent pointer from
56 * those pointing at us
57 */
58static void
59pim_upstream_remove_children (struct pim_upstream *up)
60{
61 struct listnode *ch_node;
62 struct pim_upstream *child;
63
64 // Basic sanity, (*,*) not currently supported
4ed0af70
DS
65 if ((up->sg.src.s_addr == INADDR_ANY) &&
66 (up->sg.grp.s_addr == INADDR_ANY))
cfa91a87
DS
67 return;
68
69 // Basic sanity (S,G) have no children
4ed0af70
DS
70 if ((up->sg.src.s_addr != INADDR_ANY) &&
71 (up->sg.grp.s_addr != INADDR_ANY))
cfa91a87
DS
72 return;
73
74 for (ALL_LIST_ELEMENTS_RO (qpim_upstream_list, ch_node, child))
75 {
76 if (child->parent == up)
77 child->parent = NULL;
78 }
79}
80
81/*
82 * A (*,G) or a (*,*) is being created
83 * Find the children that would point
84 * at us.
85 */
86static void
87pim_upstream_find_new_children (struct pim_upstream *up)
88{
89 struct pim_upstream *child;
90 struct listnode *ch_node;
91
4ed0af70
DS
92 if ((up->sg.src.s_addr != INADDR_ANY) &&
93 (up->sg.grp.s_addr != INADDR_ANY))
cfa91a87
DS
94 return;
95
4ed0af70
DS
96 if ((up->sg.src.s_addr == INADDR_ANY) &&
97 (up->sg.grp.s_addr == INADDR_ANY))
cfa91a87
DS
98 return;
99
100 for (ALL_LIST_ELEMENTS_RO (qpim_upstream_list, ch_node, child))
101 {
4ed0af70
DS
102 if ((up->sg.grp.s_addr != INADDR_ANY) &&
103 (child->sg.grp.s_addr == up->sg.grp.s_addr) &&
cfa91a87
DS
104 (child != up))
105 child->parent = up;
106 }
107}
108
4d99418b
DS
109/*
110 * If we have a (*,*) || (S,*) there is no parent
111 * If we have a (S,G), find the (*,G)
112 * If we have a (*,G), find the (*,*)
113 */
114static struct pim_upstream *
4ed0af70 115pim_upstream_find_parent (struct prefix_sg *sg)
4d99418b 116{
4ed0af70 117 struct prefix_sg any = *sg;
4d99418b
DS
118
119 // (*,*) || (S,*)
4ed0af70
DS
120 if (((sg->src.s_addr == INADDR_ANY) &&
121 (sg->grp.s_addr == INADDR_ANY)) ||
122 ((sg->src.s_addr != INADDR_ANY) &&
123 (sg->grp.s_addr == INADDR_ANY)))
4d99418b
DS
124 return NULL;
125
126 // (S,G)
4ed0af70
DS
127 if ((sg->src.s_addr != INADDR_ANY) &&
128 (sg->grp.s_addr != INADDR_ANY))
4d99418b 129 {
4ed0af70 130 any.src.s_addr = INADDR_ANY;
4d99418b
DS
131 return pim_upstream_find (&any);
132 }
133
134 // (*,G)
4ed0af70 135 any.grp.s_addr = INADDR_ANY;
4d99418b
DS
136 return pim_upstream_find (&any);
137}
138
12e41d03
DL
139void pim_upstream_free(struct pim_upstream *up)
140{
141 XFREE(MTYPE_PIM_UPSTREAM, up);
142}
143
144static void upstream_channel_oil_detach(struct pim_upstream *up)
145{
146 if (up->channel_oil) {
147 pim_channel_oil_del(up->channel_oil);
25a335e0 148 up->channel_oil = NULL;
12e41d03
DL
149 }
150}
151
152void pim_upstream_delete(struct pim_upstream *up)
153{
154 THREAD_OFF(up->t_join_timer);
f14248dd 155 THREAD_OFF(up->t_ka_timer);
792f4d29 156 THREAD_OFF(up->t_rs_timer);
12e41d03 157
cfa91a87 158 pim_upstream_remove_children (up);
12e41d03
DL
159 upstream_channel_oil_detach(up);
160
161 /*
162 notice that listnode_delete() can't be moved
163 into pim_upstream_free() because the later is
164 called by list_delete_all_node()
165 */
166 listnode_delete(qpim_upstream_list, up);
167
168 pim_upstream_free(up);
169}
170
56638739
DS
171void
172pim_upstream_send_join (struct pim_upstream *up)
12e41d03 173{
12e41d03 174 if (PIM_DEBUG_PIM_TRACE) {
56638739 175 char rpf_str[100];
56638739 176 pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
05e451f8
DS
177 zlog_debug ("%s: RPF'%s=%s(%s) for Interface %s", __PRETTY_FUNCTION__,
178 pim_str_sg_dump (&up->sg), rpf_str, pim_upstream_state2str (up),
56638739 179 up->rpf.source_nexthop.interface->name);
12e41d03 180 if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) {
05e451f8 181 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
56638739 182 __PRETTY_FUNCTION__,
05e451f8 183 pim_str_sg_dump (&up->sg), rpf_str);
12e41d03
DL
184 /* warning only */
185 }
186 }
56638739
DS
187
188 /*
189 * In the case of a FHR we will not have anyone to send this to.
190 */
191 if (up->fhr)
192 return;
193
194 zassert(up->join_state == PIM_UPSTREAM_JOINED);
12e41d03
DL
195
196 /* send Join(S,G) to the current upstream neighbor */
197 pim_joinprune_send(up->rpf.source_nexthop.interface,
198 up->rpf.rpf_addr,
05e451f8 199 &up->sg,
12e41d03
DL
200 1 /* join */);
201}
202
203static int on_join_timer(struct thread *t)
204{
205 struct pim_upstream *up;
206
207 zassert(t);
208 up = THREAD_ARG(t);
209 zassert(up);
210
56638739 211 pim_upstream_send_join (up);
12e41d03 212
4a4c4a07 213 up->t_join_timer = NULL;
12e41d03
DL
214 join_timer_start(up);
215
216 return 0;
217}
218
219static void join_timer_start(struct pim_upstream *up)
220{
221 if (PIM_DEBUG_PIM_EVENTS) {
05e451f8 222 zlog_debug("%s: starting %d sec timer for upstream (S,G)=%s",
12e41d03
DL
223 __PRETTY_FUNCTION__,
224 qpim_t_periodic,
05e451f8 225 pim_str_sg_dump (&up->sg));
12e41d03
DL
226 }
227
228 zassert(!up->t_join_timer);
229
230 THREAD_TIMER_ON(master, up->t_join_timer,
231 on_join_timer,
232 up, qpim_t_periodic);
233}
234
235void pim_upstream_join_timer_restart(struct pim_upstream *up)
236{
237 THREAD_OFF(up->t_join_timer);
238 join_timer_start(up);
239}
240
241static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
242 int interval_msec)
243{
244 if (PIM_DEBUG_PIM_EVENTS) {
05e451f8 245 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
12e41d03
DL
246 __PRETTY_FUNCTION__,
247 interval_msec,
05e451f8 248 pim_str_sg_dump (&up->sg));
12e41d03
DL
249 }
250
251 THREAD_OFF(up->t_join_timer);
252 THREAD_TIMER_MSEC_ON(master, up->t_join_timer,
253 on_join_timer,
254 up, interval_msec);
255}
256
257void pim_upstream_join_suppress(struct pim_upstream *up,
258 struct in_addr rpf_addr,
259 int holdtime)
260{
261 long t_joinsuppress_msec;
262 long join_timer_remain_msec;
263
264 t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
265 1000 * holdtime);
266
267 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
268
269 if (PIM_DEBUG_PIM_TRACE) {
12e41d03 270 char rpf_str[100];
12e41d03 271 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
05e451f8 272 zlog_debug("%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
12e41d03 273 __FILE__, __PRETTY_FUNCTION__,
05e451f8 274 pim_str_sg_dump (&up->sg),
12e41d03
DL
275 rpf_str,
276 join_timer_remain_msec, t_joinsuppress_msec);
277 }
278
279 if (join_timer_remain_msec < t_joinsuppress_msec) {
280 if (PIM_DEBUG_PIM_TRACE) {
05e451f8 281 zlog_debug("%s %s: suppressing Join(S,G)=%s for %ld msec",
12e41d03 282 __FILE__, __PRETTY_FUNCTION__,
05e451f8 283 pim_str_sg_dump (&up->sg), t_joinsuppress_msec);
12e41d03
DL
284 }
285
286 pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
287 }
288}
289
290void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
291 struct pim_upstream *up,
292 struct in_addr rpf_addr)
293{
294 long join_timer_remain_msec;
295 int t_override_msec;
296
297 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
298 t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface);
299
300 if (PIM_DEBUG_PIM_TRACE) {
12e41d03 301 char rpf_str[100];
12e41d03 302 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
05e451f8 303 zlog_debug("%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
12e41d03 304 debug_label,
05e451f8 305 pim_str_sg_dump (&up->sg), rpf_str,
12e41d03
DL
306 join_timer_remain_msec, t_override_msec);
307 }
308
309 if (join_timer_remain_msec > t_override_msec) {
310 if (PIM_DEBUG_PIM_TRACE) {
05e451f8 311 zlog_debug("%s: decreasing (S,G)=%s join timer to t_override=%d msec",
12e41d03 312 debug_label,
05e451f8 313 pim_str_sg_dump (&up->sg),
12e41d03
DL
314 t_override_msec);
315 }
316
317 pim_upstream_join_timer_restart_msec(up, t_override_msec);
318 }
319}
320
321static void forward_on(struct pim_upstream *up)
322{
323 struct listnode *ifnode;
324 struct listnode *ifnextnode;
325 struct listnode *chnode;
326 struct listnode *chnextnode;
327 struct interface *ifp;
328 struct pim_interface *pim_ifp;
329 struct pim_ifchannel *ch;
330
331 /* scan all interfaces */
469351b3 332 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
333 pim_ifp = ifp->info;
334 if (!pim_ifp)
335 continue;
336
337 /* scan per-interface (S,G) state */
338 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
339
340 if (ch->upstream != up)
341 continue;
342
343 if (pim_macro_chisin_oiflist(ch))
344 pim_forward_start(ch);
345
346 } /* scan iface channel list */
347 } /* scan iflist */
348}
349
350static void forward_off(struct pim_upstream *up)
351{
352 struct listnode *ifnode;
353 struct listnode *ifnextnode;
354 struct listnode *chnode;
355 struct listnode *chnextnode;
356 struct interface *ifp;
357 struct pim_interface *pim_ifp;
358 struct pim_ifchannel *ch;
359
360 /* scan all interfaces */
469351b3 361 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
362 pim_ifp = ifp->info;
363 if (!pim_ifp)
364 continue;
365
366 /* scan per-interface (S,G) state */
367 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
368
369 if (ch->upstream != up)
370 continue;
371
372 pim_forward_stop(ch);
373
374 } /* scan iface channel list */
375 } /* scan iflist */
376}
377
7fcdfb34
DS
378void
379pim_upstream_switch(struct pim_upstream *up,
380 enum pim_upstream_state new_state)
12e41d03
DL
381{
382 enum pim_upstream_state old_state = up->join_state;
383
12e41d03
DL
384 up->join_state = new_state;
385 up->state_transition = pim_time_monotonic_sec();
386
387 if (PIM_DEBUG_PIM_EVENTS) {
05e451f8 388 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G)=%s",
12e41d03
DL
389 __PRETTY_FUNCTION__,
390 ((new_state == PIM_UPSTREAM_JOINED) ? "JOINED" : "NOTJOINED"),
05e451f8 391 pim_str_sg_dump (&up->sg));
12e41d03
DL
392 }
393
394 pim_upstream_update_assert_tracking_desired(up);
395
396 if (new_state == PIM_UPSTREAM_JOINED) {
81900c5a
DS
397 if (old_state != PIM_UPSTREAM_JOINED)
398 {
399 forward_on(up);
400 pim_upstream_send_join (up);
401 join_timer_start(up);
402 }
403 else
404 {
405 forward_on (up);
406 }
12e41d03
DL
407 }
408 else {
409 forward_off(up);
410 pim_joinprune_send(up->rpf.source_nexthop.interface,
411 up->rpf.rpf_addr,
05e451f8 412 &up->sg,
12e41d03 413 0 /* prune */);
7fcdfb34
DS
414 if (up->t_join_timer)
415 THREAD_OFF(up->t_join_timer);
12e41d03 416 }
12e41d03
DL
417}
418
4ed0af70 419static struct pim_upstream *pim_upstream_new(struct prefix_sg *sg,
651d0f71 420 struct interface *incoming)
12e41d03
DL
421{
422 struct pim_upstream *up;
2f702571 423 enum pim_rpf_result rpf_result;
12e41d03 424
36d9e7dc 425 up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
12e41d03 426 if (!up) {
36d9e7dc 427 zlog_err("%s: PIM XCALLOC(%zu) failure",
12e41d03 428 __PRETTY_FUNCTION__, sizeof(*up));
8f5f5e91 429 return NULL;
12e41d03
DL
430 }
431
5074a423 432 up->sg = *sg;
4ed0af70 433 if (!pim_rp_set_upstream_addr (&up->upstream_addr, sg->src))
8f5f5e91
DS
434 {
435 if (PIM_DEBUG_PIM_TRACE)
436 zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
437
438 XFREE (MTYPE_PIM_UPSTREAM, up);
439 return NULL;
440 }
441
4d99418b 442 up->parent = pim_upstream_find_parent (sg);
cfa91a87 443 pim_upstream_find_new_children (up);
12e41d03
DL
444 up->flags = 0;
445 up->ref_count = 1;
4a4c4a07
DS
446 up->t_join_timer = NULL;
447 up->t_ka_timer = NULL;
792f4d29 448 up->t_rs_timer = NULL;
12e41d03
DL
449 up->join_state = 0;
450 up->state_transition = pim_time_monotonic_sec();
4a4c4a07 451 up->channel_oil = NULL;
f9e0ab5b 452 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
12e41d03
DL
453
454 up->rpf.source_nexthop.interface = 0;
455 up->rpf.source_nexthop.mrib_nexthop_addr.s_addr = PIM_NET_INADDR_ANY;
456 up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference;
457 up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric;
458 up->rpf.rpf_addr.s_addr = PIM_NET_INADDR_ANY;
459
651d0f71 460 rpf_result = pim_rpf_update(up, 0, incoming);
2f702571
DS
461 if (rpf_result == PIM_RPF_FAILURE) {
462 XFREE(MTYPE_PIM_UPSTREAM, up);
463 return NULL;
464 }
12e41d03
DL
465
466 listnode_add(qpim_upstream_list, up);
467
468 return up;
469}
470
6c629103
DS
471/*
472 * For a given sg, find any non * source
473 */
4ed0af70 474struct pim_upstream *pim_upstream_find_non_any (struct prefix_sg *sg)
6c629103
DS
475{
476 struct listnode *up_node;
4ed0af70 477 struct prefix_sg any = *sg;
6c629103
DS
478 struct pim_upstream *up;
479
4ed0af70 480 any.src.s_addr = INADDR_ANY;
6c629103
DS
481
482 for (ALL_LIST_ELEMENTS_RO (qpim_upstream_list, up_node, up))
483 {
4ed0af70
DS
484 if ((any.grp.s_addr == up->sg.grp.s_addr) &&
485 (up->sg.src.s_addr != any.src.s_addr))
6c629103
DS
486 return up;
487 }
488
489 return NULL;
490}
491
4ed0af70 492struct pim_upstream *pim_upstream_find(struct prefix_sg *sg)
12e41d03
DL
493{
494 struct listnode *up_node;
495 struct pim_upstream *up;
496
497 for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) {
4ed0af70
DS
498 if ((sg->grp.s_addr == up->sg.grp.s_addr) &&
499 (sg->src.s_addr == up->sg.src.s_addr))
a3b58b4a 500 return up;
12e41d03
DL
501 }
502
d7259eac 503 return NULL;
12e41d03
DL
504}
505
4ed0af70 506struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
651d0f71 507 struct interface *incoming)
12e41d03
DL
508{
509 struct pim_upstream *up;
510
5074a423 511 up = pim_upstream_find(sg);
12e41d03
DL
512 if (up) {
513 ++up->ref_count;
514 }
515 else {
5074a423 516 up = pim_upstream_new(sg, incoming);
12e41d03
DL
517 }
518
519 return up;
520}
521
522void pim_upstream_del(struct pim_upstream *up)
523{
524 --up->ref_count;
525
526 if (up->ref_count < 1) {
527 pim_upstream_delete(up);
528 }
529}
530
531/*
532 Evaluate JoinDesired(S,G):
533
534 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
535 in the set:
536
537 inherited_olist(S,G) =
538 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
539
540 JoinDesired(S,G) may be affected by changes in the following:
541
542 pim_ifp->primary_address
543 pim_ifp->pim_dr_addr
544 ch->ifassert_winner_metric
545 ch->ifassert_winner
546 ch->local_ifmembership
547 ch->ifjoin_state
548 ch->upstream->rpf.source_nexthop.mrib_metric_preference
549 ch->upstream->rpf.source_nexthop.mrib_route_metric
550 ch->upstream->rpf.source_nexthop.interface
551
552 See also pim_upstream_update_join_desired() below.
553 */
554int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
555{
556 struct listnode *ifnode;
557 struct listnode *ifnextnode;
558 struct listnode *chnode;
559 struct listnode *chnextnode;
560 struct interface *ifp;
561 struct pim_interface *pim_ifp;
562 struct pim_ifchannel *ch;
563
564 /* scan all interfaces */
469351b3 565 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
566 pim_ifp = ifp->info;
567 if (!pim_ifp)
568 continue;
569
570 /* scan per-interface (S,G) state */
571 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
572 if (ch->upstream != up)
573 continue;
574
575 if (pim_macro_ch_lost_assert(ch))
576 continue; /* keep searching */
577
578 if (pim_macro_chisin_joins_or_include(ch))
579 return 1; /* true */
580 } /* scan iface channel list */
581 } /* scan iflist */
582
583 return 0; /* false */
584}
585
586/*
587 See also pim_upstream_evaluate_join_desired() above.
588*/
589void pim_upstream_update_join_desired(struct pim_upstream *up)
590{
591 int was_join_desired; /* boolean */
592 int is_join_desired; /* boolean */
593
594 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
595
596 is_join_desired = pim_upstream_evaluate_join_desired(up);
597 if (is_join_desired)
598 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
599 else
600 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
601
602 /* switched from false to true */
603 if (is_join_desired && !was_join_desired) {
12e41d03
DL
604 pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
605 return;
606 }
607
608 /* switched from true to false */
609 if (!is_join_desired && was_join_desired) {
610 zassert(up->join_state == PIM_UPSTREAM_JOINED);
611 pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
612 return;
613 }
614}
615
616/*
617 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
618 Transitions from Joined State
619 RPF'(S,G) GenID changes
620
621 The upstream (S,G) state machine remains in Joined state. If the
622 Join Timer is set to expire in more than t_override seconds, reset
623 it so that it expires after t_override seconds.
624*/
625void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
626{
627 struct listnode *up_node;
628 struct listnode *up_nextnode;
629 struct pim_upstream *up;
630
631 /*
632 Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
633 */
634 for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
635
636 if (PIM_DEBUG_PIM_TRACE) {
637 char neigh_str[100];
12e41d03
DL
638 char rpf_addr_str[100];
639 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
12e41d03 640 pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
05e451f8 641 zlog_debug("%s: matching neigh=%s against upstream (S,G)=%s joined=%d rpf_addr=%s",
12e41d03 642 __PRETTY_FUNCTION__,
05e451f8 643 neigh_str, pim_str_sg_dump (&up->sg),
12e41d03
DL
644 up->join_state == PIM_UPSTREAM_JOINED,
645 rpf_addr_str);
646 }
647
648 /* consider only (S,G) upstream in Joined state */
649 if (up->join_state != PIM_UPSTREAM_JOINED)
650 continue;
651
652 /* match RPF'(S,G)=neigh_addr */
653 if (up->rpf.rpf_addr.s_addr != neigh_addr.s_addr)
654 continue;
655
656 pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
657 up, neigh_addr);
658 }
659}
660
661
662void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
663 struct interface *old_rpf_ifp)
664{
665 struct listnode *ifnode;
666 struct listnode *ifnextnode;
667 struct interface *ifp;
668
669 /* scan all interfaces */
469351b3 670 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
671 struct listnode *chnode;
672 struct listnode *chnextnode;
673 struct pim_ifchannel *ch;
674 struct pim_interface *pim_ifp;
675
676 pim_ifp = ifp->info;
677 if (!pim_ifp)
678 continue;
679
680 /* search all ifchannels */
681 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
682 if (ch->upstream != up)
683 continue;
684
685 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
686 if (
687 /* RPF_interface(S) was NOT I */
688 (old_rpf_ifp == ch->interface)
689 &&
690 /* RPF_interface(S) stopped being I */
691 (ch->upstream->rpf.source_nexthop.interface != ch->interface)
692 ) {
693 assert_action_a5(ch);
694 }
695 } /* PIM_IFASSERT_I_AM_LOSER */
696
697 pim_ifchannel_update_assert_tracking_desired(ch);
698 }
699 }
700}
701
702void pim_upstream_update_could_assert(struct pim_upstream *up)
703{
704 struct listnode *ifnode;
705 struct listnode *ifnextnode;
706 struct listnode *chnode;
707 struct listnode *chnextnode;
708 struct interface *ifp;
709 struct pim_interface *pim_ifp;
710 struct pim_ifchannel *ch;
711
712 /* scan all interfaces */
469351b3 713 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
714 pim_ifp = ifp->info;
715 if (!pim_ifp)
716 continue;
717
718 /* scan per-interface (S,G) state */
719 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
720
721 if (ch->upstream != up)
722 continue;
723
724 pim_ifchannel_update_could_assert(ch);
725
726 } /* scan iface channel list */
727 } /* scan iflist */
728}
729
730void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
731{
732 struct listnode *ifnode;
733 struct listnode *ifnextnode;
734 struct listnode *chnode;
735 struct listnode *chnextnode;
736 struct interface *ifp;
737 struct pim_interface *pim_ifp;
738 struct pim_ifchannel *ch;
739
740 /* scan all interfaces */
469351b3 741 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
742 pim_ifp = ifp->info;
743 if (!pim_ifp)
744 continue;
745
746 /* scan per-interface (S,G) state */
747 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
748
749 if (ch->upstream != up)
750 continue;
751
752 pim_ifchannel_update_my_assert_metric(ch);
753
754 } /* scan iface channel list */
755 } /* scan iflist */
756}
757
758static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
759{
760 struct listnode *ifnode;
761 struct listnode *ifnextnode;
762 struct listnode *chnode;
763 struct listnode *chnextnode;
764 struct interface *ifp;
765 struct pim_interface *pim_ifp;
766 struct pim_ifchannel *ch;
767
768 /* scan all interfaces */
469351b3 769 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
770 pim_ifp = ifp->info;
771 if (!pim_ifp)
772 continue;
773
774 /* scan per-interface (S,G) state */
775 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
776
777 if (ch->upstream != up)
778 continue;
779
780 pim_ifchannel_update_assert_tracking_desired(ch);
781
782 } /* scan iface channel list */
783 } /* scan iflist */
784}
f14248dd
DS
785
786/*
787 * On an RP, the PMBR value must be cleared when the
788 * Keepalive Timer expires
789 */
790static int
791pim_upstream_keep_alive_timer (struct thread *t)
792{
793 struct pim_upstream *up;
794
795 up = THREAD_ARG(t);
796
4ed0af70 797 if (I_am_RP (up->sg.grp))
25a335e0 798 {
65e1fcd7 799 pim_br_clear_pmbr (&up->sg);
25a335e0
DS
800 /*
801 * We need to do more here :)
802 * But this is the start.
803 */
804 }
805 else
806 {
807 pim_mroute_update_counters (up->channel_oil);
f14248dd 808
25a335e0
DS
809 if (up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt)
810 {
811 pim_mroute_del (up->channel_oil);
812 pim_upstream_delete (up);
813 }
814 else
815 {
816 up->t_ka_timer = NULL;
817 pim_upstream_keep_alive_timer_start (up, PIM_KEEPALIVE_PERIOD);
818 }
819 }
cb40b272 820 return 1;
f14248dd
DS
821}
822
f14248dd
DS
823void
824pim_upstream_keep_alive_timer_start (struct pim_upstream *up,
825 uint32_t time)
826{
827 THREAD_TIMER_ON (master,
828 up->t_ka_timer,
829 pim_upstream_keep_alive_timer,
830 up, time);
831}
cb40b272
DS
832
833/*
834 * 4.2.1 Last-Hop Switchover to the SPT
835 *
836 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
837 * RP. Once traffic from sources to joined groups arrives at a last-hop
838 * router, it has the option of switching to receive the traffic on a
839 * shortest path tree (SPT).
840 *
841 * The decision for a router to switch to the SPT is controlled as
842 * follows:
843 *
844 * void
845 * CheckSwitchToSpt(S,G) {
846 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
847 * (+) pim_include(S,G) != NULL )
848 * AND SwitchToSptDesired(S,G) ) {
849 * # Note: Restarting the KAT will result in the SPT switch
850 * set KeepaliveTimer(S,G) to Keepalive_Period
851 * }
852 * }
853 *
854 * SwitchToSptDesired(S,G) is a policy function that is implementation
855 * defined. An "infinite threshold" policy can be implemented by making
856 * SwitchToSptDesired(S,G) return false all the time. A "switch on
857 * first packet" policy can be implemented by making
858 * SwitchToSptDesired(S,G) return true once a single packet has been
859 * received for the source and group.
860 */
861int
4ed0af70 862pim_upstream_switch_to_spt_desired (struct prefix_sg *sg)
cb40b272 863{
4ed0af70 864 if (I_am_RP (sg->grp))
a3b58b4a
DS
865 return 1;
866
cb40b272
DS
867 return 0;
868}
d7259eac
DS
869
870const char *
871pim_upstream_state2str (struct pim_upstream *up)
872{
873 switch (up->join_state)
874 {
875 case PIM_UPSTREAM_NOTJOINED:
876 return "NtJnd";
877 break;
878 case PIM_UPSTREAM_JOINED:
879 return "Jnd";
880 break;
881 case PIM_UPSTREAM_JOIN_PENDING:
882 return "JPend";
883 break;
884 case PIM_UPSTREAM_PRUNE:
885 return "Prune";
886 break;
887 }
888 return "Unkwn";
889}
627ed2a3
DS
890
891static int
892pim_upstream_register_stop_timer (struct thread *t)
893{
894 struct pim_upstream *up;
895 struct pim_rpf *rpg;
896 struct ip ip_hdr;
897
898 up = THREAD_ARG (t);
899
900 up->t_rs_timer = NULL;
901
902 if (PIM_DEBUG_TRACE)
903 {
05e451f8
DS
904 zlog_debug ("%s: (S,G)=%s upstream register stop timer %d",
905 __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg), up->join_state);
627ed2a3
DS
906 }
907
908 switch (up->join_state)
909 {
910 case PIM_UPSTREAM_JOIN_PENDING:
911 up->join_state = PIM_UPSTREAM_JOINED;
912 break;
913 case PIM_UPSTREAM_PRUNE:
914 up->join_state = PIM_UPSTREAM_JOIN_PENDING;
915 pim_upstream_start_register_stop_timer (up, 1);
916
4ed0af70 917 rpg = RP (up->sg.grp);
627ed2a3
DS
918 memset (&ip_hdr, 0, sizeof (struct ip));
919 ip_hdr.ip_p = PIM_IP_PROTO_PIM;
920 ip_hdr.ip_hl = 5;
921 ip_hdr.ip_v = 4;
4ed0af70
DS
922 ip_hdr.ip_src = up->sg.src;
923 ip_hdr.ip_dst = up->sg.grp;
627ed2a3
DS
924 ip_hdr.ip_len = 20;
925 // checksum is broken
926 pim_register_send ((uint8_t *)&ip_hdr, sizeof (struct ip), rpg, 1);
927 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
928 break;
929 default:
930 break;
931 }
932
933 return 0;
934}
935
936void
937pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_register)
938{
939 uint32_t time;
940
941 if (up->t_rs_timer)
942 {
943 THREAD_TIMER_OFF (up->t_rs_timer);
944 up->t_rs_timer = NULL;
945 }
946
947 if (!null_register)
948 {
949 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
950 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
951 time = lower + (random () % (upper - lower + 1)) - PIM_REGISTER_PROBE_PERIOD;
952 }
953 else
954 time = PIM_REGISTER_PROBE_PERIOD;
955
956 if (PIM_DEBUG_TRACE)
957 {
05e451f8
DS
958 zlog_debug ("%s: (S,G)=%s Starting upstream register stop timer %d",
959 __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg), time);
627ed2a3
DS
960 }
961 THREAD_TIMER_ON (master, up->t_rs_timer,
962 pim_upstream_register_stop_timer,
963 up, time);
964}
4fdc8f36
DS
965
966/*
967 * For a given upstream, determine the inherited_olist
968 * and apply it.
219e0013
DS
969 *
970 * inherited_olist(S,G,rpt) =
971 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
972 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
973 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
974 *
975 * inherited_olist(S,G) =
976 * inherited_olist(S,G,rpt) (+)
977 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
978 *
4fdc8f36
DS
979 * return 1 if there are any output interfaces
980 * return 0 if there are not any output interfaces
981 */
982int
983pim_upstream_inherited_olist (struct pim_upstream *up)
984{
219e0013
DS
985 struct pim_upstream *anysrc_up;
986 struct pim_interface *pim_ifp;
987 struct listnode *ifnextnode;
988 struct listnode *chnextnode;
989 struct pim_ifchannel *ch;
990 struct listnode *chnode;
991 struct listnode *ifnode;
992 struct interface *ifp;
4ed0af70 993 struct prefix_sg anysrc;
219e0013
DS
994 int output_intf = 0;
995
3667b0bc
DS
996 pim_ifp = up->rpf.source_nexthop.interface->info;
997 zlog_debug ("Channel Oil%s: %p", pim_str_sg_dump (&up->sg), up->channel_oil);
998 if (!up->channel_oil)
999 up->channel_oil = pim_channel_oil_add (&up->sg, pim_ifp->mroute_vif_index);
219e0013 1000 anysrc = up->sg;
4ed0af70 1001 anysrc.src.s_addr = INADDR_ANY;
219e0013
DS
1002
1003 anysrc_up = pim_upstream_find (&anysrc);
1004 if (anysrc_up)
1005 {
1006 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp))
1007 {
1008 pim_ifp = ifp->info;
1009 if (!pim_ifp)
1010 continue;
1011
1012 for (ALL_LIST_ELEMENTS (pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch))
1013 {
3667b0bc 1014 //struct pim_ifchannel *nch;
216bb84f 1015
219e0013
DS
1016 if (ch->upstream != anysrc_up)
1017 continue;
1018
1019 if (ch->ifjoin_state == PIM_IFJOIN_JOIN)
1020 {
3667b0bc
DS
1021 pim_channel_add_oif (up->channel_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
1022 //nch = pim_ifchannel_add (ifp, &up->sg);
1023 //pim_ifchannel_ifjoin_switch (__PRETTY_FUNCTION__, nch, PIM_IFJOIN_JOIN);
1024 //pim_forward_start (ch);
219e0013
DS
1025 output_intf++;
1026 }
1027 }
1028 }
1029 }
1030
1031 if (output_intf)
216bb84f
DS
1032 if (up->join_state != PIM_UPSTREAM_JOINED)
1033 pim_upstream_switch (up, PIM_UPSTREAM_JOINED);
219e0013
DS
1034
1035 return output_intf;
4fdc8f36 1036}