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"
36 #include "pim_iface.h"
40 #include "pim_upstream.h"
43 #include "pim_msdp_packet.h"
44 #include "pim_msdp_socket.h"
46 struct pim_msdp pim_msdp
, *msdp
= &pim_msdp
;
48 static void pim_msdp_peer_listen(struct pim_msdp_peer
*mp
);
49 static void pim_msdp_peer_cr_timer_setup(struct pim_msdp_peer
*mp
, bool start
);
50 static void pim_msdp_peer_ka_timer_setup(struct pim_msdp_peer
*mp
, bool start
);
51 static void pim_msdp_peer_hold_timer_setup(struct pim_msdp_peer
*mp
, bool start
);
52 static void pim_msdp_peer_free(struct pim_msdp_peer
*mp
);
53 static void pim_msdp_enable(void);
54 static void pim_msdp_sa_adv_timer_setup(bool start
);
55 static void pim_msdp_sa_deref(struct pim_msdp_sa
*sa
, enum pim_msdp_sa_flags flags
);
56 static int pim_msdp_mg_mbr_comp(const void *p1
, const void *p2
);
57 static void pim_msdp_mg_mbr_free(struct pim_msdp_mg_mbr
*mbr
);
58 static void pim_msdp_mg_mbr_do_del(struct pim_msdp_mg
*mg
, struct pim_msdp_mg_mbr
*mbr
);
60 /************************ SA cache management ******************************/
62 pim_msdp_sa_timer_expiry_log(struct pim_msdp_sa
*sa
, const char *timer_str
)
64 zlog_debug("MSDP SA %s %s timer expired", sa
->sg_str
, timer_str
);
67 /* RFC-3618:Sec-5.1 - global active source advertisement timer */
69 pim_msdp_sa_adv_timer_cb(struct thread
*t
)
71 msdp
->sa_adv_timer
= NULL
;
72 if (PIM_DEBUG_MSDP_EVENTS
) {
73 zlog_debug("MSDP SA advertisment timer expired");
77 pim_msdp_sa_adv_timer_setup(true /* start */);
81 pim_msdp_sa_adv_timer_setup(bool start
)
83 THREAD_OFF(msdp
->sa_adv_timer
);
85 THREAD_TIMER_ON(msdp
->master
, msdp
->sa_adv_timer
,
86 pim_msdp_sa_adv_timer_cb
, NULL
, PIM_MSDP_SA_ADVERTISMENT_TIME
);
90 /* RFC-3618:Sec-5.3 - SA cache state timer */
92 pim_msdp_sa_state_timer_cb(struct thread
*t
)
94 struct pim_msdp_sa
*sa
;
97 sa
->sa_state_timer
= NULL
;
99 if (PIM_DEBUG_MSDP_EVENTS
) {
100 pim_msdp_sa_timer_expiry_log(sa
, "state");
103 pim_msdp_sa_deref(sa
, PIM_MSDP_SAF_PEER
);
107 pim_msdp_sa_state_timer_setup(struct pim_msdp_sa
*sa
, bool start
)
109 THREAD_OFF(sa
->sa_state_timer
);
111 THREAD_TIMER_ON(msdp
->master
, sa
->sa_state_timer
,
112 pim_msdp_sa_state_timer_cb
, sa
, PIM_MSDP_SA_HOLD_TIME
);
117 pim_msdp_sa_upstream_del(struct pim_msdp_sa
*sa
)
119 struct pim_upstream
*up
= sa
->up
;
125 if (PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up
->flags
)) {
126 PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(up
->flags
);
127 pim_upstream_del(up
, __PRETTY_FUNCTION__
);
130 if (PIM_DEBUG_MSDP_EVENTS
) {
131 zlog_debug("MSDP SA %s de-referenced SPT", sa
->sg_str
);
136 pim_msdp_sa_upstream_add_ok(struct pim_msdp_sa
*sa
, struct pim_upstream
*xg_up
)
138 if (!(sa
->flags
& PIM_MSDP_SAF_PEER
)) {
139 /* SA should have been rxed from a peer */
142 /* check if we are RP */
143 if (!I_am_RP(sa
->sg
.grp
)) {
147 /* check if we have a (*, G) with a non-empty immediate OIL */
151 memset(&sg
, 0, sizeof(sg
));
154 xg_up
= pim_upstream_find(&sg
);
156 if (!xg_up
|| (xg_up
->join_state
!= PIM_UPSTREAM_JOINED
)) {
157 /* join desired will be true for such (*, G) entries so we will
158 * just look at join_state and let the PIM state machine do the rest of
166 /* Upstream add evaluation needs to happen everytime -
167 * 1. Peer reference is added or removed.
168 * 2. The RP for a group changes.
169 * 3. joinDesired for the associated (*, G) changes
170 * 4. associated (*, G) is removed - this seems like a bit redundant
171 * (considering #4); but just in case an entry gets nuked without
172 * upstream state transition
175 pim_msdp_sa_upstream_update(struct pim_msdp_sa
*sa
,
176 struct pim_upstream
*xg_up
, const char *ctx
)
178 struct pim_upstream
*up
;
180 if (!pim_msdp_sa_upstream_add_ok(sa
, xg_up
)) {
181 pim_msdp_sa_upstream_del(sa
);
190 up
= pim_upstream_find(&sa
->sg
);
191 if (up
&& (PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up
->flags
))) {
192 /* somehow we lost track of the upstream ptr? best log it */
194 if (PIM_DEBUG_MSDP_EVENTS
) {
195 zlog_debug("MSDP SA %s SPT reference missing", sa
->sg_str
);
200 /* RFC3618: "RP triggers a (S, G) join event towards the data source
201 * as if a JP message was rxed addressed to the RP itself." */
202 up
= pim_upstream_add(&sa
->sg
, NULL
/* iif */,
203 PIM_UPSTREAM_FLAG_MASK_SRC_MSDP
,
204 __PRETTY_FUNCTION__
);
208 /* update inherited oil */
209 pim_upstream_inherited_olist(up
);
210 /* should we also start the kat in parallel? we will need it when the
212 if (PIM_DEBUG_MSDP_EVENTS
) {
213 zlog_debug("MSDP SA %s referenced SPT", sa
->sg_str
);
216 if (PIM_DEBUG_MSDP_EVENTS
) {
217 zlog_debug("MSDP SA %s SPT reference failed", sa
->sg_str
);
222 /* release all mem associated with a sa */
224 pim_msdp_sa_free(struct pim_msdp_sa
*sa
)
226 XFREE(MTYPE_PIM_MSDP_SA
, sa
);
229 static struct pim_msdp_sa
*
230 pim_msdp_sa_new(struct prefix_sg
*sg
, struct in_addr rp
)
232 struct pim_msdp_sa
*sa
;
234 sa
= XCALLOC(MTYPE_PIM_MSDP_SA
, sizeof(*sa
));
236 zlog_err("%s: PIM XCALLOC(%zu) failure",
237 __PRETTY_FUNCTION__
, sizeof(*sa
));
242 pim_str_sg_set(sg
, sa
->sg_str
);
244 sa
->uptime
= pim_time_monotonic_sec();
246 /* insert into misc tables for easy access */
247 sa
= hash_get(msdp
->sa_hash
, sa
, hash_alloc_intern
);
249 zlog_err("%s: PIM hash get failure", __PRETTY_FUNCTION__
);
250 pim_msdp_sa_free(sa
);
253 listnode_add_sort(msdp
->sa_list
, sa
);
255 if (PIM_DEBUG_MSDP_EVENTS
) {
256 zlog_debug("MSDP SA %s created", sa
->sg_str
);
262 static struct pim_msdp_sa
*
263 pim_msdp_sa_find(struct prefix_sg
*sg
)
265 struct pim_msdp_sa lookup
;
268 return hash_lookup(msdp
->sa_hash
, &lookup
);
271 static struct pim_msdp_sa
*
272 pim_msdp_sa_add(struct prefix_sg
*sg
, struct in_addr rp
)
274 struct pim_msdp_sa
*sa
;
276 sa
= pim_msdp_sa_find(sg
);
281 return pim_msdp_sa_new(sg
, rp
);
285 pim_msdp_sa_del(struct pim_msdp_sa
* sa
)
287 /* this is somewhat redundant - still want to be careful not to leave
288 * stale upstream references */
289 pim_msdp_sa_upstream_del(sa
);
292 pim_msdp_sa_state_timer_setup(sa
, false /* start */);
294 /* remove the entry from various tables */
295 listnode_delete(msdp
->sa_list
, sa
);
296 hash_release(msdp
->sa_hash
, sa
);
298 if (PIM_DEBUG_MSDP_EVENTS
) {
299 zlog_debug("MSDP SA %s deleted", sa
->sg_str
);
302 /* free up any associated memory */
303 pim_msdp_sa_free(sa
);
307 pim_msdp_sa_peer_ip_set(struct pim_msdp_sa
*sa
, struct pim_msdp_peer
*mp
, struct in_addr rp
)
309 struct pim_msdp_peer
*old_mp
;
311 /* optimize the "no change" case as it will happen
312 * frequently/periodically */
313 if (mp
&& (sa
->peer
.s_addr
== mp
->peer
.s_addr
)) {
317 /* any time the peer ip changes also update the rp address */
318 if (PIM_INADDR_ISNOT_ANY(sa
->peer
)) {
319 old_mp
= pim_msdp_peer_find(sa
->peer
);
320 if (old_mp
&& old_mp
->sa_cnt
) {
329 sa
->peer
.s_addr
= PIM_NET_INADDR_ANY
;
334 /* When a local active-source is removed there is no way to withdraw the
335 * source from peers. We will simply remove it from the SA cache so it will
336 * not be sent in supsequent SA updates. Peers will consequently timeout the
338 * Similarly a "peer-added" SA is never explicitly deleted. It is simply
339 * aged out overtime if not seen in the SA updates from the peers.
340 * XXX: should we provide a knob to drop entries learnt from a peer when the
343 pim_msdp_sa_deref(struct pim_msdp_sa
*sa
, enum pim_msdp_sa_flags flags
)
345 bool update_up
= false;
347 if ((sa
->flags
&PIM_MSDP_SAF_LOCAL
)) {
348 if (flags
& PIM_MSDP_SAF_LOCAL
) {
349 if (PIM_DEBUG_MSDP_EVENTS
) {
350 zlog_debug("MSDP SA %s local reference removed", sa
->sg_str
);
357 if ((sa
->flags
&PIM_MSDP_SAF_PEER
)) {
358 if (flags
& PIM_MSDP_SAF_PEER
) {
361 if (PIM_DEBUG_MSDP_EVENTS
) {
362 zlog_debug("MSDP SA %s peer reference removed", sa
->sg_str
);
364 pim_msdp_sa_state_timer_setup(sa
, false /* start */);
365 rp
.s_addr
= INADDR_ANY
;
366 pim_msdp_sa_peer_ip_set(sa
, NULL
/* mp */, rp
);
367 /* if peer ref was removed we need to remove the msdp reference on the
375 pim_msdp_sa_upstream_update(sa
, NULL
/* xg_up */, "sa-deref");
378 if (!(sa
->flags
& PIM_MSDP_SAF_REF
)) {
384 pim_msdp_sa_ref(struct pim_msdp_peer
*mp
, struct prefix_sg
*sg
,
387 struct pim_msdp_sa
*sa
;
389 sa
= pim_msdp_sa_add(sg
, rp
);
396 if (!(sa
->flags
& PIM_MSDP_SAF_PEER
)) {
397 sa
->flags
|= PIM_MSDP_SAF_PEER
;
398 if (PIM_DEBUG_MSDP_EVENTS
) {
399 zlog_debug("MSDP SA %s added by peer", sa
->sg_str
);
402 pim_msdp_sa_peer_ip_set(sa
, mp
, rp
);
403 /* start/re-start the state timer to prevent cache expiry */
404 pim_msdp_sa_state_timer_setup(sa
, true /* start */);
405 /* We re-evaluate SA "SPT-trigger" everytime we hear abt it from a
406 * peer. XXX: If this becomes too much of a periodic overhead we
407 * can make it event based */
408 pim_msdp_sa_upstream_update(sa
, NULL
/* xg_up */, "peer-ref");
410 if (!(sa
->flags
& PIM_MSDP_SAF_LOCAL
)) {
411 sa
->flags
|= PIM_MSDP_SAF_LOCAL
;
413 if (PIM_DEBUG_MSDP_EVENTS
) {
414 zlog_debug("MSDP SA %s added locally", sa
->sg_str
);
416 /* send an immediate SA update to peers */
417 pim_msdp_pkt_sa_tx_one(sa
);
419 sa
->flags
&= ~PIM_MSDP_SAF_STALE
;
423 /* The following criteria must be met to originate an SA from the MSDP
425 * 1. KAT must be running i.e. source is active.
426 * 2. We must be RP for the group.
427 * 3. Source must be registrable to the RP (this is where the RFC is vague
428 * and especially ambiguous in CLOS networks; with anycast RP all sources
429 * are potentially registrable to all RPs in the domain). We assume #3 is
431 * a. We are also the FHR-DR for the source (OR)
432 * b. We rxed a pim register (null or data encapsulated) within the last
433 * (3 * (1.5 * register_suppression_timer))).
436 pim_msdp_sa_local_add_ok(struct pim_upstream
*up
)
438 if (!(msdp
->flags
& PIM_MSDPF_ENABLE
)) {
442 if (!up
->t_ka_timer
) {
443 /* stream is not active */
447 if (!I_am_RP(up
->sg
.grp
)) {
448 /* we are not RP for the group */
452 /* we are the FHR-DR for this stream or we are RP and have seen registers
453 * from a FHR for this source */
454 if (PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) || up
->t_msdp_reg_timer
) {
462 pim_msdp_sa_local_add(struct prefix_sg
*sg
)
466 pim_msdp_sa_ref(NULL
/* mp */, sg
, rp
);
470 pim_msdp_sa_local_del(struct prefix_sg
*sg
)
472 struct pim_msdp_sa
*sa
;
474 sa
= pim_msdp_sa_find(sg
);
476 pim_msdp_sa_deref(sa
, PIM_MSDP_SAF_LOCAL
);
480 /* Local SA qualification needs to be re-evaluated when -
481 * 1. KAT is started or stopped
483 * 3. Whenever FHR status changes for a (S,G) - XXX - currently there
484 * is no clear path to transition an entry out of "MASK_FHR" need
485 * to discuss this with Donald. May result in some strangeness if the
486 * FHR is also the RP.
487 * 4. When msdp_reg timer is started or stopped
490 pim_msdp_sa_local_update(struct pim_upstream
*up
)
492 if (pim_msdp_sa_local_add_ok(up
)) {
493 pim_msdp_sa_local_add(&up
->sg
);
495 pim_msdp_sa_local_del(&up
->sg
);
500 pim_msdp_sa_local_setup(void)
502 struct pim_upstream
*up
;
503 struct listnode
*up_node
;
505 for (ALL_LIST_ELEMENTS_RO(pim_upstream_list
, up_node
, up
)) {
506 pim_msdp_sa_local_update(up
);
510 /* whenever the RP changes we need to re-evaluate the "local" SA-cache */
511 /* XXX: needs to be tested */
513 pim_msdp_i_am_rp_changed(void)
515 struct listnode
*sanode
;
516 struct listnode
*nextnode
;
517 struct pim_msdp_sa
*sa
;
519 if (!(msdp
->flags
& PIM_MSDPF_ENABLE
)) {
520 /* if the feature is not enabled do nothing */
524 if (PIM_DEBUG_MSDP_INTERNAL
) {
525 zlog_debug("MSDP i_am_rp changed");
528 /* mark all local entries as stale */
529 for (ALL_LIST_ELEMENTS_RO(msdp
->sa_list
, sanode
, sa
)) {
530 if (sa
->flags
& PIM_MSDP_SAF_LOCAL
) {
531 sa
->flags
|= PIM_MSDP_SAF_STALE
;
535 /* re-setup local SA entries */
536 pim_msdp_sa_local_setup();
538 for (ALL_LIST_ELEMENTS(msdp
->sa_list
, sanode
, nextnode
, sa
)) {
539 /* purge stale SA entries */
540 if (sa
->flags
& PIM_MSDP_SAF_STALE
) {
541 /* clear the stale flag; the entry may be kept even after
543 sa
->flags
&= ~PIM_MSDP_SAF_STALE
;
544 /* sa_deref can end up freeing the sa; so don't access contents after */
545 pim_msdp_sa_deref(sa
, PIM_MSDP_SAF_LOCAL
);
547 /* if the souce is still active check if we can influence SPT */
548 pim_msdp_sa_upstream_update(sa
, NULL
/* xg_up */, "rp-change");
553 /* We track the join state of (*, G) entries. If G has sources in the SA-cache
554 * we need to setup or teardown SPT when the JoinDesired status changes for
557 pim_msdp_up_join_state_changed(struct pim_upstream
*xg_up
)
559 struct listnode
*sanode
;
560 struct pim_msdp_sa
*sa
;
562 if (PIM_DEBUG_MSDP_INTERNAL
) {
563 zlog_debug("MSDP join state changed for %s", xg_up
->sg_str
);
566 /* If this is not really an XG entry just move on */
567 if ((xg_up
->sg
.src
.s_addr
!= INADDR_ANY
) ||
568 (xg_up
->sg
.grp
.s_addr
== INADDR_ANY
)) {
572 /* XXX: Need to maintain SAs per-group to avoid all this unnecessary
574 for (ALL_LIST_ELEMENTS_RO(msdp
->sa_list
, sanode
, sa
)) {
575 if (sa
->sg
.grp
.s_addr
!= xg_up
->sg
.grp
.s_addr
) {
578 pim_msdp_sa_upstream_update(sa
, xg_up
, "up-jp-change");
583 pim_msdp_up_xg_del(struct prefix_sg
*sg
)
585 struct listnode
*sanode
;
586 struct pim_msdp_sa
*sa
;
588 if (PIM_DEBUG_MSDP_INTERNAL
) {
589 zlog_debug("MSDP %s del", pim_str_sg_dump(sg
));
592 /* If this is not really an XG entry just move on */
593 if ((sg
->src
.s_addr
!= INADDR_ANY
) ||
594 (sg
->grp
.s_addr
== INADDR_ANY
)) {
598 /* XXX: Need to maintain SAs per-group to avoid all this unnecessary
600 for (ALL_LIST_ELEMENTS_RO(msdp
->sa_list
, sanode
, sa
)) {
601 if (sa
->sg
.grp
.s_addr
!= sg
->grp
.s_addr
) {
604 pim_msdp_sa_upstream_update(sa
, NULL
/* xg */, "up-jp-change");
608 /* sa hash and peer list helpers */
610 pim_msdp_sa_hash_key_make(void *p
)
612 struct pim_msdp_sa
*sa
= p
;
614 return (jhash_2words(sa
->sg
.src
.s_addr
, sa
->sg
.grp
.s_addr
, 0));
618 pim_msdp_sa_hash_eq(const void *p1
, const void *p2
)
620 const struct pim_msdp_sa
*sa1
= p1
;
621 const struct pim_msdp_sa
*sa2
= p2
;
623 return ((sa1
->sg
.src
.s_addr
== sa2
->sg
.src
.s_addr
) &&
624 (sa1
->sg
.grp
.s_addr
== sa2
->sg
.grp
.s_addr
));
628 pim_msdp_sa_comp(const void *p1
, const void *p2
)
630 const struct pim_msdp_sa
*sa1
= p1
;
631 const struct pim_msdp_sa
*sa2
= p2
;
633 if (ntohl(sa1
->sg
.grp
.s_addr
) < ntohl(sa2
->sg
.grp
.s_addr
))
636 if (ntohl(sa1
->sg
.grp
.s_addr
) > ntohl(sa2
->sg
.grp
.s_addr
))
639 if (ntohl(sa1
->sg
.src
.s_addr
) < ntohl(sa2
->sg
.src
.s_addr
))
642 if (ntohl(sa1
->sg
.src
.s_addr
) > ntohl(sa2
->sg
.src
.s_addr
))
648 /* RFC-3618:Sec-10.1.3 - Peer-RPF forwarding */
649 /* XXX: this can use a bit of refining and extensions */
651 pim_msdp_peer_rpf_check(struct pim_msdp_peer
*mp
, struct in_addr rp
)
653 if (mp
->peer
.s_addr
== rp
.s_addr
) {
660 /************************ Peer session management **************************/
662 pim_msdp_state_dump(enum pim_msdp_peer_state state
, char *buf
, int buf_size
)
665 case PIM_MSDP_DISABLED
:
666 snprintf(buf
, buf_size
, "%s", "disabled");
668 case PIM_MSDP_INACTIVE
:
669 snprintf(buf
, buf_size
, "%s", "inactive");
671 case PIM_MSDP_LISTEN
:
672 snprintf(buf
, buf_size
, "%s", "listen");
674 case PIM_MSDP_CONNECTING
:
675 snprintf(buf
, buf_size
, "%s", "connecting");
677 case PIM_MSDP_ESTABLISHED
:
678 snprintf(buf
, buf_size
, "%s", "established");
681 snprintf(buf
, buf_size
, "unk-%d", state
);
687 pim_msdp_peer_key_dump(struct pim_msdp_peer
*mp
, char *buf
, int buf_size
, bool long_format
)
689 char peer_str
[INET_ADDRSTRLEN
];
690 char local_str
[INET_ADDRSTRLEN
];
692 pim_inet4_dump("<peer?>", mp
->peer
, peer_str
, sizeof(peer_str
));
694 pim_inet4_dump("<local?>", mp
->local
, local_str
, sizeof(local_str
));
695 snprintf(buf
, buf_size
, "MSDP peer %s local %s mg %s",
696 peer_str
, local_str
, mp
->mesh_group_name
);
698 snprintf(buf
, buf_size
, "MSDP peer %s", peer_str
);
705 pim_msdp_peer_state_chg_log(struct pim_msdp_peer
*mp
)
707 char state_str
[PIM_MSDP_STATE_STRLEN
];
709 pim_msdp_state_dump(mp
->state
, state_str
, sizeof(state_str
));
710 zlog_debug("MSDP peer %s state chg to %s", mp
->key_str
, state_str
);
713 /* MSDP Connection State Machine actions (defined in RFC-3618:Sec-11.2) */
714 /* 11.2.A2: active peer - start connect retry timer; when the timer fires
715 * a tcp connection will be made */
717 pim_msdp_peer_connect(struct pim_msdp_peer
*mp
)
719 mp
->state
= PIM_MSDP_CONNECTING
;
720 if (PIM_DEBUG_MSDP_EVENTS
) {
721 pim_msdp_peer_state_chg_log(mp
);
724 pim_msdp_peer_cr_timer_setup(mp
, true /* start */);
727 /* 11.2.A3: passive peer - just listen for connections */
729 pim_msdp_peer_listen(struct pim_msdp_peer
*mp
)
731 mp
->state
= PIM_MSDP_LISTEN
;
732 if (PIM_DEBUG_MSDP_EVENTS
) {
733 pim_msdp_peer_state_chg_log(mp
);
736 /* this is interntionally asymmetric i.e. we set up listen-socket when the
737 * first listening peer is configured; but don't bother tearing it down when
738 * all the peers go down */
739 pim_msdp_sock_listen();
742 /* 11.2.A4 and 11.2.A5: transition active or passive peer to
743 * established state */
745 pim_msdp_peer_established(struct pim_msdp_peer
*mp
)
747 if (mp
->state
!= PIM_MSDP_ESTABLISHED
) {
751 mp
->state
= PIM_MSDP_ESTABLISHED
;
752 mp
->uptime
= pim_time_monotonic_sec();
754 if (PIM_DEBUG_MSDP_EVENTS
) {
755 pim_msdp_peer_state_chg_log(mp
);
758 /* stop retry timer on active peers */
759 pim_msdp_peer_cr_timer_setup(mp
, false /* start */);
761 /* send KA; start KA and hold timers */
762 pim_msdp_pkt_ka_tx(mp
);
763 pim_msdp_peer_ka_timer_setup(mp
, true /* start */);
764 pim_msdp_peer_hold_timer_setup(mp
, true /* start */);
766 pim_msdp_pkt_sa_tx_to_one_peer(mp
);
768 PIM_MSDP_PEER_WRITE_ON(mp
);
769 PIM_MSDP_PEER_READ_ON(mp
);
772 /* 11.2.A6, 11.2.A7 and 11.2.A8: shutdown the peer tcp connection */
774 pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer
*mp
, bool chg_state
)
777 if (mp
->state
== PIM_MSDP_ESTABLISHED
) {
780 mp
->state
= PIM_MSDP_INACTIVE
;
781 if (PIM_DEBUG_MSDP_EVENTS
) {
782 pim_msdp_peer_state_chg_log(mp
);
786 if (PIM_DEBUG_MSDP_INTERNAL
) {
787 zlog_debug("MSDP peer %s pim_msdp_peer_stop_tcp_conn", mp
->key_str
);
789 /* stop read and write threads */
790 PIM_MSDP_PEER_READ_OFF(mp
);
791 PIM_MSDP_PEER_WRITE_OFF(mp
);
795 stream_reset(mp
->ibuf
);
797 stream_fifo_clean(mp
->obuf
);
799 /* stop all peer timers */
800 pim_msdp_peer_ka_timer_setup(mp
, false /* start */);
801 pim_msdp_peer_cr_timer_setup(mp
, false /* start */);
802 pim_msdp_peer_hold_timer_setup(mp
, false /* start */);
804 /* close connection */
811 /* RFC-3618:Sec-5.6 - stop the peer tcp connection and startover */
813 pim_msdp_peer_reset_tcp_conn(struct pim_msdp_peer
*mp
, const char *rc_str
)
815 if (PIM_DEBUG_EVENTS
) {
816 zlog_debug("MSDP peer %s tcp reset %s", mp
->key_str
, rc_str
);
817 snprintf(mp
->last_reset
, sizeof(mp
->last_reset
), "%s", rc_str
);
820 /* close the connection and transition to listening or connecting */
821 pim_msdp_peer_stop_tcp_conn(mp
, true /* chg_state */);
822 if (PIM_MSDP_PEER_IS_LISTENER(mp
)) {
823 pim_msdp_peer_listen(mp
);
825 pim_msdp_peer_connect(mp
);
830 pim_msdp_peer_timer_expiry_log(struct pim_msdp_peer
*mp
, const char *timer_str
)
832 zlog_debug("MSDP peer %s %s timer expired", mp
->key_str
, timer_str
);
835 /* RFC-3618:Sec-5.4 - peer hold timer */
837 pim_msdp_peer_hold_timer_cb(struct thread
*t
)
839 struct pim_msdp_peer
*mp
;
842 mp
->hold_timer
= NULL
;
844 if (PIM_DEBUG_MSDP_EVENTS
) {
845 pim_msdp_peer_timer_expiry_log(mp
, "hold");
848 if (mp
->state
!= PIM_MSDP_ESTABLISHED
) {
852 if (PIM_DEBUG_MSDP_EVENTS
) {
853 pim_msdp_peer_state_chg_log(mp
);
855 pim_msdp_peer_reset_tcp_conn(mp
, "ht-expired");
859 pim_msdp_peer_hold_timer_setup(struct pim_msdp_peer
*mp
, bool start
)
861 THREAD_OFF(mp
->hold_timer
);
863 THREAD_TIMER_ON(msdp
->master
, mp
->hold_timer
,
864 pim_msdp_peer_hold_timer_cb
, mp
, PIM_MSDP_PEER_HOLD_TIME
);
869 /* RFC-3618:Sec-5.5 - peer keepalive timer */
871 pim_msdp_peer_ka_timer_cb(struct thread
*t
)
873 struct pim_msdp_peer
*mp
;
878 if (PIM_DEBUG_MSDP_EVENTS
) {
879 pim_msdp_peer_timer_expiry_log(mp
, "ka");
882 pim_msdp_pkt_ka_tx(mp
);
883 pim_msdp_peer_ka_timer_setup(mp
, true /* start */);
887 pim_msdp_peer_ka_timer_setup(struct pim_msdp_peer
*mp
, bool start
)
889 THREAD_OFF(mp
->ka_timer
);
891 THREAD_TIMER_ON(msdp
->master
, mp
->ka_timer
,
892 pim_msdp_peer_ka_timer_cb
, mp
, PIM_MSDP_PEER_KA_TIME
);
897 pim_msdp_peer_active_connect(struct pim_msdp_peer
*mp
)
901 rc
= pim_msdp_sock_connect(mp
);
903 if (PIM_DEBUG_MSDP_INTERNAL
) {
904 zlog_debug("MSDP peer %s pim_msdp_peer_active_connect: %d", mp
->key_str
, rc
);
910 /* connect failed restart the connect-retry timer */
911 pim_msdp_peer_cr_timer_setup(mp
, true /* start */);
914 case connect_success
:
915 /* connect was sucessful move to established */
916 pim_msdp_peer_established(mp
);
919 case connect_in_progress
:
920 /* for NB content we need to wait till sock is readable or
922 PIM_MSDP_PEER_WRITE_ON(mp
);
923 PIM_MSDP_PEER_READ_ON(mp
);
924 /* also restart connect-retry timer to reset the socket if connect is
926 pim_msdp_peer_cr_timer_setup(mp
, true /* start */);
931 /* RFC-3618:Sec-5.6 - connection retry on active peer */
933 pim_msdp_peer_cr_timer_cb(struct thread
*t
)
935 struct pim_msdp_peer
*mp
;
940 if (PIM_DEBUG_MSDP_EVENTS
) {
941 pim_msdp_peer_timer_expiry_log(mp
, "connect-retry");
944 if (mp
->state
!= PIM_MSDP_CONNECTING
|| PIM_MSDP_PEER_IS_LISTENER(mp
)) {
948 pim_msdp_peer_active_connect(mp
);
952 pim_msdp_peer_cr_timer_setup(struct pim_msdp_peer
*mp
, bool start
)
954 THREAD_OFF(mp
->cr_timer
);
956 THREAD_TIMER_ON(msdp
->master
, mp
->cr_timer
,
957 pim_msdp_peer_cr_timer_cb
, mp
, PIM_MSDP_PEER_CONNECT_RETRY_TIME
);
961 /* if a valid packet is rxed from the peer we can restart hold timer */
963 pim_msdp_peer_pkt_rxed(struct pim_msdp_peer
*mp
)
965 if (mp
->state
== PIM_MSDP_ESTABLISHED
) {
966 pim_msdp_peer_hold_timer_setup(mp
, true /* start */);
970 /* if a valid packet is txed to the peer we can restart ka timer and avoid
971 * unnecessary ka noise in the network */
973 pim_msdp_peer_pkt_txed(struct pim_msdp_peer
*mp
)
975 if (mp
->state
== PIM_MSDP_ESTABLISHED
) {
976 pim_msdp_peer_ka_timer_setup(mp
, true /* start */);
980 static void pim_msdp_addr2su(union sockunion
*su
, struct in_addr addr
)
983 su
->sin
.sin_addr
= addr
;
984 su
->sin
.sin_family
= AF_INET
;
985 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
986 su
->sin
.sin_len
= sizeof(struct sockaddr_in
);
987 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
990 /* 11.2.A1: create a new peer and transition state to listen or connecting */
991 static enum pim_msdp_err
992 pim_msdp_peer_new(struct in_addr peer_addr
, struct in_addr local_addr
,
993 const char *mesh_group_name
, struct pim_msdp_peer
**mp_p
)
995 struct pim_msdp_peer
*mp
;
999 mp
= XCALLOC(MTYPE_PIM_MSDP_PEER
, sizeof(*mp
));
1001 zlog_err("%s: PIM XCALLOC(%zu) failure",
1002 __PRETTY_FUNCTION__
, sizeof(*mp
));
1003 return PIM_MSDP_ERR_OOM
;
1006 mp
->peer
= peer_addr
;
1007 pim_inet4_dump("<peer?>", mp
->peer
, mp
->key_str
, sizeof(mp
->key_str
));
1008 pim_msdp_addr2su(&mp
->su_peer
, mp
->peer
);
1009 mp
->local
= local_addr
;
1010 /* XXX: originator_id setting needs to move to the mesh group */
1011 msdp
->originator_id
= local_addr
;
1012 pim_msdp_addr2su(&mp
->su_local
, mp
->local
);
1013 mp
->mesh_group_name
= XSTRDUP(MTYPE_PIM_MSDP_MG_NAME
, mesh_group_name
);
1014 mp
->state
= PIM_MSDP_INACTIVE
;
1016 strcpy(mp
->last_reset
, "-");
1017 /* higher IP address is listener */
1018 if (ntohl(mp
->local
.s_addr
) > ntohl(mp
->peer
.s_addr
)) {
1019 mp
->flags
|= PIM_MSDP_PEERF_LISTENER
;
1022 /* setup packet buffers */
1023 mp
->ibuf
= stream_new(PIM_MSDP_MAX_PACKET_SIZE
);
1024 mp
->obuf
= stream_fifo_new();
1026 /* insert into misc tables for easy access */
1027 mp
= hash_get(msdp
->peer_hash
, mp
, hash_alloc_intern
);
1028 listnode_add_sort(msdp
->peer_list
, mp
);
1030 if (PIM_DEBUG_MSDP_EVENTS
) {
1031 zlog_debug("MSDP peer %s created", mp
->key_str
);
1033 pim_msdp_peer_state_chg_log(mp
);
1036 /* fireup the connect state machine */
1037 if (PIM_MSDP_PEER_IS_LISTENER(mp
)) {
1038 pim_msdp_peer_listen(mp
);
1040 pim_msdp_peer_connect(mp
);
1045 return PIM_MSDP_ERR_NONE
;
1048 struct pim_msdp_peer
*
1049 pim_msdp_peer_find(struct in_addr peer_addr
)
1051 struct pim_msdp_peer lookup
;
1053 lookup
.peer
= peer_addr
;
1054 return hash_lookup(msdp
->peer_hash
, &lookup
);
1057 /* add peer configuration if it doesn't already exist */
1059 pim_msdp_peer_add(struct in_addr peer_addr
, struct in_addr local_addr
,
1060 const char *mesh_group_name
, struct pim_msdp_peer
**mp_p
)
1062 struct pim_msdp_peer
*mp
;
1068 if (peer_addr
.s_addr
== local_addr
.s_addr
) {
1069 /* skip session setup if config is invalid */
1070 if (PIM_DEBUG_MSDP_EVENTS
) {
1071 char peer_str
[INET_ADDRSTRLEN
];
1073 pim_inet4_dump("<peer?>", peer_addr
, peer_str
, sizeof(peer_str
));
1074 zlog_debug("%s add skipped as DIP=SIP", peer_str
);
1076 return PIM_MSDP_ERR_SIP_EQ_DIP
;
1079 mp
= pim_msdp_peer_find(peer_addr
);
1084 return PIM_MSDP_ERR_PEER_EXISTS
;
1087 return pim_msdp_peer_new(peer_addr
, local_addr
, mesh_group_name
, mp_p
);
1090 /* release all mem associated with a peer */
1092 pim_msdp_peer_free(struct pim_msdp_peer
*mp
)
1095 stream_free(mp
->ibuf
);
1099 stream_fifo_free(mp
->obuf
);
1102 if (mp
->mesh_group_name
) {
1103 XFREE(MTYPE_PIM_MSDP_MG_NAME
, mp
->mesh_group_name
);
1105 XFREE(MTYPE_PIM_MSDP_PEER
, mp
);
1108 /* delete the peer config */
1109 static enum pim_msdp_err
1110 pim_msdp_peer_do_del(struct pim_msdp_peer
*mp
)
1112 /* stop the tcp connection and shutdown all timers */
1113 pim_msdp_peer_stop_tcp_conn(mp
, true /* chg_state */);
1115 /* remove the session from various tables */
1116 listnode_delete(msdp
->peer_list
, mp
);
1117 hash_release(msdp
->peer_hash
, mp
);
1119 if (PIM_DEBUG_MSDP_EVENTS
) {
1120 zlog_debug("MSDP peer %s deleted", mp
->key_str
);
1123 /* free up any associated memory */
1124 pim_msdp_peer_free(mp
);
1126 return PIM_MSDP_ERR_NONE
;
1130 pim_msdp_peer_del(struct in_addr peer_addr
)
1132 struct pim_msdp_peer
*mp
;
1134 mp
= pim_msdp_peer_find(peer_addr
);
1136 return PIM_MSDP_ERR_NO_PEER
;
1139 return pim_msdp_peer_do_del(mp
);
1142 /* peer hash and peer list helpers */
1144 pim_msdp_peer_hash_key_make(void *p
)
1146 struct pim_msdp_peer
*mp
= p
;
1147 return (jhash_1word(mp
->peer
.s_addr
, 0));
1151 pim_msdp_peer_hash_eq(const void *p1
, const void *p2
)
1153 const struct pim_msdp_peer
*mp1
= p1
;
1154 const struct pim_msdp_peer
*mp2
= p2
;
1156 return (mp1
->peer
.s_addr
== mp2
->peer
.s_addr
);
1160 pim_msdp_peer_comp(const void *p1
, const void *p2
)
1162 const struct pim_msdp_peer
*mp1
= p1
;
1163 const struct pim_msdp_peer
*mp2
= p2
;
1165 if (ntohl(mp1
->peer
.s_addr
) < ntohl(mp2
->peer
.s_addr
))
1168 if (ntohl(mp1
->peer
.s_addr
) > ntohl(mp2
->peer
.s_addr
))
1174 /************************** Mesh group management **************************/
1176 pim_msdp_mg_free(struct pim_msdp_mg
*mg
)
1178 /* If the mesh-group has valid member or src_ip don't delete it */
1179 if (!mg
|| mg
->mbr_cnt
|| (mg
->src_ip
.s_addr
!= INADDR_ANY
)) {
1183 if (PIM_DEBUG_MSDP_EVENTS
) {
1184 zlog_debug("MSDP mesh-group %s deleted", mg
->mesh_group_name
);
1186 if (mg
->mesh_group_name
)
1187 XFREE(MTYPE_PIM_MSDP_MG_NAME
, mg
->mesh_group_name
);
1190 list_free(mg
->mbr_list
);
1192 XFREE(MTYPE_PIM_MSDP_MG
, mg
);
1196 static struct pim_msdp_mg
*
1197 pim_msdp_mg_new(const char *mesh_group_name
)
1199 struct pim_msdp_mg
*mg
;
1201 mg
= XCALLOC(MTYPE_PIM_MSDP_MG
, sizeof(*mg
));
1203 zlog_err("%s: PIM XCALLOC(%zu) failure",
1204 __PRETTY_FUNCTION__
, sizeof(*mg
));
1208 mg
->mesh_group_name
= XSTRDUP(MTYPE_PIM_MSDP_MG_NAME
, mesh_group_name
);
1209 mg
->mbr_list
= list_new();
1210 mg
->mbr_list
->del
= (void (*)(void *))pim_msdp_mg_mbr_free
;
1211 mg
->mbr_list
->cmp
= (int (*)(void *, void *))pim_msdp_mg_mbr_comp
;
1213 if (PIM_DEBUG_MSDP_EVENTS
) {
1214 zlog_debug("MSDP mesh-group %s created", mg
->mesh_group_name
);
1220 pim_msdp_mg_del(const char *mesh_group_name
)
1222 struct pim_msdp_mg
*mg
= msdp
->mg
;
1223 struct pim_msdp_mg_mbr
*mbr
;
1225 if (!mg
|| strcmp(mg
->mesh_group_name
, mesh_group_name
)) {
1226 return PIM_MSDP_ERR_NO_MG
;
1229 /* delete all the mesh-group members */
1230 while (!list_isempty(mg
->mbr_list
)) {
1231 mbr
= listnode_head(mg
->mbr_list
);
1232 pim_msdp_mg_mbr_do_del(mg
, mbr
);
1236 mg
->src_ip
.s_addr
= INADDR_ANY
;
1238 /* free up the mesh-group */
1239 pim_msdp_mg_free(mg
);
1240 return PIM_MSDP_ERR_NONE
;
1243 static enum pim_msdp_err
1244 pim_msdp_mg_add(const char *mesh_group_name
)
1247 if (!strcmp(msdp
->mg
->mesh_group_name
, mesh_group_name
)) {
1248 return PIM_MSDP_ERR_NONE
;
1250 /* currently only one mesh-group can exist at a time */
1251 return PIM_MSDP_ERR_MAX_MESH_GROUPS
;
1254 msdp
->mg
= pim_msdp_mg_new(mesh_group_name
);
1256 return PIM_MSDP_ERR_OOM
;
1259 return PIM_MSDP_ERR_NONE
;
1263 pim_msdp_mg_mbr_comp(const void *p1
, const void *p2
)
1265 const struct pim_msdp_mg_mbr
*mbr1
= p1
;
1266 const struct pim_msdp_mg_mbr
*mbr2
= p2
;
1268 if (ntohl(mbr1
->mbr_ip
.s_addr
) < ntohl(mbr2
->mbr_ip
.s_addr
))
1271 if (ntohl(mbr1
->mbr_ip
.s_addr
) > ntohl(mbr2
->mbr_ip
.s_addr
))
1278 pim_msdp_mg_mbr_free(struct pim_msdp_mg_mbr
*mbr
)
1280 XFREE(MTYPE_PIM_MSDP_MG_MBR
, mbr
);
1283 static struct pim_msdp_mg_mbr
*
1284 pim_msdp_mg_mbr_find(struct in_addr mbr_ip
)
1286 struct pim_msdp_mg_mbr
*mbr
;
1287 struct listnode
*mbr_node
;
1292 /* we can move this to a hash but considering that number of peers in
1293 * a mesh-group that seems like bit of an overkill */
1294 for (ALL_LIST_ELEMENTS_RO(msdp
->mg
->mbr_list
, mbr_node
, mbr
)) {
1295 if (mbr
->mbr_ip
.s_addr
== mbr_ip
.s_addr
) {
1303 pim_msdp_mg_mbr_add(const char *mesh_group_name
, struct in_addr mbr_ip
)
1306 struct pim_msdp_mg_mbr
*mbr
;
1307 struct pim_msdp_mg
*mg
;
1309 rc
= pim_msdp_mg_add(mesh_group_name
);
1310 if (rc
!= PIM_MSDP_ERR_NONE
) {
1315 mbr
= pim_msdp_mg_mbr_find(mbr_ip
);
1317 return PIM_MSDP_ERR_MG_MBR_EXISTS
;
1320 mbr
= XCALLOC(MTYPE_PIM_MSDP_MG_MBR
, sizeof(*mbr
));
1322 zlog_err("%s: PIM XCALLOC(%zu) failure",
1323 __PRETTY_FUNCTION__
, sizeof(*mbr
));
1324 /* if there are no references to the mg free it */
1325 pim_msdp_mg_free(mg
);
1326 return PIM_MSDP_ERR_OOM
;
1328 mbr
->mbr_ip
= mbr_ip
;
1329 listnode_add_sort(mg
->mbr_list
, mbr
);
1331 /* if valid SIP has been configured add peer session */
1332 if (mg
->src_ip
.s_addr
!= INADDR_ANY
) {
1333 pim_msdp_peer_add(mbr_ip
, mg
->src_ip
, mesh_group_name
,
1337 if (PIM_DEBUG_MSDP_EVENTS
) {
1338 char ip_str
[INET_ADDRSTRLEN
];
1339 pim_inet4_dump("<mbr?>", mbr
->mbr_ip
, ip_str
, sizeof(ip_str
));
1340 zlog_debug("MSDP mesh-group %s mbr %s created", mg
->mesh_group_name
, ip_str
);
1343 return PIM_MSDP_ERR_NONE
;
1347 pim_msdp_mg_mbr_do_del(struct pim_msdp_mg
*mg
, struct pim_msdp_mg_mbr
*mbr
)
1349 /* Delete active peer session if any */
1351 pim_msdp_peer_do_del(mbr
->mp
);
1354 listnode_delete(mg
->mbr_list
, mbr
);
1355 if (PIM_DEBUG_MSDP_EVENTS
) {
1356 char ip_str
[INET_ADDRSTRLEN
];
1357 pim_inet4_dump("<mbr?>", mbr
->mbr_ip
, ip_str
, sizeof(ip_str
));
1358 zlog_debug("MSDP mesh-group %s mbr %s deleted", mg
->mesh_group_name
, ip_str
);
1360 pim_msdp_mg_mbr_free(mbr
);
1367 pim_msdp_mg_mbr_del(const char *mesh_group_name
, struct in_addr mbr_ip
)
1369 struct pim_msdp_mg_mbr
*mbr
;
1370 struct pim_msdp_mg
*mg
= msdp
->mg
;
1372 if (!mg
|| strcmp(mg
->mesh_group_name
, mesh_group_name
)) {
1373 return PIM_MSDP_ERR_NO_MG
;
1376 mbr
= pim_msdp_mg_mbr_find(mbr_ip
);
1378 return PIM_MSDP_ERR_NO_MG_MBR
;
1381 pim_msdp_mg_mbr_do_del(mg
, mbr
);
1382 /* if there are no references to the mg free it */
1383 pim_msdp_mg_free(mg
);
1385 return PIM_MSDP_ERR_NONE
;
1389 pim_msdp_mg_src_do_del(void)
1391 struct pim_msdp_mg_mbr
*mbr
;
1392 struct listnode
*mbr_node
;
1393 struct pim_msdp_mg
*mg
= msdp
->mg
;
1395 /* SIP is being removed - tear down all active peer sessions */
1396 for (ALL_LIST_ELEMENTS_RO(mg
->mbr_list
, mbr_node
, mbr
)) {
1398 pim_msdp_peer_do_del(mbr
->mp
);
1402 if (PIM_DEBUG_MSDP_EVENTS
) {
1403 zlog_debug("MSDP mesh-group %s src cleared", mg
->mesh_group_name
);
1408 pim_msdp_mg_src_del(const char *mesh_group_name
)
1410 struct pim_msdp_mg
*mg
= msdp
->mg
;
1412 if (!mg
|| strcmp(mg
->mesh_group_name
, mesh_group_name
)) {
1413 return PIM_MSDP_ERR_NO_MG
;
1416 if (mg
->src_ip
.s_addr
!= INADDR_ANY
) {
1417 mg
->src_ip
.s_addr
= INADDR_ANY
;
1418 pim_msdp_mg_src_do_del();
1419 /* if there are no references to the mg free it */
1420 pim_msdp_mg_free(mg
);
1422 return PIM_MSDP_ERR_NONE
;
1426 pim_msdp_mg_src_add(const char *mesh_group_name
, struct in_addr src_ip
)
1429 struct pim_msdp_mg_mbr
*mbr
;
1430 struct listnode
*mbr_node
;
1431 struct pim_msdp_mg
*mg
;
1433 if (src_ip
.s_addr
== INADDR_ANY
) {
1434 pim_msdp_mg_src_del(mesh_group_name
);
1435 return PIM_MSDP_ERR_NONE
;
1438 rc
= pim_msdp_mg_add(mesh_group_name
);
1439 if (rc
!= PIM_MSDP_ERR_NONE
) {
1444 if (mg
->src_ip
.s_addr
!= INADDR_ANY
) {
1445 pim_msdp_mg_src_do_del();
1447 mg
->src_ip
= src_ip
;
1449 for (ALL_LIST_ELEMENTS_RO(mg
->mbr_list
, mbr_node
, mbr
)) {
1450 pim_msdp_peer_add(mbr
->mbr_ip
, mg
->src_ip
, mesh_group_name
,
1454 if (PIM_DEBUG_MSDP_EVENTS
) {
1455 char ip_str
[INET_ADDRSTRLEN
];
1456 pim_inet4_dump("<src?>", mg
->src_ip
, ip_str
, sizeof(ip_str
));
1457 zlog_debug("MSDP mesh-group %s src %s set", mg
->mesh_group_name
, ip_str
);
1459 return PIM_MSDP_ERR_NONE
;
1462 /*********************** MSDP feature APIs *********************************/
1464 pim_msdp_config_write(struct vty
*vty
)
1466 struct listnode
*mbrnode
;
1467 struct pim_msdp_mg_mbr
*mbr
;
1468 struct pim_msdp_mg
*mg
= msdp
->mg
;
1469 char mbr_str
[INET_ADDRSTRLEN
];
1470 char src_str
[INET_ADDRSTRLEN
];
1477 if (mg
->src_ip
.s_addr
!= INADDR_ANY
) {
1478 pim_inet4_dump("<src?>", mg
->src_ip
, src_str
, sizeof(src_str
));
1479 vty_out(vty
, "ip msdp mesh-group %s source %s%s",
1480 mg
->mesh_group_name
, src_str
, VTY_NEWLINE
);
1484 for (ALL_LIST_ELEMENTS_RO(mg
->mbr_list
, mbrnode
, mbr
)) {
1485 pim_inet4_dump("<mbr?>", mbr
->mbr_ip
, mbr_str
, sizeof(mbr_str
));
1486 vty_out(vty
, "ip msdp mesh-group %s member %s%s",
1487 mg
->mesh_group_name
, mbr_str
, VTY_NEWLINE
);
1493 /* Enable feature including active/periodic timers etc. on the first peer
1494 * config. Till then MSDP should just stay quiet. */
1496 pim_msdp_enable(void)
1498 if (msdp
->flags
& PIM_MSDPF_ENABLE
) {
1499 /* feature is already enabled */
1502 msdp
->flags
|= PIM_MSDPF_ENABLE
;
1503 msdp
->work_obuf
= stream_new(PIM_MSDP_MAX_PACKET_SIZE
);
1504 pim_msdp_sa_adv_timer_setup(true /* start */);
1505 /* setup sa cache based on local sources */
1506 pim_msdp_sa_local_setup();
1511 pim_msdp_init(struct thread_master
*master
)
1513 msdp
->master
= master
;
1515 msdp
->peer_hash
= hash_create(pim_msdp_peer_hash_key_make
,
1516 pim_msdp_peer_hash_eq
);
1517 msdp
->peer_list
= list_new();
1518 msdp
->peer_list
->del
= (void (*)(void *))pim_msdp_peer_free
;
1519 msdp
->peer_list
->cmp
= (int (*)(void *, void *))pim_msdp_peer_comp
;
1521 msdp
->sa_hash
= hash_create(pim_msdp_sa_hash_key_make
,
1522 pim_msdp_sa_hash_eq
);
1523 msdp
->sa_list
= list_new();
1524 msdp
->sa_list
->del
= (void (*)(void *))pim_msdp_sa_free
;
1525 msdp
->sa_list
->cmp
= (int (*)(void *, void *))pim_msdp_sa_comp
;
1528 /* counterpart to MSDP init; XXX: unused currently */
1532 /* XXX: stop listener and delete all peer sessions */
1534 if (msdp
->peer_hash
) {
1535 hash_free(msdp
->peer_hash
);
1536 msdp
->peer_hash
= NULL
;
1539 if (msdp
->peer_list
) {
1540 list_free(msdp
->peer_list
);
1541 msdp
->peer_list
= NULL
;