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