]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_upstream.c
pimd: Add packed data structures for building j/p messages
[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"
12e41d03 54
0f588989
DS
55struct hash *pim_upstream_hash = NULL;
56struct list *pim_upstream_list = NULL;
9c5e4d62 57struct timer_wheel *pim_upstream_sg_wheel = NULL;
0f588989 58
12e41d03
DL
59static void join_timer_start(struct pim_upstream *up);
60static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
61
cfa91a87
DS
62/*
63 * A (*,G) or a (*,*) is going away
64 * remove the parent pointer from
65 * those pointing at us
66 */
67static void
68pim_upstream_remove_children (struct pim_upstream *up)
69{
cfa91a87
DS
70 struct pim_upstream *child;
71
03417ccd 72 if (!up->sources)
cfa91a87
DS
73 return;
74
03417ccd 75 while (!list_isempty (up->sources))
cfa91a87 76 {
03417ccd
DS
77 child = listnode_head (up->sources);
78 child->parent = NULL;
79 listnode_delete (up->sources, child);
cfa91a87
DS
80 }
81}
82
83/*
84 * A (*,G) or a (*,*) is being created
85 * Find the children that would point
86 * at us.
87 */
88static void
89pim_upstream_find_new_children (struct pim_upstream *up)
90{
91 struct pim_upstream *child;
92 struct listnode *ch_node;
93
4ed0af70
DS
94 if ((up->sg.src.s_addr != INADDR_ANY) &&
95 (up->sg.grp.s_addr != INADDR_ANY))
cfa91a87
DS
96 return;
97
4ed0af70
DS
98 if ((up->sg.src.s_addr == INADDR_ANY) &&
99 (up->sg.grp.s_addr == INADDR_ANY))
cfa91a87
DS
100 return;
101
0f588989 102 for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, ch_node, child))
cfa91a87 103 {
4ed0af70 104 if ((up->sg.grp.s_addr != INADDR_ANY) &&
0f588989 105 (child->sg.grp.s_addr == up->sg.grp.s_addr) &&
cfa91a87 106 (child != up))
03417ccd
DS
107 {
108 child->parent = up;
109 listnode_add_sort (up->sources, child);
110 }
cfa91a87
DS
111 }
112}
113
4d99418b
DS
114/*
115 * If we have a (*,*) || (S,*) there is no parent
116 * If we have a (S,G), find the (*,G)
117 * If we have a (*,G), find the (*,*)
118 */
119static struct pim_upstream *
03417ccd 120pim_upstream_find_parent (struct pim_upstream *child)
4d99418b 121{
03417ccd
DS
122 struct prefix_sg any = child->sg;
123 struct pim_upstream *up = NULL;
4d99418b
DS
124
125 // (S,G)
03417ccd
DS
126 if ((child->sg.src.s_addr != INADDR_ANY) &&
127 (child->sg.grp.s_addr != INADDR_ANY))
4d99418b 128 {
4ed0af70 129 any.src.s_addr = INADDR_ANY;
03417ccd
DS
130 up = pim_upstream_find (&any);
131
132 if (up)
133 listnode_add (up->sources, child);
134
135 return up;
4d99418b
DS
136 }
137
03417ccd 138 return NULL;
4d99418b
DS
139}
140
12e41d03
DL
141void pim_upstream_free(struct pim_upstream *up)
142{
143 XFREE(MTYPE_PIM_UPSTREAM, up);
144}
145
146static void upstream_channel_oil_detach(struct pim_upstream *up)
147{
148 if (up->channel_oil) {
149 pim_channel_oil_del(up->channel_oil);
25a335e0 150 up->channel_oil = NULL;
12e41d03
DL
151 }
152}
153
e5905a3b
DS
154void
155pim_upstream_del(struct pim_upstream *up, const char *name)
12e41d03 156{
7667c556 157 bool notify_msdp = false;
158
3197cb1e
DS
159 if (PIM_DEBUG_TRACE)
160 zlog_debug ("%s(%s): Delete %s ref count: %d",
161 __PRETTY_FUNCTION__, name, up->sg_str, up->ref_count);
162
e5905a3b
DS
163 --up->ref_count;
164
165 if (up->ref_count >= 1)
166 return;
167
12e41d03 168 THREAD_OFF(up->t_join_timer);
f14248dd 169 THREAD_OFF(up->t_ka_timer);
792f4d29 170 THREAD_OFF(up->t_rs_timer);
1bf16443 171 THREAD_OFF(up->t_msdp_reg_timer);
12e41d03 172
7667c556 173 if (up->join_state == PIM_UPSTREAM_JOINED) {
174 pim_joinprune_send (up->rpf.source_nexthop.interface,
175 up->rpf.rpf_addr.u.prefix4,
176 up, 0);
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
DL
233 /* send Join(S,G) to the current upstream neighbor */
234 pim_joinprune_send(up->rpf.source_nexthop.interface,
63c59d0c 235 up->rpf.rpf_addr.u.prefix4,
372eab92 236 up,
12e41d03
DL
237 1 /* join */);
238}
239
240static int on_join_timer(struct thread *t)
241{
242 struct pim_upstream *up;
243
12e41d03 244 up = THREAD_ARG(t);
12e41d03 245
bb6e291f
DS
246 up->t_join_timer = NULL;
247
248 /*
249 * In the case of a HFR we will not ahve anyone to send this to.
250 */
0bf27c5c 251 if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
bb6e291f
DS
252 return 0;
253
eb345962
DS
254 /*
255 * Don't send the join if the outgoing interface is a loopback
256 * But since this might change leave the join timer running
257 */
258 if (!if_is_loopback (up->rpf.source_nexthop.interface))
259 pim_upstream_send_join (up);
12e41d03 260
12e41d03
DL
261 join_timer_start(up);
262
263 return 0;
264}
265
266static void join_timer_start(struct pim_upstream *up)
267{
268 if (PIM_DEBUG_PIM_EVENTS) {
05e451f8 269 zlog_debug("%s: starting %d sec timer for upstream (S,G)=%s",
12e41d03
DL
270 __PRETTY_FUNCTION__,
271 qpim_t_periodic,
8bfb8b67 272 up->sg_str);
12e41d03
DL
273 }
274
8e38a2cf 275 THREAD_OFF (up->t_join_timer);
12e41d03
DL
276 THREAD_TIMER_ON(master, up->t_join_timer,
277 on_join_timer,
278 up, qpim_t_periodic);
279}
280
281void pim_upstream_join_timer_restart(struct pim_upstream *up)
282{
283 THREAD_OFF(up->t_join_timer);
284 join_timer_start(up);
285}
286
287static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up,
288 int interval_msec)
289{
290 if (PIM_DEBUG_PIM_EVENTS) {
05e451f8 291 zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s",
12e41d03
DL
292 __PRETTY_FUNCTION__,
293 interval_msec,
8bfb8b67 294 up->sg_str);
12e41d03
DL
295 }
296
297 THREAD_OFF(up->t_join_timer);
298 THREAD_TIMER_MSEC_ON(master, up->t_join_timer,
299 on_join_timer,
300 up, interval_msec);
301}
302
303void pim_upstream_join_suppress(struct pim_upstream *up,
304 struct in_addr rpf_addr,
305 int holdtime)
306{
307 long t_joinsuppress_msec;
308 long join_timer_remain_msec;
309
310 t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface),
311 1000 * holdtime);
312
313 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
314
3197cb1e 315 if (PIM_DEBUG_TRACE) {
eaa54bdb 316 char rpf_str[INET_ADDRSTRLEN];
12e41d03 317 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
05e451f8 318 zlog_debug("%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec",
12e41d03 319 __FILE__, __PRETTY_FUNCTION__,
8bfb8b67 320 up->sg_str,
12e41d03
DL
321 rpf_str,
322 join_timer_remain_msec, t_joinsuppress_msec);
323 }
324
325 if (join_timer_remain_msec < t_joinsuppress_msec) {
3197cb1e 326 if (PIM_DEBUG_TRACE) {
05e451f8 327 zlog_debug("%s %s: suppressing Join(S,G)=%s for %ld msec",
12e41d03 328 __FILE__, __PRETTY_FUNCTION__,
8bfb8b67 329 up->sg_str, t_joinsuppress_msec);
12e41d03
DL
330 }
331
332 pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec);
333 }
334}
335
336void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
337 struct pim_upstream *up,
338 struct in_addr rpf_addr)
339{
340 long join_timer_remain_msec;
341 int t_override_msec;
342
343 join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer);
344 t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface);
345
3197cb1e 346 if (PIM_DEBUG_TRACE) {
eaa54bdb 347 char rpf_str[INET_ADDRSTRLEN];
12e41d03 348 pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
05e451f8 349 zlog_debug("%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
12e41d03 350 debug_label,
8bfb8b67 351 up->sg_str, rpf_str,
12e41d03
DL
352 join_timer_remain_msec, t_override_msec);
353 }
354
355 if (join_timer_remain_msec > t_override_msec) {
3197cb1e 356 if (PIM_DEBUG_TRACE) {
05e451f8 357 zlog_debug("%s: decreasing (S,G)=%s join timer to t_override=%d msec",
12e41d03 358 debug_label,
8bfb8b67 359 up->sg_str,
12e41d03
DL
360 t_override_msec);
361 }
362
363 pim_upstream_join_timer_restart_msec(up, t_override_msec);
364 }
365}
366
367static void forward_on(struct pim_upstream *up)
368{
12e41d03
DL
369 struct listnode *chnode;
370 struct listnode *chnextnode;
12e41d03
DL
371 struct pim_interface *pim_ifp;
372 struct pim_ifchannel *ch;
373
ea4a71fc
DS
374 /* scan (S,G) state */
375 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
376 pim_ifp = ch->interface->info;
12e41d03
DL
377 if (!pim_ifp)
378 continue;
379
ea4a71fc
DS
380 if (ch->upstream != up)
381 continue;
12e41d03 382
ea4a71fc
DS
383 if (pim_macro_chisin_oiflist(ch))
384 pim_forward_start(ch);
12e41d03 385
ea4a71fc 386 } /* scan iface channel list */
12e41d03
DL
387}
388
389static void forward_off(struct pim_upstream *up)
390{
12e41d03
DL
391 struct listnode *chnode;
392 struct listnode *chnextnode;
12e41d03
DL
393 struct pim_interface *pim_ifp;
394 struct pim_ifchannel *ch;
395
ea4a71fc
DS
396 /* scan per-interface (S,G) state */
397 for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
398 pim_ifp = ch->interface->info;
12e41d03
DL
399 if (!pim_ifp)
400 continue;
401
ea4a71fc
DS
402 if (ch->upstream != up)
403 continue;
12e41d03 404
ea4a71fc 405 pim_forward_stop(ch);
12e41d03 406
ea4a71fc 407 } /* scan iface channel list */
12e41d03
DL
408}
409
bb6e291f
DS
410static int
411pim_upstream_could_register (struct pim_upstream *up)
412{
413 struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info;
414
35917570 415 if (pim_ifp && PIM_I_am_DR (pim_ifp) &&
bb6e291f
DS
416 pim_if_connected_to_source (up->rpf.source_nexthop.interface, up->sg.src))
417 return 1;
418
419 return 0;
420}
421
7fcdfb34
DS
422void
423pim_upstream_switch(struct pim_upstream *up,
424 enum pim_upstream_state new_state)
12e41d03
DL
425{
426 enum pim_upstream_state old_state = up->join_state;
427
12e41d03 428 if (PIM_DEBUG_PIM_EVENTS) {
c9802954 429 zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s",
12e41d03 430 __PRETTY_FUNCTION__,
8bfb8b67 431 up->sg_str,
c9802954
DS
432 pim_upstream_state2str (up->join_state),
433 pim_upstream_state2str (new_state));
12e41d03
DL
434 }
435
bb027ee8
DS
436 /*
437 * This code still needs work.
438 */
439 switch (up->join_state)
440 {
441 case PIM_UPSTREAM_PRUNE:
0bf27c5c 442 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
7747bad6
DS
443 {
444 up->join_state = new_state;
445 up->state_transition = pim_time_monotonic_sec ();
446 }
447 break;
bb027ee8
DS
448 case PIM_UPSTREAM_JOIN_PENDING:
449 break;
450 case PIM_UPSTREAM_NOTJOINED:
451 case PIM_UPSTREAM_JOINED:
452 up->join_state = new_state;
e5b6b229
DS
453 if (old_state != new_state)
454 up->state_transition = pim_time_monotonic_sec();
bb027ee8
DS
455
456 break;
457 }
458
12e41d03
DL
459 pim_upstream_update_assert_tracking_desired(up);
460
461 if (new_state == PIM_UPSTREAM_JOINED) {
81900c5a
DS
462 if (old_state != PIM_UPSTREAM_JOINED)
463 {
0bf27c5c 464 int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags);
81900c5a 465 forward_on(up);
7667c556 466 pim_msdp_up_join_state_changed(up);
0bf27c5c 467 if (pim_upstream_could_register (up))
bb6e291f 468 {
0bf27c5c 469 PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
a9b59879 470 if (!old_fhr && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
bb6e291f
DS
471 {
472 pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
473 pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
474 }
475 }
476 else
477 {
478 pim_upstream_send_join (up);
479 join_timer_start (up);
480 }
81900c5a
DS
481 }
482 else
483 {
484 forward_on (up);
485 }
12e41d03
DL
486 }
487 else {
488 forward_off(up);
7667c556 489 if (old_state == PIM_UPSTREAM_JOINED)
490 pim_msdp_up_join_state_changed(up);
12e41d03 491 pim_joinprune_send(up->rpf.source_nexthop.interface,
63c59d0c 492 up->rpf.rpf_addr.u.prefix4,
372eab92 493 up,
12e41d03 494 0 /* prune */);
7fcdfb34
DS
495 if (up->t_join_timer)
496 THREAD_OFF(up->t_join_timer);
12e41d03 497 }
12e41d03
DL
498}
499
03417ccd
DS
500static int
501pim_upstream_compare (void *arg1, void *arg2)
502{
503 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
504 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
505
506 if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr))
507 return -1;
508
509 if (ntohl(up1->sg.grp.s_addr) > ntohl(up2->sg.grp.s_addr))
510 return 1;
511
512 if (ntohl(up1->sg.src.s_addr) < ntohl(up2->sg.src.s_addr))
513 return -1;
514
515 if (ntohl(up1->sg.src.s_addr) > ntohl(up2->sg.src.s_addr))
516 return 1;
517
518 return 0;
519}
520
07335c8d
DS
521static struct pim_upstream *
522pim_upstream_new (struct prefix_sg *sg,
523 struct interface *incoming,
524 int flags)
12e41d03 525{
2f702571 526 enum pim_rpf_result rpf_result;
07335c8d
DS
527 struct pim_interface *pim_ifp;
528 struct pim_upstream *up;
12e41d03 529
36d9e7dc 530 up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
12e41d03 531 if (!up) {
36d9e7dc 532 zlog_err("%s: PIM XCALLOC(%zu) failure",
12e41d03 533 __PRETTY_FUNCTION__, sizeof(*up));
8f5f5e91 534 return NULL;
12e41d03
DL
535 }
536
5074a423 537 up->sg = *sg;
8bfb8b67 538 pim_str_sg_set (sg, up->sg_str);
0f588989 539 up = hash_get (pim_upstream_hash, up, hash_alloc_intern);
36d6bd7d 540 if (!pim_rp_set_upstream_addr (&up->upstream_addr, sg->src, sg->grp))
8f5f5e91 541 {
3197cb1e 542 if (PIM_DEBUG_TRACE)
8f5f5e91
DS
543 zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
544
03417ccd 545 hash_release (pim_upstream_hash, up);
8f5f5e91
DS
546 XFREE (MTYPE_PIM_UPSTREAM, up);
547 return NULL;
548 }
549
03417ccd
DS
550 up->parent = pim_upstream_find_parent (up);
551 if (up->sg.src.s_addr == INADDR_ANY)
552 {
553 up->sources = list_new ();
554 up->sources->cmp = pim_upstream_compare;
555 }
556 else
557 up->sources = NULL;
558
cfa91a87 559 pim_upstream_find_new_children (up);
4a40c37a 560 up->flags = flags;
12e41d03 561 up->ref_count = 1;
4a4c4a07
DS
562 up->t_join_timer = NULL;
563 up->t_ka_timer = NULL;
792f4d29 564 up->t_rs_timer = NULL;
1bf16443 565 up->t_msdp_reg_timer = NULL;
12e41d03
DL
566 up->join_state = 0;
567 up->state_transition = pim_time_monotonic_sec();
4a4c4a07 568 up->channel_oil = NULL;
f9e0ab5b 569 up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
12e41d03 570
f24405b1 571 up->rpf.source_nexthop.interface = NULL;
63c59d0c
DS
572 up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET;
573 up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
12e41d03
DL
574 up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference;
575 up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric;
63c59d0c
DS
576 up->rpf.rpf_addr.family = AF_INET;
577 up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
12e41d03 578
9c5e4d62
DS
579 if (up->sg.src.s_addr != INADDR_ANY)
580 wheel_add_item (pim_upstream_sg_wheel, up);
581
d3dd1804 582 rpf_result = pim_rpf_update(up, NULL);
2f702571 583 if (rpf_result == PIM_RPF_FAILURE) {
3197cb1e 584 if (PIM_DEBUG_TRACE)
4a40c37a 585 zlog_debug ("%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__,
8bfb8b67 586 up->sg_str);
03417ccd
DS
587
588 if (up->parent)
589 {
590 listnode_delete (up->parent->sources, up);
591 up->parent = NULL;
592 }
9c5e4d62
DS
593
594 if (up->sg.src.s_addr != INADDR_ANY)
595 wheel_remove_item (pim_upstream_sg_wheel, up);
596
03417ccd
DS
597 pim_upstream_remove_children (up);
598 if (up->sources)
599 list_delete (up->sources);
600
601 hash_release (pim_upstream_hash, up);
2f702571
DS
602 XFREE(MTYPE_PIM_UPSTREAM, up);
603 return NULL;
604 }
12e41d03 605
07335c8d
DS
606 pim_ifp = up->rpf.source_nexthop.interface->info;
607 if (pim_ifp)
608 up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index);
609
0f588989 610 listnode_add_sort(pim_upstream_list, up);
12e41d03 611
3197cb1e 612 if (PIM_DEBUG_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)
3197cb1e 652 zlog_debug("%s(%s): %s, found: %d: ref_count: %d",
f4075cb4 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 784
3197cb1e 785 if (PIM_DEBUG_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
70e7fda8
DS
1214 if (((up->channel_oil->cc.lastused/100) > PIM_KEEPALIVE_PERIOD) &&
1215 (I_am_RP (up->sg.grp)))
1216 {
1217 if (PIM_DEBUG_TRACE)
1218 zlog_debug ("%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while", __PRETTY_FUNCTION__);
1219 return 0;
1220 }
4ed0af70 1221 rpg = RP (up->sg.grp);
627ed2a3
DS
1222 memset (&ip_hdr, 0, sizeof (struct ip));
1223 ip_hdr.ip_p = PIM_IP_PROTO_PIM;
1224 ip_hdr.ip_hl = 5;
1225 ip_hdr.ip_v = 4;
4ed0af70
DS
1226 ip_hdr.ip_src = up->sg.src;
1227 ip_hdr.ip_dst = up->sg.grp;
dc686f82 1228 ip_hdr.ip_len = htons (20);
627ed2a3 1229 // checksum is broken
4df01a4e 1230 pim_register_send ((uint8_t *)&ip_hdr, sizeof (struct ip),
0e3b3d5d 1231 pim_ifp->primary_address, rpg, 1, up);
627ed2a3
DS
1232 break;
1233 default:
1234 break;
1235 }
1236
1237 return 0;
1238}
1239
1240void
1241pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_register)
1242{
1243 uint32_t time;
1244
1245 if (up->t_rs_timer)
1246 {
1247 THREAD_TIMER_OFF (up->t_rs_timer);
1248 up->t_rs_timer = NULL;
1249 }
1250
1251 if (!null_register)
1252 {
1253 uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1254 uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD);
1255 time = lower + (random () % (upper - lower + 1)) - PIM_REGISTER_PROBE_PERIOD;
1256 }
1257 else
1258 time = PIM_REGISTER_PROBE_PERIOD;
1259
1260 if (PIM_DEBUG_TRACE)
1261 {
05e451f8 1262 zlog_debug ("%s: (S,G)=%s Starting upstream register stop timer %d",
8bfb8b67 1263 __PRETTY_FUNCTION__, up->sg_str, time);
627ed2a3
DS
1264 }
1265 THREAD_TIMER_ON (master, up->t_rs_timer,
1266 pim_upstream_register_stop_timer,
1267 up, time);
1268}
4fdc8f36 1269
4fdc8f36 1270int
b5183fd1 1271pim_upstream_inherited_olist_decide (struct pim_upstream *up)
4fdc8f36 1272{
219e0013 1273 struct pim_interface *pim_ifp;
219e0013
DS
1274 struct listnode *chnextnode;
1275 struct pim_ifchannel *ch;
1276 struct listnode *chnode;
219e0013
DS
1277 int output_intf = 0;
1278
3667b0bc 1279 pim_ifp = up->rpf.source_nexthop.interface->info;
da55afba 1280 if (pim_ifp && !up->channel_oil)
3667b0bc 1281 up->channel_oil = pim_channel_oil_add (&up->sg, pim_ifp->mroute_vif_index);
219e0013 1282
ea4a71fc 1283 for (ALL_LIST_ELEMENTS (pim_ifchannel_list, chnode, chnextnode, ch))
219e0013 1284 {
ea4a71fc 1285 pim_ifp = ch->interface->info;
7a3ddda5
DS
1286 if (!pim_ifp)
1287 continue;
219e0013 1288
ea4a71fc 1289 if (pim_upstream_evaluate_join_desired_interface (up, ch))
7a3ddda5 1290 {
781a1745
DS
1291 int flag = PIM_OIF_FLAG_PROTO_PIM;
1292
1293 if (ch->sg.src.s_addr == INADDR_ANY && ch->upstream != up)
1294 flag = PIM_OIF_FLAG_PROTO_STAR;
1295 pim_channel_add_oif (up->channel_oil, ch->interface, flag);
ea4a71fc 1296 output_intf++;
219e0013
DS
1297 }
1298 }
1299
b5183fd1
DS
1300 return output_intf;
1301}
1302
1303/*
1304 * For a given upstream, determine the inherited_olist
1305 * and apply it.
1306 *
1307 * inherited_olist(S,G,rpt) =
1308 * ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) )
1309 * (+) ( pim_include(*,G) (-) pim_exclude(S,G))
1310 * (-) ( lost_assert(*,G) (+) lost_assert(S,G,rpt) )
1311 *
1312 * inherited_olist(S,G) =
1313 * inherited_olist(S,G,rpt) (+)
1314 * joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
1315 *
1316 * return 1 if there are any output interfaces
1317 * return 0 if there are not any output interfaces
1318 */
1319int
1320pim_upstream_inherited_olist (struct pim_upstream *up)
1321{
1322 int output_intf = pim_upstream_inherited_olist_decide (up);
1323
483eef9d
DS
1324 /*
1325 * If we have output_intf switch state to Join and work like normal
1326 * If we don't have an output_intf that means we are probably a
1327 * switch on a stick so turn on forwarding to just accept the
1328 * incoming packets so we don't bother the other stuff!
1329 */
1330 if (output_intf)
1331 pim_upstream_switch (up, PIM_UPSTREAM_JOINED);
1332 else
1333 forward_on (up);
219e0013
DS
1334
1335 return output_intf;
4fdc8f36 1336}
d3dd1804 1337
80d9c3a0
DS
1338int
1339pim_upstream_empty_inherited_olist (struct pim_upstream *up)
1340{
ce0ddb4e 1341 return pim_channel_oil_empty (up->channel_oil);
80d9c3a0
DS
1342}
1343
d3dd1804
DS
1344/*
1345 * When we have a new neighbor,
1346 * find upstreams that don't have their rpf_addr
1347 * set and see if the new neighbor allows
1348 * the join to be sent
1349 */
1350void
1351pim_upstream_find_new_rpf (void)
1352{
1353 struct listnode *up_node;
1354 struct listnode *up_nextnode;
1355 struct pim_upstream *up;
1356
1357 /*
0f588989
DS
1358 * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
1359 */
1360 for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up))
d3dd1804 1361 {
63c59d0c 1362 if (pim_rpf_addr_is_inaddr_any(&up->rpf))
d3dd1804 1363 {
3197cb1e 1364 if (PIM_DEBUG_TRACE)
d3dd1804 1365 zlog_debug ("Upstream %s without a path to send join, checking",
8bfb8b67 1366 up->sg_str);
d3dd1804
DS
1367 pim_rpf_update (up, NULL);
1368 }
1369 }
1370}
0f588989 1371
0f588989
DS
1372static unsigned int
1373pim_upstream_hash_key (void *arg)
1374{
1375 struct pim_upstream *up = (struct pim_upstream *)arg;
1376
1377 return jhash_2words (up->sg.src.s_addr, up->sg.grp.s_addr, 0);
1378}
1379
1380void pim_upstream_terminate (void)
1381{
1382 if (pim_upstream_list)
693c9259 1383 list_delete (pim_upstream_list);
0f588989
DS
1384 pim_upstream_list = NULL;
1385
1386 if (pim_upstream_hash)
1387 hash_free (pim_upstream_hash);
693c9259 1388 pim_upstream_hash = NULL;
0f588989
DS
1389}
1390
1391static int
1392pim_upstream_equal (const void *arg1, const void *arg2)
1393{
1394 const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
1395 const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
1396
1397 if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr) &&
1398 (up1->sg.src.s_addr == up2->sg.src.s_addr))
1399 return 1;
1400
1401 return 0;
1402}
1403
1bf16443 1404/* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines
1405 * the cases where kat has to be restarted on rxing traffic -
1406 *
1407 * if( DirectlyConnected(S) == TRUE AND iif == RPF_interface(S) ) {
1408 * set KeepaliveTimer(S,G) to Keepalive_Period
1409 * # Note: a register state transition or UpstreamJPState(S,G)
1410 * # transition may happen as a result of restarting
1411 * # KeepaliveTimer, and must be dealt with here.
1412 * }
1413 * if( iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined AND
1414 * inherited_olist(S,G) != NULL ) {
1415 * set KeepaliveTimer(S,G) to Keepalive_Period
1416 * }
1417 */
1418static bool pim_upstream_kat_start_ok(struct pim_upstream *up)
1419{
1420 /* "iif == RPF_interface(S)" check has to be done by the kernel or hw
1421 * so we will skip that here */
1422 if (pim_if_connected_to_source(up->rpf.source_nexthop.interface,
1423 up->sg.src)) {
1424 return true;
1425 }
1426
1427 if ((up->join_state == PIM_UPSTREAM_JOINED) &&
1428 !pim_upstream_empty_inherited_olist(up)) {
1429 /* XXX: I have added this RP check just for 3.2 and it's a digression from
1430 * what rfc-4601 says. Till now we were only running KAT on FHR and RP and
1431 * there is some angst around making the change to run it all routers that
1432 * maintain the (S, G) state. This is tracked via CM-13601 and MUST be
1433 * removed to handle spt turn-arounds correctly in a 3-tier clos */
1434 if (I_am_RP (up->sg.grp))
1435 return true;
1436 }
1437
1438 return false;
1439}
1440
9c5e4d62
DS
1441/*
1442 * Code to check and see if we've received packets on a S,G mroute
1443 * and if so to set the SPT bit appropriately
1444 */
1445static void
1446pim_upstream_sg_running (void *arg)
1447{
1448 struct pim_upstream *up = (struct pim_upstream *)arg;
e43b8697
DS
1449
1450 // No packet can have arrived here if this is the case
1451 if (!up->channel_oil || !up->channel_oil->installed)
1452 {
1453 if (PIM_DEBUG_TRACE)
1454 zlog_debug ("%s: %s is not installed in mroute",
8bfb8b67 1455 __PRETTY_FUNCTION__, up->sg_str);
e43b8697
DS
1456 return;
1457 }
1458
bfdf4096
DS
1459 /*
1460 * This is a bit of a hack
1461 * We've noted that we should rescan but
1462 * we've missed the window for doing so in
1463 * pim_zebra.c for some reason. I am
1464 * only doing this at this point in time
1465 * to get us up and working for the moment
1466 */
1467 if (up->channel_oil->oil_inherited_rescan)
1468 {
1469 if (PIM_DEBUG_TRACE)
1470 zlog_debug ("%s: Handling unscanned inherited_olist for %s", __PRETTY_FUNCTION__, up->sg_str);
1471 pim_upstream_inherited_olist_decide (up);
1472 up->channel_oil->oil_inherited_rescan = 0;
1473 }
e43b8697
DS
1474 pim_mroute_update_counters (up->channel_oil);
1475
1476 // Have we seen packets?
1bf16443 1477 if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt) &&
e43b8697
DS
1478 (up->channel_oil->cc.lastused/100 > 30))
1479 {
1480 if (PIM_DEBUG_TRACE)
1481 {
eeedae06
DS
1482 zlog_debug ("%s: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)",
1483 __PRETTY_FUNCTION__, up->sg_str,
1484 up->channel_oil->cc.oldpktcnt,
1485 up->channel_oil->cc.pktcnt,
1486 up->channel_oil->cc.lastused/100);
e43b8697
DS
1487 }
1488 return;
1489 }
1490
1bf16443 1491 if (pim_upstream_kat_start_ok(up)) {
1492 /* Add a source reference to the stream if
1493 * one doesn't already exist */
1494 if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
1495 {
1496 if (PIM_DEBUG_TRACE)
8bfb8b67
DS
1497 zlog_debug ("source reference created on kat restart %s", up->sg_str);
1498
1bf16443 1499 pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM);
1500 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
1501 pim_upstream_fhr_kat_start(up);
1502 }
1503 pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
1504 }
1505
1506 if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE)
1507 {
1508 pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
1509 }
e43b8697 1510 return;
9c5e4d62
DS
1511}
1512
040d86ad
DS
1513void
1514pim_upstream_init (void)
0f588989 1515{
9c5e4d62
DS
1516 pim_upstream_sg_wheel = wheel_init (master, 31000, 100,
1517 pim_upstream_hash_key,
1518 pim_upstream_sg_running);
0f588989
DS
1519 pim_upstream_hash = hash_create_size (8192, pim_upstream_hash_key,
1520 pim_upstream_equal);
1521
1522 pim_upstream_list = list_new ();
1523 pim_upstream_list->del = (void (*)(void *)) pim_upstream_free;
03417ccd 1524 pim_upstream_list->cmp = pim_upstream_compare;
0f588989
DS
1525
1526}