]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_upstream.c
pimd: Remove unused zclient_debug variable
[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);
6a78764e 191 pim_mroute_del (up->channel_oil, __PRETTY_FUNCTION__);
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
07335c8d
DS
522static struct pim_upstream *
523pim_upstream_new (struct prefix_sg *sg,
524 struct interface *incoming,
525 int flags)
12e41d03 526{
2f702571 527 enum pim_rpf_result rpf_result;
07335c8d
DS
528 struct pim_interface *pim_ifp;
529 struct pim_upstream *up;
12e41d03 530
36d9e7dc 531 up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
12e41d03 532 if (!up) {
36d9e7dc 533 zlog_err("%s: PIM XCALLOC(%zu) failure",
12e41d03 534 __PRETTY_FUNCTION__, sizeof(*up));
8f5f5e91 535 return NULL;
12e41d03
DL
536 }
537
5074a423 538 up->sg = *sg;
8bfb8b67 539 pim_str_sg_set (sg, up->sg_str);
0f588989 540 up = hash_get (pim_upstream_hash, up, hash_alloc_intern);
36d6bd7d 541 if (!pim_rp_set_upstream_addr (&up->upstream_addr, sg->src, sg->grp))
8f5f5e91 542 {
3197cb1e 543 if (PIM_DEBUG_TRACE)
8f5f5e91
DS
544 zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
545
03417ccd 546 hash_release (pim_upstream_hash, up);
8f5f5e91
DS
547 XFREE (MTYPE_PIM_UPSTREAM, up);
548 return NULL;
549 }
550
03417ccd
DS
551 up->parent = pim_upstream_find_parent (up);
552 if (up->sg.src.s_addr == INADDR_ANY)
553 {
554 up->sources = list_new ();
555 up->sources->cmp = pim_upstream_compare;
556 }
557 else
558 up->sources = NULL;
559
cfa91a87 560 pim_upstream_find_new_children (up);
4a40c37a 561 up->flags = flags;
12e41d03 562 up->ref_count = 1;
4a4c4a07
DS
563 up->t_join_timer = NULL;
564 up->t_ka_timer = NULL;
792f4d29 565 up->t_rs_timer = NULL;
1bf16443 566 up->t_msdp_reg_timer = NULL;
12e41d03
DL
567 up->join_state = 0;
568 up->state_transition = pim_time_monotonic_sec();
4a4c4a07 569 up->channel_oil = NULL;
f9e0ab5b 570 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
12e41d03 571
f24405b1 572 up->rpf.source_nexthop.interface = NULL;
63c59d0c
DS
573 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
574 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
12e41d03
DL
575 up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference;
576 up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric;
63c59d0c
DS
577 up->rpf.rpf_addr.family = AF_INET;
578 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
12e41d03 579
9c5e4d62
DS
580 if (up->sg.src.s_addr != INADDR_ANY)
581 wheel_add_item (pim_upstream_sg_wheel, up);
582
d3dd1804 583 rpf_result = pim_rpf_update(up, NULL);
2f702571 584 if (rpf_result == PIM_RPF_FAILURE) {
3197cb1e 585 if (PIM_DEBUG_TRACE)
4a40c37a 586 zlog_debug ("%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__,
8bfb8b67 587 up->sg_str);
03417ccd
DS
588
589 if (up->parent)
590 {
591 listnode_delete (up->parent->sources, up);
592 up->parent = NULL;
593 }
9c5e4d62
DS
594
595 if (up->sg.src.s_addr != INADDR_ANY)
596 wheel_remove_item (pim_upstream_sg_wheel, up);
597
03417ccd
DS
598 pim_upstream_remove_children (up);
599 if (up->sources)
600 list_delete (up->sources);
601
602 hash_release (pim_upstream_hash, up);
2f702571
DS
603 XFREE(MTYPE_PIM_UPSTREAM, up);
604 return NULL;
605 }
12e41d03 606
07335c8d
DS
607 pim_ifp = up->rpf.source_nexthop.interface->info;
608 if (pim_ifp)
609 up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index);
610
0f588989 611 listnode_add_sort(pim_upstream_list, up);
12e41d03 612
3197cb1e 613 if (PIM_DEBUG_TRACE)
8bfb8b67 614 zlog_debug ("%s: Created Upstream %s", __PRETTY_FUNCTION__, up->sg_str);
03417ccd 615
12e41d03
DL
616 return up;
617}
618
4ed0af70 619struct pim_upstream *pim_upstream_find(struct prefix_sg *sg)
12e41d03 620{
0f588989
DS
621 struct pim_upstream lookup;
622 struct pim_upstream *up = NULL;
12e41d03 623
0f588989
DS
624 lookup.sg = *sg;
625 up = hash_lookup (pim_upstream_hash, &lookup);
626 return up;
12e41d03
DL
627}
628
1bf16443 629static void pim_upstream_ref(struct pim_upstream *up, int flags)
630{
631 up->flags |= flags;
632 ++up->ref_count;
633}
634
4ed0af70 635struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
4a40c37a 636 struct interface *incoming,
e5905a3b 637 int flags, const char *name)
12e41d03 638{
594a78cc 639 struct pim_upstream *up = NULL;
e5905a3b 640 int found = 0;
5074a423 641 up = pim_upstream_find(sg);
12e41d03 642 if (up) {
1bf16443 643 pim_upstream_ref(up, flags);
e5905a3b 644 found = 1;
12e41d03
DL
645 }
646 else {
4a40c37a 647 up = pim_upstream_new(sg, incoming, flags);
12e41d03
DL
648 }
649
e5905a3b 650 if (PIM_DEBUG_TRACE)
f4075cb4
DS
651 {
652 if (up)
3197cb1e 653 zlog_debug("%s(%s): %s, found: %d: ref_count: %d",
f4075cb4 654 __PRETTY_FUNCTION__, name,
8bfb8b67 655 up->sg_str, found,
f4075cb4
DS
656 up->ref_count);
657 else
658 zlog_debug("%s(%s): (%s) failure to create",
659 __PRETTY_FUNCTION__, name,
660 pim_str_sg_dump (sg));
661 }
12e41d03 662
e5905a3b 663 return up;
12e41d03
DL
664}
665
7a3ddda5
DS
666static int
667pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up,
668 struct pim_ifchannel *ch)
669{
670 struct pim_upstream *parent = up->parent;
671
672 if (ch->upstream == up)
673 {
674 if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch))
675 return 1;
46c8aab8
DS
676
677 if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
678 return 0;
7a3ddda5 679 }
46c8aab8 680
7a3ddda5
DS
681 /*
682 * joins (*,G)
683 */
684 if (parent && ch->upstream == parent)
685 {
686 if (!pim_macro_ch_lost_assert (ch) && pim_macro_chisin_joins_or_include (ch))
687 return 1;
688 }
689
690 return 0;
691}
692
12e41d03
DL
693/*
694 Evaluate JoinDesired(S,G):
695
696 JoinDesired(S,G) is true if there is a downstream (S,G) interface I
697 in the set:
698
699 inherited_olist(S,G) =
700 joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
701
702 JoinDesired(S,G) may be affected by changes in the following:
703
704 pim_ifp->primary_address
705 pim_ifp->pim_dr_addr
706 ch->ifassert_winner_metric
707 ch->ifassert_winner
708 ch->local_ifmembership
709 ch->ifjoin_state
710 ch->upstream->rpf.source_nexthop.mrib_metric_preference
711 ch->upstream->rpf.source_nexthop.mrib_route_metric
712 ch->upstream->rpf.source_nexthop.interface
713
714 See also pim_upstream_update_join_desired() below.
715 */
716int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
717{
12e41d03
DL
718 struct listnode *chnode;
719 struct listnode *chnextnode;
12e41d03
DL
720 struct pim_interface *pim_ifp;
721 struct pim_ifchannel *ch;
7a3ddda5 722 int ret = 0;
12e41d03 723
ea4a71fc
DS
724 /* scan per-interface (S,G) state */
725 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch))
726 {
727 pim_ifp = ch->interface->info;
728 if (!pim_ifp)
729 continue;
12e41d03 730
ea4a71fc
DS
731 ret += pim_upstream_evaluate_join_desired_interface (up, ch);
732 } /* scan iface channel list */
12e41d03 733
7a3ddda5 734 return ret; /* false */
12e41d03
DL
735}
736
737/*
738 See also pim_upstream_evaluate_join_desired() above.
739*/
740void pim_upstream_update_join_desired(struct pim_upstream *up)
741{
742 int was_join_desired; /* boolean */
743 int is_join_desired; /* boolean */
744
745 was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags);
746
747 is_join_desired = pim_upstream_evaluate_join_desired(up);
748 if (is_join_desired)
749 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags);
750 else
751 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags);
752
753 /* switched from false to true */
754 if (is_join_desired && !was_join_desired) {
12e41d03
DL
755 pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
756 return;
757 }
758
759 /* switched from true to false */
760 if (!is_join_desired && was_join_desired) {
12e41d03
DL
761 pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED);
762 return;
763 }
764}
765
766/*
767 RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
768 Transitions from Joined State
769 RPF'(S,G) GenID changes
770
771 The upstream (S,G) state machine remains in Joined state. If the
772 Join Timer is set to expire in more than t_override seconds, reset
773 it so that it expires after t_override seconds.
774*/
775void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr)
776{
777 struct listnode *up_node;
778 struct listnode *up_nextnode;
779 struct pim_upstream *up;
780
781 /*
0f588989
DS
782 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
783 */
784 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) {
12e41d03 785
3197cb1e 786 if (PIM_DEBUG_TRACE) {
eaa54bdb
DW
787 char neigh_str[INET_ADDRSTRLEN];
788 char rpf_addr_str[PREFIX_STRLEN];
12e41d03 789 pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str));
63c59d0c 790 pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str));
05e451f8 791 zlog_debug("%s: matching neigh=%s against upstream (S,G)=%s joined=%d rpf_addr=%s",
12e41d03 792 __PRETTY_FUNCTION__,
8bfb8b67 793 neigh_str, up->sg_str,
12e41d03
DL
794 up->join_state == PIM_UPSTREAM_JOINED,
795 rpf_addr_str);
796 }
797
798 /* consider only (S,G) upstream in Joined state */
799 if (up->join_state != PIM_UPSTREAM_JOINED)
800 continue;
801
802 /* match RPF'(S,G)=neigh_addr */
63c59d0c 803 if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr)
12e41d03
DL
804 continue;
805
806 pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
807 up, neigh_addr);
808 }
809}
810
811
812void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
813 struct interface *old_rpf_ifp)
814{
ea4a71fc
DS
815 struct listnode *chnode;
816 struct listnode *chnextnode;
817 struct pim_ifchannel *ch;
818 struct pim_interface *pim_ifp;
819
820 /* search all ifchannels */
821 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
822
823 pim_ifp = ch->interface->info;
12e41d03
DL
824 if (!pim_ifp)
825 continue;
826
ea4a71fc
DS
827 if (ch->upstream != up)
828 continue;
12e41d03 829
ea4a71fc
DS
830 if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
831 if (
832 /* RPF_interface(S) was NOT I */
833 (old_rpf_ifp == ch->interface)
834 &&
835 /* RPF_interface(S) stopped being I */
836 (ch->upstream->rpf.source_nexthop.interface != ch->interface)
837 ) {
838 assert_action_a5(ch);
839 }
840 } /* PIM_IFASSERT_I_AM_LOSER */
12e41d03 841
ea4a71fc 842 pim_ifchannel_update_assert_tracking_desired(ch);
12e41d03
DL
843 }
844}
845
846void pim_upstream_update_could_assert(struct pim_upstream *up)
847{
12e41d03
DL
848 struct listnode *chnode;
849 struct listnode *chnextnode;
12e41d03
DL
850 struct pim_interface *pim_ifp;
851 struct pim_ifchannel *ch;
852
ea4a71fc
DS
853 /* scan per-interface (S,G) state */
854 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
855 pim_ifp = ch->interface->info;
12e41d03
DL
856 if (!pim_ifp)
857 continue;
858
ea4a71fc
DS
859 if (ch->upstream != up)
860 continue;
12e41d03 861
ea4a71fc
DS
862 pim_ifchannel_update_could_assert(ch);
863 } /* scan iface channel list */
12e41d03
DL
864}
865
866void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
867{
12e41d03
DL
868 struct listnode *chnode;
869 struct listnode *chnextnode;
12e41d03
DL
870 struct pim_interface *pim_ifp;
871 struct pim_ifchannel *ch;
872
ea4a71fc
DS
873 /* scan per-interface (S,G) state */
874 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
875 pim_ifp = ch->interface->info;
12e41d03
DL
876 if (!pim_ifp)
877 continue;
878
ea4a71fc
DS
879 if (ch->upstream != up)
880 continue;
12e41d03 881
ea4a71fc 882 pim_ifchannel_update_my_assert_metric(ch);
12e41d03 883
ea4a71fc 884 } /* scan iface channel list */
12e41d03
DL
885}
886
887static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
888{
12e41d03
DL
889 struct listnode *chnode;
890 struct listnode *chnextnode;
12e41d03
DL
891 struct pim_interface *pim_ifp;
892 struct pim_ifchannel *ch;
893
ea4a71fc
DS
894 /* scan per-interface (S,G) state */
895 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
896 pim_ifp = ch->interface->info;
12e41d03
DL
897 if (!pim_ifp)
898 continue;
899
ea4a71fc
DS
900 if (ch->upstream != up)
901 continue;
12e41d03 902
ea4a71fc 903 pim_ifchannel_update_assert_tracking_desired(ch);
12e41d03 904
ea4a71fc 905 } /* scan iface channel list */
12e41d03 906}
f14248dd 907
1bf16443 908/* When kat is stopped CouldRegister goes to false so we need to
909 * transition the (S, G) on FHR to NI state and remove reg tunnel
910 * from the OIL */
911static void pim_upstream_fhr_kat_expiry(struct pim_upstream *up)
912{
913 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
914 return;
915
916 if (PIM_DEBUG_TRACE)
8bfb8b67
DS
917 zlog_debug ("kat expired on %s; clear fhr reg state", up->sg_str);
918
1bf16443 919 /* stop reg-stop timer */
920 THREAD_OFF(up->t_rs_timer);
921 /* remove regiface from the OIL if it is there*/
922 pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
923 /* move to "not-joined" */
924 up->join_state = PIM_UPSTREAM_NOTJOINED;
925 PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags);
926}
927
928/* When kat is started CouldRegister can go to true. And if it does we
929 * need to transition the (S, G) on FHR to JOINED state and add reg tunnel
930 * to the OIL */
931static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
932{
933 if (pim_upstream_could_register(up)) {
934 if (PIM_DEBUG_TRACE)
8bfb8b67
DS
935 zlog_debug ("kat started on %s; set fhr reg state to joined", up->sg_str);
936
1bf16443 937 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
938 if (up->join_state == PIM_UPSTREAM_NOTJOINED) {
939 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
940 up->join_state = PIM_UPSTREAM_JOINED;
941 }
942 }
943}
944
f14248dd
DS
945/*
946 * On an RP, the PMBR value must be cleared when the
947 * Keepalive Timer expires
1bf16443 948 * KAT expiry indicates that flow is inactive. If the flow was created or
949 * maintained by activity now is the time to deref it.
f14248dd
DS
950 */
951static int
952pim_upstream_keep_alive_timer (struct thread *t)
953{
954 struct pim_upstream *up;
955
956 up = THREAD_ARG(t);
1bf16443 957 up->t_ka_timer = NULL;
f14248dd 958
4ed0af70 959 if (I_am_RP (up->sg.grp))
1bf16443 960 {
961 pim_br_clear_pmbr (&up->sg);
962 /*
963 * We need to do more here :)
964 * But this is the start.
965 */
966 }
14315ea8 967
1bf16443 968 /* source is no longer active - pull the SA from MSDP's cache */
969 pim_msdp_sa_local_del(&up->sg);
14315ea8 970
1bf16443 971 /* if entry was created because of activity we need to deref it */
972 if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
973 {
974 pim_upstream_fhr_kat_expiry(up);
975 if (PIM_DEBUG_TRACE)
8bfb8b67 976 zlog_debug ("kat expired on %s; remove stream reference", up->sg_str);
1bf16443 977 PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
978 pim_upstream_del(up, __PRETTY_FUNCTION__);
979 }
14315ea8 980
1bf16443 981 return 0;
f14248dd
DS
982}
983
f14248dd
DS
984void
985pim_upstream_keep_alive_timer_start (struct pim_upstream *up,
986 uint32_t time)
987{
1bf16443 988 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) {
989 if (PIM_DEBUG_TRACE)
8bfb8b67 990 zlog_debug ("kat start on %s with no stream reference", up->sg_str);
1bf16443 991 }
00d2f9e4 992 THREAD_OFF (up->t_ka_timer);
f14248dd
DS
993 THREAD_TIMER_ON (master,
994 up->t_ka_timer,
995 pim_upstream_keep_alive_timer,
996 up, time);
1bf16443 997
998 /* any time keepalive is started against a SG we will have to
999 * re-evaluate our active source database */
1000 pim_msdp_sa_local_update(up);
1001}
1002
1003/* MSDP on RP needs to know if a source is registerable to this RP */
1004static int
1005pim_upstream_msdp_reg_timer(struct thread *t)
1006{
1007 struct pim_upstream *up;
1008
1009 up = THREAD_ARG(t);
1010 up->t_msdp_reg_timer = NULL;
1011
1012 /* source is no longer active - pull the SA from MSDP's cache */
1013 pim_msdp_sa_local_del(&up->sg);
1014 return 1;
1015}
1016void
1017pim_upstream_msdp_reg_timer_start(struct pim_upstream *up)
1018{
1019 THREAD_OFF(up->t_msdp_reg_timer);
1020 THREAD_TIMER_ON(master, up->t_msdp_reg_timer,
1021 pim_upstream_msdp_reg_timer, up, PIM_MSDP_REG_RXED_PERIOD);
1022
1023 pim_msdp_sa_local_update(up);
f14248dd 1024}
cb40b272
DS
1025
1026/*
1027 * 4.2.1 Last-Hop Switchover to the SPT
1028 *
1029 * In Sparse-Mode PIM, last-hop routers join the shared tree towards the
1030 * RP. Once traffic from sources to joined groups arrives at a last-hop
1031 * router, it has the option of switching to receive the traffic on a
1032 * shortest path tree (SPT).
1033 *
1034 * The decision for a router to switch to the SPT is controlled as
1035 * follows:
1036 *
1037 * void
1038 * CheckSwitchToSpt(S,G) {
1039 * if ( ( pim_include(*,G) (-) pim_exclude(S,G)
1040 * (+) pim_include(S,G) != NULL )
1041 * AND SwitchToSptDesired(S,G) ) {
1042 * # Note: Restarting the KAT will result in the SPT switch
1043 * set KeepaliveTimer(S,G) to Keepalive_Period
1044 * }
1045 * }
1046 *
1047 * SwitchToSptDesired(S,G) is a policy function that is implementation
1048 * defined. An "infinite threshold" policy can be implemented by making
1049 * SwitchToSptDesired(S,G) return false all the time. A "switch on
1050 * first packet" policy can be implemented by making
1051 * SwitchToSptDesired(S,G) return true once a single packet has been
1052 * received for the source and group.
1053 */
1054int
4ed0af70 1055pim_upstream_switch_to_spt_desired (struct prefix_sg *sg)
cb40b272 1056{
4ed0af70 1057 if (I_am_RP (sg->grp))
a3b58b4a
DS
1058 return 1;
1059
cb40b272
DS
1060 return 0;
1061}
d7259eac 1062
80d9c3a0
DS
1063int
1064pim_upstream_is_sg_rpt (struct pim_upstream *up)
1065{
f21597f0
DS
1066 struct listnode *chnode;
1067 struct pim_ifchannel *ch;
1068
1069 for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, chnode, ch))
1070 {
1071 if ((ch->upstream == up) &&
1072 (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)))
1073 return 1;
1074 }
e43b8697 1075
80d9c3a0
DS
1076 return 0;
1077}
3a66b17b
DS
1078/*
1079 * After receiving a packet set SPTbit:
1080 * void
1081 * Update_SPTbit(S,G,iif) {
1082 * if ( iif == RPF_interface(S)
1083 * AND JoinDesired(S,G) == TRUE
1084 * AND ( DirectlyConnected(S) == TRUE
1085 * OR RPF_interface(S) != RPF_interface(RP(G))
1086 * OR inherited_olist(S,G,rpt) == NULL
1087 * OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1088 * ( RPF'(S,G) != NULL ) )
1089 * OR ( I_Am_Assert_Loser(S,G,iif) ) {
1090 * Set SPTbit(S,G) to TRUE
1091 * }
1092 * }
1093 */
1094void
1095pim_upstream_set_sptbit (struct pim_upstream *up, struct interface *incoming)
1096{
1097 struct pim_rpf *grpf = NULL;
1098
1099 // iif == RPF_interfvace(S)
1100 if (up->rpf.source_nexthop.interface != incoming)
1101 {
1102 if (PIM_DEBUG_TRACE)
1103 zlog_debug ("%s: Incoming Interface: %s is different than RPF_interface(S) %s",
1104 __PRETTY_FUNCTION__, incoming->name, up->rpf.source_nexthop.interface->name);
1105 return;
1106 }
1107
1108 // AND JoinDesired(S,G) == TRUE
1109 // FIXME
1110
1111 // DirectlyConnected(S) == TRUE
1112 if (pim_if_connected_to_source (up->rpf.source_nexthop.interface, up->sg.src))
1113 {
1114 if (PIM_DEBUG_TRACE)
1115 zlog_debug ("%s: %s is directly connected to the source", __PRETTY_FUNCTION__,
8bfb8b67 1116 up->sg_str);
3a66b17b
DS
1117 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1118 return;
1119 }
1120
1121 // OR RPF_interface(S) != RPF_interface(RP(G))
1122 grpf = RP(up->sg.grp);
1123 if (!grpf || up->rpf.source_nexthop.interface != grpf->source_nexthop.interface)
1124 {
1125 if (PIM_DEBUG_TRACE)
1126 zlog_debug ("%s: %s RPF_interface(S) != RPF_interface(RP(G))",
8bfb8b67 1127 __PRETTY_FUNCTION__, up->sg_str);
3a66b17b
DS
1128 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1129 return;
1130 }
1131
1132 // OR inherited_olist(S,G,rpt) == NULL
1133 if (pim_upstream_is_sg_rpt(up) && pim_upstream_empty_inherited_olist(up))
1134 {
1135 if (PIM_DEBUG_TRACE)
1136 zlog_debug ("%s: %s OR inherited_olist(S,G,rpt) == NULL", __PRETTY_FUNCTION__,
8bfb8b67 1137 up->sg_str);
3a66b17b
DS
1138 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1139 return;
1140 }
1141
1142 // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND
1143 // ( RPF'(S,G) != NULL ) )
1144 if (up->parent && pim_rpf_is_same (&up->rpf, &up->parent->rpf))
1145 {
1146 if (PIM_DEBUG_TRACE)
1147 zlog_debug ("%s: %s RPF'(S,G) is the same as RPF'(*,G)", __PRETTY_FUNCTION__,
8bfb8b67 1148 up->sg_str);
3a66b17b
DS
1149 up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
1150 return;
1151 }
1152
1153 return;
1154}
80d9c3a0 1155
d7259eac 1156const char *
c9802954 1157pim_upstream_state2str (enum pim_upstream_state join_state)
d7259eac 1158{
c9802954 1159 switch (join_state)
d7259eac
DS
1160 {
1161 case PIM_UPSTREAM_NOTJOINED:
e775c0a4 1162 return "NotJoined";
d7259eac
DS
1163 break;
1164 case PIM_UPSTREAM_JOINED:
e775c0a4 1165 return "Joined";
d7259eac
DS
1166 break;
1167 case PIM_UPSTREAM_JOIN_PENDING:
e775c0a4 1168 return "JoinPending";
d7259eac
DS
1169 break;
1170 case PIM_UPSTREAM_PRUNE:
1171 return "Prune";
1172 break;
1173 }
e775c0a4 1174 return "Unknown";
d7259eac 1175}
627ed2a3
DS
1176
1177static int
1178pim_upstream_register_stop_timer (struct thread *t)
1179{
4df01a4e 1180 struct pim_interface *pim_ifp;
627ed2a3
DS
1181 struct pim_upstream *up;
1182 struct pim_rpf *rpg;
1183 struct ip ip_hdr;
627ed2a3
DS
1184 up = THREAD_ARG (t);
1185
1186 up->t_rs_timer = NULL;
1187
1188 if (PIM_DEBUG_TRACE)
1189 {
d5ed8a9c 1190 zlog_debug ("%s: (S,G)=%s upstream register stop timer %s",
8bfb8b67 1191 __PRETTY_FUNCTION__, up->sg_str,
c9802954 1192 pim_upstream_state2str(up->join_state));
627ed2a3
DS
1193 }
1194
1195 switch (up->join_state)
1196 {
1197 case PIM_UPSTREAM_JOIN_PENDING:
1198 up->join_state = PIM_UPSTREAM_JOINED;
bb027ee8
DS
1199 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
1200 break;
1201 case PIM_UPSTREAM_JOINED:
627ed2a3
DS
1202 break;
1203 case PIM_UPSTREAM_PRUNE:
4df01a4e 1204 pim_ifp = up->rpf.source_nexthop.interface->info;
7ef66046
DS
1205 if (!pim_ifp)
1206 {
1207 if (PIM_DEBUG_TRACE)
1208 zlog_debug ("%s: Interface: %s is not configured for pim",
1209 __PRETTY_FUNCTION__, up->rpf.source_nexthop.interface->name);
1210 return 0;
1211 }
627ed2a3
DS
1212 up->join_state = PIM_UPSTREAM_JOIN_PENDING;
1213 pim_upstream_start_register_stop_timer (up, 1);
1214
70e7fda8
DS
1215 if (((up->channel_oil->cc.lastused/100) > PIM_KEEPALIVE_PERIOD) &&
1216 (I_am_RP (up->sg.grp)))
1217 {
1218 if (PIM_DEBUG_TRACE)
1219 zlog_debug ("%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while", __PRETTY_FUNCTION__);
1220 return 0;
1221 }
4ed0af70 1222 rpg = RP (up->sg.grp);
627ed2a3
DS
1223 memset (&ip_hdr, 0, sizeof (struct ip));
1224 ip_hdr.ip_p = PIM_IP_PROTO_PIM;
1225 ip_hdr.ip_hl = 5;
1226 ip_hdr.ip_v = 4;
4ed0af70
DS
1227 ip_hdr.ip_src = up->sg.src;
1228 ip_hdr.ip_dst = up->sg.grp;
dc686f82 1229 ip_hdr.ip_len = htons (20);
627ed2a3 1230 // checksum is broken
4df01a4e 1231 pim_register_send ((uint8_t *)&ip_hdr, sizeof (struct ip),
0e3b3d5d 1232 pim_ifp->primary_address, rpg, 1, up);
627ed2a3
DS
1233 break;
1234 default:
1235 break;
1236 }
1237
1238 return 0;
1239}
1240
1241void
1242pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_register)
1243{
1244 uint32_t time;
1245
1246 if (up->t_rs_timer)
1247 {
1248 THREAD_TIMER_OFF (up->t_rs_timer);
1249 up->t_rs_timer = NULL;
1250 }
1251
1252 if (!null_register)
1253 {
1254 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1255 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1256 time = lower + (random () % (upper - lower + 1)) - PIM_REGISTER_PROBE_PERIOD;
1257 }
1258 else
1259 time = PIM_REGISTER_PROBE_PERIOD;
1260
1261 if (PIM_DEBUG_TRACE)
1262 {
05e451f8 1263 zlog_debug ("%s: (S,G)=%s Starting upstream register stop timer %d",
8bfb8b67 1264 __PRETTY_FUNCTION__, up->sg_str, time);
627ed2a3
DS
1265 }
1266 THREAD_TIMER_ON (master, up->t_rs_timer,
1267 pim_upstream_register_stop_timer,
1268 up, time);
1269}
4fdc8f36
DS
1270
1271/*
1272 * For a given upstream, determine the inherited_olist
1273 * and apply it.
219e0013
DS
1274 *
1275 * inherited_olist(S,G,rpt) =
1276 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1277 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1278 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1279 *
1280 * inherited_olist(S,G) =
1281 * inherited_olist(S,G,rpt) (+)
1282 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1283 *
4fdc8f36
DS
1284 * return 1 if there are any output interfaces
1285 * return 0 if there are not any output interfaces
1286 */
1287int
1288pim_upstream_inherited_olist (struct pim_upstream *up)
1289{
219e0013 1290 struct pim_interface *pim_ifp;
219e0013
DS
1291 struct listnode *chnextnode;
1292 struct pim_ifchannel *ch;
1293 struct listnode *chnode;
219e0013
DS
1294 int output_intf = 0;
1295
3667b0bc 1296 pim_ifp = up->rpf.source_nexthop.interface->info;
da55afba 1297 if (pim_ifp && !up->channel_oil)
3667b0bc 1298 up->channel_oil = pim_channel_oil_add (&up->sg, pim_ifp->mroute_vif_index);
219e0013 1299
ea4a71fc 1300 for (ALL_LIST_ELEMENTS (pim_ifchannel_list, chnode, chnextnode, ch))
219e0013 1301 {
ea4a71fc 1302 pim_ifp = ch->interface->info;
7a3ddda5
DS
1303 if (!pim_ifp)
1304 continue;
219e0013 1305
ea4a71fc 1306 if (pim_upstream_evaluate_join_desired_interface (up, ch))
7a3ddda5 1307 {
ea4a71fc
DS
1308 pim_channel_add_oif (up->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM);
1309 output_intf++;
219e0013
DS
1310 }
1311 }
1312
483eef9d
DS
1313 /*
1314 * If we have output_intf switch state to Join and work like normal
1315 * If we don't have an output_intf that means we are probably a
1316 * switch on a stick so turn on forwarding to just accept the
1317 * incoming packets so we don't bother the other stuff!
1318 */
1319 if (output_intf)
1320 pim_upstream_switch (up, PIM_UPSTREAM_JOINED);
1321 else
1322 forward_on (up);
219e0013
DS
1323
1324 return output_intf;
4fdc8f36 1325}
d3dd1804 1326
80d9c3a0
DS
1327int
1328pim_upstream_empty_inherited_olist (struct pim_upstream *up)
1329{
ce0ddb4e 1330 return pim_channel_oil_empty (up->channel_oil);
80d9c3a0
DS
1331}
1332
d3dd1804
DS
1333/*
1334 * When we have a new neighbor,
1335 * find upstreams that don't have their rpf_addr
1336 * set and see if the new neighbor allows
1337 * the join to be sent
1338 */
1339void
1340pim_upstream_find_new_rpf (void)
1341{
1342 struct listnode *up_node;
1343 struct listnode *up_nextnode;
1344 struct pim_upstream *up;
1345
1346 /*
0f588989
DS
1347 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1348 */
1349 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up))
d3dd1804 1350 {
63c59d0c 1351 if (pim_rpf_addr_is_inaddr_any(&up->rpf))
d3dd1804 1352 {
3197cb1e 1353 if (PIM_DEBUG_TRACE)
d3dd1804 1354 zlog_debug ("Upstream %s without a path to send join, checking",
8bfb8b67 1355 up->sg_str);
d3dd1804
DS
1356 pim_rpf_update (up, NULL);
1357 }
1358 }
1359}
0f588989 1360
0f588989
DS
1361static unsigned int
1362pim_upstream_hash_key (void *arg)
1363{
1364 struct pim_upstream *up = (struct pim_upstream *)arg;
1365
1366 return jhash_2words (up->sg.src.s_addr, up->sg.grp.s_addr, 0);
1367}
1368
1369void pim_upstream_terminate (void)
1370{
1371 if (pim_upstream_list)
1372 list_free (pim_upstream_list);
1373 pim_upstream_list = NULL;
1374
1375 if (pim_upstream_hash)
1376 hash_free (pim_upstream_hash);
1377}
1378
1379static int
1380pim_upstream_equal (const void *arg1, const void *arg2)
1381{
1382 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1383 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
1384
1385 if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr) &&
1386 (up1->sg.src.s_addr == up2->sg.src.s_addr))
1387 return 1;
1388
1389 return 0;
1390}
1391
1bf16443 1392/* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1393 * the cases where kat has to be restarted on rxing traffic -
1394 *
1395 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1396 * set KeepaliveTimer(S,G) to Keepalive_Period
1397 * # Note: a register state transition or UpstreamJPState(S,G)
1398 * # transition may happen as a result of restarting
1399 * # KeepaliveTimer, and must be dealt with here.
1400 * }
1401 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1402 * inherited_olist(S,G) != NULL ) {
1403 * set KeepaliveTimer(S,G) to Keepalive_Period
1404 * }
1405 */
1406static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
1407{
1408 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1409 * so we will skip that here */
1410 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1411 up->sg.src)) {
1412 return true;
1413 }
1414
1415 if ((up->join_state == PIM_UPSTREAM_JOINED) &&
1416 !pim_upstream_empty_inherited_olist(up)) {
1417 /* XXX: I have added this RP check just for 3.2 and it's a digression from
1418 * what rfc-4601 says. Till now we were only running KAT on FHR and RP and
1419 * there is some angst around making the change to run it all routers that
1420 * maintain the (S, G) state. This is tracked via CM-13601 and MUST be
1421 * removed to handle spt turn-arounds correctly in a 3-tier clos */
1422 if (I_am_RP (up->sg.grp))
1423 return true;
1424 }
1425
1426 return false;
1427}
1428
9c5e4d62
DS
1429/*
1430 * Code to check and see if we've received packets on a S,G mroute
1431 * and if so to set the SPT bit appropriately
1432 */
1433static void
1434pim_upstream_sg_running (void *arg)
1435{
1436 struct pim_upstream *up = (struct pim_upstream *)arg;
e43b8697
DS
1437
1438 // No packet can have arrived here if this is the case
1439 if (!up->channel_oil || !up->channel_oil->installed)
1440 {
1441 if (PIM_DEBUG_TRACE)
1442 zlog_debug ("%s: %s is not installed in mroute",
8bfb8b67 1443 __PRETTY_FUNCTION__, up->sg_str);
e43b8697
DS
1444 return;
1445 }
1446
e43b8697
DS
1447
1448 pim_mroute_update_counters (up->channel_oil);
1449
1450 // Have we seen packets?
1bf16443 1451 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt) &&
e43b8697
DS
1452 (up->channel_oil->cc.lastused/100 > 30))
1453 {
1454 if (PIM_DEBUG_TRACE)
1455 {
eeedae06
DS
1456 zlog_debug ("%s: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1457 __PRETTY_FUNCTION__, up->sg_str,
1458 up->channel_oil->cc.oldpktcnt,
1459 up->channel_oil->cc.pktcnt,
1460 up->channel_oil->cc.lastused/100);
e43b8697
DS
1461 }
1462 return;
1463 }
1464
1bf16443 1465 if (pim_upstream_kat_start_ok(up)) {
1466 /* Add a source reference to the stream if
1467 * one doesn't already exist */
1468 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
1469 {
1470 if (PIM_DEBUG_TRACE)
8bfb8b67
DS
1471 zlog_debug ("source reference created on kat restart %s", up->sg_str);
1472
1bf16443 1473 pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM);
1474 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
1475 pim_upstream_fhr_kat_start(up);
1476 }
1477 pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
1478 }
1479
1480 if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE)
1481 {
1482 pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
1483 }
e43b8697 1484 return;
9c5e4d62
DS
1485}
1486
040d86ad
DS
1487void
1488pim_upstream_init (void)
0f588989 1489{
9c5e4d62
DS
1490 pim_upstream_sg_wheel = wheel_init (master, 31000, 100,
1491 pim_upstream_hash_key,
1492 pim_upstream_sg_running);
0f588989
DS
1493 pim_upstream_hash = hash_create_size (8192, pim_upstream_hash_key,
1494 pim_upstream_equal);
1495
1496 pim_upstream_list = list_new ();
1497 pim_upstream_list->del = (void (*)(void *)) pim_upstream_free;
03417ccd 1498 pim_upstream_list->cmp = pim_upstream_compare;
0f588989
DS
1499
1500}