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