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");
76 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 sa
->flags
|= PIM_MSDP_SAF_UP_DEL_IN_PROG
;
128 pim_upstream_del(up
, __PRETTY_FUNCTION__
);
129 sa
->flags
&= ~PIM_MSDP_SAF_UP_DEL_IN_PROG
;
132 if (PIM_DEBUG_MSDP_EVENTS
) {
133 zlog_debug("MSDP SA %s de-referenced SPT", sa
->sg_str
);
138 pim_msdp_sa_upstream_add_ok(struct pim_msdp_sa
*sa
, struct pim_upstream
*xg_up
)
140 if (!(sa
->flags
& PIM_MSDP_SAF_PEER
)) {
141 /* SA should have been rxed from a peer */
144 /* check if we are RP */
145 if (!I_am_RP(sa
->sg
.grp
)) {
149 /* check if we have a (*, G) with a non-empty immediate OIL */
153 memset(&sg
, 0, sizeof(sg
));
156 xg_up
= pim_upstream_find(&sg
);
158 if (!xg_up
|| (xg_up
->join_state
!= PIM_UPSTREAM_JOINED
)) {
159 /* join desired will be true for such (*, G) entries so we will
160 * just look at join_state and let the PIM state machine do the rest of
168 /* Upstream add evaluation needs to happen everytime -
169 * 1. Peer reference is added or removed.
170 * 2. The RP for a group changes.
171 * 3. joinDesired for the associated (*, G) changes
172 * 4. associated (*, G) is removed - this seems like a bit redundant
173 * (considering #4); but just in case an entry gets nuked without
174 * upstream state transition
177 pim_msdp_sa_upstream_update(struct pim_msdp_sa
*sa
,
178 struct pim_upstream
*xg_up
, const char *ctx
)
180 struct pim_upstream
*up
;
182 if (!pim_msdp_sa_upstream_add_ok(sa
, xg_up
)) {
183 pim_msdp_sa_upstream_del(sa
);
192 up
= pim_upstream_find(&sa
->sg
);
193 if (up
&& (PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up
->flags
))) {
194 /* somehow we lost track of the upstream ptr? best log it */
196 if (PIM_DEBUG_MSDP_EVENTS
) {
197 zlog_debug("MSDP SA %s SPT reference missing", sa
->sg_str
);
202 /* RFC3618: "RP triggers a (S, G) join event towards the data source
203 * as if a JP message was rxed addressed to the RP itself." */
204 up
= pim_upstream_add(&sa
->sg
, NULL
/* iif */,
205 PIM_UPSTREAM_FLAG_MASK_SRC_MSDP
,
206 __PRETTY_FUNCTION__
);
210 /* update inherited oil */
211 pim_upstream_inherited_olist(up
);
212 /* should we also start the kat in parallel? we will need it when the
214 if (PIM_DEBUG_MSDP_EVENTS
) {
215 zlog_debug("MSDP SA %s referenced SPT", sa
->sg_str
);
218 if (PIM_DEBUG_MSDP_EVENTS
) {
219 zlog_debug("MSDP SA %s SPT reference failed", sa
->sg_str
);
224 /* release all mem associated with a sa */
226 pim_msdp_sa_free(struct pim_msdp_sa
*sa
)
228 XFREE(MTYPE_PIM_MSDP_SA
, sa
);
231 static struct pim_msdp_sa
*
232 pim_msdp_sa_new(struct prefix_sg
*sg
, struct in_addr rp
)
234 struct pim_msdp_sa
*sa
;
236 sa
= XCALLOC(MTYPE_PIM_MSDP_SA
, sizeof(*sa
));
238 zlog_err("%s: PIM XCALLOC(%zu) failure",
239 __PRETTY_FUNCTION__
, sizeof(*sa
));
244 pim_str_sg_set(sg
, sa
->sg_str
);
246 sa
->uptime
= pim_time_monotonic_sec();
248 /* insert into misc tables for easy access */
249 sa
= hash_get(msdp
->sa_hash
, sa
, hash_alloc_intern
);
251 zlog_err("%s: PIM hash get failure", __PRETTY_FUNCTION__
);
252 pim_msdp_sa_free(sa
);
255 listnode_add_sort(msdp
->sa_list
, sa
);
257 if (PIM_DEBUG_MSDP_EVENTS
) {
258 zlog_debug("MSDP SA %s created", sa
->sg_str
);
264 static struct pim_msdp_sa
*
265 pim_msdp_sa_find(struct prefix_sg
*sg
)
267 struct pim_msdp_sa lookup
;
270 return hash_lookup(msdp
->sa_hash
, &lookup
);
273 static struct pim_msdp_sa
*
274 pim_msdp_sa_add(struct prefix_sg
*sg
, struct in_addr rp
)
276 struct pim_msdp_sa
*sa
;
278 sa
= pim_msdp_sa_find(sg
);
283 return pim_msdp_sa_new(sg
, rp
);
287 pim_msdp_sa_del(struct pim_msdp_sa
* sa
)
289 /* this is somewhat redundant - still want to be careful not to leave
290 * stale upstream references */
291 pim_msdp_sa_upstream_del(sa
);
294 pim_msdp_sa_state_timer_setup(sa
, false /* start */);
296 /* remove the entry from various tables */
297 listnode_delete(msdp
->sa_list
, sa
);
298 hash_release(msdp
->sa_hash
, sa
);
300 if (PIM_DEBUG_MSDP_EVENTS
) {
301 zlog_debug("MSDP SA %s deleted", sa
->sg_str
);
304 /* free up any associated memory */
305 pim_msdp_sa_free(sa
);
309 pim_msdp_sa_peer_ip_set(struct pim_msdp_sa
*sa
, struct pim_msdp_peer
*mp
, struct in_addr rp
)
311 struct pim_msdp_peer
*old_mp
;
313 /* optimize the "no change" case as it will happen
314 * frequently/periodically */
315 if (mp
&& (sa
->peer
.s_addr
== mp
->peer
.s_addr
)) {
319 /* any time the peer ip changes also update the rp address */
320 if (PIM_INADDR_ISNOT_ANY(sa
->peer
)) {
321 old_mp
= pim_msdp_peer_find(sa
->peer
);
322 if (old_mp
&& old_mp
->sa_cnt
) {
331 sa
->peer
.s_addr
= PIM_NET_INADDR_ANY
;
336 /* When a local active-source is removed there is no way to withdraw the
337 * source from peers. We will simply remove it from the SA cache so it will
338 * not be sent in supsequent SA updates. Peers will consequently timeout the
340 * Similarly a "peer-added" SA is never explicitly deleted. It is simply
341 * aged out overtime if not seen in the SA updates from the peers.
342 * XXX: should we provide a knob to drop entries learnt from a peer when the
345 pim_msdp_sa_deref(struct pim_msdp_sa
*sa
, enum pim_msdp_sa_flags flags
)
347 bool update_up
= false;
349 if ((sa
->flags
&PIM_MSDP_SAF_LOCAL
)) {
350 if (flags
& PIM_MSDP_SAF_LOCAL
) {
351 if (PIM_DEBUG_MSDP_EVENTS
) {
352 zlog_debug("MSDP SA %s local reference removed", sa
->sg_str
);
359 if ((sa
->flags
&PIM_MSDP_SAF_PEER
)) {
360 if (flags
& PIM_MSDP_SAF_PEER
) {
363 if (PIM_DEBUG_MSDP_EVENTS
) {
364 zlog_debug("MSDP SA %s peer reference removed", sa
->sg_str
);
366 pim_msdp_sa_state_timer_setup(sa
, false /* start */);
367 rp
.s_addr
= INADDR_ANY
;
368 pim_msdp_sa_peer_ip_set(sa
, NULL
/* mp */, rp
);
369 /* if peer ref was removed we need to remove the msdp reference on the
377 pim_msdp_sa_upstream_update(sa
, NULL
/* xg_up */, "sa-deref");
380 if (!(sa
->flags
& PIM_MSDP_SAF_REF
)) {
386 pim_msdp_sa_ref(struct pim_msdp_peer
*mp
, struct prefix_sg
*sg
,
389 struct pim_msdp_sa
*sa
;
391 sa
= pim_msdp_sa_add(sg
, rp
);
398 if (!(sa
->flags
& PIM_MSDP_SAF_PEER
)) {
399 sa
->flags
|= PIM_MSDP_SAF_PEER
;
400 if (PIM_DEBUG_MSDP_EVENTS
) {
401 zlog_debug("MSDP SA %s added by peer", sa
->sg_str
);
404 pim_msdp_sa_peer_ip_set(sa
, mp
, rp
);
405 /* start/re-start the state timer to prevent cache expiry */
406 pim_msdp_sa_state_timer_setup(sa
, true /* start */);
407 /* We re-evaluate SA "SPT-trigger" everytime we hear abt it from a
408 * peer. XXX: If this becomes too much of a periodic overhead we
409 * can make it event based */
410 pim_msdp_sa_upstream_update(sa
, NULL
/* xg_up */, "peer-ref");
412 if (!(sa
->flags
& PIM_MSDP_SAF_LOCAL
)) {
413 sa
->flags
|= PIM_MSDP_SAF_LOCAL
;
415 if (PIM_DEBUG_MSDP_EVENTS
) {
416 zlog_debug("MSDP SA %s added locally", sa
->sg_str
);
418 /* send an immediate SA update to peers */
419 pim_msdp_pkt_sa_tx_one(sa
);
421 sa
->flags
&= ~PIM_MSDP_SAF_STALE
;
425 /* The following criteria must be met to originate an SA from the MSDP
427 * 1. KAT must be running i.e. source is active.
428 * 2. We must be RP for the group.
429 * 3. Source must be registrable to the RP (this is where the RFC is vague
430 * and especially ambiguous in CLOS networks; with anycast RP all sources
431 * are potentially registrable to all RPs in the domain). We assume #3 is
433 * a. We are also the FHR-DR for the source (OR)
434 * b. We rxed a pim register (null or data encapsulated) within the last
435 * (3 * (1.5 * register_suppression_timer))).
438 pim_msdp_sa_local_add_ok(struct pim_upstream
*up
)
440 if (!(msdp
->flags
& PIM_MSDPF_ENABLE
)) {
444 if (!up
->t_ka_timer
) {
445 /* stream is not active */
449 if (!I_am_RP(up
->sg
.grp
)) {
450 /* we are not RP for the group */
454 /* we are the FHR-DR for this stream or we are RP and have seen registers
455 * from a FHR for this source */
456 if (PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
) || up
->t_msdp_reg_timer
) {
464 pim_msdp_sa_local_add(struct prefix_sg
*sg
)
468 pim_msdp_sa_ref(NULL
/* mp */, sg
, rp
);
472 pim_msdp_sa_local_del(struct prefix_sg
*sg
)
474 struct pim_msdp_sa
*sa
;
476 sa
= pim_msdp_sa_find(sg
);
478 pim_msdp_sa_deref(sa
, PIM_MSDP_SAF_LOCAL
);
482 /* we need to be very cautious with this API as SA del too can trigger an
483 * upstream del and we will get stuck in a simple loop */
485 pim_msdp_sa_local_del_on_up_del(struct prefix_sg
*sg
)
487 struct pim_msdp_sa
*sa
;
489 sa
= pim_msdp_sa_find(sg
);
491 if (PIM_DEBUG_MSDP_INTERNAL
) {
492 zlog_debug("MSDP local sa %s del on up del", sa
->sg_str
);
495 /* if there is no local reference escape */
496 if (!(sa
->flags
& PIM_MSDP_SAF_LOCAL
)) {
497 if (PIM_DEBUG_MSDP_INTERNAL
) {
498 zlog_debug("MSDP local sa %s del; no local ref", sa
->sg_str
);
503 if (sa
->flags
& PIM_MSDP_SAF_UP_DEL_IN_PROG
) {
504 /* MSDP is the one that triggered the upstream del. if this happens
505 * we most certainly have a bug in the PIM upstream state machine. We
506 * will not have a local reference unless the KAT is running. And if the
507 * KAT is running there MUST be an additional source-stream reference to
508 * the flow. Accounting for such cases requires lot of changes; perhaps
509 * address this in the next release? - XXX */
510 zlog_err("MSDP sa %s SPT teardown is causing the local entry to be removed", sa
->sg_str
);
514 /* we are dropping the sa on upstream del we should not have an
515 * upstream reference */
517 if (PIM_DEBUG_MSDP_INTERNAL
) {
518 zlog_debug("MSDP local sa %s del; up non-NULL", sa
->sg_str
);
522 pim_msdp_sa_deref(sa
, PIM_MSDP_SAF_LOCAL
);
526 /* Local SA qualification needs to be re-evaluated when -
527 * 1. KAT is started or stopped
529 * 3. Whenever FHR status changes for a (S,G) - XXX - currently there
530 * is no clear path to transition an entry out of "MASK_FHR" need
531 * to discuss this with Donald. May result in some strangeness if the
532 * FHR is also the RP.
533 * 4. When msdp_reg timer is started or stopped
536 pim_msdp_sa_local_update(struct pim_upstream
*up
)
538 if (pim_msdp_sa_local_add_ok(up
)) {
539 pim_msdp_sa_local_add(&up
->sg
);
541 pim_msdp_sa_local_del(&up
->sg
);
546 pim_msdp_sa_local_setup(void)
548 struct pim_upstream
*up
;
549 struct listnode
*up_node
;
551 for (ALL_LIST_ELEMENTS_RO(pim_upstream_list
, up_node
, up
)) {
552 pim_msdp_sa_local_update(up
);
556 /* whenever the RP changes we need to re-evaluate the "local" SA-cache */
557 /* XXX: needs to be tested */
559 pim_msdp_i_am_rp_changed(void)
561 struct listnode
*sanode
;
562 struct listnode
*nextnode
;
563 struct pim_msdp_sa
*sa
;
565 if (!(msdp
->flags
& PIM_MSDPF_ENABLE
)) {
566 /* if the feature is not enabled do nothing */
570 if (PIM_DEBUG_MSDP_INTERNAL
) {
571 zlog_debug("MSDP i_am_rp changed");
574 /* mark all local entries as stale */
575 for (ALL_LIST_ELEMENTS_RO(msdp
->sa_list
, sanode
, sa
)) {
576 if (sa
->flags
& PIM_MSDP_SAF_LOCAL
) {
577 sa
->flags
|= PIM_MSDP_SAF_STALE
;
581 /* re-setup local SA entries */
582 pim_msdp_sa_local_setup();
584 for (ALL_LIST_ELEMENTS(msdp
->sa_list
, sanode
, nextnode
, sa
)) {
585 /* purge stale SA entries */
586 if (sa
->flags
& PIM_MSDP_SAF_STALE
) {
587 /* clear the stale flag; the entry may be kept even after
589 sa
->flags
&= ~PIM_MSDP_SAF_STALE
;
590 /* sa_deref can end up freeing the sa; so don't access contents after */
591 pim_msdp_sa_deref(sa
, PIM_MSDP_SAF_LOCAL
);
593 /* if the souce is still active check if we can influence SPT */
594 pim_msdp_sa_upstream_update(sa
, NULL
/* xg_up */, "rp-change");
599 /* We track the join state of (*, G) entries. If G has sources in the SA-cache
600 * we need to setup or teardown SPT when the JoinDesired status changes for
603 pim_msdp_up_join_state_changed(struct pim_upstream
*xg_up
)
605 struct listnode
*sanode
;
606 struct pim_msdp_sa
*sa
;
608 if (PIM_DEBUG_MSDP_INTERNAL
) {
609 zlog_debug("MSDP join state changed for %s", xg_up
->sg_str
);
612 /* If this is not really an XG entry just move on */
613 if ((xg_up
->sg
.src
.s_addr
!= INADDR_ANY
) ||
614 (xg_up
->sg
.grp
.s_addr
== INADDR_ANY
)) {
618 /* XXX: Need to maintain SAs per-group to avoid all this unnecessary
620 for (ALL_LIST_ELEMENTS_RO(msdp
->sa_list
, sanode
, sa
)) {
621 if (sa
->sg
.grp
.s_addr
!= xg_up
->sg
.grp
.s_addr
) {
624 pim_msdp_sa_upstream_update(sa
, xg_up
, "up-jp-change");
629 pim_msdp_up_xg_del(struct prefix_sg
*sg
)
631 struct listnode
*sanode
;
632 struct pim_msdp_sa
*sa
;
634 if (PIM_DEBUG_MSDP_INTERNAL
) {
635 zlog_debug("MSDP %s del", pim_str_sg_dump(sg
));
638 /* If this is not really an XG entry just move on */
639 if ((sg
->src
.s_addr
!= INADDR_ANY
) ||
640 (sg
->grp
.s_addr
== INADDR_ANY
)) {
644 /* XXX: Need to maintain SAs per-group to avoid all this unnecessary
646 for (ALL_LIST_ELEMENTS_RO(msdp
->sa_list
, sanode
, sa
)) {
647 if (sa
->sg
.grp
.s_addr
!= sg
->grp
.s_addr
) {
650 pim_msdp_sa_upstream_update(sa
, NULL
/* xg */, "up-jp-change");
655 pim_msdp_up_del(struct prefix_sg
*sg
)
657 if (PIM_DEBUG_MSDP_INTERNAL
) {
658 zlog_debug("MSDP up %s del", pim_str_sg_dump(sg
));
660 if (sg
->src
.s_addr
== INADDR_ANY
) {
661 pim_msdp_up_xg_del(sg
);
663 pim_msdp_sa_local_del_on_up_del(sg
);
667 /* sa hash and peer list helpers */
669 pim_msdp_sa_hash_key_make(void *p
)
671 struct pim_msdp_sa
*sa
= p
;
673 return (jhash_2words(sa
->sg
.src
.s_addr
, sa
->sg
.grp
.s_addr
, 0));
677 pim_msdp_sa_hash_eq(const void *p1
, const void *p2
)
679 const struct pim_msdp_sa
*sa1
= p1
;
680 const struct pim_msdp_sa
*sa2
= p2
;
682 return ((sa1
->sg
.src
.s_addr
== sa2
->sg
.src
.s_addr
) &&
683 (sa1
->sg
.grp
.s_addr
== sa2
->sg
.grp
.s_addr
));
687 pim_msdp_sa_comp(const void *p1
, const void *p2
)
689 const struct pim_msdp_sa
*sa1
= p1
;
690 const struct pim_msdp_sa
*sa2
= p2
;
692 if (ntohl(sa1
->sg
.grp
.s_addr
) < ntohl(sa2
->sg
.grp
.s_addr
))
695 if (ntohl(sa1
->sg
.grp
.s_addr
) > ntohl(sa2
->sg
.grp
.s_addr
))
698 if (ntohl(sa1
->sg
.src
.s_addr
) < ntohl(sa2
->sg
.src
.s_addr
))
701 if (ntohl(sa1
->sg
.src
.s_addr
) > ntohl(sa2
->sg
.src
.s_addr
))
707 /* RFC-3618:Sec-10.1.3 - Peer-RPF forwarding */
708 /* XXX: this can use a bit of refining and extensions */
710 pim_msdp_peer_rpf_check(struct pim_msdp_peer
*mp
, struct in_addr rp
)
712 if (mp
->peer
.s_addr
== rp
.s_addr
) {
719 /************************ Peer session management **************************/
721 pim_msdp_state_dump(enum pim_msdp_peer_state state
, char *buf
, int buf_size
)
724 case PIM_MSDP_DISABLED
:
725 snprintf(buf
, buf_size
, "%s", "disabled");
727 case PIM_MSDP_INACTIVE
:
728 snprintf(buf
, buf_size
, "%s", "inactive");
730 case PIM_MSDP_LISTEN
:
731 snprintf(buf
, buf_size
, "%s", "listen");
733 case PIM_MSDP_CONNECTING
:
734 snprintf(buf
, buf_size
, "%s", "connecting");
736 case PIM_MSDP_ESTABLISHED
:
737 snprintf(buf
, buf_size
, "%s", "established");
740 snprintf(buf
, buf_size
, "unk-%d", state
);
746 pim_msdp_peer_key_dump(struct pim_msdp_peer
*mp
, char *buf
, int buf_size
, bool long_format
)
748 char peer_str
[INET_ADDRSTRLEN
];
749 char local_str
[INET_ADDRSTRLEN
];
751 pim_inet4_dump("<peer?>", mp
->peer
, peer_str
, sizeof(peer_str
));
753 pim_inet4_dump("<local?>", mp
->local
, local_str
, sizeof(local_str
));
754 snprintf(buf
, buf_size
, "MSDP peer %s local %s mg %s",
755 peer_str
, local_str
, mp
->mesh_group_name
);
757 snprintf(buf
, buf_size
, "MSDP peer %s", peer_str
);
764 pim_msdp_peer_state_chg_log(struct pim_msdp_peer
*mp
)
766 char state_str
[PIM_MSDP_STATE_STRLEN
];
768 pim_msdp_state_dump(mp
->state
, state_str
, sizeof(state_str
));
769 zlog_debug("MSDP peer %s state chg to %s", mp
->key_str
, state_str
);
772 /* MSDP Connection State Machine actions (defined in RFC-3618:Sec-11.2) */
773 /* 11.2.A2: active peer - start connect retry timer; when the timer fires
774 * a tcp connection will be made */
776 pim_msdp_peer_connect(struct pim_msdp_peer
*mp
)
778 mp
->state
= PIM_MSDP_CONNECTING
;
779 if (PIM_DEBUG_MSDP_EVENTS
) {
780 pim_msdp_peer_state_chg_log(mp
);
783 pim_msdp_peer_cr_timer_setup(mp
, true /* start */);
786 /* 11.2.A3: passive peer - just listen for connections */
788 pim_msdp_peer_listen(struct pim_msdp_peer
*mp
)
790 mp
->state
= PIM_MSDP_LISTEN
;
791 if (PIM_DEBUG_MSDP_EVENTS
) {
792 pim_msdp_peer_state_chg_log(mp
);
795 /* this is interntionally asymmetric i.e. we set up listen-socket when the
796 * first listening peer is configured; but don't bother tearing it down when
797 * all the peers go down */
798 pim_msdp_sock_listen();
801 /* 11.2.A4 and 11.2.A5: transition active or passive peer to
802 * established state */
804 pim_msdp_peer_established(struct pim_msdp_peer
*mp
)
806 if (mp
->state
!= PIM_MSDP_ESTABLISHED
) {
810 mp
->state
= PIM_MSDP_ESTABLISHED
;
811 mp
->uptime
= pim_time_monotonic_sec();
813 if (PIM_DEBUG_MSDP_EVENTS
) {
814 pim_msdp_peer_state_chg_log(mp
);
817 /* stop retry timer on active peers */
818 pim_msdp_peer_cr_timer_setup(mp
, false /* start */);
820 /* send KA; start KA and hold timers */
821 pim_msdp_pkt_ka_tx(mp
);
822 pim_msdp_peer_ka_timer_setup(mp
, true /* start */);
823 pim_msdp_peer_hold_timer_setup(mp
, true /* start */);
825 pim_msdp_pkt_sa_tx_to_one_peer(mp
);
827 PIM_MSDP_PEER_WRITE_ON(mp
);
828 PIM_MSDP_PEER_READ_ON(mp
);
831 /* 11.2.A6, 11.2.A7 and 11.2.A8: shutdown the peer tcp connection */
833 pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer
*mp
, bool chg_state
)
836 if (mp
->state
== PIM_MSDP_ESTABLISHED
) {
839 mp
->state
= PIM_MSDP_INACTIVE
;
840 if (PIM_DEBUG_MSDP_EVENTS
) {
841 pim_msdp_peer_state_chg_log(mp
);
845 if (PIM_DEBUG_MSDP_INTERNAL
) {
846 zlog_debug("MSDP peer %s pim_msdp_peer_stop_tcp_conn", mp
->key_str
);
848 /* stop read and write threads */
849 PIM_MSDP_PEER_READ_OFF(mp
);
850 PIM_MSDP_PEER_WRITE_OFF(mp
);
855 stream_reset(mp
->ibuf
);
857 stream_fifo_clean(mp
->obuf
);
859 /* stop all peer timers */
860 pim_msdp_peer_ka_timer_setup(mp
, false /* start */);
861 pim_msdp_peer_cr_timer_setup(mp
, false /* start */);
862 pim_msdp_peer_hold_timer_setup(mp
, false /* start */);
864 /* close connection */
871 /* RFC-3618:Sec-5.6 - stop the peer tcp connection and startover */
873 pim_msdp_peer_reset_tcp_conn(struct pim_msdp_peer
*mp
, const char *rc_str
)
875 if (PIM_DEBUG_EVENTS
) {
876 zlog_debug("MSDP peer %s tcp reset %s", mp
->key_str
, rc_str
);
877 snprintf(mp
->last_reset
, sizeof(mp
->last_reset
), "%s", rc_str
);
880 /* close the connection and transition to listening or connecting */
881 pim_msdp_peer_stop_tcp_conn(mp
, true /* chg_state */);
882 if (PIM_MSDP_PEER_IS_LISTENER(mp
)) {
883 pim_msdp_peer_listen(mp
);
885 pim_msdp_peer_connect(mp
);
890 pim_msdp_peer_timer_expiry_log(struct pim_msdp_peer
*mp
, const char *timer_str
)
892 zlog_debug("MSDP peer %s %s timer expired", mp
->key_str
, timer_str
);
895 /* RFC-3618:Sec-5.4 - peer hold timer */
897 pim_msdp_peer_hold_timer_cb(struct thread
*t
)
899 struct pim_msdp_peer
*mp
;
902 mp
->hold_timer
= NULL
;
904 if (PIM_DEBUG_MSDP_EVENTS
) {
905 pim_msdp_peer_timer_expiry_log(mp
, "hold");
908 if (mp
->state
!= PIM_MSDP_ESTABLISHED
) {
912 if (PIM_DEBUG_MSDP_EVENTS
) {
913 pim_msdp_peer_state_chg_log(mp
);
915 pim_msdp_peer_reset_tcp_conn(mp
, "ht-expired");
919 pim_msdp_peer_hold_timer_setup(struct pim_msdp_peer
*mp
, bool start
)
921 THREAD_OFF(mp
->hold_timer
);
923 THREAD_TIMER_ON(msdp
->master
, mp
->hold_timer
,
924 pim_msdp_peer_hold_timer_cb
, mp
, PIM_MSDP_PEER_HOLD_TIME
);
929 /* RFC-3618:Sec-5.5 - peer keepalive timer */
931 pim_msdp_peer_ka_timer_cb(struct thread
*t
)
933 struct pim_msdp_peer
*mp
;
938 if (PIM_DEBUG_MSDP_EVENTS
) {
939 pim_msdp_peer_timer_expiry_log(mp
, "ka");
942 pim_msdp_pkt_ka_tx(mp
);
943 pim_msdp_peer_ka_timer_setup(mp
, true /* start */);
947 pim_msdp_peer_ka_timer_setup(struct pim_msdp_peer
*mp
, bool start
)
949 THREAD_OFF(mp
->ka_timer
);
951 THREAD_TIMER_ON(msdp
->master
, mp
->ka_timer
,
952 pim_msdp_peer_ka_timer_cb
, mp
, PIM_MSDP_PEER_KA_TIME
);
957 pim_msdp_peer_active_connect(struct pim_msdp_peer
*mp
)
961 rc
= pim_msdp_sock_connect(mp
);
963 if (PIM_DEBUG_MSDP_INTERNAL
) {
964 zlog_debug("MSDP peer %s pim_msdp_peer_active_connect: %d", mp
->key_str
, rc
);
970 /* connect failed restart the connect-retry timer */
971 pim_msdp_peer_cr_timer_setup(mp
, true /* start */);
974 case connect_success
:
975 /* connect was sucessful move to established */
976 pim_msdp_peer_established(mp
);
979 case connect_in_progress
:
980 /* for NB content we need to wait till sock is readable or
982 PIM_MSDP_PEER_WRITE_ON(mp
);
983 PIM_MSDP_PEER_READ_ON(mp
);
984 /* also restart connect-retry timer to reset the socket if connect is
986 pim_msdp_peer_cr_timer_setup(mp
, true /* start */);
991 /* RFC-3618:Sec-5.6 - connection retry on active peer */
993 pim_msdp_peer_cr_timer_cb(struct thread
*t
)
995 struct pim_msdp_peer
*mp
;
1000 if (PIM_DEBUG_MSDP_EVENTS
) {
1001 pim_msdp_peer_timer_expiry_log(mp
, "connect-retry");
1004 if (mp
->state
!= PIM_MSDP_CONNECTING
|| PIM_MSDP_PEER_IS_LISTENER(mp
)) {
1008 pim_msdp_peer_active_connect(mp
);
1012 pim_msdp_peer_cr_timer_setup(struct pim_msdp_peer
*mp
, bool start
)
1014 THREAD_OFF(mp
->cr_timer
);
1016 THREAD_TIMER_ON(msdp
->master
, mp
->cr_timer
,
1017 pim_msdp_peer_cr_timer_cb
, mp
, PIM_MSDP_PEER_CONNECT_RETRY_TIME
);
1021 /* if a valid packet is rxed from the peer we can restart hold timer */
1023 pim_msdp_peer_pkt_rxed(struct pim_msdp_peer
*mp
)
1025 if (mp
->state
== PIM_MSDP_ESTABLISHED
) {
1026 pim_msdp_peer_hold_timer_setup(mp
, true /* start */);
1030 /* if a valid packet is txed to the peer we can restart ka timer and avoid
1031 * unnecessary ka noise in the network */
1033 pim_msdp_peer_pkt_txed(struct pim_msdp_peer
*mp
)
1035 if (mp
->state
== PIM_MSDP_ESTABLISHED
) {
1036 pim_msdp_peer_ka_timer_setup(mp
, true /* start */);
1037 if (PIM_DEBUG_MSDP_INTERNAL
) {
1038 zlog_debug("MSDP ka timer restart on pkt tx to %s", mp
->key_str
);
1043 static void pim_msdp_addr2su(union sockunion
*su
, struct in_addr addr
)
1046 su
->sin
.sin_addr
= addr
;
1047 su
->sin
.sin_family
= AF_INET
;
1048 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
1049 su
->sin
.sin_len
= sizeof(struct sockaddr_in
);
1050 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
1053 /* 11.2.A1: create a new peer and transition state to listen or connecting */
1054 static enum pim_msdp_err
1055 pim_msdp_peer_new(struct in_addr peer_addr
, struct in_addr local_addr
,
1056 const char *mesh_group_name
, struct pim_msdp_peer
**mp_p
)
1058 struct pim_msdp_peer
*mp
;
1062 mp
= XCALLOC(MTYPE_PIM_MSDP_PEER
, sizeof(*mp
));
1064 zlog_err("%s: PIM XCALLOC(%zu) failure",
1065 __PRETTY_FUNCTION__
, sizeof(*mp
));
1066 return PIM_MSDP_ERR_OOM
;
1069 mp
->peer
= peer_addr
;
1070 pim_inet4_dump("<peer?>", mp
->peer
, mp
->key_str
, sizeof(mp
->key_str
));
1071 pim_msdp_addr2su(&mp
->su_peer
, mp
->peer
);
1072 mp
->local
= local_addr
;
1073 /* XXX: originator_id setting needs to move to the mesh group */
1074 msdp
->originator_id
= local_addr
;
1075 pim_msdp_addr2su(&mp
->su_local
, mp
->local
);
1076 mp
->mesh_group_name
= XSTRDUP(MTYPE_PIM_MSDP_MG_NAME
, mesh_group_name
);
1077 mp
->state
= PIM_MSDP_INACTIVE
;
1079 strcpy(mp
->last_reset
, "-");
1080 /* higher IP address is listener */
1081 if (ntohl(mp
->local
.s_addr
) > ntohl(mp
->peer
.s_addr
)) {
1082 mp
->flags
|= PIM_MSDP_PEERF_LISTENER
;
1085 /* setup packet buffers */
1086 mp
->ibuf
= stream_new(PIM_MSDP_MAX_PACKET_SIZE
);
1087 mp
->obuf
= stream_fifo_new();
1089 /* insert into misc tables for easy access */
1090 mp
= hash_get(msdp
->peer_hash
, mp
, hash_alloc_intern
);
1091 listnode_add_sort(msdp
->peer_list
, mp
);
1093 if (PIM_DEBUG_MSDP_EVENTS
) {
1094 zlog_debug("MSDP peer %s created", mp
->key_str
);
1096 pim_msdp_peer_state_chg_log(mp
);
1099 /* fireup the connect state machine */
1100 if (PIM_MSDP_PEER_IS_LISTENER(mp
)) {
1101 pim_msdp_peer_listen(mp
);
1103 pim_msdp_peer_connect(mp
);
1108 return PIM_MSDP_ERR_NONE
;
1111 struct pim_msdp_peer
*
1112 pim_msdp_peer_find(struct in_addr peer_addr
)
1114 struct pim_msdp_peer lookup
;
1116 lookup
.peer
= peer_addr
;
1117 return hash_lookup(msdp
->peer_hash
, &lookup
);
1120 /* add peer configuration if it doesn't already exist */
1122 pim_msdp_peer_add(struct in_addr peer_addr
, struct in_addr local_addr
,
1123 const char *mesh_group_name
, struct pim_msdp_peer
**mp_p
)
1125 struct pim_msdp_peer
*mp
;
1131 if (peer_addr
.s_addr
== local_addr
.s_addr
) {
1132 /* skip session setup if config is invalid */
1133 if (PIM_DEBUG_MSDP_EVENTS
) {
1134 char peer_str
[INET_ADDRSTRLEN
];
1136 pim_inet4_dump("<peer?>", peer_addr
, peer_str
, sizeof(peer_str
));
1137 zlog_debug("%s add skipped as DIP=SIP", peer_str
);
1139 return PIM_MSDP_ERR_SIP_EQ_DIP
;
1142 mp
= pim_msdp_peer_find(peer_addr
);
1147 return PIM_MSDP_ERR_PEER_EXISTS
;
1150 return pim_msdp_peer_new(peer_addr
, local_addr
, mesh_group_name
, mp_p
);
1153 /* release all mem associated with a peer */
1155 pim_msdp_peer_free(struct pim_msdp_peer
*mp
)
1158 stream_free(mp
->ibuf
);
1162 stream_fifo_free(mp
->obuf
);
1165 if (mp
->mesh_group_name
) {
1166 XFREE(MTYPE_PIM_MSDP_MG_NAME
, mp
->mesh_group_name
);
1168 XFREE(MTYPE_PIM_MSDP_PEER
, mp
);
1171 /* delete the peer config */
1172 static enum pim_msdp_err
1173 pim_msdp_peer_do_del(struct pim_msdp_peer
*mp
)
1175 /* stop the tcp connection and shutdown all timers */
1176 pim_msdp_peer_stop_tcp_conn(mp
, true /* chg_state */);
1178 /* remove the session from various tables */
1179 listnode_delete(msdp
->peer_list
, mp
);
1180 hash_release(msdp
->peer_hash
, mp
);
1182 if (PIM_DEBUG_MSDP_EVENTS
) {
1183 zlog_debug("MSDP peer %s deleted", mp
->key_str
);
1186 /* free up any associated memory */
1187 pim_msdp_peer_free(mp
);
1189 return PIM_MSDP_ERR_NONE
;
1193 pim_msdp_peer_del(struct in_addr peer_addr
)
1195 struct pim_msdp_peer
*mp
;
1197 mp
= pim_msdp_peer_find(peer_addr
);
1199 return PIM_MSDP_ERR_NO_PEER
;
1202 return pim_msdp_peer_do_del(mp
);
1205 /* peer hash and peer list helpers */
1207 pim_msdp_peer_hash_key_make(void *p
)
1209 struct pim_msdp_peer
*mp
= p
;
1210 return (jhash_1word(mp
->peer
.s_addr
, 0));
1214 pim_msdp_peer_hash_eq(const void *p1
, const void *p2
)
1216 const struct pim_msdp_peer
*mp1
= p1
;
1217 const struct pim_msdp_peer
*mp2
= p2
;
1219 return (mp1
->peer
.s_addr
== mp2
->peer
.s_addr
);
1223 pim_msdp_peer_comp(const void *p1
, const void *p2
)
1225 const struct pim_msdp_peer
*mp1
= p1
;
1226 const struct pim_msdp_peer
*mp2
= p2
;
1228 if (ntohl(mp1
->peer
.s_addr
) < ntohl(mp2
->peer
.s_addr
))
1231 if (ntohl(mp1
->peer
.s_addr
) > ntohl(mp2
->peer
.s_addr
))
1237 /************************** Mesh group management **************************/
1239 pim_msdp_mg_free(struct pim_msdp_mg
*mg
)
1241 /* If the mesh-group has valid member or src_ip don't delete it */
1242 if (!mg
|| mg
->mbr_cnt
|| (mg
->src_ip
.s_addr
!= INADDR_ANY
)) {
1246 if (PIM_DEBUG_MSDP_EVENTS
) {
1247 zlog_debug("MSDP mesh-group %s deleted", mg
->mesh_group_name
);
1249 if (mg
->mesh_group_name
)
1250 XFREE(MTYPE_PIM_MSDP_MG_NAME
, mg
->mesh_group_name
);
1253 list_free(mg
->mbr_list
);
1255 XFREE(MTYPE_PIM_MSDP_MG
, mg
);
1259 static struct pim_msdp_mg
*
1260 pim_msdp_mg_new(const char *mesh_group_name
)
1262 struct pim_msdp_mg
*mg
;
1264 mg
= XCALLOC(MTYPE_PIM_MSDP_MG
, sizeof(*mg
));
1266 zlog_err("%s: PIM XCALLOC(%zu) failure",
1267 __PRETTY_FUNCTION__
, sizeof(*mg
));
1271 mg
->mesh_group_name
= XSTRDUP(MTYPE_PIM_MSDP_MG_NAME
, mesh_group_name
);
1272 mg
->mbr_list
= list_new();
1273 mg
->mbr_list
->del
= (void (*)(void *))pim_msdp_mg_mbr_free
;
1274 mg
->mbr_list
->cmp
= (int (*)(void *, void *))pim_msdp_mg_mbr_comp
;
1276 if (PIM_DEBUG_MSDP_EVENTS
) {
1277 zlog_debug("MSDP mesh-group %s created", mg
->mesh_group_name
);
1283 pim_msdp_mg_del(const char *mesh_group_name
)
1285 struct pim_msdp_mg
*mg
= msdp
->mg
;
1286 struct pim_msdp_mg_mbr
*mbr
;
1288 if (!mg
|| strcmp(mg
->mesh_group_name
, mesh_group_name
)) {
1289 return PIM_MSDP_ERR_NO_MG
;
1292 /* delete all the mesh-group members */
1293 while (!list_isempty(mg
->mbr_list
)) {
1294 mbr
= listnode_head(mg
->mbr_list
);
1295 pim_msdp_mg_mbr_do_del(mg
, mbr
);
1299 mg
->src_ip
.s_addr
= INADDR_ANY
;
1301 /* free up the mesh-group */
1302 pim_msdp_mg_free(mg
);
1303 return PIM_MSDP_ERR_NONE
;
1306 static enum pim_msdp_err
1307 pim_msdp_mg_add(const char *mesh_group_name
)
1310 if (!strcmp(msdp
->mg
->mesh_group_name
, mesh_group_name
)) {
1311 return PIM_MSDP_ERR_NONE
;
1313 /* currently only one mesh-group can exist at a time */
1314 return PIM_MSDP_ERR_MAX_MESH_GROUPS
;
1317 msdp
->mg
= pim_msdp_mg_new(mesh_group_name
);
1319 return PIM_MSDP_ERR_OOM
;
1322 return PIM_MSDP_ERR_NONE
;
1326 pim_msdp_mg_mbr_comp(const void *p1
, const void *p2
)
1328 const struct pim_msdp_mg_mbr
*mbr1
= p1
;
1329 const struct pim_msdp_mg_mbr
*mbr2
= p2
;
1331 if (ntohl(mbr1
->mbr_ip
.s_addr
) < ntohl(mbr2
->mbr_ip
.s_addr
))
1334 if (ntohl(mbr1
->mbr_ip
.s_addr
) > ntohl(mbr2
->mbr_ip
.s_addr
))
1341 pim_msdp_mg_mbr_free(struct pim_msdp_mg_mbr
*mbr
)
1343 XFREE(MTYPE_PIM_MSDP_MG_MBR
, mbr
);
1346 static struct pim_msdp_mg_mbr
*
1347 pim_msdp_mg_mbr_find(struct in_addr mbr_ip
)
1349 struct pim_msdp_mg_mbr
*mbr
;
1350 struct listnode
*mbr_node
;
1355 /* we can move this to a hash but considering that number of peers in
1356 * a mesh-group that seems like bit of an overkill */
1357 for (ALL_LIST_ELEMENTS_RO(msdp
->mg
->mbr_list
, mbr_node
, mbr
)) {
1358 if (mbr
->mbr_ip
.s_addr
== mbr_ip
.s_addr
) {
1366 pim_msdp_mg_mbr_add(const char *mesh_group_name
, struct in_addr mbr_ip
)
1369 struct pim_msdp_mg_mbr
*mbr
;
1370 struct pim_msdp_mg
*mg
;
1372 rc
= pim_msdp_mg_add(mesh_group_name
);
1373 if (rc
!= PIM_MSDP_ERR_NONE
) {
1378 mbr
= pim_msdp_mg_mbr_find(mbr_ip
);
1380 return PIM_MSDP_ERR_MG_MBR_EXISTS
;
1383 mbr
= XCALLOC(MTYPE_PIM_MSDP_MG_MBR
, sizeof(*mbr
));
1385 zlog_err("%s: PIM XCALLOC(%zu) failure",
1386 __PRETTY_FUNCTION__
, sizeof(*mbr
));
1387 /* if there are no references to the mg free it */
1388 pim_msdp_mg_free(mg
);
1389 return PIM_MSDP_ERR_OOM
;
1391 mbr
->mbr_ip
= mbr_ip
;
1392 listnode_add_sort(mg
->mbr_list
, mbr
);
1394 /* if valid SIP has been configured add peer session */
1395 if (mg
->src_ip
.s_addr
!= INADDR_ANY
) {
1396 pim_msdp_peer_add(mbr_ip
, mg
->src_ip
, mesh_group_name
,
1400 if (PIM_DEBUG_MSDP_EVENTS
) {
1401 char ip_str
[INET_ADDRSTRLEN
];
1402 pim_inet4_dump("<mbr?>", mbr
->mbr_ip
, ip_str
, sizeof(ip_str
));
1403 zlog_debug("MSDP mesh-group %s mbr %s created", mg
->mesh_group_name
, ip_str
);
1406 return PIM_MSDP_ERR_NONE
;
1410 pim_msdp_mg_mbr_do_del(struct pim_msdp_mg
*mg
, struct pim_msdp_mg_mbr
*mbr
)
1412 /* Delete active peer session if any */
1414 pim_msdp_peer_do_del(mbr
->mp
);
1417 listnode_delete(mg
->mbr_list
, mbr
);
1418 if (PIM_DEBUG_MSDP_EVENTS
) {
1419 char ip_str
[INET_ADDRSTRLEN
];
1420 pim_inet4_dump("<mbr?>", mbr
->mbr_ip
, ip_str
, sizeof(ip_str
));
1421 zlog_debug("MSDP mesh-group %s mbr %s deleted", mg
->mesh_group_name
, ip_str
);
1423 pim_msdp_mg_mbr_free(mbr
);
1430 pim_msdp_mg_mbr_del(const char *mesh_group_name
, struct in_addr mbr_ip
)
1432 struct pim_msdp_mg_mbr
*mbr
;
1433 struct pim_msdp_mg
*mg
= msdp
->mg
;
1435 if (!mg
|| strcmp(mg
->mesh_group_name
, mesh_group_name
)) {
1436 return PIM_MSDP_ERR_NO_MG
;
1439 mbr
= pim_msdp_mg_mbr_find(mbr_ip
);
1441 return PIM_MSDP_ERR_NO_MG_MBR
;
1444 pim_msdp_mg_mbr_do_del(mg
, mbr
);
1445 /* if there are no references to the mg free it */
1446 pim_msdp_mg_free(mg
);
1448 return PIM_MSDP_ERR_NONE
;
1452 pim_msdp_mg_src_do_del(void)
1454 struct pim_msdp_mg_mbr
*mbr
;
1455 struct listnode
*mbr_node
;
1456 struct pim_msdp_mg
*mg
= msdp
->mg
;
1458 /* SIP is being removed - tear down all active peer sessions */
1459 for (ALL_LIST_ELEMENTS_RO(mg
->mbr_list
, mbr_node
, mbr
)) {
1461 pim_msdp_peer_do_del(mbr
->mp
);
1465 if (PIM_DEBUG_MSDP_EVENTS
) {
1466 zlog_debug("MSDP mesh-group %s src cleared", mg
->mesh_group_name
);
1471 pim_msdp_mg_src_del(const char *mesh_group_name
)
1473 struct pim_msdp_mg
*mg
= msdp
->mg
;
1475 if (!mg
|| strcmp(mg
->mesh_group_name
, mesh_group_name
)) {
1476 return PIM_MSDP_ERR_NO_MG
;
1479 if (mg
->src_ip
.s_addr
!= INADDR_ANY
) {
1480 mg
->src_ip
.s_addr
= INADDR_ANY
;
1481 pim_msdp_mg_src_do_del();
1482 /* if there are no references to the mg free it */
1483 pim_msdp_mg_free(mg
);
1485 return PIM_MSDP_ERR_NONE
;
1489 pim_msdp_mg_src_add(const char *mesh_group_name
, struct in_addr src_ip
)
1492 struct pim_msdp_mg_mbr
*mbr
;
1493 struct listnode
*mbr_node
;
1494 struct pim_msdp_mg
*mg
;
1496 if (src_ip
.s_addr
== INADDR_ANY
) {
1497 pim_msdp_mg_src_del(mesh_group_name
);
1498 return PIM_MSDP_ERR_NONE
;
1501 rc
= pim_msdp_mg_add(mesh_group_name
);
1502 if (rc
!= PIM_MSDP_ERR_NONE
) {
1507 if (mg
->src_ip
.s_addr
!= INADDR_ANY
) {
1508 pim_msdp_mg_src_do_del();
1510 mg
->src_ip
= src_ip
;
1512 for (ALL_LIST_ELEMENTS_RO(mg
->mbr_list
, mbr_node
, mbr
)) {
1513 pim_msdp_peer_add(mbr
->mbr_ip
, mg
->src_ip
, mesh_group_name
,
1517 if (PIM_DEBUG_MSDP_EVENTS
) {
1518 char ip_str
[INET_ADDRSTRLEN
];
1519 pim_inet4_dump("<src?>", mg
->src_ip
, ip_str
, sizeof(ip_str
));
1520 zlog_debug("MSDP mesh-group %s src %s set", mg
->mesh_group_name
, ip_str
);
1522 return PIM_MSDP_ERR_NONE
;
1525 /*********************** MSDP feature APIs *********************************/
1527 pim_msdp_config_write(struct vty
*vty
)
1529 struct listnode
*mbrnode
;
1530 struct pim_msdp_mg_mbr
*mbr
;
1531 struct pim_msdp_mg
*mg
= msdp
->mg
;
1532 char mbr_str
[INET_ADDRSTRLEN
];
1533 char src_str
[INET_ADDRSTRLEN
];
1540 if (mg
->src_ip
.s_addr
!= INADDR_ANY
) {
1541 pim_inet4_dump("<src?>", mg
->src_ip
, src_str
, sizeof(src_str
));
1542 vty_out(vty
, "ip msdp mesh-group %s source %s%s",
1543 mg
->mesh_group_name
, src_str
, VTY_NEWLINE
);
1547 for (ALL_LIST_ELEMENTS_RO(mg
->mbr_list
, mbrnode
, mbr
)) {
1548 pim_inet4_dump("<mbr?>", mbr
->mbr_ip
, mbr_str
, sizeof(mbr_str
));
1549 vty_out(vty
, "ip msdp mesh-group %s member %s%s",
1550 mg
->mesh_group_name
, mbr_str
, VTY_NEWLINE
);
1556 /* Enable feature including active/periodic timers etc. on the first peer
1557 * config. Till then MSDP should just stay quiet. */
1559 pim_msdp_enable(void)
1561 if (msdp
->flags
& PIM_MSDPF_ENABLE
) {
1562 /* feature is already enabled */
1565 msdp
->flags
|= PIM_MSDPF_ENABLE
;
1566 msdp
->work_obuf
= stream_new(PIM_MSDP_MAX_PACKET_SIZE
);
1567 pim_msdp_sa_adv_timer_setup(true /* start */);
1568 /* setup sa cache based on local sources */
1569 pim_msdp_sa_local_setup();
1574 pim_msdp_init(struct thread_master
*master
)
1576 msdp
->master
= master
;
1578 msdp
->peer_hash
= hash_create(pim_msdp_peer_hash_key_make
,
1579 pim_msdp_peer_hash_eq
);
1580 msdp
->peer_list
= list_new();
1581 msdp
->peer_list
->del
= (void (*)(void *))pim_msdp_peer_free
;
1582 msdp
->peer_list
->cmp
= (int (*)(void *, void *))pim_msdp_peer_comp
;
1584 msdp
->sa_hash
= hash_create(pim_msdp_sa_hash_key_make
,
1585 pim_msdp_sa_hash_eq
);
1586 msdp
->sa_list
= list_new();
1587 msdp
->sa_list
->del
= (void (*)(void *))pim_msdp_sa_free
;
1588 msdp
->sa_list
->cmp
= (int (*)(void *, void *))pim_msdp_sa_comp
;
1591 /* counterpart to MSDP init; XXX: unused currently */
1595 /* XXX: stop listener and delete all peer sessions */
1597 if (msdp
->peer_hash
) {
1598 hash_free(msdp
->peer_hash
);
1599 msdp
->peer_hash
= NULL
;
1602 if (msdp
->peer_list
) {
1603 list_free(msdp
->peer_list
);
1604 msdp
->peer_list
= NULL
;