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