]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_upstream.c
pimd: Fix so creation of prefix happens one time
[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"
0f588989
DS
33#include "hash.h"
34#include "jhash.h"
9c5e4d62 35#include "wheel.h"
12e41d03
DL
36
37#include "pimd.h"
38#include "pim_pim.h"
39#include "pim_str.h"
40#include "pim_time.h"
41#include "pim_iface.h"
42#include "pim_join.h"
43#include "pim_zlookup.h"
44#include "pim_upstream.h"
45#include "pim_ifchannel.h"
46#include "pim_neighbor.h"
47#include "pim_rpf.h"
48#include "pim_zebra.h"
49#include "pim_oil.h"
50#include "pim_macro.h"
8f5f5e91 51#include "pim_rp.h"
f14248dd 52#include "pim_br.h"
627ed2a3 53#include "pim_register.h"
3c72d654 54#include "pim_msdp.h"
12e41d03 55
0f588989
DS
56struct hash *pim_upstream_hash = NULL;
57struct list *pim_upstream_list = NULL;
9c5e4d62 58struct timer_wheel *pim_upstream_sg_wheel = NULL;
0f588989 59
12e41d03
DL
60static void join_timer_start(struct pim_upstream *up);
61static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
62
cfa91a87
DS
63/*
64 * A (*,G) or a (*,*) is going away
65 * remove the parent pointer from
66 * those pointing at us
67 */
68static void
69pim_upstream_remove_children (struct pim_upstream *up)
70{
cfa91a87
DS
71 struct pim_upstream *child;
72
03417ccd 73 if (!up->sources)
cfa91a87
DS
74 return;
75
03417ccd 76 while (!list_isempty (up->sources))
cfa91a87 77 {
03417ccd
DS
78 child = listnode_head (up->sources);
79 child->parent = NULL;
80 listnode_delete (up->sources, child);
cfa91a87
DS
81 }
82}
83
84/*
85 * A (*,G) or a (*,*) is being created
86 * Find the children that would point
87 * at us.
88 */
89static void
90pim_upstream_find_new_children (struct pim_upstream *up)
91{
92 struct pim_upstream *child;
93 struct listnode *ch_node;
94
4ed0af70
DS
95 if ((up->sg.src.s_addr != INADDR_ANY) &&
96 (up->sg.grp.s_addr != INADDR_ANY))
cfa91a87
DS
97 return;
98
4ed0af70
DS
99 if ((up->sg.src.s_addr == INADDR_ANY) &&
100 (up->sg.grp.s_addr == INADDR_ANY))
cfa91a87
DS
101 return;
102
0f588989 103 for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, ch_node, child))
cfa91a87 104 {
4ed0af70 105 if ((up->sg.grp.s_addr != INADDR_ANY) &&
0f588989 106 (child->sg.grp.s_addr == up->sg.grp.s_addr) &&
cfa91a87 107 (child != up))
03417ccd
DS
108 {
109 child->parent = up;
110 listnode_add_sort (up->sources, child);
111 }
cfa91a87
DS
112 }
113}
114
4d99418b
DS
115/*
116 * If we have a (*,*) || (S,*) there is no parent
117 * If we have a (S,G), find the (*,G)
118 * If we have a (*,G), find the (*,*)
119 */
120static struct pim_upstream *
03417ccd 121pim_upstream_find_parent (struct pim_upstream *child)
4d99418b 122{
03417ccd
DS
123 struct prefix_sg any = child->sg;
124 struct pim_upstream *up = NULL;
4d99418b
DS
125
126 // (S,G)
03417ccd
DS
127 if ((child->sg.src.s_addr != INADDR_ANY) &&
128 (child->sg.grp.s_addr != INADDR_ANY))
4d99418b 129 {
4ed0af70 130 any.src.s_addr = INADDR_ANY;
03417ccd
DS
131 up = pim_upstream_find (&any);
132
133 if (up)
134 listnode_add (up->sources, child);
135
136 return up;
4d99418b
DS
137 }
138
03417ccd 139 return NULL;
4d99418b
DS
140}
141
12e41d03
DL
142void pim_upstream_free(struct pim_upstream *up)
143{
144 XFREE(MTYPE_PIM_UPSTREAM, up);
145}
146
147static void upstream_channel_oil_detach(struct pim_upstream *up)
148{
149 if (up->channel_oil) {
150 pim_channel_oil_del(up->channel_oil);
25a335e0 151 up->channel_oil = NULL;
12e41d03
DL
152 }
153}
154
e5905a3b
DS
155void
156pim_upstream_del(struct pim_upstream *up, const char *name)
12e41d03 157{
7667c556 158 bool notify_msdp = false;
159
e5905a3b
DS
160 if (PIM_DEBUG_PIM_TRACE)
161 {
162 zlog_debug ("%s: Delete (%s) ref count: %d",
8bfb8b67 163 name, up->sg_str, up->ref_count);
e5905a3b
DS
164 }
165 --up->ref_count;
166
167 if (up->ref_count >= 1)
168 return;
169
594a78cc
DS
170 if (PIM_DEBUG_PIM_TRACE)
171 zlog_debug ("%s: %s is being deleted",
8bfb8b67
DS
172 __PRETTY_FUNCTION__, up->sg_str);
173
12e41d03 174 THREAD_OFF(up->t_join_timer);
f14248dd 175 THREAD_OFF(up->t_ka_timer);
792f4d29 176 THREAD_OFF(up->t_rs_timer);
1bf16443 177 THREAD_OFF(up->t_msdp_reg_timer);
12e41d03 178
7667c556 179 if (up->join_state == PIM_UPSTREAM_JOINED) {
180 pim_joinprune_send (up->rpf.source_nexthop.interface,
181 up->rpf.rpf_addr.u.prefix4,
182 up, 0);
183 if (up->sg.src.s_addr == INADDR_ANY) {
184 /* if a (*, G) entry in the joined state is being deleted we
185 * need to notify MSDP */
186 notify_msdp = true;
187 }
188 }
189
9c5e4d62
DS
190 if (up->sg.src.s_addr != INADDR_ANY)
191 wheel_remove_item (pim_upstream_sg_wheel, up);
192
cfa91a87 193 pim_upstream_remove_children (up);
7fe1f662 194 pim_mroute_del (up->channel_oil);
12e41d03
DL
195 upstream_channel_oil_detach(up);
196
03417ccd
DS
197 if (up->sources)
198 list_delete (up->sources);
199 up->sources = NULL;
200
12e41d03
DL
201 /*
202 notice that listnode_delete() can't be moved
203 into pim_upstream_free() because the later is
204 called by list_delete_all_node()
205 */
03417ccd
DS
206 if (up->parent)
207 {
208 listnode_delete (up->parent->sources, up);
209 up->parent = NULL;
210 }
0f588989
DS
211 listnode_delete (pim_upstream_list, up);
212 hash_release (pim_upstream_hash, up);
12e41d03 213
7667c556 214 if (notify_msdp) {
215 pim_msdp_up_xg_del(&up->sg);
216 }
12e41d03
DL
217 pim_upstream_free(up);
218}
219
56638739
DS
220void
221pim_upstream_send_join (struct pim_upstream *up)
12e41d03 222{
12e41d03 223 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb 224 char rpf_str[PREFIX_STRLEN];
63c59d0c 225 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str, sizeof(rpf_str));
05e451f8 226 zlog_debug ("%s: RPF'%s=%s(%s) for Interface %s", __PRETTY_FUNCTION__,
8bfb8b67 227 up->sg_str, rpf_str, pim_upstream_state2str (up->join_state),
56638739 228 up->rpf.source_nexthop.interface->name);
63c59d0c 229 if (pim_rpf_addr_is_inaddr_any(&up->rpf)) {
05e451f8 230 zlog_debug("%s: can't send join upstream: RPF'%s=%s",
56638739 231 __PRETTY_FUNCTION__,
8bfb8b67 232 up->sg_str, rpf_str);
12e41d03
DL
233 /* warning only */
234 }
235 }
56638739 236
12e41d03
DL
237 /* send Join(S,G) to the current upstream neighbor */
238 pim_joinprune_send(up->rpf.source_nexthop.interface,
63c59d0c 239 up->rpf.rpf_addr.u.prefix4,
372eab92 240 up,
12e41d03
DL
241 1 /* join */);
242}
243
244static int on_join_timer(struct thread *t)
245{
246 struct pim_upstream *up;
247
12e41d03 248 up = THREAD_ARG(t);
12e41d03 249
bb6e291f
DS
250 up->t_join_timer = NULL;
251
252 /*
253 * In the case of a HFR we will not ahve anyone to send this to.
254 */
0bf27c5c 255 if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
bb6e291f
DS
256 return 0;
257
eb345962
DS
258 /*
259 * Don't send the join if the outgoing interface is a loopback
260 * But since this might change leave the join timer running
261 */
262 if (!if_is_loopback (up->rpf.source_nexthop.interface))
263 pim_upstream_send_join (up);
12e41d03 264
12e41d03
DL
265 join_timer_start(up);
266
267 return 0;
268}
269
270static void join_timer_start(struct pim_upstream *up)
271{
272 if (PIM_DEBUG_PIM_EVENTS) {
05e451f8 273 zlog_debug("%s: starting %d sec timer for upstream (S,G)=%s",
12e41d03
DL
274 __PRETTY_FUNCTION__,
275 qpim_t_periodic,
8bfb8b67 276 up->sg_str);
12e41d03
DL
277 }
278
8e38a2cf 279 THREAD_OFF (up->t_join_timer);
12e41d03
DL
280 THREAD_TIMER_ON(master, up->t_join_timer,
281 on_join_timer,
282 up, qpim_t_periodic);
283}
284
285void pim_upstream_join_timer_restart(struct pim_upstream *up)
286{
287 THREAD_OFF(up->t_join_timer);
288 join_timer_start(up);
289}
290
291static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
292 int interval_msec)
293{
294 if (PIM_DEBUG_PIM_EVENTS) {
05e451f8 295 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
12e41d03
DL
296 __PRETTY_FUNCTION__,
297 interval_msec,
8bfb8b67 298 up->sg_str);
12e41d03
DL
299 }
300
301 THREAD_OFF(up->t_join_timer);
302 THREAD_TIMER_MSEC_ON(master, up->t_join_timer,
303 on_join_timer,
304 up, interval_msec);
305}
306
307void pim_upstream_join_suppress(struct pim_upstream *up,
308 struct in_addr rpf_addr,
309 int holdtime)
310{
311 long t_joinsuppress_msec;
312 long join_timer_remain_msec;
313
314 t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
315 1000 * holdtime);
316
317 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
318
319 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb 320 char rpf_str[INET_ADDRSTRLEN];
12e41d03 321 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
05e451f8 322 zlog_debug("%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
12e41d03 323 __FILE__, __PRETTY_FUNCTION__,
8bfb8b67 324 up->sg_str,
12e41d03
DL
325 rpf_str,
326 join_timer_remain_msec, t_joinsuppress_msec);
327 }
328
329 if (join_timer_remain_msec < t_joinsuppress_msec) {
330 if (PIM_DEBUG_PIM_TRACE) {
05e451f8 331 zlog_debug("%s %s: suppressing Join(S,G)=%s for %ld msec",
12e41d03 332 __FILE__, __PRETTY_FUNCTION__,
8bfb8b67 333 up->sg_str, t_joinsuppress_msec);
12e41d03
DL
334 }
335
336 pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
337 }
338}
339
340void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
341 struct pim_upstream *up,
342 struct in_addr rpf_addr)
343{
344 long join_timer_remain_msec;
345 int t_override_msec;
346
347 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
348 t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface);
349
350 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb 351 char rpf_str[INET_ADDRSTRLEN];
12e41d03 352 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
05e451f8 353 zlog_debug("%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
12e41d03 354 debug_label,
8bfb8b67 355 up->sg_str, rpf_str,
12e41d03
DL
356 join_timer_remain_msec, t_override_msec);
357 }
358
359 if (join_timer_remain_msec > t_override_msec) {
360 if (PIM_DEBUG_PIM_TRACE) {
05e451f8 361 zlog_debug("%s: decreasing (S,G)=%s join timer to t_override=%d msec",
12e41d03 362 debug_label,
8bfb8b67 363 up->sg_str,
12e41d03
DL
364 t_override_msec);
365 }
366
367 pim_upstream_join_timer_restart_msec(up, t_override_msec);
368 }
369}
370
371static void forward_on(struct pim_upstream *up)
372{
12e41d03
DL
373 struct listnode *chnode;
374 struct listnode *chnextnode;
12e41d03
DL
375 struct pim_interface *pim_ifp;
376 struct pim_ifchannel *ch;
377
ea4a71fc
DS
378 /* scan (S,G) state */
379 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
380 pim_ifp = ch->interface->info;
12e41d03
DL
381 if (!pim_ifp)
382 continue;
383
ea4a71fc
DS
384 if (ch->upstream != up)
385 continue;
12e41d03 386
ea4a71fc
DS
387 if (pim_macro_chisin_oiflist(ch))
388 pim_forward_start(ch);
12e41d03 389
ea4a71fc 390 } /* scan iface channel list */
12e41d03
DL
391}
392
393static void forward_off(struct pim_upstream *up)
394{
12e41d03
DL
395 struct listnode *chnode;
396 struct listnode *chnextnode;
12e41d03
DL
397 struct pim_interface *pim_ifp;
398 struct pim_ifchannel *ch;
399
ea4a71fc
DS
400 /* scan per-interface (S,G) state */
401 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
402 pim_ifp = ch->interface->info;
12e41d03
DL
403 if (!pim_ifp)
404 continue;
405
ea4a71fc
DS
406 if (ch->upstream != up)
407 continue;
12e41d03 408
ea4a71fc 409 pim_forward_stop(ch);
12e41d03 410
ea4a71fc 411 } /* scan iface channel list */
12e41d03
DL
412}
413
bb6e291f
DS
414static int
415pim_upstream_could_register (struct pim_upstream *up)
416{
417 struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info;
418
35917570 419 if (pim_ifp && PIM_I_am_DR (pim_ifp) &&
bb6e291f
DS
420 pim_if_connected_to_source (up->rpf.source_nexthop.interface, up->sg.src))
421 return 1;
422
423 return 0;
424}
425
7fcdfb34
DS
426void
427pim_upstream_switch(struct pim_upstream *up,
428 enum pim_upstream_state new_state)
12e41d03
DL
429{
430 enum pim_upstream_state old_state = up->join_state;
431
12e41d03 432 if (PIM_DEBUG_PIM_EVENTS) {
c9802954 433 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
12e41d03 434 __PRETTY_FUNCTION__,
8bfb8b67 435 up->sg_str,
c9802954
DS
436 pim_upstream_state2str (up->join_state),
437 pim_upstream_state2str (new_state));
12e41d03
DL
438 }
439
bb027ee8
DS
440 /*
441 * This code still needs work.
442 */
443 switch (up->join_state)
444 {
445 case PIM_UPSTREAM_PRUNE:
0bf27c5c 446 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
7747bad6
DS
447 {
448 up->join_state = new_state;
449 up->state_transition = pim_time_monotonic_sec ();
450 }
451 break;
bb027ee8
DS
452 case PIM_UPSTREAM_JOIN_PENDING:
453 break;
454 case PIM_UPSTREAM_NOTJOINED:
455 case PIM_UPSTREAM_JOINED:
456 up->join_state = new_state;
e5b6b229
DS
457 if (old_state != new_state)
458 up->state_transition = pim_time_monotonic_sec();
bb027ee8
DS
459
460 break;
461 }
462
12e41d03
DL
463 pim_upstream_update_assert_tracking_desired(up);
464
465 if (new_state == PIM_UPSTREAM_JOINED) {
81900c5a
DS
466 if (old_state != PIM_UPSTREAM_JOINED)
467 {
0bf27c5c 468 int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags);
81900c5a 469 forward_on(up);
7667c556 470 pim_msdp_up_join_state_changed(up);
0bf27c5c 471 if (pim_upstream_could_register (up))
bb6e291f 472 {
0bf27c5c 473 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
a9b59879 474 if (!old_fhr && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
bb6e291f
DS
475 {
476 pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
477 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
478 }
479 }
480 else
481 {
482 pim_upstream_send_join (up);
483 join_timer_start (up);
484 }
81900c5a
DS
485 }
486 else
487 {
488 forward_on (up);
489 }
12e41d03
DL
490 }
491 else {
492 forward_off(up);
7667c556 493 if (old_state == PIM_UPSTREAM_JOINED)
494 pim_msdp_up_join_state_changed(up);
12e41d03 495 pim_joinprune_send(up->rpf.source_nexthop.interface,
63c59d0c 496 up->rpf.rpf_addr.u.prefix4,
372eab92 497 up,
12e41d03 498 0 /* prune */);
7fcdfb34
DS
499 if (up->t_join_timer)
500 THREAD_OFF(up->t_join_timer);
12e41d03 501 }
12e41d03
DL
502}
503
03417ccd
DS
504static int
505pim_upstream_compare (void *arg1, void *arg2)
506{
507 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
508 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
509
510 if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr))
511 return -1;
512
513 if (ntohl(up1->sg.grp.s_addr) > ntohl(up2->sg.grp.s_addr))
514 return 1;
515
516 if (ntohl(up1->sg.src.s_addr) < ntohl(up2->sg.src.s_addr))
517 return -1;
518
519 if (ntohl(up1->sg.src.s_addr) > ntohl(up2->sg.src.s_addr))
520 return 1;
521
522 return 0;
523}
524
4ed0af70 525static struct pim_upstream *pim_upstream_new(struct prefix_sg *sg,
4a40c37a
DS
526 struct interface *incoming,
527 int flags)
12e41d03
DL
528{
529 struct pim_upstream *up;
2f702571 530 enum pim_rpf_result rpf_result;
12e41d03 531
36d9e7dc 532 up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
12e41d03 533 if (!up) {
36d9e7dc 534 zlog_err("%s: PIM XCALLOC(%zu) failure",
12e41d03 535 __PRETTY_FUNCTION__, sizeof(*up));
8f5f5e91 536 return NULL;
12e41d03
DL
537 }
538
5074a423 539 up->sg = *sg;
8bfb8b67 540 pim_str_sg_set (sg, up->sg_str);
0f588989 541 up = hash_get (pim_upstream_hash, up, hash_alloc_intern);
36d6bd7d 542 if (!pim_rp_set_upstream_addr (&up->upstream_addr, sg->src, sg->grp))
8f5f5e91
DS
543 {
544 if (PIM_DEBUG_PIM_TRACE)
545 zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
546
03417ccd 547 hash_release (pim_upstream_hash, up);
8f5f5e91
DS
548 XFREE (MTYPE_PIM_UPSTREAM, up);
549 return NULL;
550 }
551
03417ccd
DS
552 up->parent = pim_upstream_find_parent (up);
553 if (up->sg.src.s_addr == INADDR_ANY)
554 {
555 up->sources = list_new ();
556 up->sources->cmp = pim_upstream_compare;
557 }
558 else
559 up->sources = NULL;
560
cfa91a87 561 pim_upstream_find_new_children (up);
4a40c37a 562 up->flags = flags;
12e41d03 563 up->ref_count = 1;
4a4c4a07
DS
564 up->t_join_timer = NULL;
565 up->t_ka_timer = NULL;
792f4d29 566 up->t_rs_timer = NULL;
1bf16443 567 up->t_msdp_reg_timer = NULL;
12e41d03
DL
568 up->join_state = 0;
569 up->state_transition = pim_time_monotonic_sec();
4a4c4a07 570 up->channel_oil = NULL;
f9e0ab5b 571 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
12e41d03 572
f24405b1 573 up->rpf.source_nexthop.interface = NULL;
63c59d0c
DS
574 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
575 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
12e41d03
DL
576 up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference;
577 up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric;
63c59d0c
DS
578 up->rpf.rpf_addr.family = AF_INET;
579 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
12e41d03 580
9c5e4d62
DS
581 if (up->sg.src.s_addr != INADDR_ANY)
582 wheel_add_item (pim_upstream_sg_wheel, up);
583
d3dd1804 584 rpf_result = pim_rpf_update(up, NULL);
2f702571 585 if (rpf_result == PIM_RPF_FAILURE) {
4a40c37a
DS
586 if (PIM_DEBUG_PIM_TRACE)
587 zlog_debug ("%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__,
8bfb8b67 588 up->sg_str);
03417ccd
DS
589
590 if (up->parent)
591 {
592 listnode_delete (up->parent->sources, up);
593 up->parent = NULL;
594 }
9c5e4d62
DS
595
596 if (up->sg.src.s_addr != INADDR_ANY)
597 wheel_remove_item (pim_upstream_sg_wheel, up);
598
03417ccd
DS
599 pim_upstream_remove_children (up);
600 if (up->sources)
601 list_delete (up->sources);
602
603 hash_release (pim_upstream_hash, up);
2f702571
DS
604 XFREE(MTYPE_PIM_UPSTREAM, up);
605 return NULL;
606 }
12e41d03 607
0f588989 608 listnode_add_sort(pim_upstream_list, up);
12e41d03 609
03417ccd 610 if (PIM_DEBUG_PIM_TRACE)
8bfb8b67 611 zlog_debug ("%s: Created Upstream %s", __PRETTY_FUNCTION__, up->sg_str);
03417ccd 612
12e41d03
DL
613 return up;
614}
615
4ed0af70 616struct pim_upstream *pim_upstream_find(struct prefix_sg *sg)
12e41d03 617{
0f588989
DS
618 struct pim_upstream lookup;
619 struct pim_upstream *up = NULL;
12e41d03 620
0f588989
DS
621 lookup.sg = *sg;
622 up = hash_lookup (pim_upstream_hash, &lookup);
623 return up;
12e41d03
DL
624}
625
1bf16443 626static void pim_upstream_ref(struct pim_upstream *up, int flags)
627{
628 up->flags |= flags;
629 ++up->ref_count;
630}
631
4ed0af70 632struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
4a40c37a 633 struct interface *incoming,
e5905a3b 634 int flags, const char *name)
12e41d03 635{
594a78cc 636 struct pim_upstream *up = NULL;
e5905a3b 637 int found = 0;
5074a423 638 up = pim_upstream_find(sg);
12e41d03 639 if (up) {
1bf16443 640 pim_upstream_ref(up, flags);
e5905a3b 641 found = 1;
12e41d03
DL
642 }
643 else {
4a40c37a 644 up = pim_upstream_new(sg, incoming, flags);
12e41d03
DL
645 }
646
e5905a3b 647 if (PIM_DEBUG_TRACE)
f4075cb4
DS
648 {
649 if (up)
650 zlog_debug("%s(%s): (%s), found: %d: ref_count: %d",
651 __PRETTY_FUNCTION__, name,
8bfb8b67 652 up->sg_str, found,
f4075cb4
DS
653 up->ref_count);
654 else
655 zlog_debug("%s(%s): (%s) failure to create",
656 __PRETTY_FUNCTION__, name,
657 pim_str_sg_dump (sg));
658 }
12e41d03 659
e5905a3b 660 return up;
12e41d03
DL
661}
662
7a3ddda5
DS
663static int
664pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up,
665 struct pim_ifchannel *ch)
666{
667 struct pim_upstream *parent = up->parent;
668
669 if (ch->upstream == up)
670 {
671 if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch))
672 return 1;
46c8aab8
DS
673
674 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
675 return 0;
7a3ddda5 676 }
46c8aab8 677
7a3ddda5
DS
678 /*
679 * joins (*,G)
680 */
681 if (parent && ch->upstream == parent)
682 {
683 if (!pim_macro_ch_lost_assert (ch) && pim_macro_chisin_joins_or_include (ch))
684 return 1;
685 }
686
687 return 0;
688}
689
12e41d03
DL
690/*
691 Evaluate JoinDesired(S,G):
692
693 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
694 in the set:
695
696 inherited_olist(S,G) =
697 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
698
699 JoinDesired(S,G) may be affected by changes in the following:
700
701 pim_ifp->primary_address
702 pim_ifp->pim_dr_addr
703 ch->ifassert_winner_metric
704 ch->ifassert_winner
705 ch->local_ifmembership
706 ch->ifjoin_state
707 ch->upstream->rpf.source_nexthop.mrib_metric_preference
708 ch->upstream->rpf.source_nexthop.mrib_route_metric
709 ch->upstream->rpf.source_nexthop.interface
710
711 See also pim_upstream_update_join_desired() below.
712 */
713int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
714{
12e41d03
DL
715 struct listnode *chnode;
716 struct listnode *chnextnode;
12e41d03
DL
717 struct pim_interface *pim_ifp;
718 struct pim_ifchannel *ch;
7a3ddda5 719 int ret = 0;
12e41d03 720
ea4a71fc
DS
721 /* scan per-interface (S,G) state */
722 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch))
723 {
724 pim_ifp = ch->interface->info;
725 if (!pim_ifp)
726 continue;
12e41d03 727
ea4a71fc
DS
728 ret += pim_upstream_evaluate_join_desired_interface (up, ch);
729 } /* scan iface channel list */
12e41d03 730
7a3ddda5 731 return ret; /* false */
12e41d03
DL
732}
733
734/*
735 See also pim_upstream_evaluate_join_desired() above.
736*/
737void pim_upstream_update_join_desired(struct pim_upstream *up)
738{
739 int was_join_desired; /* boolean */
740 int is_join_desired; /* boolean */
741
742 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
743
744 is_join_desired = pim_upstream_evaluate_join_desired(up);
745 if (is_join_desired)
746 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
747 else
748 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
749
750 /* switched from false to true */
751 if (is_join_desired && !was_join_desired) {
12e41d03
DL
752 pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
753 return;
754 }
755
756 /* switched from true to false */
757 if (!is_join_desired && was_join_desired) {
12e41d03
DL
758 pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
759 return;
760 }
761}
762
763/*
764 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
765 Transitions from Joined State
766 RPF'(S,G) GenID changes
767
768 The upstream (S,G) state machine remains in Joined state. If the
769 Join Timer is set to expire in more than t_override seconds, reset
770 it so that it expires after t_override seconds.
771*/
772void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
773{
774 struct listnode *up_node;
775 struct listnode *up_nextnode;
776 struct pim_upstream *up;
777
778 /*
0f588989
DS
779 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
780 */
781 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
12e41d03
DL
782
783 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb
DW
784 char neigh_str[INET_ADDRSTRLEN];
785 char rpf_addr_str[PREFIX_STRLEN];
12e41d03 786 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
63c59d0c 787 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
05e451f8 788 zlog_debug("%s: matching neigh=%s against upstream (S,G)=%s joined=%d rpf_addr=%s",
12e41d03 789 __PRETTY_FUNCTION__,
8bfb8b67 790 neigh_str, up->sg_str,
12e41d03
DL
791 up->join_state == PIM_UPSTREAM_JOINED,
792 rpf_addr_str);
793 }
794
795 /* consider only (S,G) upstream in Joined state */
796 if (up->join_state != PIM_UPSTREAM_JOINED)
797 continue;
798
799 /* match RPF'(S,G)=neigh_addr */
63c59d0c 800 if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr)
12e41d03
DL
801 continue;
802
803 pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
804 up, neigh_addr);
805 }
806}
807
808
809void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
810 struct interface *old_rpf_ifp)
811{
ea4a71fc
DS
812 struct listnode *chnode;
813 struct listnode *chnextnode;
814 struct pim_ifchannel *ch;
815 struct pim_interface *pim_ifp;
816
817 /* search all ifchannels */
818 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
819
820 pim_ifp = ch->interface->info;
12e41d03
DL
821 if (!pim_ifp)
822 continue;
823
ea4a71fc
DS
824 if (ch->upstream != up)
825 continue;
12e41d03 826
ea4a71fc
DS
827 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
828 if (
829 /* RPF_interface(S) was NOT I */
830 (old_rpf_ifp == ch->interface)
831 &&
832 /* RPF_interface(S) stopped being I */
833 (ch->upstream->rpf.source_nexthop.interface != ch->interface)
834 ) {
835 assert_action_a5(ch);
836 }
837 } /* PIM_IFASSERT_I_AM_LOSER */
12e41d03 838
ea4a71fc 839 pim_ifchannel_update_assert_tracking_desired(ch);
12e41d03
DL
840 }
841}
842
843void pim_upstream_update_could_assert(struct pim_upstream *up)
844{
12e41d03
DL
845 struct listnode *chnode;
846 struct listnode *chnextnode;
12e41d03
DL
847 struct pim_interface *pim_ifp;
848 struct pim_ifchannel *ch;
849
ea4a71fc
DS
850 /* scan per-interface (S,G) state */
851 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
852 pim_ifp = ch->interface->info;
12e41d03
DL
853 if (!pim_ifp)
854 continue;
855
ea4a71fc
DS
856 if (ch->upstream != up)
857 continue;
12e41d03 858
ea4a71fc
DS
859 pim_ifchannel_update_could_assert(ch);
860 } /* scan iface channel list */
12e41d03
DL
861}
862
863void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
864{
12e41d03
DL
865 struct listnode *chnode;
866 struct listnode *chnextnode;
12e41d03
DL
867 struct pim_interface *pim_ifp;
868 struct pim_ifchannel *ch;
869
ea4a71fc
DS
870 /* scan per-interface (S,G) state */
871 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
872 pim_ifp = ch->interface->info;
12e41d03
DL
873 if (!pim_ifp)
874 continue;
875
ea4a71fc
DS
876 if (ch->upstream != up)
877 continue;
12e41d03 878
ea4a71fc 879 pim_ifchannel_update_my_assert_metric(ch);
12e41d03 880
ea4a71fc 881 } /* scan iface channel list */
12e41d03
DL
882}
883
884static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
885{
12e41d03
DL
886 struct listnode *chnode;
887 struct listnode *chnextnode;
12e41d03
DL
888 struct pim_interface *pim_ifp;
889 struct pim_ifchannel *ch;
890
ea4a71fc
DS
891 /* scan per-interface (S,G) state */
892 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
893 pim_ifp = ch->interface->info;
12e41d03
DL
894 if (!pim_ifp)
895 continue;
896
ea4a71fc
DS
897 if (ch->upstream != up)
898 continue;
12e41d03 899
ea4a71fc 900 pim_ifchannel_update_assert_tracking_desired(ch);
12e41d03 901
ea4a71fc 902 } /* scan iface channel list */
12e41d03 903}
f14248dd 904
1bf16443 905/* When kat is stopped CouldRegister goes to false so we need to
906 * transition the (S, G) on FHR to NI state and remove reg tunnel
907 * from the OIL */
908static void pim_upstream_fhr_kat_expiry(struct pim_upstream *up)
909{
910 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
911 return;
912
913 if (PIM_DEBUG_TRACE)
8bfb8b67
DS
914 zlog_debug ("kat expired on %s; clear fhr reg state", up->sg_str);
915
1bf16443 916 /* stop reg-stop timer */
917 THREAD_OFF(up->t_rs_timer);
918 /* remove regiface from the OIL if it is there*/
919 pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
920 /* move to "not-joined" */
921 up->join_state = PIM_UPSTREAM_NOTJOINED;
922 PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags);
923}
924
925/* When kat is started CouldRegister can go to true. And if it does we
926 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
927 * to the OIL */
928static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
929{
930 if (pim_upstream_could_register(up)) {
931 if (PIM_DEBUG_TRACE)
8bfb8b67
DS
932 zlog_debug ("kat started on %s; set fhr reg state to joined", up->sg_str);
933
1bf16443 934 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
935 if (up->join_state == PIM_UPSTREAM_NOTJOINED) {
936 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
937 up->join_state = PIM_UPSTREAM_JOINED;
938 }
939 }
940}
941
f14248dd
DS
942/*
943 * On an RP, the PMBR value must be cleared when the
944 * Keepalive Timer expires
1bf16443 945 * KAT expiry indicates that flow is inactive. If the flow was created or
946 * maintained by activity now is the time to deref it.
f14248dd
DS
947 */
948static int
949pim_upstream_keep_alive_timer (struct thread *t)
950{
951 struct pim_upstream *up;
952
953 up = THREAD_ARG(t);
1bf16443 954 up->t_ka_timer = NULL;
f14248dd 955
4ed0af70 956 if (I_am_RP (up->sg.grp))
1bf16443 957 {
958 pim_br_clear_pmbr (&up->sg);
959 /*
960 * We need to do more here :)
961 * But this is the start.
962 */
963 }
14315ea8 964
1bf16443 965 /* source is no longer active - pull the SA from MSDP's cache */
966 pim_msdp_sa_local_del(&up->sg);
14315ea8 967
1bf16443 968 /* if entry was created because of activity we need to deref it */
969 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
970 {
971 pim_upstream_fhr_kat_expiry(up);
972 if (PIM_DEBUG_TRACE)
8bfb8b67 973 zlog_debug ("kat expired on %s; remove stream reference", up->sg_str);
1bf16443 974 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
975 pim_upstream_del(up, __PRETTY_FUNCTION__);
976 }
14315ea8 977
1bf16443 978 return 0;
f14248dd
DS
979}
980
f14248dd
DS
981void
982pim_upstream_keep_alive_timer_start (struct pim_upstream *up,
983 uint32_t time)
984{
1bf16443 985 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
986 if (PIM_DEBUG_TRACE)
8bfb8b67 987 zlog_debug ("kat start on %s with no stream reference", up->sg_str);
1bf16443 988 }
00d2f9e4 989 THREAD_OFF (up->t_ka_timer);
f14248dd
DS
990 THREAD_TIMER_ON (master,
991 up->t_ka_timer,
992 pim_upstream_keep_alive_timer,
993 up, time);
1bf16443 994
995 /* any time keepalive is started against a SG we will have to
996 * re-evaluate our active source database */
997 pim_msdp_sa_local_update(up);
998}
999
1000/* MSDP on RP needs to know if a source is registerable to this RP */
1001static int
1002pim_upstream_msdp_reg_timer(struct thread *t)
1003{
1004 struct pim_upstream *up;
1005
1006 up = THREAD_ARG(t);
1007 up->t_msdp_reg_timer = NULL;
1008
1009 /* source is no longer active - pull the SA from MSDP's cache */
1010 pim_msdp_sa_local_del(&up->sg);
1011 return 1;
1012}
1013void
1014pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
1015{
1016 THREAD_OFF(up->t_msdp_reg_timer);
1017 THREAD_TIMER_ON(master, up->t_msdp_reg_timer,
1018 pim_upstream_msdp_reg_timer, up, PIM_MSDP_REG_RXED_PERIOD);
1019
1020 pim_msdp_sa_local_update(up);
f14248dd 1021}
cb40b272
DS
1022
1023/*
1024 * 4.2.1 Last-Hop Switchover to the SPT
1025 *
1026 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1027 * RP. Once traffic from sources to joined groups arrives at a last-hop
1028 * router, it has the option of switching to receive the traffic on a
1029 * shortest path tree (SPT).
1030 *
1031 * The decision for a router to switch to the SPT is controlled as
1032 * follows:
1033 *
1034 * void
1035 * CheckSwitchToSpt(S,G) {
1036 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1037 * (+) pim_include(S,G) != NULL )
1038 * AND SwitchToSptDesired(S,G) ) {
1039 * # Note: Restarting the KAT will result in the SPT switch
1040 * set KeepaliveTimer(S,G) to Keepalive_Period
1041 * }
1042 * }
1043 *
1044 * SwitchToSptDesired(S,G) is a policy function that is implementation
1045 * defined. An "infinite threshold" policy can be implemented by making
1046 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1047 * first packet" policy can be implemented by making
1048 * SwitchToSptDesired(S,G) return true once a single packet has been
1049 * received for the source and group.
1050 */
1051int
4ed0af70 1052pim_upstream_switch_to_spt_desired (struct prefix_sg *sg)
cb40b272 1053{
4ed0af70 1054 if (I_am_RP (sg->grp))
a3b58b4a
DS
1055 return 1;
1056
cb40b272
DS
1057 return 0;
1058}
d7259eac 1059
80d9c3a0
DS
1060int
1061pim_upstream_is_sg_rpt (struct pim_upstream *up)
1062{
f21597f0
DS
1063 struct listnode *chnode;
1064 struct pim_ifchannel *ch;
1065
1066 for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, chnode, ch))
1067 {
1068 if ((ch->upstream == up) &&
1069 (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)))
1070 return 1;
1071 }
e43b8697 1072
80d9c3a0
DS
1073 return 0;
1074}
3a66b17b
DS
1075/*
1076 * After receiving a packet set SPTbit:
1077 * void
1078 * Update_SPTbit(S,G,iif) {
1079 * if ( iif == RPF_interface(S)
1080 * AND JoinDesired(S,G) == TRUE
1081 * AND ( DirectlyConnected(S) == TRUE
1082 * OR RPF_interface(S) != RPF_interface(RP(G))
1083 * OR inherited_olist(S,G,rpt) == NULL
1084 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1085 * ( RPF'(S,G) != NULL ) )
1086 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1087 * Set SPTbit(S,G) to TRUE
1088 * }
1089 * }
1090 */
1091void
1092pim_upstream_set_sptbit (struct pim_upstream *up, struct interface *incoming)
1093{
1094 struct pim_rpf *grpf = NULL;
1095
1096 // iif == RPF_interfvace(S)
1097 if (up->rpf.source_nexthop.interface != incoming)
1098 {
1099 if (PIM_DEBUG_TRACE)
1100 zlog_debug ("%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1101 __PRETTY_FUNCTION__, incoming->name, up->rpf.source_nexthop.interface->name);
1102 return;
1103 }
1104
1105 // AND JoinDesired(S,G) == TRUE
1106 // FIXME
1107
1108 // DirectlyConnected(S) == TRUE
1109 if (pim_if_connected_to_source (up->rpf.source_nexthop.interface, up->sg.src))
1110 {
1111 if (PIM_DEBUG_TRACE)
1112 zlog_debug ("%s: %s is directly connected to the source", __PRETTY_FUNCTION__,
8bfb8b67 1113 up->sg_str);
3a66b17b
DS
1114 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1115 return;
1116 }
1117
1118 // OR RPF_interface(S) != RPF_interface(RP(G))
1119 grpf = RP(up->sg.grp);
1120 if (!grpf || up->rpf.source_nexthop.interface != grpf->source_nexthop.interface)
1121 {
1122 if (PIM_DEBUG_TRACE)
1123 zlog_debug ("%s: %s RPF_interface(S) != RPF_interface(RP(G))",
8bfb8b67 1124 __PRETTY_FUNCTION__, up->sg_str);
3a66b17b
DS
1125 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1126 return;
1127 }
1128
1129 // OR inherited_olist(S,G,rpt) == NULL
1130 if (pim_upstream_is_sg_rpt(up) && pim_upstream_empty_inherited_olist(up))
1131 {
1132 if (PIM_DEBUG_TRACE)
1133 zlog_debug ("%s: %s OR inherited_olist(S,G,rpt) == NULL", __PRETTY_FUNCTION__,
8bfb8b67 1134 up->sg_str);
3a66b17b
DS
1135 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1136 return;
1137 }
1138
1139 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1140 // ( RPF'(S,G) != NULL ) )
1141 if (up->parent && pim_rpf_is_same (&up->rpf, &up->parent->rpf))
1142 {
1143 if (PIM_DEBUG_TRACE)
1144 zlog_debug ("%s: %s RPF'(S,G) is the same as RPF'(*,G)", __PRETTY_FUNCTION__,
8bfb8b67 1145 up->sg_str);
3a66b17b
DS
1146 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1147 return;
1148 }
1149
1150 return;
1151}
80d9c3a0 1152
d7259eac 1153const char *
c9802954 1154pim_upstream_state2str (enum pim_upstream_state join_state)
d7259eac 1155{
c9802954 1156 switch (join_state)
d7259eac
DS
1157 {
1158 case PIM_UPSTREAM_NOTJOINED:
e775c0a4 1159 return "NotJoined";
d7259eac
DS
1160 break;
1161 case PIM_UPSTREAM_JOINED:
e775c0a4 1162 return "Joined";
d7259eac
DS
1163 break;
1164 case PIM_UPSTREAM_JOIN_PENDING:
e775c0a4 1165 return "JoinPending";
d7259eac
DS
1166 break;
1167 case PIM_UPSTREAM_PRUNE:
1168 return "Prune";
1169 break;
1170 }
e775c0a4 1171 return "Unknown";
d7259eac 1172}
627ed2a3
DS
1173
1174static int
1175pim_upstream_register_stop_timer (struct thread *t)
1176{
4df01a4e 1177 struct pim_interface *pim_ifp;
627ed2a3
DS
1178 struct pim_upstream *up;
1179 struct pim_rpf *rpg;
1180 struct ip ip_hdr;
627ed2a3
DS
1181 up = THREAD_ARG (t);
1182
1183 up->t_rs_timer = NULL;
1184
1185 if (PIM_DEBUG_TRACE)
1186 {
d5ed8a9c 1187 zlog_debug ("%s: (S,G)=%s upstream register stop timer %s",
8bfb8b67 1188 __PRETTY_FUNCTION__, up->sg_str,
c9802954 1189 pim_upstream_state2str(up->join_state));
627ed2a3
DS
1190 }
1191
1192 switch (up->join_state)
1193 {
1194 case PIM_UPSTREAM_JOIN_PENDING:
1195 up->join_state = PIM_UPSTREAM_JOINED;
bb027ee8
DS
1196 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
1197 break;
1198 case PIM_UPSTREAM_JOINED:
627ed2a3
DS
1199 break;
1200 case PIM_UPSTREAM_PRUNE:
4df01a4e 1201 pim_ifp = up->rpf.source_nexthop.interface->info;
7ef66046
DS
1202 if (!pim_ifp)
1203 {
1204 if (PIM_DEBUG_TRACE)
1205 zlog_debug ("%s: Interface: %s is not configured for pim",
1206 __PRETTY_FUNCTION__, up->rpf.source_nexthop.interface->name);
1207 return 0;
1208 }
627ed2a3
DS
1209 up->join_state = PIM_UPSTREAM_JOIN_PENDING;
1210 pim_upstream_start_register_stop_timer (up, 1);
1211
4ed0af70 1212 rpg = RP (up->sg.grp);
627ed2a3
DS
1213 memset (&ip_hdr, 0, sizeof (struct ip));
1214 ip_hdr.ip_p = PIM_IP_PROTO_PIM;
1215 ip_hdr.ip_hl = 5;
1216 ip_hdr.ip_v = 4;
4ed0af70
DS
1217 ip_hdr.ip_src = up->sg.src;
1218 ip_hdr.ip_dst = up->sg.grp;
dc686f82 1219 ip_hdr.ip_len = htons (20);
627ed2a3 1220 // checksum is broken
4df01a4e 1221 pim_register_send ((uint8_t *)&ip_hdr, sizeof (struct ip),
0e3b3d5d 1222 pim_ifp->primary_address, rpg, 1, up);
627ed2a3
DS
1223 break;
1224 default:
1225 break;
1226 }
1227
1228 return 0;
1229}
1230
1231void
1232pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_register)
1233{
1234 uint32_t time;
1235
1236 if (up->t_rs_timer)
1237 {
1238 THREAD_TIMER_OFF (up->t_rs_timer);
1239 up->t_rs_timer = NULL;
1240 }
1241
1242 if (!null_register)
1243 {
1244 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1245 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1246 time = lower + (random () % (upper - lower + 1)) - PIM_REGISTER_PROBE_PERIOD;
1247 }
1248 else
1249 time = PIM_REGISTER_PROBE_PERIOD;
1250
1251 if (PIM_DEBUG_TRACE)
1252 {
05e451f8 1253 zlog_debug ("%s: (S,G)=%s Starting upstream register stop timer %d",
8bfb8b67 1254 __PRETTY_FUNCTION__, up->sg_str, time);
627ed2a3
DS
1255 }
1256 THREAD_TIMER_ON (master, up->t_rs_timer,
1257 pim_upstream_register_stop_timer,
1258 up, time);
1259}
4fdc8f36
DS
1260
1261/*
1262 * For a given upstream, determine the inherited_olist
1263 * and apply it.
219e0013
DS
1264 *
1265 * inherited_olist(S,G,rpt) =
1266 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1267 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1268 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1269 *
1270 * inherited_olist(S,G) =
1271 * inherited_olist(S,G,rpt) (+)
1272 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1273 *
4fdc8f36
DS
1274 * return 1 if there are any output interfaces
1275 * return 0 if there are not any output interfaces
1276 */
1277int
1278pim_upstream_inherited_olist (struct pim_upstream *up)
1279{
219e0013 1280 struct pim_interface *pim_ifp;
219e0013
DS
1281 struct listnode *chnextnode;
1282 struct pim_ifchannel *ch;
1283 struct listnode *chnode;
219e0013
DS
1284 int output_intf = 0;
1285
3667b0bc 1286 pim_ifp = up->rpf.source_nexthop.interface->info;
da55afba 1287 if (pim_ifp && !up->channel_oil)
3667b0bc 1288 up->channel_oil = pim_channel_oil_add (&up->sg, pim_ifp->mroute_vif_index);
219e0013 1289
ea4a71fc 1290 for (ALL_LIST_ELEMENTS (pim_ifchannel_list, chnode, chnextnode, ch))
219e0013 1291 {
ea4a71fc 1292 pim_ifp = ch->interface->info;
7a3ddda5
DS
1293 if (!pim_ifp)
1294 continue;
219e0013 1295
ea4a71fc 1296 if (pim_upstream_evaluate_join_desired_interface (up, ch))
7a3ddda5 1297 {
ea4a71fc
DS
1298 pim_channel_add_oif (up->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM);
1299 output_intf++;
219e0013
DS
1300 }
1301 }
1302
483eef9d
DS
1303 /*
1304 * If we have output_intf switch state to Join and work like normal
1305 * If we don't have an output_intf that means we are probably a
1306 * switch on a stick so turn on forwarding to just accept the
1307 * incoming packets so we don't bother the other stuff!
1308 */
1309 if (output_intf)
1310 pim_upstream_switch (up, PIM_UPSTREAM_JOINED);
1311 else
1312 forward_on (up);
219e0013
DS
1313
1314 return output_intf;
4fdc8f36 1315}
d3dd1804 1316
80d9c3a0
DS
1317int
1318pim_upstream_empty_inherited_olist (struct pim_upstream *up)
1319{
ce0ddb4e 1320 return pim_channel_oil_empty (up->channel_oil);
80d9c3a0
DS
1321}
1322
d3dd1804
DS
1323/*
1324 * When we have a new neighbor,
1325 * find upstreams that don't have their rpf_addr
1326 * set and see if the new neighbor allows
1327 * the join to be sent
1328 */
1329void
1330pim_upstream_find_new_rpf (void)
1331{
1332 struct listnode *up_node;
1333 struct listnode *up_nextnode;
1334 struct pim_upstream *up;
1335
1336 /*
0f588989
DS
1337 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1338 */
1339 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up))
d3dd1804 1340 {
63c59d0c 1341 if (pim_rpf_addr_is_inaddr_any(&up->rpf))
d3dd1804
DS
1342 {
1343 if (PIM_DEBUG_PIM_TRACE)
1344 zlog_debug ("Upstream %s without a path to send join, checking",
8bfb8b67 1345 up->sg_str);
d3dd1804
DS
1346 pim_rpf_update (up, NULL);
1347 }
1348 }
1349}
0f588989 1350
0f588989
DS
1351static unsigned int
1352pim_upstream_hash_key (void *arg)
1353{
1354 struct pim_upstream *up = (struct pim_upstream *)arg;
1355
1356 return jhash_2words (up->sg.src.s_addr, up->sg.grp.s_addr, 0);
1357}
1358
1359void pim_upstream_terminate (void)
1360{
1361 if (pim_upstream_list)
1362 list_free (pim_upstream_list);
1363 pim_upstream_list = NULL;
1364
1365 if (pim_upstream_hash)
1366 hash_free (pim_upstream_hash);
1367}
1368
1369static int
1370pim_upstream_equal (const void *arg1, const void *arg2)
1371{
1372 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1373 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
1374
1375 if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr) &&
1376 (up1->sg.src.s_addr == up2->sg.src.s_addr))
1377 return 1;
1378
1379 return 0;
1380}
1381
1bf16443 1382/* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1383 * the cases where kat has to be restarted on rxing traffic -
1384 *
1385 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1386 * set KeepaliveTimer(S,G) to Keepalive_Period
1387 * # Note: a register state transition or UpstreamJPState(S,G)
1388 * # transition may happen as a result of restarting
1389 * # KeepaliveTimer, and must be dealt with here.
1390 * }
1391 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1392 * inherited_olist(S,G) != NULL ) {
1393 * set KeepaliveTimer(S,G) to Keepalive_Period
1394 * }
1395 */
1396static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
1397{
1398 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1399 * so we will skip that here */
1400 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1401 up->sg.src)) {
1402 return true;
1403 }
1404
1405 if ((up->join_state == PIM_UPSTREAM_JOINED) &&
1406 !pim_upstream_empty_inherited_olist(up)) {
1407 /* XXX: I have added this RP check just for 3.2 and it's a digression from
1408 * what rfc-4601 says. Till now we were only running KAT on FHR and RP and
1409 * there is some angst around making the change to run it all routers that
1410 * maintain the (S, G) state. This is tracked via CM-13601 and MUST be
1411 * removed to handle spt turn-arounds correctly in a 3-tier clos */
1412 if (I_am_RP (up->sg.grp))
1413 return true;
1414 }
1415
1416 return false;
1417}
1418
9c5e4d62
DS
1419/*
1420 * Code to check and see if we've received packets on a S,G mroute
1421 * and if so to set the SPT bit appropriately
1422 */
1423static void
1424pim_upstream_sg_running (void *arg)
1425{
1426 struct pim_upstream *up = (struct pim_upstream *)arg;
e43b8697
DS
1427
1428 // No packet can have arrived here if this is the case
1429 if (!up->channel_oil || !up->channel_oil->installed)
1430 {
1431 if (PIM_DEBUG_TRACE)
1432 zlog_debug ("%s: %s is not installed in mroute",
8bfb8b67 1433 __PRETTY_FUNCTION__, up->sg_str);
e43b8697
DS
1434 return;
1435 }
1436
e43b8697
DS
1437
1438 pim_mroute_update_counters (up->channel_oil);
1439
1440 // Have we seen packets?
1bf16443 1441 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt) &&
e43b8697
DS
1442 (up->channel_oil->cc.lastused/100 > 30))
1443 {
1444 if (PIM_DEBUG_TRACE)
1445 {
1446 zlog_debug ("%s: %s old packet count is equal or lastused is greater than 30",
8bfb8b67 1447 __PRETTY_FUNCTION__, up->sg_str);
e43b8697
DS
1448 zlog_debug ("%s: %ld %ld %lld", __PRETTY_FUNCTION__, up->channel_oil->cc.oldpktcnt, up->channel_oil->cc.pktcnt, up->channel_oil->cc.lastused/100);
1449 }
1450 return;
1451 }
1452
1bf16443 1453 if (pim_upstream_kat_start_ok(up)) {
1454 /* Add a source reference to the stream if
1455 * one doesn't already exist */
1456 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
1457 {
1458 if (PIM_DEBUG_TRACE)
8bfb8b67
DS
1459 zlog_debug ("source reference created on kat restart %s", up->sg_str);
1460
1bf16443 1461 pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM);
1462 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
1463 pim_upstream_fhr_kat_start(up);
1464 }
1465 pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
1466 }
1467
1468 if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE)
1469 {
1470 pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
1471 }
e43b8697 1472 return;
9c5e4d62
DS
1473}
1474
040d86ad
DS
1475void
1476pim_upstream_init (void)
0f588989 1477{
9c5e4d62
DS
1478 pim_upstream_sg_wheel = wheel_init (master, 31000, 100,
1479 pim_upstream_hash_key,
1480 pim_upstream_sg_running);
0f588989
DS
1481 pim_upstream_hash = hash_create_size (8192, pim_upstream_hash_key,
1482 pim_upstream_equal);
1483
1484 pim_upstream_list = list_new ();
1485 pim_upstream_list->del = (void (*)(void *)) pim_upstream_free;
03417ccd 1486 pim_upstream_list->cmp = pim_upstream_compare;
0f588989
DS
1487
1488}