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