3 * Copyright (C) 2016 Cumulus Networks, Inc.
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.
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.
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,
24 #include <lib/jhash.h>
26 #include <lib/prefix.h>
27 #include <lib/sockunion.h>
28 #include <lib/stream.h>
29 #include <lib/thread.h>
31 #include <lib/plist.h>
35 #include "pim_memory.h"
41 #include "pim_msdp_packet.h"
42 #include "pim_msdp_socket.h"
44 struct pim_msdp pim_msdp
, *msdp
= &pim_msdp
;
46 static void pim_msdp_peer_listen(struct pim_msdp_peer
*mp
);
47 static void pim_msdp_peer_cr_timer_setup(struct pim_msdp_peer
*mp
, bool start
);
48 static void pim_msdp_peer_ka_timer_setup(struct pim_msdp_peer
*mp
, bool start
);
49 static void pim_msdp_peer_hold_timer_setup(struct pim_msdp_peer
*mp
, bool start
);
50 static void pim_msdp_peer_free(struct pim_msdp_peer
*mp
);
51 static void pim_msdp_enable(void);
52 static void pim_msdp_sa_adv_timer_setup(bool start
);
53 static void pim_msdp_sa_deref(struct pim_msdp_sa
*sa
, enum pim_msdp_sa_flags flags
);
55 /************************ SA cache management ******************************/
57 pim_msdp_sa_key_dump(struct pim_msdp_sa
*sa
, char *buf
, int buf_size
, bool long_format
)
59 char rp_str
[INET_ADDRSTRLEN
];
61 if (long_format
&& (sa
->flags
& PIM_MSDP_SAF_PEER
)) {
62 pim_inet4_dump("<rp?>", sa
->rp
, rp_str
, sizeof(rp_str
));
63 snprintf(buf
, buf_size
, "MSDP SA %s rp %s",
64 pim_str_sg_dump(&sa
->sg
), rp_str
);
66 snprintf(buf
, buf_size
, "MSDP SA %s", pim_str_sg_dump(&sa
->sg
));
73 pim_msdp_sa_timer_expiry_log(struct pim_msdp_sa
*sa
, const char *timer_str
)
75 char key_str
[PIM_MSDP_SA_KEY_STRLEN
];
77 pim_msdp_sa_key_dump(sa
, key_str
, sizeof(key_str
), false);
78 zlog_debug("%s %s timer expired", key_str
, timer_str
);
81 /* RFC-3618:Sec-5.1 - global active source advertisement timer */
83 pim_msdp_sa_adv_timer_cb(struct thread
*t
)
85 msdp
->sa_adv_timer
= NULL
;
86 if (PIM_DEBUG_MSDP_INTERNAL
) {
87 zlog_debug("MSDP SA advertisment timer expired");
91 pim_msdp_sa_adv_timer_setup(true /* start */);
95 pim_msdp_sa_adv_timer_setup(bool start
)
97 THREAD_OFF(msdp
->sa_adv_timer
);
99 THREAD_TIMER_ON(msdp
->master
, msdp
->sa_adv_timer
,
100 pim_msdp_sa_adv_timer_cb
, NULL
, PIM_MSDP_SA_ADVERTISMENT_TIME
);
104 /* RFC-3618:Sec-5.3 - SA cache state timer */
106 pim_msdp_sa_state_timer_cb(struct thread
*t
)
108 struct pim_msdp_sa
*sa
;
111 sa
->sa_state_timer
= NULL
;
113 if (PIM_DEBUG_MSDP_EVENTS
) {
114 pim_msdp_sa_timer_expiry_log(sa
, "state");
117 pim_msdp_sa_deref(sa
, PIM_MSDP_SAF_PEER
);
121 pim_msdp_sa_state_timer_setup(struct pim_msdp_sa
*sa
, bool start
)
123 THREAD_OFF(sa
->sa_state_timer
);
125 THREAD_TIMER_ON(msdp
->master
, sa
->sa_state_timer
,
126 pim_msdp_sa_state_timer_cb
, sa
, PIM_MSDP_SA_HOLD_TIME
);
131 pim_msdp_sa_upstream_del(struct pim_msdp_sa
*sa
)
133 struct pim_upstream
*up
= sa
->up
;
139 /* XXX: we can't pull the plug on an active flow even if the SA entry is
140 * removed. so ideally we want to start the kat in parallel and let the
141 * entry age out; but running the kat has fatal consequences. need to
142 * check with Donald on the best way to go abt this */
143 if (PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up
->flags
)) {
144 PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(up
->flags
);
145 pim_upstream_del(up
, __PRETTY_FUNCTION__
);
148 if (PIM_DEBUG_MSDP_EVENTS
) {
149 char key_str
[PIM_MSDP_SA_KEY_STRLEN
];
150 pim_msdp_sa_key_dump(sa
, key_str
, sizeof(key_str
), true);
151 zlog_debug("%s de-referenced SPT", key_str
);
156 pim_msdp_sa_upstream_add_ok(struct pim_msdp_sa
*sa
, struct pim_upstream
*xg_up
)
158 if (sa
->flags
& PIM_MSDP_SAF_LOCAL
) {
159 /* if there is a local reference we should NEVER use it for setting up
160 * SPTs otherwise we will get stuck in a simple circular deadlock */
164 if (!(sa
->flags
& PIM_MSDP_SAF_PEER
)) {
165 /* SA should have been rxed from a peer */
168 /* check if we are RP */
169 if (!I_am_RP(sa
->sg
.grp
)) {
173 /* check if we have a (*, G) with a non-empty immediate OIL */
177 memset(&sg
, 0, sizeof(sg
));
180 xg_up
= pim_upstream_find(&sg
);
182 if (!xg_up
|| (xg_up
->join_state
!= PIM_UPSTREAM_JOINED
)) {
183 /* join desired will be true for such (*, G) entries so we will
184 * just look at join_state and let the PIM state machine do the rest of
192 /* Upstream add evaluation needs to happen everytime -
193 * 1. Peer reference is added or removed.
194 * 2. Local reference is added or removed.
195 * 3. The RP for a group changes.
196 * 4. joinDesired for the associated (*, G) changes
197 * 5. associated (*, G) is removed - this seems like a bit redundant
198 * (considering #4); but just in case an entry gets nuked without
199 * upstream state transition
202 pim_msdp_sa_upstream_update(struct pim_msdp_sa
*sa
,
203 struct pim_upstream
*xg_up
, const char *ctx
)
205 struct pim_upstream
*up
;
206 char key_str
[PIM_MSDP_SA_KEY_STRLEN
];
208 if (PIM_DEBUG_MSDP_EVENTS
|| PIM_DEBUG_MSDP_INTERNAL
) {
209 pim_msdp_sa_key_dump(sa
, key_str
, sizeof(key_str
), true);
212 if (PIM_DEBUG_MSDP_INTERNAL
) {
213 zlog_debug("%s upstream update on %s", key_str
, ctx
);
216 if (!pim_msdp_sa_upstream_add_ok(sa
, xg_up
)) {
217 pim_msdp_sa_upstream_del(sa
);
226 up
= pim_upstream_find(&sa
->sg
);
227 if (up
&& (PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up
->flags
))) {
228 /* somehow we lost track of the upstream ptr? best log it */
230 if (PIM_DEBUG_MSDP_EVENTS
) {
231 zlog_debug("%s SPT reference missing", key_str
);
236 /* RFC3618: "RP triggers a (S, G) join event towards the data source
237 * as if a JP message was rxed addressed to the RP itself." */
238 up
= pim_upstream_add(&sa
->sg
, NULL
/* iif */,
239 PIM_UPSTREAM_FLAG_MASK_SRC_MSDP
,
240 __PRETTY_FUNCTION__
);
244 /* update inherited oil */
245 pim_upstream_inherited_olist(up
);
246 /* should we also start the kat in parallel? we will need it when the
248 if (PIM_DEBUG_MSDP_EVENTS
) {
249 zlog_debug("%s referenced SPT", key_str
);
252 if (PIM_DEBUG_MSDP_EVENTS
) {
253 zlog_debug("%s SPT reference failed", key_str
);
258 /* release all mem associated with a sa */
260 pim_msdp_sa_free(struct pim_msdp_sa
*sa
)
262 XFREE(MTYPE_PIM_MSDP_SA
, sa
);
265 static struct pim_msdp_sa
*
266 pim_msdp_sa_new(struct prefix_sg
*sg
, struct in_addr rp
)
268 struct pim_msdp_sa
*sa
;
270 sa
= XCALLOC(MTYPE_PIM_MSDP_SA
, sizeof(*sa
));
272 zlog_err("%s: PIM XCALLOC(%zu) failure",
273 __PRETTY_FUNCTION__
, sizeof(*sa
));
279 sa
->uptime
= pim_time_monotonic_sec();
281 /* insert into misc tables for easy access */
282 sa
= hash_get(msdp
->sa_hash
, sa
, hash_alloc_intern
);
284 zlog_err("%s: PIM hash get failure", __PRETTY_FUNCTION__
);
285 pim_msdp_sa_free(sa
);
288 listnode_add_sort(msdp
->sa_list
, sa
);
290 if (PIM_DEBUG_MSDP_EVENTS
) {
291 char key_str
[PIM_MSDP_SA_KEY_STRLEN
];
293 pim_msdp_sa_key_dump(sa
, key_str
, sizeof(key_str
), true);
294 zlog_debug("%s created", key_str
);
300 static struct pim_msdp_sa
*
301 pim_msdp_sa_find(struct prefix_sg
*sg
)
303 struct pim_msdp_sa lookup
;
306 return hash_lookup(msdp
->sa_hash
, &lookup
);
309 static struct pim_msdp_sa
*
310 pim_msdp_sa_add(struct prefix_sg
*sg
, struct in_addr rp
)
312 struct pim_msdp_sa
*sa
;
314 sa
= pim_msdp_sa_find(sg
);
319 return pim_msdp_sa_new(sg
, rp
);
323 pim_msdp_sa_del(struct pim_msdp_sa
* sa
)
325 /* this is somewhat redundant - still want to be careful not to leave
326 * stale upstream references */
327 pim_msdp_sa_upstream_del(sa
);
330 pim_msdp_sa_state_timer_setup(sa
, false /* start */);
332 /* remove the entry from various tables */
333 listnode_delete(msdp
->sa_list
, sa
);
334 hash_release(msdp
->sa_hash
, sa
);
336 if (PIM_DEBUG_MSDP_EVENTS
) {
337 char key_str
[PIM_MSDP_SA_KEY_STRLEN
];
339 pim_msdp_sa_key_dump(sa
, key_str
, sizeof(key_str
), true /* long */);
340 zlog_debug("%s deleted", key_str
);
343 /* free up any associated memory */
344 pim_msdp_sa_free(sa
);
347 /* When a local active-source is removed there is no way to withdraw the
348 * source from peers. We will simply remove it from the SA cache so it will
349 * not be sent in supsequent SA updates. Peers will consequently timeout the
351 * Similarly a "peer-added" SA is never explicitly deleted. It is simply
352 * aged out overtime if not seen in the SA updates from the peers.
353 * XXX: should we provide a knob to drop entries learnt from a peer when the
356 pim_msdp_sa_deref(struct pim_msdp_sa
*sa
, enum pim_msdp_sa_flags flags
)
358 char key_str
[PIM_MSDP_SA_KEY_STRLEN
];
360 pim_msdp_sa_key_dump(sa
, key_str
, sizeof(key_str
), true);
362 if ((sa
->flags
&PIM_MSDP_SAF_LOCAL
)) {
363 if (flags
& PIM_MSDP_SAF_LOCAL
) {
364 zlog_debug("%s local reference removed", key_str
);
370 if ((sa
->flags
&PIM_MSDP_SAF_PEER
)) {
371 if (flags
& PIM_MSDP_SAF_PEER
) {
372 zlog_debug("%s peer reference removed", key_str
);
373 pim_msdp_sa_state_timer_setup(sa
, false /* start */);
378 pim_msdp_sa_upstream_update(sa
, NULL
/* xg_up */, "sa-deref");
379 if (!(sa
->flags
& PIM_MSDP_SAF_REF
)) {
385 pim_msdp_sa_ref(struct pim_msdp_peer
*mp
, struct prefix_sg
*sg
,
388 struct pim_msdp_sa
*sa
;
389 char key_str
[PIM_MSDP_SA_KEY_STRLEN
];
391 sa
= pim_msdp_sa_add(sg
, rp
);
396 if (PIM_DEBUG_MSDP_EVENTS
) {
397 pim_msdp_sa_key_dump(sa
, key_str
, sizeof(key_str
), true);
402 if (!(sa
->flags
& PIM_MSDP_SAF_PEER
)) {
403 sa
->flags
|= PIM_MSDP_SAF_PEER
;
404 if (PIM_DEBUG_MSDP_EVENTS
) {
405 zlog_debug("%s added by peer", key_str
);
409 /* start/re-start the state timer to prevent cache expiry */
410 pim_msdp_sa_state_timer_setup(sa
, true /* start */);
411 /* We re-evaluate SA "SPT-trigger" everytime we hear abt it from a
412 * peer. XXX: If this becomes too much of a periodic overhead we
413 * can make it event based */
414 pim_msdp_sa_upstream_update(sa
, NULL
/* xg_up */, "peer-ref");
416 if (!(sa
->flags
& PIM_MSDP_SAF_LOCAL
)) {
417 sa
->flags
|= PIM_MSDP_SAF_LOCAL
;
419 if (PIM_DEBUG_MSDP_EVENTS
) {
420 zlog_debug("%s added locally", key_str
);
422 /* send an immediate SA update to peers */
423 pim_msdp_pkt_sa_tx_one(sa
);
424 pim_msdp_sa_upstream_update(sa
, NULL
/* xg_up */, "local-ref");
426 sa
->flags
&= ~PIM_MSDP_SAF_STALE
;
431 pim_msdp_sa_local_add(struct prefix_sg
*sg
)
435 if (!(msdp
->flags
& PIM_MSDPF_ENABLE
)) {
436 /* if the feature is not enabled do nothing; we will collect all local
437 * sources whenever it is */
441 /* check if I am RP for this group. XXX: is this check really needed? */
442 if (!I_am_RP(sg
->grp
)) {
446 pim_msdp_sa_ref(NULL
/* mp */, sg
, rp
);
450 pim_msdp_sa_local_del(struct prefix_sg
*sg
)
452 struct pim_msdp_sa
*sa
;
454 if (!(msdp
->flags
& PIM_MSDPF_ENABLE
)) {
455 /* if the feature is not enabled do nothing; we will collect all local
456 * sources whenever it is */
460 sa
= pim_msdp_sa_find(sg
);
462 pim_msdp_sa_deref(sa
, PIM_MSDP_SAF_LOCAL
);
467 pim_msdp_sa_local_setup(void)
469 struct pim_upstream
*up
;
470 struct listnode
*up_node
;
472 for (ALL_LIST_ELEMENTS_RO(pim_upstream_list
, up_node
, up
)) {
473 if (PIM_UPSTREAM_FLAG_TEST_CREATED_BY_UPSTREAM(up
->flags
)) {
474 pim_msdp_sa_local_add(&up
->sg
);
479 /* whenever the RP changes we need to re-evaluate the "local" SA-cache */
480 /* XXX: needs to be tested */
482 pim_msdp_i_am_rp_changed(void)
484 struct listnode
*sanode
;
485 struct pim_msdp_sa
*sa
;
487 if (!(msdp
->flags
& PIM_MSDPF_ENABLE
)) {
488 /* if the feature is not enabled do nothing */
492 if (PIM_DEBUG_MSDP_INTERNAL
) {
493 zlog_debug("MSDP i_am_rp changed");
496 /* mark all local entries as stale */
497 for (ALL_LIST_ELEMENTS_RO(msdp
->sa_list
, sanode
, sa
)) {
498 if (sa
->flags
& PIM_MSDP_SAF_LOCAL
) {
499 sa
->flags
|= PIM_MSDP_SAF_STALE
;
503 /* re-setup local SA entries */
504 pim_msdp_sa_local_setup();
506 for (ALL_LIST_ELEMENTS_RO(msdp
->sa_list
, sanode
, sa
)) {
507 /* purge stale SA entries */
508 if (sa
->flags
& PIM_MSDP_SAF_STALE
) {
509 /* clear the stale flag; the entry may be kept even after
511 sa
->flags
&= ~PIM_MSDP_SAF_STALE
;
512 pim_msdp_sa_deref(sa
, PIM_MSDP_SAF_LOCAL
);
514 /* also check if we can still influence SPT */
515 pim_msdp_sa_upstream_update(sa
, NULL
/* xg_up */, "rp-change");
519 /* We track the join state of (*, G) entries. If G has sources in the SA-cache
520 * we need to setup or teardown SPT when the JoinDesired status changes for
523 pim_msdp_up_join_state_changed(struct pim_upstream
*xg_up
)
525 struct listnode
*sanode
;
526 struct pim_msdp_sa
*sa
;
528 if (PIM_DEBUG_MSDP_INTERNAL
) {
529 zlog_debug("MSDP join state changed for %s", pim_str_sg_dump(&xg_up
->sg
));
532 /* If this is not really an XG entry just move on */
533 if ((xg_up
->sg
.src
.s_addr
!= INADDR_ANY
) ||
534 (xg_up
->sg
.grp
.s_addr
== INADDR_ANY
)) {
538 /* XXX: Need to maintain SAs per-group to avoid all this unnecessary
540 for (ALL_LIST_ELEMENTS_RO(msdp
->sa_list
, sanode
, sa
)) {
541 if (sa
->sg
.grp
.s_addr
!= xg_up
->sg
.grp
.s_addr
) {
544 pim_msdp_sa_upstream_update(sa
, xg_up
, "up-jp-change");
548 /* XXX: Need to maintain SAs per-group to avoid all this unnecessary
551 pim_msdp_up_xg_del(struct prefix_sg
*sg
)
553 struct listnode
*sanode
;
554 struct pim_msdp_sa
*sa
;
556 if (PIM_DEBUG_MSDP_INTERNAL
) {
557 zlog_debug("MSDP %s del", pim_str_sg_dump(sg
));
560 /* If this is not really an XG entry just move on */
561 if ((sg
->src
.s_addr
!= INADDR_ANY
) ||
562 (sg
->grp
.s_addr
== INADDR_ANY
)) {
566 /* XXX: Need to maintain SAs per-group to avoid all this unnecessary
568 for (ALL_LIST_ELEMENTS_RO(msdp
->sa_list
, sanode
, sa
)) {
569 if (sa
->sg
.grp
.s_addr
!= sg
->grp
.s_addr
) {
572 pim_msdp_sa_upstream_update(sa
, NULL
/* xg */, "up-jp-change");
576 /* sa hash and peer list helpers */
578 pim_msdp_sa_hash_key_make(void *p
)
580 struct pim_msdp_sa
*sa
= p
;
582 return (jhash_2words(sa
->sg
.src
.s_addr
, sa
->sg
.grp
.s_addr
, 0));
586 pim_msdp_sa_hash_eq(const void *p1
, const void *p2
)
588 const struct pim_msdp_sa
*sa1
= p1
;
589 const struct pim_msdp_sa
*sa2
= p2
;
591 return ((sa1
->sg
.src
.s_addr
== sa2
->sg
.src
.s_addr
) &&
592 (sa1
->sg
.grp
.s_addr
== sa2
->sg
.grp
.s_addr
));
596 pim_msdp_sa_comp(const void *p1
, const void *p2
)
598 const struct pim_msdp_sa
*sa1
= p1
;
599 const struct pim_msdp_sa
*sa2
= p2
;
601 if (ntohl(sa1
->sg
.grp
.s_addr
) < ntohl(sa2
->sg
.grp
.s_addr
))
604 if (ntohl(sa1
->sg
.grp
.s_addr
) > ntohl(sa2
->sg
.grp
.s_addr
))
607 if (ntohl(sa1
->sg
.src
.s_addr
) < ntohl(sa2
->sg
.src
.s_addr
))
610 if (ntohl(sa1
->sg
.src
.s_addr
) > ntohl(sa2
->sg
.src
.s_addr
))
616 /* RFC-3618:Sec-10.1.3 - Peer-RPF forwarding */
617 /* XXX: this can use a bit of refining and extensions */
619 pim_msdp_peer_rpf_check(struct pim_msdp_peer
*mp
, struct in_addr rp
)
621 if (mp
->peer
.s_addr
== rp
.s_addr
) {
628 /************************ Peer session management **************************/
630 pim_msdp_state_dump(enum pim_msdp_peer_state state
, char *buf
, int buf_size
)
633 case PIM_MSDP_DISABLED
:
634 snprintf(buf
, buf_size
, "%s", "disabled");
636 case PIM_MSDP_INACTIVE
:
637 snprintf(buf
, buf_size
, "%s", "inactive");
639 case PIM_MSDP_LISTEN
:
640 snprintf(buf
, buf_size
, "%s", "listen");
642 case PIM_MSDP_CONNECTING
:
643 snprintf(buf
, buf_size
, "%s", "connecting");
645 case PIM_MSDP_ESTABLISHED
:
646 snprintf(buf
, buf_size
, "%s", "established");
649 snprintf(buf
, buf_size
, "unk-%d", state
);
655 pim_msdp_peer_key_dump(struct pim_msdp_peer
*mp
, char *buf
, int buf_size
, bool long_format
)
657 char peer_str
[INET_ADDRSTRLEN
];
658 char local_str
[INET_ADDRSTRLEN
];
660 pim_inet4_dump("<peer?>", mp
->peer
, peer_str
, sizeof(peer_str
));
662 pim_inet4_dump("<local?>", mp
->local
, local_str
, sizeof(local_str
));
663 snprintf(buf
, buf_size
, "MSDP peer %s local %s mg %s",
664 peer_str
, local_str
, mp
->mesh_group_name
);
666 snprintf(buf
, buf_size
, "MSDP peer %s", peer_str
);
673 pim_msdp_peer_state_chg_log(struct pim_msdp_peer
*mp
)
675 char state_str
[PIM_MSDP_STATE_STRLEN
];
676 char key_str
[PIM_MSDP_PEER_KEY_STRLEN
];
678 pim_msdp_state_dump(mp
->state
, state_str
, sizeof(state_str
));
679 pim_msdp_peer_key_dump(mp
, key_str
, sizeof(key_str
), false);
680 zlog_debug("%s state chg to %s", key_str
, state_str
);
683 /* MSDP Connection State Machine actions (defined in RFC-3618:Sec-11.2) */
684 /* 11.2.A2: active peer - start connect retry timer; when the timer fires
685 * a tcp connection will be made */
687 pim_msdp_peer_connect(struct pim_msdp_peer
*mp
)
689 mp
->state
= PIM_MSDP_CONNECTING
;
690 if (PIM_DEBUG_MSDP_EVENTS
) {
691 pim_msdp_peer_state_chg_log(mp
);
694 pim_msdp_peer_cr_timer_setup(mp
, true /* start */);
697 /* 11.2.A3: passive peer - just listen for connections */
699 pim_msdp_peer_listen(struct pim_msdp_peer
*mp
)
701 mp
->state
= PIM_MSDP_LISTEN
;
702 if (PIM_DEBUG_MSDP_EVENTS
) {
703 pim_msdp_peer_state_chg_log(mp
);
706 /* this is interntionally asymmetric i.e. we set up listen-socket when the
707 * first listening peer is configured; but don't bother tearing it down when
708 * all the peers go down */
709 pim_msdp_sock_listen();
712 /* 11.2.A4 and 11.2.A5: transition active or passive peer to
713 * established state */
715 pim_msdp_peer_established(struct pim_msdp_peer
*mp
)
717 mp
->state
= PIM_MSDP_ESTABLISHED
;
718 mp
->uptime
= pim_time_monotonic_sec();
720 if (PIM_DEBUG_MSDP_EVENTS
) {
721 pim_msdp_peer_state_chg_log(mp
);
724 /* stop retry timer on active peers */
725 pim_msdp_peer_cr_timer_setup(mp
, false /* start */);
727 /* send KA; start KA and hold timers */
728 pim_msdp_pkt_ka_tx(mp
);
729 pim_msdp_peer_ka_timer_setup(mp
, true /* start */);
730 pim_msdp_peer_hold_timer_setup(mp
, true /* start */);
732 pim_msdp_pkt_sa_tx_to_one_peer(mp
);
734 PIM_MSDP_PEER_WRITE_ON(mp
);
735 PIM_MSDP_PEER_READ_ON(mp
);
738 /* 11.2.A6, 11.2.A7 and 11.2.A8: shutdown the peer tcp connection */
740 pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer
*mp
, bool chg_state
)
743 mp
->state
= PIM_MSDP_INACTIVE
;
744 if (PIM_DEBUG_MSDP_EVENTS
) {
745 pim_msdp_peer_state_chg_log(mp
);
749 if (PIM_DEBUG_MSDP_INTERNAL
) {
750 char key_str
[PIM_MSDP_PEER_KEY_STRLEN
];
752 pim_msdp_peer_key_dump(mp
, key_str
, sizeof(key_str
), false);
753 zlog_debug("%s pim_msdp_peer_stop_tcp_conn", key_str
);
755 /* stop read and write threads */
756 PIM_MSDP_PEER_READ_OFF(mp
);
757 PIM_MSDP_PEER_WRITE_OFF(mp
);
761 stream_reset(mp
->ibuf
);
763 stream_fifo_clean(mp
->obuf
);
765 /* stop all peer timers */
766 pim_msdp_peer_ka_timer_setup(mp
, false /* start */);
767 pim_msdp_peer_cr_timer_setup(mp
, false /* start */);
768 pim_msdp_peer_hold_timer_setup(mp
, false /* start */);
770 /* close connection */
777 /* RFC-3618:Sec-5.6 - stop the peer tcp connection and startover */
779 pim_msdp_peer_reset_tcp_conn(struct pim_msdp_peer
*mp
, const char *rc_str
)
781 if (PIM_DEBUG_EVENTS
) {
782 char key_str
[PIM_MSDP_PEER_KEY_STRLEN
];
784 pim_msdp_peer_key_dump(mp
, key_str
, sizeof(key_str
), false);
785 zlog_debug("%s tcp reset %s", key_str
, rc_str
);
788 /* close the connection and transition to listening or connecting */
789 pim_msdp_peer_stop_tcp_conn(mp
, true /* chg_state */);
790 if (PIM_MSDP_PEER_IS_LISTENER(mp
)) {
791 pim_msdp_peer_listen(mp
);
793 pim_msdp_peer_connect(mp
);
798 pim_msdp_peer_timer_expiry_log(struct pim_msdp_peer
*mp
, const char *timer_str
)
800 char key_str
[PIM_MSDP_PEER_KEY_STRLEN
];
802 pim_msdp_peer_key_dump(mp
, key_str
, sizeof(key_str
), false);
803 zlog_debug("%s %s timer expired", key_str
, timer_str
);
806 /* RFC-3618:Sec-5.4 - peer hold timer */
808 pim_msdp_peer_hold_timer_cb(struct thread
*t
)
810 struct pim_msdp_peer
*mp
;
813 mp
->hold_timer
= NULL
;
815 if (PIM_DEBUG_MSDP_EVENTS
) {
816 pim_msdp_peer_timer_expiry_log(mp
, "hold");
819 if (mp
->state
!= PIM_MSDP_ESTABLISHED
) {
823 if (PIM_DEBUG_MSDP_EVENTS
) {
824 pim_msdp_peer_state_chg_log(mp
);
826 pim_msdp_peer_reset_tcp_conn(mp
, "ht-expired");
830 pim_msdp_peer_hold_timer_setup(struct pim_msdp_peer
*mp
, bool start
)
832 THREAD_OFF(mp
->hold_timer
);
834 THREAD_TIMER_ON(msdp
->master
, mp
->hold_timer
,
835 pim_msdp_peer_hold_timer_cb
, mp
, PIM_MSDP_PEER_HOLD_TIME
);
840 /* RFC-3618:Sec-5.5 - peer keepalive timer */
842 pim_msdp_peer_ka_timer_cb(struct thread
*t
)
844 struct pim_msdp_peer
*mp
;
849 if (PIM_DEBUG_MSDP_EVENTS
) {
850 pim_msdp_peer_timer_expiry_log(mp
, "ka");
853 pim_msdp_pkt_ka_tx(mp
);
854 pim_msdp_peer_ka_timer_setup(mp
, true /* start */);
858 pim_msdp_peer_ka_timer_setup(struct pim_msdp_peer
*mp
, bool start
)
860 THREAD_OFF(mp
->ka_timer
);
862 THREAD_TIMER_ON(msdp
->master
, mp
->ka_timer
,
863 pim_msdp_peer_ka_timer_cb
, mp
, PIM_MSDP_PEER_KA_TIME
);
868 pim_msdp_peer_active_connect(struct pim_msdp_peer
*mp
)
871 rc
= pim_msdp_sock_connect(mp
);
873 if (PIM_DEBUG_MSDP_INTERNAL
) {
874 char key_str
[PIM_MSDP_PEER_KEY_STRLEN
];
876 pim_msdp_peer_key_dump(mp
, key_str
, sizeof(key_str
), false);
877 zlog_debug("%s pim_msdp_peer_active_connect: %d", key_str
, rc
);
882 /* connect failed restart the connect-retry timer */
883 pim_msdp_peer_cr_timer_setup(mp
, true /* start */);
886 case connect_success
:
887 /* connect was sucessful move to established */
888 pim_msdp_peer_established(mp
);
891 case connect_in_progress
:
892 /* for NB content we need to wait till sock is readable or
894 PIM_MSDP_PEER_WRITE_ON(mp
);
895 PIM_MSDP_PEER_READ_ON(mp
);
896 /* also restart connect-retry timer to reset the socket if connect is
898 pim_msdp_peer_cr_timer_setup(mp
, true /* start */);
903 /* RFC-3618:Sec-5.6 - connection retry on active peer */
905 pim_msdp_peer_cr_timer_cb(struct thread
*t
)
907 struct pim_msdp_peer
*mp
;
912 if (PIM_DEBUG_MSDP_EVENTS
) {
913 pim_msdp_peer_timer_expiry_log(mp
, "connect-retry");
916 if (mp
->state
!= PIM_MSDP_CONNECTING
|| PIM_MSDP_PEER_IS_LISTENER(mp
)) {
920 pim_msdp_peer_active_connect(mp
);
924 pim_msdp_peer_cr_timer_setup(struct pim_msdp_peer
*mp
, bool start
)
926 THREAD_OFF(mp
->cr_timer
);
928 THREAD_TIMER_ON(msdp
->master
, mp
->cr_timer
,
929 pim_msdp_peer_cr_timer_cb
, mp
, PIM_MSDP_PEER_CONNECT_RETRY_TIME
);
933 /* if a valid packet is rxed from the peer we can restart hold timer */
935 pim_msdp_peer_pkt_rxed(struct pim_msdp_peer
*mp
)
937 if (mp
->state
== PIM_MSDP_ESTABLISHED
) {
938 pim_msdp_peer_hold_timer_setup(mp
, true /* start */);
942 /* if a valid packet is txed to the peer we can restart ka timer and avoid
943 * unnecessary ka noise in the network */
945 pim_msdp_peer_pkt_txed(struct pim_msdp_peer
*mp
)
947 if (mp
->state
== PIM_MSDP_ESTABLISHED
) {
948 pim_msdp_peer_ka_timer_setup(mp
, true /* start */);
952 static void pim_msdp_addr2su(union sockunion
*su
, struct in_addr addr
)
955 su
->sin
.sin_addr
= addr
;
956 su
->sin
.sin_family
= AF_INET
;
957 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
958 su
->sin
.sin_len
= sizeof(struct sockaddr_in
);
959 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
962 /* 11.2.A1: create a new peer and transition state to listen or connecting */
963 static enum pim_msdp_err
964 pim_msdp_peer_new(struct in_addr peer_addr
, struct in_addr local_addr
,
965 const char *mesh_group_name
)
967 struct pim_msdp_peer
*mp
;
971 mp
= XCALLOC(MTYPE_PIM_MSDP_PEER
, sizeof(*mp
));
973 zlog_err("%s: PIM XCALLOC(%zu) failure",
974 __PRETTY_FUNCTION__
, sizeof(*mp
));
975 return PIM_MSDP_ERR_OOM
;
978 mp
->peer
= peer_addr
;
979 pim_msdp_addr2su(&mp
->su_peer
, mp
->peer
);
980 mp
->local
= local_addr
;
981 /* XXX: originator_id setting needs to move to the mesh group */
982 msdp
->originator_id
= local_addr
;
983 pim_msdp_addr2su(&mp
->su_local
, mp
->local
);
984 mp
->mesh_group_name
= XSTRDUP(MTYPE_PIM_MSDP_PEER_MG_NAME
, mesh_group_name
);
985 mp
->state
= PIM_MSDP_INACTIVE
;
987 /* higher IP address is listener */
988 if (ntohl(mp
->local
.s_addr
) > ntohl(mp
->peer
.s_addr
)) {
989 mp
->flags
|= PIM_MSDP_PEERF_LISTENER
;
992 /* setup packet buffers */
993 mp
->ibuf
= stream_new(PIM_MSDP_MAX_PACKET_SIZE
);
994 mp
->obuf
= stream_fifo_new();
996 /* insert into misc tables for easy access */
997 mp
= hash_get(msdp
->peer_hash
, mp
, hash_alloc_intern
);
999 zlog_err("%s: PIM hash get failure", __PRETTY_FUNCTION__
);
1000 pim_msdp_peer_free(mp
);
1001 return PIM_MSDP_ERR_OOM
;
1003 listnode_add_sort(msdp
->peer_list
, mp
);
1005 if (PIM_DEBUG_MSDP_EVENTS
) {
1006 char key_str
[PIM_MSDP_PEER_KEY_STRLEN
];
1008 pim_msdp_peer_key_dump(mp
, key_str
, sizeof(key_str
), true);
1009 zlog_debug("%s created", key_str
);
1011 pim_msdp_peer_state_chg_log(mp
);
1014 /* fireup the connect state machine */
1015 if (PIM_MSDP_PEER_IS_LISTENER(mp
)) {
1016 pim_msdp_peer_listen(mp
);
1018 pim_msdp_peer_connect(mp
);
1020 return PIM_MSDP_ERR_NONE
;
1023 struct pim_msdp_peer
*
1024 pim_msdp_peer_find(struct in_addr peer_addr
)
1026 struct pim_msdp_peer lookup
;
1028 lookup
.peer
= peer_addr
;
1029 return hash_lookup(msdp
->peer_hash
, &lookup
);
1032 /* add peer configuration if it doesn't already exist */
1034 pim_msdp_peer_add(struct in_addr peer_addr
, struct in_addr local_addr
,
1035 const char *mesh_group_name
)
1037 struct pim_msdp_peer
*mp
;
1039 mp
= pim_msdp_peer_find(peer_addr
);
1041 return PIM_MSDP_ERR_PEER_EXISTS
;
1044 return pim_msdp_peer_new(peer_addr
, local_addr
, mesh_group_name
);
1047 /* release all mem associated with a peer */
1049 pim_msdp_peer_free(struct pim_msdp_peer
*mp
)
1052 stream_free(mp
->ibuf
);
1056 stream_fifo_free(mp
->obuf
);
1059 if (mp
->mesh_group_name
) {
1060 XFREE(MTYPE_PIM_MSDP_PEER_MG_NAME
, mp
->mesh_group_name
);
1062 XFREE(MTYPE_PIM_MSDP_PEER
, mp
);
1065 /* delete the peer config */
1067 pim_msdp_peer_del(struct in_addr peer_addr
)
1069 struct pim_msdp_peer
*mp
;
1071 mp
= pim_msdp_peer_find(peer_addr
);
1073 return PIM_MSDP_ERR_NO_PEER
;
1076 /* stop the tcp connection and shutdown all timers */
1077 pim_msdp_peer_stop_tcp_conn(mp
, true /* chg_state */);
1079 /* remove the session from various tables */
1080 listnode_delete(msdp
->peer_list
, mp
);
1081 hash_release(msdp
->peer_hash
, mp
);
1083 if (PIM_DEBUG_MSDP_EVENTS
) {
1084 char key_str
[PIM_MSDP_PEER_KEY_STRLEN
];
1086 pim_msdp_peer_key_dump(mp
, key_str
, sizeof(key_str
), true);
1087 zlog_debug("%s deleted", key_str
);
1090 /* free up any associated memory */
1091 pim_msdp_peer_free(mp
);
1093 return PIM_MSDP_ERR_NONE
;
1096 /* peer hash and peer list helpers */
1098 pim_msdp_peer_hash_key_make(void *p
)
1100 struct pim_msdp_peer
*mp
= p
;
1101 return (jhash_1word(mp
->peer
.s_addr
, 0));
1105 pim_msdp_peer_hash_eq(const void *p1
, const void *p2
)
1107 const struct pim_msdp_peer
*mp1
= p1
;
1108 const struct pim_msdp_peer
*mp2
= p2
;
1110 return (mp1
->peer
.s_addr
== mp2
->peer
.s_addr
);
1114 pim_msdp_peer_comp(const void *p1
, const void *p2
)
1116 const struct pim_msdp_peer
*mp1
= p1
;
1117 const struct pim_msdp_peer
*mp2
= p2
;
1119 if (ntohl(mp1
->peer
.s_addr
) < ntohl(mp2
->peer
.s_addr
))
1122 if (ntohl(mp1
->peer
.s_addr
) > ntohl(mp2
->peer
.s_addr
))
1128 /*********************** MSDP feature APIs *********************************/
1130 pim_msdp_config_write(struct vty
*vty
)
1132 struct listnode
*mpnode
;
1133 struct pim_msdp_peer
*mp
;
1134 char peer_str
[INET_ADDRSTRLEN
];
1135 char local_str
[INET_ADDRSTRLEN
];
1138 for (ALL_LIST_ELEMENTS_RO(msdp
->peer_list
, mpnode
, mp
)) {
1139 pim_inet4_dump("<peer?>", mp
->peer
, peer_str
, sizeof(peer_str
));
1140 pim_inet4_dump("<local?>", mp
->local
, local_str
, sizeof(local_str
));
1141 vty_out(vty
, "ip msdp peer %s source %s%s",
1142 peer_str
, local_str
, VTY_NEWLINE
);
1148 /* Enable feature including active/periodic timers etc. on the first peer
1149 * config. Till then MSDP should just stay quiet. */
1151 pim_msdp_enable(void)
1153 if (msdp
->flags
& PIM_MSDPF_ENABLE
) {
1154 /* feature is already enabled */
1157 msdp
->flags
|= PIM_MSDPF_ENABLE
;
1158 msdp
->work_obuf
= stream_new(PIM_MSDP_MAX_PACKET_SIZE
);
1159 pim_msdp_sa_adv_timer_setup(true /* start */);
1160 /* setup sa cache based on local sources */
1161 pim_msdp_sa_local_setup();
1166 pim_msdp_init(struct thread_master
*master
)
1168 /* XXX: temporarily enable noisy logs; will be disabled once dev is
1170 PIM_DO_DEBUG_MSDP_INTERNAL
;
1172 msdp
->master
= master
;
1174 msdp
->peer_hash
= hash_create(pim_msdp_peer_hash_key_make
,
1175 pim_msdp_peer_hash_eq
);
1176 msdp
->peer_list
= list_new();
1177 msdp
->peer_list
->del
= (void (*)(void *))pim_msdp_peer_free
;
1178 msdp
->peer_list
->cmp
= (int (*)(void *, void *))pim_msdp_peer_comp
;
1180 msdp
->sa_hash
= hash_create(pim_msdp_sa_hash_key_make
,
1181 pim_msdp_sa_hash_eq
);
1182 msdp
->sa_list
= list_new();
1183 msdp
->sa_list
->del
= (void (*)(void *))pim_msdp_sa_free
;
1184 msdp
->sa_list
->cmp
= (int (*)(void *, void *))pim_msdp_sa_comp
;
1187 /* counterpart to MSDP init; XXX: unused currently */
1191 /* XXX: stop listener and delete all peer sessions */
1193 if (msdp
->peer_hash
) {
1194 hash_free(msdp
->peer_hash
);
1195 msdp
->peer_hash
= NULL
;
1198 if (msdp
->peer_list
) {
1199 list_free(msdp
->peer_list
);
1200 msdp
->peer_list
= NULL
;