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