1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
9 #include "lib/libfrr.h"
10 #include "lib/queue.h"
11 #include "lib/stream.h"
12 #include "lib/zclient.h"
13 #include "lib/printfrr.h"
22 struct ptm_client_notification
{
23 struct bfd_session
*pcn_bs
;
24 struct ptm_client
*pcn_pc
;
26 TAILQ_ENTRY(ptm_client_notification
) pcn_entry
;
28 TAILQ_HEAD(pcnqueue
, ptm_client_notification
);
32 struct pcnqueue pc_pcnqueue
;
34 TAILQ_ENTRY(ptm_client
) pc_entry
;
36 TAILQ_HEAD(pcqueue
, ptm_client
);
38 static struct pcqueue pcqueue
;
39 static struct zclient
*zclient
;
45 static int _ptm_msg_address(struct stream
*msg
, int family
, const void *addr
);
47 static void _ptm_msg_read_address(struct stream
*msg
, struct sockaddr_any
*sa
);
48 static int _ptm_msg_read(struct stream
*msg
, int command
, vrf_id_t vrf_id
,
49 struct bfd_peer_cfg
*bpc
, struct ptm_client
**pc
);
51 static struct ptm_client
*pc_lookup(uint32_t pid
);
52 static struct ptm_client
*pc_new(uint32_t pid
);
53 static void pc_free(struct ptm_client
*pc
);
54 static void pc_free_all(void);
55 static struct ptm_client_notification
*pcn_new(struct ptm_client
*pc
,
56 struct bfd_session
*bs
);
57 static struct ptm_client_notification
*pcn_lookup(struct ptm_client
*pc
,
58 struct bfd_session
*bs
);
59 static void pcn_free(struct ptm_client_notification
*pcn
);
62 static void bfdd_dest_register(struct stream
*msg
, vrf_id_t vrf_id
);
63 static void bfdd_dest_deregister(struct stream
*msg
, vrf_id_t vrf_id
);
64 static void bfdd_client_register(struct stream
*msg
);
65 static void bfdd_client_deregister(struct stream
*msg
);
71 static void debug_printbpc(const struct bfd_peer_cfg
*bpc
, const char *fmt
, ...)
73 char timers
[3][128] = {};
74 char minttl_str
[32] = {};
75 char addr
[3][128] = {};
76 char profile
[128] = {};
81 /* Avoid debug calculations if it's disabled. */
82 if (bglobal
.debug_zebra
== false)
85 snprintf(addr
[0], sizeof(addr
[0]), "peer:%s", satostr(&bpc
->bpc_peer
));
86 if (bpc
->bpc_local
.sa_sin
.sin_family
)
87 snprintf(addr
[1], sizeof(addr
[1]), " local:%s",
88 satostr(&bpc
->bpc_local
));
90 if (bpc
->bpc_has_localif
)
91 snprintf(addr
[2], sizeof(addr
[2]), " ifname:%s",
94 if (bpc
->bpc_has_vrfname
)
95 snprintf(addr
[2], sizeof(addr
[2]), " vrf:%s", bpc
->bpc_vrfname
);
97 if (bpc
->bpc_has_recvinterval
)
98 snprintfrr(timers
[0], sizeof(timers
[0]), " rx:%" PRIu64
,
99 bpc
->bpc_recvinterval
);
101 if (bpc
->bpc_has_txinterval
)
102 snprintfrr(timers
[1], sizeof(timers
[1]), " tx:%" PRIu64
,
103 bpc
->bpc_recvinterval
);
105 if (bpc
->bpc_has_detectmultiplier
)
106 snprintf(timers
[2], sizeof(timers
[2]), " detect-multiplier:%d",
107 bpc
->bpc_detectmultiplier
);
109 snprintf(cbit_str
, sizeof(cbit_str
), " cbit:0x%02x", bpc
->bpc_cbit
);
111 if (bpc
->bpc_has_minimum_ttl
)
112 snprintf(minttl_str
, sizeof(minttl_str
), " minimum-ttl:%d",
113 bpc
->bpc_minimum_ttl
);
115 if (bpc
->bpc_has_profile
)
116 snprintf(profile
, sizeof(profile
), " profile:%s",
120 vsnprintf(msgbuf
, sizeof(msgbuf
), fmt
, vl
);
123 zlog_debug("%s [mhop:%s %s%s%s%s%s%s%s%s%s]", msgbuf
,
124 bpc
->bpc_mhop
? "yes" : "no", addr
[0], addr
[1], addr
[2],
125 timers
[0], timers
[1], timers
[2], cbit_str
, minttl_str
,
129 static void _ptm_bfd_session_del(struct bfd_session
*bs
, uint8_t diag
)
131 if (bglobal
.debug_peer_event
)
132 zlog_debug("session-delete: %s", bs_to_string(bs
));
134 /* Change state and notify peer. */
135 bs
->ses_state
= PTM_BFD_DOWN
;
136 bs
->local_diag
= diag
;
139 /* Session reached refcount == 0, lets delete it. */
140 if (bs
->refcount
== 0) {
142 * Sanity check: if there is a refcount bug, we can't delete
143 * the session a user configured manually. Lets leave a
144 * message here so we can catch the bug if it exists.
146 if (CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_CONFIG
)) {
148 "ptm-del-session: [%s] session refcount is zero but it was configured by CLI",
151 control_notify_config(BCM_NOTIFY_CONFIG_DELETE
, bs
);
152 bfd_session_free(bs
);
157 static int _ptm_msg_address(struct stream
*msg
, int family
, const void *addr
)
159 stream_putc(msg
, family
);
163 stream_put(msg
, addr
, sizeof(struct in_addr
));
164 stream_putc(msg
, 32);
168 stream_put(msg
, addr
, sizeof(struct in6_addr
));
169 stream_putc(msg
, 128);
180 int ptm_bfd_notify(struct bfd_session
*bs
, uint8_t notify_state
)
184 bs
->stats
.znotification
++;
188 * - header: command, vrf
189 * - l: interface index
205 * Commands: ZEBRA_BFD_DEST_REPLAY
207 * q(64), l(32), w(16), c(8)
212 /* TODO: VRF handling */
214 zclient_create_header(msg
, ZEBRA_BFD_DEST_REPLAY
, bs
->vrf
->vrf_id
);
216 zclient_create_header(msg
, ZEBRA_BFD_DEST_REPLAY
, VRF_DEFAULT
);
218 /* This header will be handled by `zebra_ptm.c`. */
219 stream_putl(msg
, ZEBRA_INTERFACE_BFD_DEST_UPDATE
);
221 /* NOTE: Interface is a shortcut to avoid comparing source address. */
222 if (!CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_MH
) && bs
->ifp
!= NULL
)
223 stream_putl(msg
, bs
->ifp
->ifindex
);
225 stream_putl(msg
, IFINDEX_INTERNAL
);
227 /* BFD destination prefix information. */
228 _ptm_msg_address(msg
, bs
->key
.family
, &bs
->key
.peer
);
231 switch (notify_state
) {
233 stream_putl(msg
, BFD_STATUS_UP
);
236 case PTM_BFD_ADM_DOWN
:
237 stream_putl(msg
, BFD_STATUS_ADMIN_DOWN
);
242 stream_putl(msg
, BFD_STATUS_DOWN
);
246 stream_putl(msg
, BFD_STATUS_UNKNOWN
);
250 /* BFD source prefix information. */
251 _ptm_msg_address(msg
, bs
->key
.family
, &bs
->key
.local
);
253 stream_putc(msg
, bs
->remote_cbit
);
255 /* Write packet size. */
256 stream_putw_at(msg
, 0, stream_get_endp(msg
));
258 return zclient_send_message(zclient
);
261 static void _ptm_msg_read_address(struct stream
*msg
, struct sockaddr_any
*sa
)
265 STREAM_GETW(msg
, family
);
269 sa
->sa_sin
.sin_family
= family
;
270 STREAM_GET(&sa
->sa_sin
.sin_addr
, msg
,
271 sizeof(sa
->sa_sin
.sin_addr
));
272 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
273 sa
->sa_sin
.sin_len
= sizeof(sa
->sa_sin
);
274 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
278 sa
->sa_sin6
.sin6_family
= family
;
279 STREAM_GET(&sa
->sa_sin6
.sin6_addr
, msg
,
280 sizeof(sa
->sa_sin6
.sin6_addr
));
281 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
282 sa
->sa_sin6
.sin6_len
= sizeof(sa
->sa_sin6
);
283 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
287 zlog_warn("ptm-read-address: invalid family: %d", family
);
292 memset(sa
, 0, sizeof(*sa
));
295 static int _ptm_msg_read(struct stream
*msg
, int command
, vrf_id_t vrf_id
,
296 struct bfd_peer_cfg
*bpc
, struct ptm_client
**pc
)
302 * Register/Deregister/Update Message format:
304 * Old format (being used by PTM BFD).
305 * - header: Command, VRF
309 * - l: destination ipv4
311 * - 16 bytes: destination IPv6
312 * - command != ZEBRA_BFD_DEST_DEREGISTER
315 * - c: detect multiplier
320 * - l: source IPv4 address
322 * - 16 bytes: source IPv6 address
327 * - 16 bytes: source IPv6 address
329 * - X bytes: interface name
332 * - header: Command, VRF
336 * - l: destination IPv4 address
338 * - 16 bytes: destination IPv6 address
341 * - c: detect multiplier
345 * - l: source IPv4 address
347 * - 16 bytes: source IPv6 address
350 * - X bytes: interface name
352 * - c: profile name length.
353 * - X bytes: profile name.
355 * q(64), l(32), w(16), c(8)
358 /* Initialize parameters return values. */
359 memset(bpc
, 0, sizeof(*bpc
));
362 /* Find or allocate process context data. */
363 STREAM_GETL(msg
, pid
);
367 /* Register/update peer information. */
368 _ptm_msg_read_address(msg
, &bpc
->bpc_peer
);
370 /* Determine IP type from peer destination. */
371 bpc
->bpc_ipv4
= (bpc
->bpc_peer
.sa_sin
.sin_family
== AF_INET
);
373 /* Get peer configuration. */
374 STREAM_GETL(msg
, bpc
->bpc_recvinterval
);
375 bpc
->bpc_has_recvinterval
=
376 (bpc
->bpc_recvinterval
!= BPC_DEF_RECEIVEINTERVAL
);
378 STREAM_GETL(msg
, bpc
->bpc_txinterval
);
379 bpc
->bpc_has_txinterval
=
380 (bpc
->bpc_txinterval
!= BPC_DEF_TRANSMITINTERVAL
);
382 STREAM_GETC(msg
, bpc
->bpc_detectmultiplier
);
383 bpc
->bpc_has_detectmultiplier
=
384 (bpc
->bpc_detectmultiplier
!= BPC_DEF_DETECTMULTIPLIER
);
386 /* Read (single|multi)hop and its options. */
387 STREAM_GETC(msg
, bpc
->bpc_mhop
);
389 /* Read multihop source address and TTL. */
390 _ptm_msg_read_address(msg
, &bpc
->bpc_local
);
392 /* Read the minimum TTL (0 means unset or invalid). */
393 STREAM_GETC(msg
, bpc
->bpc_minimum_ttl
);
394 if (bpc
->bpc_minimum_ttl
== 0) {
395 bpc
->bpc_minimum_ttl
= BFD_DEF_MHOP_TTL
;
396 bpc
->bpc_has_minimum_ttl
= false;
398 bpc
->bpc_minimum_ttl
= (BFD_TTL_VAL
+ 1) - bpc
->bpc_minimum_ttl
;
399 bpc
->bpc_has_minimum_ttl
= true;
403 * Read interface name and make sure it fits our data
404 * structure, otherwise fail.
406 STREAM_GETC(msg
, ifnamelen
);
407 if (ifnamelen
>= sizeof(bpc
->bpc_localif
)) {
408 zlog_err("ptm-read: interface name is too big");
412 bpc
->bpc_has_localif
= ifnamelen
> 0;
413 if (bpc
->bpc_has_localif
) {
414 STREAM_GET(bpc
->bpc_localif
, msg
, ifnamelen
);
415 bpc
->bpc_localif
[ifnamelen
] = 0;
418 if (vrf_id
!= VRF_DEFAULT
) {
421 vrf
= vrf_lookup_by_id(vrf_id
);
423 bpc
->bpc_has_vrfname
= true;
424 strlcpy(bpc
->bpc_vrfname
, vrf
->name
, sizeof(bpc
->bpc_vrfname
));
426 zlog_err("ptm-read: vrf id %u could not be identified",
431 bpc
->bpc_has_vrfname
= true;
432 strlcpy(bpc
->bpc_vrfname
, VRF_DEFAULT_NAME
, sizeof(bpc
->bpc_vrfname
));
435 /* Read control plane independant configuration. */
436 STREAM_GETC(msg
, bpc
->bpc_cbit
);
438 /* Handle profile names. */
439 STREAM_GETC(msg
, ifnamelen
);
440 bpc
->bpc_has_profile
= ifnamelen
> 0;
441 if (bpc
->bpc_has_profile
) {
442 STREAM_GET(bpc
->bpc_profile
, msg
, ifnamelen
);
443 bpc
->bpc_profile
[ifnamelen
] = 0;
446 /* Sanity check: peer and local address must match IP types. */
447 if (bpc
->bpc_local
.sa_sin
.sin_family
!= AF_UNSPEC
448 && (bpc
->bpc_local
.sa_sin
.sin_family
449 != bpc
->bpc_peer
.sa_sin
.sin_family
)) {
450 zlog_warn("ptm-read: peer family doesn't match local type");
460 static void bfdd_dest_register(struct stream
*msg
, vrf_id_t vrf_id
)
462 struct ptm_client
*pc
;
463 struct bfd_session
*bs
;
464 struct bfd_peer_cfg bpc
;
466 /* Read the client context and peer data. */
467 if (_ptm_msg_read(msg
, ZEBRA_BFD_DEST_REGISTER
, vrf_id
, &bpc
, &pc
) == -1)
470 debug_printbpc(&bpc
, "ptm-add-dest: register peer");
472 /* Find or start new BFD session. */
473 bs
= bs_peer_find(&bpc
);
475 bs
= ptm_bfd_sess_new(&bpc
);
477 if (bglobal
.debug_zebra
)
479 "ptm-add-dest: failed to create BFD session");
484 * BFD session was already created, we are just updating the
487 * `ptm-bfd` (or `HAVE_BFDD == 0`) is the only implementation
488 * that allow users to set peer specific timers via protocol.
489 * BFD daemon (this code) on the other hand only supports
490 * changing peer configuration manually (through `peer` node)
493 if (bpc
.bpc_has_profile
)
494 bfd_profile_apply(bpc
.bpc_profile
, bs
);
497 /* Create client peer notification register. */
500 ptm_bfd_notify(bs
, bs
->ses_state
);
503 static void bfdd_dest_deregister(struct stream
*msg
, vrf_id_t vrf_id
)
505 struct ptm_client
*pc
;
506 struct ptm_client_notification
*pcn
;
507 struct bfd_session
*bs
;
508 struct bfd_peer_cfg bpc
;
510 /* Read the client context and peer data. */
511 if (_ptm_msg_read(msg
, ZEBRA_BFD_DEST_DEREGISTER
, vrf_id
, &bpc
, &pc
) == -1)
514 debug_printbpc(&bpc
, "ptm-del-dest: deregister peer");
516 /* Find or start new BFD session. */
517 bs
= bs_peer_find(&bpc
);
519 if (bglobal
.debug_zebra
)
520 zlog_debug("ptm-del-dest: failed to find BFD session");
524 /* Unregister client peer notification. */
525 pcn
= pcn_lookup(pc
, bs
);
531 if (bglobal
.debug_zebra
)
532 zlog_debug("ptm-del-dest: failed to find BFD session");
535 * XXX: We either got a double deregistration or the daemon who
536 * created this is no longer around. Lets try to delete it anyway
537 * and the worst case is the refcount will detain us.
539 _ptm_bfd_session_del(bs
, BD_NEIGHBOR_DOWN
);
543 * header: command, VRF
546 static void bfdd_client_register(struct stream
*msg
)
550 /* Find or allocate process context data. */
551 STREAM_GETL(msg
, pid
);
558 zlog_err("ptm-add-client: failed to register client");
562 * header: command, VRF
565 static void bfdd_client_deregister(struct stream
*msg
)
567 struct ptm_client
*pc
;
570 /* Find or allocate process context data. */
571 STREAM_GETL(msg
, pid
);
575 if (bglobal
.debug_zebra
)
576 zlog_debug("ptm-del-client: failed to find client: %u",
581 if (bglobal
.debug_zebra
)
582 zlog_debug("ptm-del-client: client pid %u", pid
);
589 zlog_err("ptm-del-client: failed to deregister client");
592 static int bfdd_replay(ZAPI_CALLBACK_ARGS
)
594 struct stream
*msg
= zclient
->ibuf
;
597 STREAM_GETL(msg
, rcmd
);
600 case ZEBRA_BFD_DEST_REGISTER
:
601 case ZEBRA_BFD_DEST_UPDATE
:
602 bfdd_dest_register(msg
, vrf_id
);
604 case ZEBRA_BFD_DEST_DEREGISTER
:
605 bfdd_dest_deregister(msg
, vrf_id
);
607 case ZEBRA_BFD_CLIENT_REGISTER
:
608 bfdd_client_register(msg
);
610 case ZEBRA_BFD_CLIENT_DEREGISTER
:
611 bfdd_client_deregister(msg
);
615 if (bglobal
.debug_zebra
)
616 zlog_debug("ptm-replay: invalid message type %u", rcmd
);
623 zlog_err("ptm-replay: failed to find command");
627 static void bfdd_zebra_connected(struct zclient
*zc
)
629 struct stream
*msg
= zc
->obuf
;
631 /* Clean-up and free ptm clients data memory. */
635 * The replay is an empty message just to trigger client daemons
636 * configuration replay.
639 zclient_create_header(msg
, ZEBRA_BFD_DEST_REPLAY
, VRF_DEFAULT
);
640 stream_putl(msg
, ZEBRA_BFD_DEST_REPLAY
);
641 stream_putw_at(msg
, 0, stream_get_endp(msg
));
643 /* Ask for interfaces information. */
644 zclient_create_header(msg
, ZEBRA_INTERFACE_ADD
, VRF_DEFAULT
);
647 zclient_send_message(zclient
);
650 static void bfdd_sessions_enable_interface(struct interface
*ifp
)
652 struct bfd_session_observer
*bso
;
653 struct bfd_session
*bs
;
658 TAILQ_FOREACH(bso
, &bglobal
.bg_obslist
, bso_entry
) {
661 if (bs
->key
.vrfname
[0] &&
662 strcmp(vrf
->name
, bs
->key
.vrfname
))
665 /* If Interface matches vrfname, then bypass iface check */
666 if (vrf_is_backend_netns() || strcmp(ifp
->name
, vrf
->name
)) {
667 /* Interface name mismatch. */
668 if (bs
->key
.ifname
[0] &&
669 strcmp(ifp
->name
, bs
->key
.ifname
))
673 /* Skip enabled sessions. */
677 /* Try to enable it. */
678 bfd_session_enable(bs
);
682 static void bfdd_sessions_disable_interface(struct interface
*ifp
)
684 struct bfd_session_observer
*bso
;
685 struct bfd_session
*bs
;
687 TAILQ_FOREACH(bso
, &bglobal
.bg_obslist
, bso_entry
) {
693 /* Skip disabled sessions. */
694 if (bs
->sock
== -1) {
699 bfd_session_disable(bs
);
704 void bfdd_sessions_enable_vrf(struct vrf
*vrf
)
706 struct bfd_session_observer
*bso
;
707 struct bfd_session
*bs
;
709 /* it may affect configs without interfaces */
710 TAILQ_FOREACH(bso
, &bglobal
.bg_obslist
, bso_entry
) {
714 if (bs
->key
.vrfname
[0] &&
715 strcmp(vrf
->name
, bs
->key
.vrfname
))
717 /* need to update the vrf information on
718 * bs so that callbacks are handled
721 /* Skip enabled sessions. */
724 /* Try to enable it. */
725 bfd_session_enable(bs
);
729 void bfdd_sessions_disable_vrf(struct vrf
*vrf
)
731 struct bfd_session_observer
*bso
;
732 struct bfd_session
*bs
;
734 TAILQ_FOREACH(bso
, &bglobal
.bg_obslist
, bso_entry
) {
736 if (bs
->key
.vrfname
[0] &&
737 strcmp(vrf
->name
, bs
->key
.vrfname
))
739 /* Skip disabled sessions. */
743 bfd_session_disable(bs
);
748 static int bfd_ifp_destroy(struct interface
*ifp
)
750 if (bglobal
.debug_zebra
)
751 zlog_debug("zclient: delete interface %s (VRF %s(%u))",
752 ifp
->name
, ifp
->vrf
->name
, ifp
->vrf
->vrf_id
);
754 bfdd_sessions_disable_interface(ifp
);
759 static int bfdd_interface_vrf_update(ZAPI_CALLBACK_ARGS
)
761 struct interface
*ifp
;
764 ifp
= zebra_interface_vrf_update_read(zclient
->ibuf
, vrf_id
, &nvrfid
);
768 if_update_to_new_vrf(ifp
, nvrfid
);
773 static void bfdd_sessions_enable_address(struct connected
*ifc
)
775 struct bfd_session_observer
*bso
;
776 struct bfd_session
*bs
;
777 struct prefix prefix
;
779 TAILQ_FOREACH(bso
, &bglobal
.bg_obslist
, bso_entry
) {
780 /* Skip enabled sessions. */
786 prefix
= bso
->bso_addr
;
787 prefix
.prefixlen
= ifc
->address
->prefixlen
;
788 if (prefix_cmp(&prefix
, ifc
->address
))
791 /* Try to enable it. */
792 bfd_session_enable(bs
);
796 static int bfdd_interface_address_update(ZAPI_CALLBACK_ARGS
)
798 struct connected
*ifc
;
800 ifc
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
804 if (bglobal
.debug_zebra
)
805 zlog_debug("zclient: %s local address %pFX (VRF %u)",
806 cmd
== ZEBRA_INTERFACE_ADDRESS_ADD
? "add"
808 ifc
->address
, vrf_id
);
810 if (cmd
== ZEBRA_INTERFACE_ADDRESS_ADD
)
811 bfdd_sessions_enable_address(ifc
);
813 connected_free(&ifc
);
818 static int bfd_ifp_create(struct interface
*ifp
)
820 if (bglobal
.debug_zebra
)
821 zlog_debug("zclient: add interface %s (VRF %s(%u))", ifp
->name
,
822 ifp
->vrf
->name
, ifp
->vrf
->vrf_id
);
823 bfdd_sessions_enable_interface(ifp
);
828 static zclient_handler
*const bfd_handlers
[] = {
830 * We'll receive all messages through replay, however it will
831 * contain a special field with the real command inside so we
832 * avoid having to create too many handlers.
834 [ZEBRA_BFD_DEST_REPLAY
] = bfdd_replay
,
836 /* Learn about interface VRF. */
837 [ZEBRA_INTERFACE_VRF_UPDATE
] = bfdd_interface_vrf_update
,
839 /* Learn about new addresses being registered. */
840 [ZEBRA_INTERFACE_ADDRESS_ADD
] = bfdd_interface_address_update
,
841 [ZEBRA_INTERFACE_ADDRESS_DELETE
] = bfdd_interface_address_update
,
844 void bfdd_zclient_init(struct zebra_privs_t
*bfdd_priv
)
846 if_zapi_callbacks(bfd_ifp_create
, NULL
, NULL
, bfd_ifp_destroy
);
847 zclient
= zclient_new(master
, &zclient_options_default
, bfd_handlers
,
848 array_size(bfd_handlers
));
849 assert(zclient
!= NULL
);
850 zclient_init(zclient
, ZEBRA_ROUTE_BFD
, 0, bfdd_priv
);
852 /* Send replay request on zebra connect. */
853 zclient
->zebra_connected
= bfdd_zebra_connected
;
856 void bfdd_zclient_register(vrf_id_t vrf_id
)
858 if (!zclient
|| zclient
->sock
< 0)
860 zclient_send_reg_requests(zclient
, vrf_id
);
863 void bfdd_zclient_unregister(vrf_id_t vrf_id
)
865 if (!zclient
|| zclient
->sock
< 0)
867 zclient_send_dereg_requests(zclient
, vrf_id
);
870 void bfdd_zclient_stop(void)
872 zclient_stop(zclient
);
874 /* Clean-up and free ptm clients data memory. */
882 static struct ptm_client
*pc_lookup(uint32_t pid
)
884 struct ptm_client
*pc
;
886 TAILQ_FOREACH (pc
, &pcqueue
, pc_entry
) {
887 if (pc
->pc_pid
!= pid
)
896 static struct ptm_client
*pc_new(uint32_t pid
)
898 struct ptm_client
*pc
;
900 /* Look up first, if not found create the client. */
905 /* Allocate the client data and save it. */
906 pc
= XCALLOC(MTYPE_BFDD_CONTROL
, sizeof(*pc
));
909 TAILQ_INSERT_HEAD(&pcqueue
, pc
, pc_entry
);
913 static void pc_free(struct ptm_client
*pc
)
915 struct ptm_client_notification
*pcn
;
917 TAILQ_REMOVE(&pcqueue
, pc
, pc_entry
);
919 while (!TAILQ_EMPTY(&pc
->pc_pcnqueue
)) {
920 pcn
= TAILQ_FIRST(&pc
->pc_pcnqueue
);
924 XFREE(MTYPE_BFDD_CONTROL
, pc
);
927 static void pc_free_all(void)
929 struct ptm_client
*pc
;
931 while (!TAILQ_EMPTY(&pcqueue
)) {
932 pc
= TAILQ_FIRST(&pcqueue
);
937 static struct ptm_client_notification
*pcn_new(struct ptm_client
*pc
,
938 struct bfd_session
*bs
)
940 struct ptm_client_notification
*pcn
;
942 /* Try to find an existing pcn fist. */
943 pcn
= pcn_lookup(pc
, bs
);
947 /* Save the client notification data. */
948 pcn
= XCALLOC(MTYPE_BFDD_NOTIFICATION
, sizeof(*pcn
));
950 TAILQ_INSERT_HEAD(&pc
->pc_pcnqueue
, pcn
, pcn_entry
);
958 static struct ptm_client_notification
*pcn_lookup(struct ptm_client
*pc
,
959 struct bfd_session
*bs
)
961 struct ptm_client_notification
*pcn
;
963 TAILQ_FOREACH (pcn
, &pc
->pc_pcnqueue
, pcn_entry
) {
964 if (pcn
->pcn_bs
!= bs
)
973 static void pcn_free(struct ptm_client_notification
*pcn
)
975 struct ptm_client
*pc
;
976 struct bfd_session
*bs
;
978 /* Handle session de-registration. */
983 /* Log modification to users. */
984 if (bglobal
.debug_zebra
)
985 zlog_debug("ptm-del-session: [%s] refcount=%" PRIu64
,
986 bs_to_string(bs
), bs
->refcount
);
988 /* Set session down. */
989 _ptm_bfd_session_del(bs
, BD_NEIGHBOR_DOWN
);
991 /* Handle ptm_client deregistration. */
994 TAILQ_REMOVE(&pc
->pc_pcnqueue
, pcn
, pcn_entry
);
996 XFREE(MTYPE_BFDD_NOTIFICATION
, pcn
);