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