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