3 * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
5 * FRR is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2, or (at your option) any
10 * FRR 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 FRR; see the file COPYING. If not, write to the Free
17 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23 #include "lib/libfrr.h"
24 #include "lib/queue.h"
25 #include "lib/stream.h"
26 #include "lib/zclient.h"
27 #include "lib/printfrr.h"
36 struct ptm_client_notification
{
37 struct bfd_session
*pcn_bs
;
38 struct ptm_client
*pcn_pc
;
40 TAILQ_ENTRY(ptm_client_notification
) pcn_entry
;
42 TAILQ_HEAD(pcnqueue
, ptm_client_notification
);
46 struct pcnqueue pc_pcnqueue
;
48 TAILQ_ENTRY(ptm_client
) pc_entry
;
50 TAILQ_HEAD(pcqueue
, ptm_client
);
52 static struct pcqueue pcqueue
;
53 static struct zclient
*zclient
;
59 static int _ptm_msg_address(struct stream
*msg
, int family
, const void *addr
);
61 static void _ptm_msg_read_address(struct stream
*msg
, struct sockaddr_any
*sa
);
62 static int _ptm_msg_read(struct stream
*msg
, int command
, vrf_id_t vrf_id
,
63 struct bfd_peer_cfg
*bpc
, struct ptm_client
**pc
);
65 static struct ptm_client
*pc_lookup(uint32_t pid
);
66 static struct ptm_client
*pc_new(uint32_t pid
);
67 static void pc_free(struct ptm_client
*pc
);
68 static void pc_free_all(void);
69 static struct ptm_client_notification
*pcn_new(struct ptm_client
*pc
,
70 struct bfd_session
*bs
);
71 static struct ptm_client_notification
*pcn_lookup(struct ptm_client
*pc
,
72 struct bfd_session
*bs
);
73 static void pcn_free(struct ptm_client_notification
*pcn
);
76 static void bfdd_dest_register(struct stream
*msg
, vrf_id_t vrf_id
);
77 static void bfdd_dest_deregister(struct stream
*msg
, vrf_id_t vrf_id
);
78 static void bfdd_client_register(struct stream
*msg
);
79 static void bfdd_client_deregister(struct stream
*msg
);
84 static void debug_printbpc(const struct bfd_peer_cfg
*bpc
, const char *fmt
, ...)
86 char timers
[3][128] = {};
87 char minttl_str
[32] = {};
88 char addr
[3][128] = {};
89 char profile
[128] = {};
94 /* Avoid debug calculations if it's disabled. */
95 if (bglobal
.debug_zebra
== false)
98 snprintf(addr
[0], sizeof(addr
[0]), "peer:%s", satostr(&bpc
->bpc_peer
));
99 if (bpc
->bpc_local
.sa_sin
.sin_family
)
100 snprintf(addr
[1], sizeof(addr
[1]), " local:%s",
101 satostr(&bpc
->bpc_local
));
103 if (bpc
->bpc_has_localif
)
104 snprintf(addr
[2], sizeof(addr
[2]), " ifname:%s",
107 if (bpc
->bpc_has_vrfname
)
108 snprintf(addr
[2], sizeof(addr
[2]), " vrf:%s", bpc
->bpc_vrfname
);
110 if (bpc
->bpc_has_recvinterval
)
111 snprintfrr(timers
[0], sizeof(timers
[0]), " rx:%" PRIu64
,
112 bpc
->bpc_recvinterval
);
114 if (bpc
->bpc_has_txinterval
)
115 snprintfrr(timers
[1], sizeof(timers
[1]), " tx:%" PRIu64
,
116 bpc
->bpc_recvinterval
);
118 if (bpc
->bpc_has_detectmultiplier
)
119 snprintf(timers
[2], sizeof(timers
[2]), " detect-multiplier:%d",
120 bpc
->bpc_detectmultiplier
);
122 snprintf(cbit_str
, sizeof(cbit_str
), " cbit:0x%02x", bpc
->bpc_cbit
);
124 if (bpc
->bpc_has_minimum_ttl
)
125 snprintf(minttl_str
, sizeof(minttl_str
), " minimum-ttl:%d",
126 bpc
->bpc_minimum_ttl
);
128 if (bpc
->bpc_has_profile
)
129 snprintf(profile
, sizeof(profile
), " profile:%s",
133 vsnprintf(msgbuf
, sizeof(msgbuf
), fmt
, vl
);
136 zlog_debug("%s [mhop:%s %s%s%s%s%s%s%s%s%s]", msgbuf
,
137 bpc
->bpc_mhop
? "yes" : "no", addr
[0], addr
[1], addr
[2],
138 timers
[0], timers
[1], timers
[2], cbit_str
, minttl_str
,
142 static void _ptm_bfd_session_del(struct bfd_session
*bs
, uint8_t diag
)
144 if (bglobal
.debug_peer_event
)
145 zlog_debug("session-delete: %s", bs_to_string(bs
));
147 /* Change state and notify peer. */
148 bs
->ses_state
= PTM_BFD_DOWN
;
149 bs
->local_diag
= diag
;
152 /* Session reached refcount == 0, lets delete it. */
153 if (bs
->refcount
== 0) {
155 * Sanity check: if there is a refcount bug, we can't delete
156 * the session a user configured manually. Lets leave a
157 * message here so we can catch the bug if it exists.
159 if (CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_CONFIG
)) {
161 "ptm-del-session: [%s] session refcount is zero but it was configured by CLI",
164 control_notify_config(BCM_NOTIFY_CONFIG_DELETE
, bs
);
165 bfd_session_free(bs
);
170 static int _ptm_msg_address(struct stream
*msg
, int family
, const void *addr
)
172 stream_putc(msg
, family
);
176 stream_put(msg
, addr
, sizeof(struct in_addr
));
177 stream_putc(msg
, 32);
181 stream_put(msg
, addr
, sizeof(struct in6_addr
));
182 stream_putc(msg
, 128);
193 int ptm_bfd_notify(struct bfd_session
*bs
, uint8_t notify_state
)
197 bs
->stats
.znotification
++;
201 * - header: command, vrf
202 * - l: interface index
218 * Commands: ZEBRA_BFD_DEST_REPLAY
220 * q(64), l(32), w(16), c(8)
225 /* TODO: VRF handling */
227 zclient_create_header(msg
, ZEBRA_BFD_DEST_REPLAY
, bs
->vrf
->vrf_id
);
229 zclient_create_header(msg
, ZEBRA_BFD_DEST_REPLAY
, VRF_DEFAULT
);
231 /* This header will be handled by `zebra_ptm.c`. */
232 stream_putl(msg
, ZEBRA_INTERFACE_BFD_DEST_UPDATE
);
234 /* NOTE: Interface is a shortcut to avoid comparing source address. */
236 stream_putl(msg
, bs
->ifp
->ifindex
);
238 stream_putl(msg
, IFINDEX_INTERNAL
);
240 /* BFD destination prefix information. */
241 _ptm_msg_address(msg
, bs
->key
.family
, &bs
->key
.peer
);
244 switch (notify_state
) {
246 stream_putl(msg
, BFD_STATUS_UP
);
249 case PTM_BFD_ADM_DOWN
:
250 stream_putl(msg
, BFD_STATUS_ADMIN_DOWN
);
255 stream_putl(msg
, BFD_STATUS_DOWN
);
259 stream_putl(msg
, BFD_STATUS_UNKNOWN
);
263 /* BFD source prefix information. */
264 _ptm_msg_address(msg
, bs
->key
.family
, &bs
->key
.local
);
266 stream_putc(msg
, bs
->remote_cbit
);
268 /* Write packet size. */
269 stream_putw_at(msg
, 0, stream_get_endp(msg
));
271 return zclient_send_message(zclient
);
274 static void _ptm_msg_read_address(struct stream
*msg
, struct sockaddr_any
*sa
)
278 STREAM_GETW(msg
, family
);
282 sa
->sa_sin
.sin_family
= family
;
283 STREAM_GET(&sa
->sa_sin
.sin_addr
, msg
,
284 sizeof(sa
->sa_sin
.sin_addr
));
285 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
286 sa
->sa_sin
.sin_len
= sizeof(sa
->sa_sin
);
287 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
291 sa
->sa_sin6
.sin6_family
= family
;
292 STREAM_GET(&sa
->sa_sin6
.sin6_addr
, msg
,
293 sizeof(sa
->sa_sin6
.sin6_addr
));
294 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
295 sa
->sa_sin6
.sin6_len
= sizeof(sa
->sa_sin6
);
296 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
300 zlog_warn("ptm-read-address: invalid family: %d", family
);
305 memset(sa
, 0, sizeof(*sa
));
308 static int _ptm_msg_read(struct stream
*msg
, int command
, vrf_id_t vrf_id
,
309 struct bfd_peer_cfg
*bpc
, struct ptm_client
**pc
)
315 * Register/Deregister/Update Message format:
317 * Old format (being used by PTM BFD).
318 * - header: Command, VRF
322 * - l: destination ipv4
324 * - 16 bytes: destination IPv6
325 * - command != ZEBRA_BFD_DEST_DEREGISTER
328 * - c: detect multiplier
333 * - l: source IPv4 address
335 * - 16 bytes: source IPv6 address
340 * - 16 bytes: source IPv6 address
342 * - X bytes: interface name
345 * - header: Command, VRF
349 * - l: destination IPv4 address
351 * - 16 bytes: destination IPv6 address
354 * - c: detect multiplier
358 * - l: source IPv4 address
360 * - 16 bytes: source IPv6 address
363 * - X bytes: interface name
365 * - c: profile name length.
366 * - X bytes: profile name.
368 * q(64), l(32), w(16), c(8)
371 /* Initialize parameters return values. */
372 memset(bpc
, 0, sizeof(*bpc
));
375 /* Find or allocate process context data. */
376 STREAM_GETL(msg
, pid
);
380 /* Register/update peer information. */
381 _ptm_msg_read_address(msg
, &bpc
->bpc_peer
);
383 /* Determine IP type from peer destination. */
384 bpc
->bpc_ipv4
= (bpc
->bpc_peer
.sa_sin
.sin_family
== AF_INET
);
386 /* Get peer configuration. */
387 STREAM_GETL(msg
, bpc
->bpc_recvinterval
);
388 bpc
->bpc_has_recvinterval
=
389 (bpc
->bpc_recvinterval
!= BPC_DEF_RECEIVEINTERVAL
);
391 STREAM_GETL(msg
, bpc
->bpc_txinterval
);
392 bpc
->bpc_has_txinterval
=
393 (bpc
->bpc_txinterval
!= BPC_DEF_TRANSMITINTERVAL
);
395 STREAM_GETC(msg
, bpc
->bpc_detectmultiplier
);
396 bpc
->bpc_has_detectmultiplier
=
397 (bpc
->bpc_detectmultiplier
!= BPC_DEF_DETECTMULTIPLIER
);
399 /* Read (single|multi)hop and its options. */
400 STREAM_GETC(msg
, bpc
->bpc_mhop
);
402 /* Read multihop source address and TTL. */
403 _ptm_msg_read_address(msg
, &bpc
->bpc_local
);
405 /* Read the minimum TTL (0 means unset or invalid). */
406 STREAM_GETC(msg
, bpc
->bpc_minimum_ttl
);
407 if (bpc
->bpc_minimum_ttl
== 0) {
408 bpc
->bpc_minimum_ttl
= BFD_DEF_MHOP_TTL
;
409 bpc
->bpc_has_minimum_ttl
= false;
411 bpc
->bpc_minimum_ttl
= (BFD_TTL_VAL
+ 1) - bpc
->bpc_minimum_ttl
;
412 bpc
->bpc_has_minimum_ttl
= true;
416 * Read interface name and make sure it fits our data
417 * structure, otherwise fail.
419 STREAM_GETC(msg
, ifnamelen
);
420 if (ifnamelen
>= sizeof(bpc
->bpc_localif
)) {
421 zlog_err("ptm-read: interface name is too big");
425 bpc
->bpc_has_localif
= ifnamelen
> 0;
426 if (bpc
->bpc_has_localif
) {
427 STREAM_GET(bpc
->bpc_localif
, msg
, ifnamelen
);
428 bpc
->bpc_localif
[ifnamelen
] = 0;
431 if (vrf_id
!= VRF_DEFAULT
) {
434 vrf
= vrf_lookup_by_id(vrf_id
);
436 bpc
->bpc_has_vrfname
= true;
437 strlcpy(bpc
->bpc_vrfname
, vrf
->name
, sizeof(bpc
->bpc_vrfname
));
439 zlog_err("ptm-read: vrf id %u could not be identified",
444 bpc
->bpc_has_vrfname
= true;
445 strlcpy(bpc
->bpc_vrfname
, VRF_DEFAULT_NAME
, sizeof(bpc
->bpc_vrfname
));
448 /* Read control plane independant configuration. */
449 STREAM_GETC(msg
, bpc
->bpc_cbit
);
451 /* Handle profile names. */
452 STREAM_GETC(msg
, ifnamelen
);
453 bpc
->bpc_has_profile
= ifnamelen
> 0;
454 if (bpc
->bpc_has_profile
) {
455 STREAM_GET(bpc
->bpc_profile
, msg
, ifnamelen
);
456 bpc
->bpc_profile
[ifnamelen
] = 0;
459 /* Sanity check: peer and local address must match IP types. */
460 if (bpc
->bpc_local
.sa_sin
.sin_family
!= 0
461 && (bpc
->bpc_local
.sa_sin
.sin_family
462 != bpc
->bpc_peer
.sa_sin
.sin_family
)) {
463 zlog_warn("ptm-read: peer family doesn't match local type");
473 static void bfdd_dest_register(struct stream
*msg
, vrf_id_t vrf_id
)
475 struct ptm_client
*pc
;
476 struct bfd_session
*bs
;
477 struct bfd_peer_cfg bpc
;
479 /* Read the client context and peer data. */
480 if (_ptm_msg_read(msg
, ZEBRA_BFD_DEST_REGISTER
, vrf_id
, &bpc
, &pc
) == -1)
483 debug_printbpc(&bpc
, "ptm-add-dest: register peer");
485 /* Find or start new BFD session. */
486 bs
= bs_peer_find(&bpc
);
488 bs
= ptm_bfd_sess_new(&bpc
);
490 if (bglobal
.debug_zebra
)
492 "ptm-add-dest: failed to create BFD session");
496 /* Protocol created peers are 'no shutdown' by default. */
497 bs
->peer_profile
.admin_shutdown
= false;
500 * BFD session was already created, we are just updating the
503 * `ptm-bfd` (or `HAVE_BFDD == 0`) is the only implementation
504 * that allow users to set peer specific timers via protocol.
505 * BFD daemon (this code) on the other hand only supports
506 * changing peer configuration manually (through `peer` node)
509 if (bpc
.bpc_has_profile
)
510 bfd_profile_apply(bpc
.bpc_profile
, bs
);
513 /* Create client peer notification register. */
516 ptm_bfd_notify(bs
, bs
->ses_state
);
519 static void bfdd_dest_deregister(struct stream
*msg
, vrf_id_t vrf_id
)
521 struct ptm_client
*pc
;
522 struct ptm_client_notification
*pcn
;
523 struct bfd_session
*bs
;
524 struct bfd_peer_cfg bpc
;
526 /* Read the client context and peer data. */
527 if (_ptm_msg_read(msg
, ZEBRA_BFD_DEST_DEREGISTER
, vrf_id
, &bpc
, &pc
) == -1)
530 debug_printbpc(&bpc
, "ptm-del-dest: deregister peer");
532 /* Find or start new BFD session. */
533 bs
= bs_peer_find(&bpc
);
535 if (bglobal
.debug_zebra
)
536 zlog_debug("ptm-del-dest: failed to find BFD session");
540 /* Unregister client peer notification. */
541 pcn
= pcn_lookup(pc
, bs
);
547 if (bglobal
.debug_zebra
)
548 zlog_debug("ptm-del-dest: failed to find BFD session");
551 * XXX: We either got a double deregistration or the daemon who
552 * created this is no longer around. Lets try to delete it anyway
553 * and the worst case is the refcount will detain us.
555 _ptm_bfd_session_del(bs
, BD_NEIGHBOR_DOWN
);
559 * header: command, VRF
562 static void bfdd_client_register(struct stream
*msg
)
566 /* Find or allocate process context data. */
567 STREAM_GETL(msg
, pid
);
574 zlog_err("ptm-add-client: failed to register client");
578 * header: command, VRF
581 static void bfdd_client_deregister(struct stream
*msg
)
583 struct ptm_client
*pc
;
586 /* Find or allocate process context data. */
587 STREAM_GETL(msg
, pid
);
591 if (bglobal
.debug_zebra
)
592 zlog_debug("ptm-del-client: failed to find client: %u",
597 if (bglobal
.debug_zebra
)
598 zlog_debug("ptm-del-client: client pid %u", pid
);
605 zlog_err("ptm-del-client: failed to deregister client");
608 static int bfdd_replay(ZAPI_CALLBACK_ARGS
)
610 struct stream
*msg
= zclient
->ibuf
;
613 STREAM_GETL(msg
, rcmd
);
616 case ZEBRA_BFD_DEST_REGISTER
:
617 case ZEBRA_BFD_DEST_UPDATE
:
618 bfdd_dest_register(msg
, vrf_id
);
620 case ZEBRA_BFD_DEST_DEREGISTER
:
621 bfdd_dest_deregister(msg
, vrf_id
);
623 case ZEBRA_BFD_CLIENT_REGISTER
:
624 bfdd_client_register(msg
);
626 case ZEBRA_BFD_CLIENT_DEREGISTER
:
627 bfdd_client_deregister(msg
);
631 if (bglobal
.debug_zebra
)
632 zlog_debug("ptm-replay: invalid message type %u", rcmd
);
639 zlog_err("ptm-replay: failed to find command");
643 static void bfdd_zebra_connected(struct zclient
*zc
)
645 struct stream
*msg
= zc
->obuf
;
647 /* Clean-up and free ptm clients data memory. */
651 * The replay is an empty message just to trigger client daemons
652 * configuration replay.
655 zclient_create_header(msg
, ZEBRA_BFD_DEST_REPLAY
, VRF_DEFAULT
);
656 stream_putl(msg
, ZEBRA_BFD_DEST_REPLAY
);
657 stream_putw_at(msg
, 0, stream_get_endp(msg
));
659 /* Ask for interfaces information. */
660 zclient_create_header(msg
, ZEBRA_INTERFACE_ADD
, VRF_DEFAULT
);
663 zclient_send_message(zclient
);
666 static void bfdd_sessions_enable_interface(struct interface
*ifp
)
668 struct bfd_session_observer
*bso
;
669 struct bfd_session
*bs
;
672 vrf
= vrf_lookup_by_id(ifp
->vrf_id
);
676 TAILQ_FOREACH(bso
, &bglobal
.bg_obslist
, bso_entry
) {
679 if (bs
->key
.vrfname
[0] &&
680 strcmp(vrf
->name
, bs
->key
.vrfname
))
683 /* If Interface matches vrfname, then bypass iface check */
684 if (vrf_is_backend_netns() || strcmp(ifp
->name
, vrf
->name
)) {
685 /* Interface name mismatch. */
686 if (strcmp(ifp
->name
, bs
->key
.ifname
))
690 /* Skip enabled sessions. */
694 /* Try to enable it. */
695 bfd_session_enable(bs
);
699 static void bfdd_sessions_disable_interface(struct interface
*ifp
)
701 struct bfd_session_observer
*bso
;
702 struct bfd_session
*bs
;
704 TAILQ_FOREACH(bso
, &bglobal
.bg_obslist
, bso_entry
) {
706 if (strcmp(ifp
->name
, bs
->key
.ifname
))
708 /* Skip disabled sessions. */
712 bfd_session_disable(bs
);
717 void bfdd_sessions_enable_vrf(struct vrf
*vrf
)
719 struct bfd_session_observer
*bso
;
720 struct bfd_session
*bs
;
722 /* it may affect configs without interfaces */
723 TAILQ_FOREACH(bso
, &bglobal
.bg_obslist
, bso_entry
) {
726 if (bs
->vrf
&& bs
->vrf
== vrf
) {
727 if (!strmatch(bs
->key
.vrfname
, vrf
->name
))
728 bfd_session_update_vrf_name(bs
, vrf
);
732 if (bs
->key
.vrfname
[0] &&
733 strcmp(vrf
->name
, bs
->key
.vrfname
))
735 /* need to update the vrf information on
736 * bs so that callbacks are handled
739 /* Skip enabled sessions. */
742 /* Try to enable it. */
743 bfd_session_enable(bs
);
747 void bfdd_sessions_disable_vrf(struct vrf
*vrf
)
749 struct bfd_session_observer
*bso
;
750 struct bfd_session
*bs
;
752 TAILQ_FOREACH(bso
, &bglobal
.bg_obslist
, bso_entry
) {
754 if (bs
->key
.vrfname
[0] &&
755 strcmp(vrf
->name
, bs
->key
.vrfname
))
757 /* Skip disabled sessions. */
761 bfd_session_disable(bs
);
766 static int bfd_ifp_destroy(struct interface
*ifp
)
768 if (bglobal
.debug_zebra
)
769 zlog_debug("zclient: delete interface %s (VRF %u)", ifp
->name
,
772 bfdd_sessions_disable_interface(ifp
);
777 static int bfdd_interface_vrf_update(ZAPI_CALLBACK_ARGS
)
779 struct interface
*ifp
;
782 ifp
= zebra_interface_vrf_update_read(zclient
->ibuf
, vrf_id
, &nvrfid
);
786 if_update_to_new_vrf(ifp
, nvrfid
);
791 static void bfdd_sessions_enable_address(struct connected
*ifc
)
793 struct bfd_session_observer
*bso
;
794 struct bfd_session
*bs
;
795 struct prefix prefix
;
797 TAILQ_FOREACH(bso
, &bglobal
.bg_obslist
, bso_entry
) {
798 /* Skip enabled sessions. */
804 prefix
= bso
->bso_addr
;
805 prefix
.prefixlen
= ifc
->address
->prefixlen
;
806 if (prefix_cmp(&prefix
, ifc
->address
))
809 /* Try to enable it. */
810 bfd_session_enable(bs
);
814 static int bfdd_interface_address_update(ZAPI_CALLBACK_ARGS
)
816 struct connected
*ifc
;
818 ifc
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
822 if (bglobal
.debug_zebra
)
823 zlog_debug("zclient: %s local address %pFX (VRF %u)",
824 cmd
== ZEBRA_INTERFACE_ADDRESS_ADD
? "add"
826 ifc
->address
, vrf_id
);
828 if (cmd
== ZEBRA_INTERFACE_ADDRESS_ADD
)
829 bfdd_sessions_enable_address(ifc
);
831 connected_free(&ifc
);
836 static int bfd_ifp_create(struct interface
*ifp
)
838 if (bglobal
.debug_zebra
)
839 zlog_debug("zclient: add interface %s (VRF %u)", ifp
->name
,
841 bfdd_sessions_enable_interface(ifp
);
846 void bfdd_zclient_init(struct zebra_privs_t
*bfdd_priv
)
848 if_zapi_callbacks(bfd_ifp_create
, NULL
, NULL
, bfd_ifp_destroy
);
849 zclient
= zclient_new(master
, &zclient_options_default
);
850 assert(zclient
!= NULL
);
851 zclient_init(zclient
, ZEBRA_ROUTE_BFD
, 0, bfdd_priv
);
854 * We'll receive all messages through replay, however it will
855 * contain a special field with the real command inside so we
856 * avoid having to create too many handlers.
858 zclient
->bfd_dest_replay
= bfdd_replay
;
860 /* Send replay request on zebra connect. */
861 zclient
->zebra_connected
= bfdd_zebra_connected
;
863 /* Learn about interface VRF. */
864 zclient
->interface_vrf_update
= bfdd_interface_vrf_update
;
866 /* Learn about new addresses being registered. */
867 zclient
->interface_address_add
= bfdd_interface_address_update
;
868 zclient
->interface_address_delete
= bfdd_interface_address_update
;
871 void bfdd_zclient_register(vrf_id_t vrf_id
)
873 if (!zclient
|| zclient
->sock
< 0)
875 zclient_send_reg_requests(zclient
, vrf_id
);
878 void bfdd_zclient_unregister(vrf_id_t vrf_id
)
880 if (!zclient
|| zclient
->sock
< 0)
882 zclient_send_dereg_requests(zclient
, vrf_id
);
885 void bfdd_zclient_stop(void)
887 zclient_stop(zclient
);
889 /* Clean-up and free ptm clients data memory. */
897 static struct ptm_client
*pc_lookup(uint32_t pid
)
899 struct ptm_client
*pc
;
901 TAILQ_FOREACH (pc
, &pcqueue
, pc_entry
) {
902 if (pc
->pc_pid
!= pid
)
911 static struct ptm_client
*pc_new(uint32_t pid
)
913 struct ptm_client
*pc
;
915 /* Look up first, if not found create the client. */
920 /* Allocate the client data and save it. */
921 pc
= XCALLOC(MTYPE_BFDD_CONTROL
, sizeof(*pc
));
924 TAILQ_INSERT_HEAD(&pcqueue
, pc
, pc_entry
);
928 static void pc_free(struct ptm_client
*pc
)
930 struct ptm_client_notification
*pcn
;
932 TAILQ_REMOVE(&pcqueue
, pc
, pc_entry
);
934 while (!TAILQ_EMPTY(&pc
->pc_pcnqueue
)) {
935 pcn
= TAILQ_FIRST(&pc
->pc_pcnqueue
);
939 XFREE(MTYPE_BFDD_CONTROL
, pc
);
942 static void pc_free_all(void)
944 struct ptm_client
*pc
;
946 while (!TAILQ_EMPTY(&pcqueue
)) {
947 pc
= TAILQ_FIRST(&pcqueue
);
952 static struct ptm_client_notification
*pcn_new(struct ptm_client
*pc
,
953 struct bfd_session
*bs
)
955 struct ptm_client_notification
*pcn
;
957 /* Try to find an existing pcn fist. */
958 pcn
= pcn_lookup(pc
, bs
);
962 /* Save the client notification data. */
963 pcn
= XCALLOC(MTYPE_BFDD_NOTIFICATION
, sizeof(*pcn
));
965 TAILQ_INSERT_HEAD(&pc
->pc_pcnqueue
, pcn
, pcn_entry
);
973 static struct ptm_client_notification
*pcn_lookup(struct ptm_client
*pc
,
974 struct bfd_session
*bs
)
976 struct ptm_client_notification
*pcn
;
978 TAILQ_FOREACH (pcn
, &pc
->pc_pcnqueue
, pcn_entry
) {
979 if (pcn
->pcn_bs
!= bs
)
988 static void pcn_free(struct ptm_client_notification
*pcn
)
990 struct ptm_client
*pc
;
991 struct bfd_session
*bs
;
993 /* Handle session de-registration. */
998 /* Log modification to users. */
999 if (bglobal
.debug_zebra
)
1000 zlog_debug("ptm-del-session: [%s] refcount=%" PRIu64
,
1001 bs_to_string(bs
), bs
->refcount
);
1003 /* Set session down. */
1004 _ptm_bfd_session_del(bs
, BD_NEIGHBOR_DOWN
);
1006 /* Handle ptm_client deregistration. */
1009 TAILQ_REMOVE(&pc
->pc_pcnqueue
, pcn
, pcn_entry
);
1011 XFREE(MTYPE_BFDD_NOTIFICATION
, pcn
);