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