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