]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_upstream.c
pimd: Allow flags to know if this is a FHR or not
[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];
63c59d0c 177 pim_addr_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);
63c59d0c 181 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
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,
63c59d0c 191 up->rpf.rpf_addr.u.prefix4,
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,
63c59d0c 460 up->rpf.rpf_addr.u.prefix4,
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;
63c59d0c
DS
504 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
505 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
12e41d03
DL
506 up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference;
507 up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric;
63c59d0c
DS
508 up->rpf.rpf_addr.family = AF_INET;
509 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
12e41d03 510
d3dd1804 511 rpf_result = pim_rpf_update(up, NULL);
2f702571
DS
512 if (rpf_result == PIM_RPF_FAILURE) {
513 XFREE(MTYPE_PIM_UPSTREAM, up);
514 return NULL;
515 }
12e41d03
DL
516
517 listnode_add(qpim_upstream_list, up);
518
519 return up;
520}
521
6c629103
DS
522/*
523 * For a given sg, find any non * source
524 */
4ed0af70 525struct pim_upstream *pim_upstream_find_non_any (struct prefix_sg *sg)
6c629103
DS
526{
527 struct listnode *up_node;
4ed0af70 528 struct prefix_sg any = *sg;
6c629103
DS
529 struct pim_upstream *up;
530
4ed0af70 531 any.src.s_addr = INADDR_ANY;
6c629103
DS
532
533 for (ALL_LIST_ELEMENTS_RO (qpim_upstream_list, up_node, up))
534 {
4ed0af70
DS
535 if ((any.grp.s_addr == up->sg.grp.s_addr) &&
536 (up->sg.src.s_addr != any.src.s_addr))
6c629103
DS
537 return up;
538 }
539
540 return NULL;
541}
542
4ed0af70 543struct pim_upstream *pim_upstream_find(struct prefix_sg *sg)
12e41d03
DL
544{
545 struct listnode *up_node;
546 struct pim_upstream *up;
547
548 for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) {
4ed0af70
DS
549 if ((sg->grp.s_addr == up->sg.grp.s_addr) &&
550 (sg->src.s_addr == up->sg.src.s_addr))
a3b58b4a 551 return up;
12e41d03
DL
552 }
553
d7259eac 554 return NULL;
12e41d03
DL
555}
556
4ed0af70 557struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
651d0f71 558 struct interface *incoming)
12e41d03
DL
559{
560 struct pim_upstream *up;
561
5074a423 562 up = pim_upstream_find(sg);
12e41d03
DL
563 if (up) {
564 ++up->ref_count;
565 }
566 else {
5074a423 567 up = pim_upstream_new(sg, incoming);
12e41d03
DL
568 }
569
570 return up;
571}
572
573void pim_upstream_del(struct pim_upstream *up)
574{
575 --up->ref_count;
576
577 if (up->ref_count < 1) {
578 pim_upstream_delete(up);
579 }
580}
581
7a3ddda5
DS
582static int
583pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up,
584 struct pim_ifchannel *ch)
585{
586 struct pim_upstream *parent = up->parent;
587
588 if (ch->upstream == up)
589 {
590 if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch))
591 return 1;
592 }
593 /*
594 * joins (*,G)
595 */
596 if (parent && ch->upstream == parent)
597 {
598 if (!pim_macro_ch_lost_assert (ch) && pim_macro_chisin_joins_or_include (ch))
599 return 1;
600 }
601
602 return 0;
603}
604
12e41d03
DL
605/*
606 Evaluate JoinDesired(S,G):
607
608 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
609 in the set:
610
611 inherited_olist(S,G) =
612 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
613
614 JoinDesired(S,G) may be affected by changes in the following:
615
616 pim_ifp->primary_address
617 pim_ifp->pim_dr_addr
618 ch->ifassert_winner_metric
619 ch->ifassert_winner
620 ch->local_ifmembership
621 ch->ifjoin_state
622 ch->upstream->rpf.source_nexthop.mrib_metric_preference
623 ch->upstream->rpf.source_nexthop.mrib_route_metric
624 ch->upstream->rpf.source_nexthop.interface
625
626 See also pim_upstream_update_join_desired() below.
627 */
628int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
629{
630 struct listnode *ifnode;
631 struct listnode *ifnextnode;
632 struct listnode *chnode;
633 struct listnode *chnextnode;
634 struct interface *ifp;
635 struct pim_interface *pim_ifp;
636 struct pim_ifchannel *ch;
7a3ddda5 637 int ret = 0;
12e41d03
DL
638
639 /* scan all interfaces */
469351b3 640 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
641 pim_ifp = ifp->info;
642 if (!pim_ifp)
643 continue;
644
645 /* scan per-interface (S,G) state */
7a3ddda5
DS
646 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch))
647 {
648 ret += pim_upstream_evaluate_join_desired_interface (up, ch);
649 } /* scan iface channel list */
12e41d03
DL
650 } /* scan iflist */
651
7a3ddda5 652 return ret; /* false */
12e41d03
DL
653}
654
655/*
656 See also pim_upstream_evaluate_join_desired() above.
657*/
658void pim_upstream_update_join_desired(struct pim_upstream *up)
659{
660 int was_join_desired; /* boolean */
661 int is_join_desired; /* boolean */
662
663 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
664
665 is_join_desired = pim_upstream_evaluate_join_desired(up);
666 if (is_join_desired)
667 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
668 else
669 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
670
671 /* switched from false to true */
672 if (is_join_desired && !was_join_desired) {
12e41d03
DL
673 pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
674 return;
675 }
676
677 /* switched from true to false */
678 if (!is_join_desired && was_join_desired) {
12e41d03
DL
679 pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
680 return;
681 }
682}
683
684/*
685 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
686 Transitions from Joined State
687 RPF'(S,G) GenID changes
688
689 The upstream (S,G) state machine remains in Joined state. If the
690 Join Timer is set to expire in more than t_override seconds, reset
691 it so that it expires after t_override seconds.
692*/
693void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
694{
695 struct listnode *up_node;
696 struct listnode *up_nextnode;
697 struct pim_upstream *up;
698
699 /*
700 Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
701 */
702 for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
703
704 if (PIM_DEBUG_PIM_TRACE) {
705 char neigh_str[100];
12e41d03
DL
706 char rpf_addr_str[100];
707 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
63c59d0c 708 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
05e451f8 709 zlog_debug("%s: matching neigh=%s against upstream (S,G)=%s joined=%d rpf_addr=%s",
12e41d03 710 __PRETTY_FUNCTION__,
05e451f8 711 neigh_str, pim_str_sg_dump (&up->sg),
12e41d03
DL
712 up->join_state == PIM_UPSTREAM_JOINED,
713 rpf_addr_str);
714 }
715
716 /* consider only (S,G) upstream in Joined state */
717 if (up->join_state != PIM_UPSTREAM_JOINED)
718 continue;
719
720 /* match RPF'(S,G)=neigh_addr */
63c59d0c 721 if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr)
12e41d03
DL
722 continue;
723
724 pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
725 up, neigh_addr);
726 }
727}
728
729
730void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
731 struct interface *old_rpf_ifp)
732{
733 struct listnode *ifnode;
734 struct listnode *ifnextnode;
735 struct interface *ifp;
736
737 /* scan all interfaces */
469351b3 738 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
739 struct listnode *chnode;
740 struct listnode *chnextnode;
741 struct pim_ifchannel *ch;
742 struct pim_interface *pim_ifp;
743
744 pim_ifp = ifp->info;
745 if (!pim_ifp)
746 continue;
747
748 /* search all ifchannels */
749 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
750 if (ch->upstream != up)
751 continue;
752
753 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
754 if (
755 /* RPF_interface(S) was NOT I */
756 (old_rpf_ifp == ch->interface)
757 &&
758 /* RPF_interface(S) stopped being I */
759 (ch->upstream->rpf.source_nexthop.interface != ch->interface)
760 ) {
761 assert_action_a5(ch);
762 }
763 } /* PIM_IFASSERT_I_AM_LOSER */
764
765 pim_ifchannel_update_assert_tracking_desired(ch);
766 }
767 }
768}
769
770void pim_upstream_update_could_assert(struct pim_upstream *up)
771{
772 struct listnode *ifnode;
773 struct listnode *ifnextnode;
774 struct listnode *chnode;
775 struct listnode *chnextnode;
776 struct interface *ifp;
777 struct pim_interface *pim_ifp;
778 struct pim_ifchannel *ch;
779
780 /* scan all interfaces */
469351b3 781 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
782 pim_ifp = ifp->info;
783 if (!pim_ifp)
784 continue;
785
786 /* scan per-interface (S,G) state */
787 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
788
789 if (ch->upstream != up)
790 continue;
791
792 pim_ifchannel_update_could_assert(ch);
793
794 } /* scan iface channel list */
795 } /* scan iflist */
796}
797
798void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
799{
800 struct listnode *ifnode;
801 struct listnode *ifnextnode;
802 struct listnode *chnode;
803 struct listnode *chnextnode;
804 struct interface *ifp;
805 struct pim_interface *pim_ifp;
806 struct pim_ifchannel *ch;
807
808 /* scan all interfaces */
469351b3 809 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
810 pim_ifp = ifp->info;
811 if (!pim_ifp)
812 continue;
813
814 /* scan per-interface (S,G) state */
815 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
816
817 if (ch->upstream != up)
818 continue;
819
820 pim_ifchannel_update_my_assert_metric(ch);
821
822 } /* scan iface channel list */
823 } /* scan iflist */
824}
825
826static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
827{
828 struct listnode *ifnode;
829 struct listnode *ifnextnode;
830 struct listnode *chnode;
831 struct listnode *chnextnode;
832 struct interface *ifp;
833 struct pim_interface *pim_ifp;
834 struct pim_ifchannel *ch;
835
836 /* scan all interfaces */
469351b3 837 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp)) {
12e41d03
DL
838 pim_ifp = ifp->info;
839 if (!pim_ifp)
840 continue;
841
842 /* scan per-interface (S,G) state */
843 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) {
844
845 if (ch->upstream != up)
846 continue;
847
848 pim_ifchannel_update_assert_tracking_desired(ch);
849
850 } /* scan iface channel list */
851 } /* scan iflist */
852}
f14248dd
DS
853
854/*
855 * On an RP, the PMBR value must be cleared when the
856 * Keepalive Timer expires
857 */
858static int
859pim_upstream_keep_alive_timer (struct thread *t)
860{
861 struct pim_upstream *up;
862
863 up = THREAD_ARG(t);
864
4ed0af70 865 if (I_am_RP (up->sg.grp))
25a335e0 866 {
65e1fcd7 867 pim_br_clear_pmbr (&up->sg);
25a335e0
DS
868 /*
869 * We need to do more here :)
870 * But this is the start.
871 */
872 }
14315ea8
DS
873
874 pim_mroute_update_counters (up->channel_oil);
875
e3be0432
DS
876 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt) &&
877 (up->channel_oil->cc.oldlastused >= up->channel_oil->cc.lastused))
14315ea8
DS
878 {
879 pim_mroute_del (up->channel_oil);
d854589a
DS
880 THREAD_OFF (up->t_ka_timer);
881 THREAD_OFF (up->t_rs_timer);
882 THREAD_OFF (up->t_join_timer);
63c59d0c 883 pim_joinprune_send (up->rpf.source_nexthop.interface, up->rpf.rpf_addr.u.prefix4,
d854589a 884 &up->sg, 0);
30df5c10 885 pim_upstream_del (up);
14315ea8 886 }
25a335e0
DS
887 else
888 {
14315ea8 889 up->t_ka_timer = NULL;
4304f95c 890 pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
25a335e0 891 }
14315ea8 892
cb40b272 893 return 1;
f14248dd
DS
894}
895
f14248dd
DS
896void
897pim_upstream_keep_alive_timer_start (struct pim_upstream *up,
898 uint32_t time)
899{
00d2f9e4 900 THREAD_OFF (up->t_ka_timer);
f14248dd
DS
901 THREAD_TIMER_ON (master,
902 up->t_ka_timer,
903 pim_upstream_keep_alive_timer,
904 up, time);
905}
cb40b272
DS
906
907/*
908 * 4.2.1 Last-Hop Switchover to the SPT
909 *
910 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
911 * RP. Once traffic from sources to joined groups arrives at a last-hop
912 * router, it has the option of switching to receive the traffic on a
913 * shortest path tree (SPT).
914 *
915 * The decision for a router to switch to the SPT is controlled as
916 * follows:
917 *
918 * void
919 * CheckSwitchToSpt(S,G) {
920 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
921 * (+) pim_include(S,G) != NULL )
922 * AND SwitchToSptDesired(S,G) ) {
923 * # Note: Restarting the KAT will result in the SPT switch
924 * set KeepaliveTimer(S,G) to Keepalive_Period
925 * }
926 * }
927 *
928 * SwitchToSptDesired(S,G) is a policy function that is implementation
929 * defined. An "infinite threshold" policy can be implemented by making
930 * SwitchToSptDesired(S,G) return false all the time. A "switch on
931 * first packet" policy can be implemented by making
932 * SwitchToSptDesired(S,G) return true once a single packet has been
933 * received for the source and group.
934 */
935int
4ed0af70 936pim_upstream_switch_to_spt_desired (struct prefix_sg *sg)
cb40b272 937{
4ed0af70 938 if (I_am_RP (sg->grp))
a3b58b4a
DS
939 return 1;
940
cb40b272
DS
941 return 0;
942}
d7259eac
DS
943
944const char *
c9802954 945pim_upstream_state2str (enum pim_upstream_state join_state)
d7259eac 946{
c9802954 947 switch (join_state)
d7259eac
DS
948 {
949 case PIM_UPSTREAM_NOTJOINED:
950 return "NtJnd";
951 break;
952 case PIM_UPSTREAM_JOINED:
953 return "Jnd";
954 break;
955 case PIM_UPSTREAM_JOIN_PENDING:
956 return "JPend";
957 break;
958 case PIM_UPSTREAM_PRUNE:
959 return "Prune";
960 break;
961 }
962 return "Unkwn";
963}
627ed2a3
DS
964
965static int
966pim_upstream_register_stop_timer (struct thread *t)
967{
4df01a4e 968 struct pim_interface *pim_ifp;
627ed2a3
DS
969 struct pim_upstream *up;
970 struct pim_rpf *rpg;
971 struct ip ip_hdr;
627ed2a3
DS
972 up = THREAD_ARG (t);
973
79ce47c0 974 THREAD_TIMER_OFF (up->t_rs_timer);
627ed2a3
DS
975 up->t_rs_timer = NULL;
976
977 if (PIM_DEBUG_TRACE)
978 {
d5ed8a9c
DS
979 zlog_debug ("%s: (S,G)=%s upstream register stop timer %s",
980 __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg),
c9802954 981 pim_upstream_state2str(up->join_state));
627ed2a3
DS
982 }
983
984 switch (up->join_state)
985 {
986 case PIM_UPSTREAM_JOIN_PENDING:
987 up->join_state = PIM_UPSTREAM_JOINED;
bb027ee8
DS
988 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
989 break;
990 case PIM_UPSTREAM_JOINED:
627ed2a3
DS
991 break;
992 case PIM_UPSTREAM_PRUNE:
4df01a4e 993 pim_ifp = up->rpf.source_nexthop.interface->info;
627ed2a3
DS
994 up->join_state = PIM_UPSTREAM_JOIN_PENDING;
995 pim_upstream_start_register_stop_timer (up, 1);
996
4ed0af70 997 rpg = RP (up->sg.grp);
627ed2a3
DS
998 memset (&ip_hdr, 0, sizeof (struct ip));
999 ip_hdr.ip_p = PIM_IP_PROTO_PIM;
1000 ip_hdr.ip_hl = 5;
1001 ip_hdr.ip_v = 4;
4ed0af70
DS
1002 ip_hdr.ip_src = up->sg.src;
1003 ip_hdr.ip_dst = up->sg.grp;
dc686f82 1004 ip_hdr.ip_len = htons (20);
627ed2a3 1005 // checksum is broken
4df01a4e
DS
1006 pim_register_send ((uint8_t *)&ip_hdr, sizeof (struct ip),
1007 pim_ifp->primary_address, rpg, 1);
627ed2a3
DS
1008 break;
1009 default:
1010 break;
1011 }
1012
1013 return 0;
1014}
1015
1016void
1017pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_register)
1018{
1019 uint32_t time;
1020
1021 if (up->t_rs_timer)
1022 {
1023 THREAD_TIMER_OFF (up->t_rs_timer);
1024 up->t_rs_timer = NULL;
1025 }
1026
1027 if (!null_register)
1028 {
1029 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1030 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1031 time = lower + (random () % (upper - lower + 1)) - PIM_REGISTER_PROBE_PERIOD;
1032 }
1033 else
1034 time = PIM_REGISTER_PROBE_PERIOD;
1035
1036 if (PIM_DEBUG_TRACE)
1037 {
05e451f8
DS
1038 zlog_debug ("%s: (S,G)=%s Starting upstream register stop timer %d",
1039 __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg), time);
627ed2a3
DS
1040 }
1041 THREAD_TIMER_ON (master, up->t_rs_timer,
1042 pim_upstream_register_stop_timer,
1043 up, time);
1044}
4fdc8f36
DS
1045
1046/*
1047 * For a given upstream, determine the inherited_olist
1048 * and apply it.
219e0013
DS
1049 *
1050 * inherited_olist(S,G,rpt) =
1051 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1052 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1053 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1054 *
1055 * inherited_olist(S,G) =
1056 * inherited_olist(S,G,rpt) (+)
1057 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1058 *
4fdc8f36
DS
1059 * return 1 if there are any output interfaces
1060 * return 0 if there are not any output interfaces
1061 */
1062int
1063pim_upstream_inherited_olist (struct pim_upstream *up)
1064{
219e0013
DS
1065 struct pim_interface *pim_ifp;
1066 struct listnode *ifnextnode;
1067 struct listnode *chnextnode;
1068 struct pim_ifchannel *ch;
1069 struct listnode *chnode;
1070 struct listnode *ifnode;
1071 struct interface *ifp;
219e0013
DS
1072 int output_intf = 0;
1073
3667b0bc 1074 pim_ifp = up->rpf.source_nexthop.interface->info;
da55afba 1075 if (pim_ifp && !up->channel_oil)
3667b0bc 1076 up->channel_oil = pim_channel_oil_add (&up->sg, pim_ifp->mroute_vif_index);
219e0013 1077
7a3ddda5 1078 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT), ifnode, ifnextnode, ifp))
219e0013 1079 {
7a3ddda5
DS
1080 pim_ifp = ifp->info;
1081 if (!pim_ifp)
1082 continue;
219e0013 1083
7a3ddda5
DS
1084 for (ALL_LIST_ELEMENTS (pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch))
1085 {
1086 if (pim_upstream_evaluate_join_desired_interface (up, ch))
219e0013 1087 {
7a3ddda5
DS
1088 pim_channel_add_oif (up->channel_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
1089 output_intf++;
219e0013
DS
1090 }
1091 }
1092 }
1093
483eef9d
DS
1094 /*
1095 * If we have output_intf switch state to Join and work like normal
1096 * If we don't have an output_intf that means we are probably a
1097 * switch on a stick so turn on forwarding to just accept the
1098 * incoming packets so we don't bother the other stuff!
1099 */
1100 if (output_intf)
1101 pim_upstream_switch (up, PIM_UPSTREAM_JOINED);
1102 else
1103 forward_on (up);
219e0013
DS
1104
1105 return output_intf;
4fdc8f36 1106}
d3dd1804
DS
1107
1108/*
1109 * When we have a new neighbor,
1110 * find upstreams that don't have their rpf_addr
1111 * set and see if the new neighbor allows
1112 * the join to be sent
1113 */
1114void
1115pim_upstream_find_new_rpf (void)
1116{
1117 struct listnode *up_node;
1118 struct listnode *up_nextnode;
1119 struct pim_upstream *up;
1120
1121 /*
1122 Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1123 */
1124 for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up))
1125 {
63c59d0c 1126 if (pim_rpf_addr_is_inaddr_any(&up->rpf))
d3dd1804
DS
1127 {
1128 if (PIM_DEBUG_PIM_TRACE)
1129 zlog_debug ("Upstream %s without a path to send join, checking",
1130 pim_str_sg_dump (&up->sg));
1131 pim_rpf_update (up, NULL);
1132 }
1133 }
1134}