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