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"
35 struct ptm_client_notification
{
36 struct bfd_session
*pcn_bs
;
37 struct ptm_client
*pcn_pc
;
39 TAILQ_ENTRY(ptm_client_notification
) pcn_entry
;
41 TAILQ_HEAD(pcnqueue
, ptm_client_notification
);
45 struct pcnqueue pc_pcnqueue
;
47 TAILQ_ENTRY(ptm_client
) pc_entry
;
49 TAILQ_HEAD(pcqueue
, ptm_client
);
51 static struct pcqueue pcqueue
;
52 static struct zclient
*zclient
;
58 static int _ptm_msg_address(struct stream
*msg
, int family
, const void *addr
);
60 static void _ptm_msg_read_address(struct stream
*msg
, struct sockaddr_any
*sa
);
61 static int _ptm_msg_read(struct stream
*msg
, int command
, vrf_id_t vrf_id
,
62 struct bfd_peer_cfg
*bpc
, struct ptm_client
**pc
);
64 static struct ptm_client
*pc_lookup(uint32_t pid
);
65 static struct ptm_client
*pc_new(uint32_t pid
);
66 static void pc_free(struct ptm_client
*pc
);
67 static void pc_free_all(void);
68 static struct ptm_client_notification
*pcn_new(struct ptm_client
*pc
,
69 struct bfd_session
*bs
);
70 static struct ptm_client_notification
*pcn_lookup(struct ptm_client
*pc
,
71 struct bfd_session
*bs
);
72 static void pcn_free(struct ptm_client_notification
*pcn
);
75 static void bfdd_dest_register(struct stream
*msg
, vrf_id_t vrf_id
);
76 static void bfdd_dest_deregister(struct stream
*msg
, vrf_id_t vrf_id
);
77 static void bfdd_client_register(struct stream
*msg
);
78 static void bfdd_client_deregister(struct stream
*msg
);
84 static void debug_printbpc(const char *func
, unsigned int line
,
85 struct bfd_peer_cfg
*bpc
);
87 static void debug_printbpc(const char *func
, unsigned int line
,
88 struct bfd_peer_cfg
*bpc
)
94 addr
[0][0] = addr
[1][0] = addr
[2][0] = timers
[0][0] = timers
[1][0] =
97 snprintf(addr
[0], sizeof(addr
[0]), "peer:%s", satostr(&bpc
->bpc_peer
));
98 if (bpc
->bpc_local
.sa_sin
.sin_family
)
99 snprintf(addr
[1], sizeof(addr
[1]), " local:%s",
100 satostr(&bpc
->bpc_local
));
102 if (bpc
->bpc_has_localif
)
103 snprintf(addr
[2], sizeof(addr
[2]), " ifname:%s",
106 if (bpc
->bpc_has_vrfname
)
107 snprintf(addr
[2], sizeof(addr
[2]), " vrf:%s", bpc
->bpc_vrfname
);
109 if (bpc
->bpc_has_recvinterval
)
110 snprintf(timers
[0], sizeof(timers
[0]), " rx:%lu",
111 bpc
->bpc_recvinterval
);
113 if (bpc
->bpc_has_txinterval
)
114 snprintf(timers
[1], sizeof(timers
[1]), " tx:%lu",
115 bpc
->bpc_recvinterval
);
117 if (bpc
->bpc_has_detectmultiplier
)
118 snprintf(timers
[2], sizeof(timers
[2]), " detect-multiplier:%d",
119 bpc
->bpc_detectmultiplier
);
121 sprintf(cbit_str
, "CB %x", bpc
->bpc_cbit
);
123 log_debug("%s:%d: %s %s%s%s%s%s%s %s", func
, line
,
124 bpc
->bpc_mhop
? "multi-hop" : "single-hop", addr
[0], addr
[1],
125 addr
[2], timers
[0], timers
[1], timers
[2], cbit_str
);
128 #define DEBUG_PRINTBPC(bpc) debug_printbpc(__FILE__, __LINE__, (bpc))
130 #define DEBUG_PRINTBPC(bpc)
131 #endif /* BFD_DEBUG */
133 static int _ptm_msg_address(struct stream
*msg
, int family
, const void *addr
)
135 stream_putc(msg
, family
);
139 stream_put(msg
, addr
, sizeof(struct in_addr
));
140 stream_putc(msg
, 32);
144 stream_put(msg
, addr
, sizeof(struct in6_addr
));
145 stream_putc(msg
, 128);
156 int ptm_bfd_notify(struct bfd_session
*bs
, uint8_t notify_state
)
160 bs
->stats
.znotification
++;
164 * - header: command, vrf
165 * - l: interface index
181 * Commands: ZEBRA_BFD_DEST_REPLAY
183 * q(64), l(32), w(16), c(8)
188 /* TODO: VRF handling */
190 zclient_create_header(msg
, ZEBRA_BFD_DEST_REPLAY
, bs
->vrf
->vrf_id
);
192 zclient_create_header(msg
, ZEBRA_BFD_DEST_REPLAY
, VRF_DEFAULT
);
194 /* This header will be handled by `zebra_ptm.c`. */
195 stream_putl(msg
, ZEBRA_INTERFACE_BFD_DEST_UPDATE
);
197 /* NOTE: Interface is a shortcut to avoid comparing source address. */
199 stream_putl(msg
, bs
->ifp
->ifindex
);
201 stream_putl(msg
, IFINDEX_INTERNAL
);
203 /* BFD destination prefix information. */
204 _ptm_msg_address(msg
, bs
->key
.family
, &bs
->key
.peer
);
207 switch (notify_state
) {
209 stream_putl(msg
, BFD_STATUS_UP
);
212 case PTM_BFD_ADM_DOWN
:
213 stream_putl(msg
, BFD_STATUS_ADMIN_DOWN
);
218 stream_putl(msg
, BFD_STATUS_DOWN
);
222 stream_putl(msg
, BFD_STATUS_UNKNOWN
);
226 /* BFD source prefix information. */
227 _ptm_msg_address(msg
, bs
->key
.family
, &bs
->key
.local
);
229 stream_putc(msg
, bs
->remote_cbit
);
231 /* Write packet size. */
232 stream_putw_at(msg
, 0, stream_get_endp(msg
));
234 return zclient_send_message(zclient
);
237 static void _ptm_msg_read_address(struct stream
*msg
, struct sockaddr_any
*sa
)
241 STREAM_GETW(msg
, family
);
245 sa
->sa_sin
.sin_family
= family
;
246 STREAM_GET(&sa
->sa_sin
.sin_addr
, msg
,
247 sizeof(sa
->sa_sin
.sin_addr
));
248 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
249 sa
->sa_sin
.sin_len
= sizeof(sa
->sa_sin
);
250 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
254 sa
->sa_sin6
.sin6_family
= family
;
255 STREAM_GET(&sa
->sa_sin6
.sin6_addr
, msg
,
256 sizeof(sa
->sa_sin6
.sin6_addr
));
257 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
258 sa
->sa_sin6
.sin6_len
= sizeof(sa
->sa_sin6
);
259 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
263 log_warning("ptm-read-address: invalid family: %d", family
);
268 memset(sa
, 0, sizeof(*sa
));
271 static int _ptm_msg_read(struct stream
*msg
, int command
, vrf_id_t vrf_id
,
272 struct bfd_peer_cfg
*bpc
, struct ptm_client
**pc
)
275 uint8_t ttl
__attribute__((unused
));
279 * Register/Deregister/Update Message format:
280 * - header: Command, VRF
284 * - l: destination ipv4
286 * - 16 bytes: destination IPv6
287 * - command != ZEBRA_BFD_DEST_DEREGISTER
290 * - c: detect multiplier
295 * - l: destination ipv4
297 * - 16 bytes: destination IPv6
302 * - 16 bytes: ipv6 address
304 * - X bytes: interface name
307 * q(64), l(32), w(16), c(8)
310 /* Initialize parameters return values. */
311 memset(bpc
, 0, sizeof(*bpc
));
314 /* Find or allocate process context data. */
315 STREAM_GETL(msg
, pid
);
319 log_debug("ptm-read: failed to allocate memory");
323 /* Register/update peer information. */
324 _ptm_msg_read_address(msg
, &bpc
->bpc_peer
);
326 /* Determine IP type from peer destination. */
327 bpc
->bpc_ipv4
= (bpc
->bpc_peer
.sa_sin
.sin_family
== AF_INET
);
329 /* Get peer configuration. */
330 if (command
!= ZEBRA_BFD_DEST_DEREGISTER
) {
331 STREAM_GETL(msg
, bpc
->bpc_recvinterval
);
332 bpc
->bpc_has_recvinterval
=
333 (bpc
->bpc_recvinterval
!= BPC_DEF_RECEIVEINTERVAL
);
335 STREAM_GETL(msg
, bpc
->bpc_txinterval
);
336 bpc
->bpc_has_txinterval
=
337 (bpc
->bpc_txinterval
!= BPC_DEF_TRANSMITINTERVAL
);
339 STREAM_GETC(msg
, bpc
->bpc_detectmultiplier
);
340 bpc
->bpc_has_detectmultiplier
=
341 (bpc
->bpc_detectmultiplier
!= BPC_DEF_DETECTMULTIPLIER
);
344 /* Read (single|multi)hop and its options. */
345 STREAM_GETC(msg
, bpc
->bpc_mhop
);
347 /* Read multihop source address and TTL. */
348 _ptm_msg_read_address(msg
, &bpc
->bpc_local
);
349 STREAM_GETC(msg
, ttl
);
351 /* If target is IPv6, then we must obtain local address. */
352 if (bpc
->bpc_ipv4
== false)
353 _ptm_msg_read_address(msg
, &bpc
->bpc_local
);
356 * Read interface name and make sure it fits our data
357 * structure, otherwise fail.
359 STREAM_GETC(msg
, ifnamelen
);
360 if (ifnamelen
>= sizeof(bpc
->bpc_localif
)) {
361 log_error("ptm-read: interface name is too big");
365 bpc
->bpc_has_localif
= ifnamelen
> 0;
366 if (bpc
->bpc_has_localif
) {
367 STREAM_GET(bpc
->bpc_localif
, msg
, ifnamelen
);
368 bpc
->bpc_localif
[ifnamelen
] = 0;
371 if (vrf_id
!= VRF_DEFAULT
) {
374 vrf
= vrf_lookup_by_id(vrf_id
);
376 bpc
->bpc_has_vrfname
= true;
377 strlcpy(bpc
->bpc_vrfname
, vrf
->name
, sizeof(bpc
->bpc_vrfname
));
379 log_error("ptm-read: vrf id %u could not be identified", vrf_id
);
383 bpc
->bpc_has_vrfname
= true;
384 strlcpy(bpc
->bpc_vrfname
, VRF_DEFAULT_NAME
, sizeof(bpc
->bpc_vrfname
));
387 STREAM_GETC(msg
, bpc
->bpc_cbit
);
389 /* Sanity check: peer and local address must match IP types. */
390 if (bpc
->bpc_local
.sa_sin
.sin_family
!= 0
391 && (bpc
->bpc_local
.sa_sin
.sin_family
392 != bpc
->bpc_peer
.sa_sin
.sin_family
)) {
393 log_warning("ptm-read: peer family doesn't match local type");
403 static void bfdd_dest_register(struct stream
*msg
, vrf_id_t vrf_id
)
405 struct ptm_client
*pc
;
406 struct ptm_client_notification
*pcn
;
407 struct bfd_session
*bs
;
408 struct bfd_peer_cfg bpc
;
410 /* Read the client context and peer data. */
411 if (_ptm_msg_read(msg
, ZEBRA_BFD_DEST_REGISTER
, vrf_id
, &bpc
, &pc
) == -1)
414 DEBUG_PRINTBPC(&bpc
);
416 /* Find or start new BFD session. */
417 bs
= bs_peer_find(&bpc
);
419 bs
= ptm_bfd_sess_new(&bpc
);
421 log_debug("ptm-add-dest: failed to create BFD session");
425 /* Don't try to change echo/shutdown state. */
426 bpc
.bpc_echo
= BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_ECHO
);
428 BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_SHUTDOWN
);
431 /* Create client peer notification register. */
432 pcn
= pcn_new(pc
, bs
);
434 log_error("ptm-add-dest: failed to registrate notifications");
438 ptm_bfd_notify(bs
, bs
->ses_state
);
441 static void bfdd_dest_deregister(struct stream
*msg
, vrf_id_t vrf_id
)
443 struct ptm_client
*pc
;
444 struct ptm_client_notification
*pcn
;
445 struct bfd_session
*bs
;
446 struct bfd_peer_cfg bpc
;
448 /* Read the client context and peer data. */
449 if (_ptm_msg_read(msg
, ZEBRA_BFD_DEST_DEREGISTER
, vrf_id
, &bpc
, &pc
) == -1)
452 DEBUG_PRINTBPC(&bpc
);
454 /* Find or start new BFD session. */
455 bs
= bs_peer_find(&bpc
);
457 log_debug("ptm-del-dest: failed to find BFD session");
461 /* Unregister client peer notification. */
462 pcn
= pcn_lookup(pc
, bs
);
465 BFD_CHECK_FLAG(bs
->flags
, BFD_SESS_FLAG_CONFIG
))
468 bs
->ses_state
= PTM_BFD_ADM_DOWN
;
471 ptm_bfd_sess_del(&bpc
);
475 * header: command, VRF
478 static void bfdd_client_register(struct stream
*msg
)
480 struct ptm_client
*pc
;
483 /* Find or allocate process context data. */
484 STREAM_GETL(msg
, pid
);
488 log_error("ptm-add-client: failed to register client: %u", pid
);
495 log_error("ptm-add-client: failed to register client");
499 * header: command, VRF
502 static void bfdd_client_deregister(struct stream
*msg
)
504 struct ptm_client
*pc
;
507 /* Find or allocate process context data. */
508 STREAM_GETL(msg
, pid
);
512 log_debug("ptm-del-client: failed to find client: %u", pid
);
521 log_error("ptm-del-client: failed to deregister client");
524 static int bfdd_replay(ZAPI_CALLBACK_ARGS
)
526 struct stream
*msg
= zclient
->ibuf
;
529 STREAM_GETL(msg
, rcmd
);
532 case ZEBRA_BFD_DEST_REGISTER
:
533 case ZEBRA_BFD_DEST_UPDATE
:
534 bfdd_dest_register(msg
, vrf_id
);
536 case ZEBRA_BFD_DEST_DEREGISTER
:
537 bfdd_dest_deregister(msg
, vrf_id
);
539 case ZEBRA_BFD_CLIENT_REGISTER
:
540 bfdd_client_register(msg
);
542 case ZEBRA_BFD_CLIENT_DEREGISTER
:
543 bfdd_client_deregister(msg
);
547 log_debug("ptm-replay: invalid message type %u", rcmd
);
554 log_error("ptm-replay: failed to find command");
558 static void bfdd_zebra_connected(struct zclient
*zc
)
560 struct stream
*msg
= zc
->obuf
;
562 /* Clean-up and free ptm clients data memory. */
566 * The replay is an empty message just to trigger client daemons
567 * configuration replay.
570 zclient_create_header(msg
, ZEBRA_BFD_DEST_REPLAY
, VRF_DEFAULT
);
571 stream_putl(msg
, ZEBRA_BFD_DEST_REPLAY
);
572 stream_putw_at(msg
, 0, stream_get_endp(msg
));
574 /* Ask for interfaces information. */
575 zclient_create_header(msg
, ZEBRA_INTERFACE_ADD
, VRF_DEFAULT
);
578 zclient_send_message(zclient
);
581 static void bfdd_sessions_enable_interface(struct interface
*ifp
)
583 struct bfd_session_observer
*bso
;
584 struct bfd_session
*bs
;
587 TAILQ_FOREACH(bso
, &bglobal
.bg_obslist
, bso_entry
) {
589 /* Interface name mismatch. */
590 if (strcmp(ifp
->name
, bs
->key
.ifname
))
592 vrf
= vrf_lookup_by_id(ifp
->vrf_id
);
595 if (bs
->key
.vrfname
[0] &&
596 strcmp(vrf
->name
, bs
->key
.vrfname
))
598 /* Skip enabled sessions. */
602 /* Try to enable it. */
603 bfd_session_enable(bs
);
607 static void bfdd_sessions_disable_interface(struct interface
*ifp
)
609 struct bfd_session_observer
*bso
;
610 struct bfd_session
*bs
;
612 TAILQ_FOREACH(bso
, &bglobal
.bg_obslist
, bso_entry
) {
614 if (strcmp(ifp
->name
, bs
->key
.ifname
))
616 /* Skip disabled sessions. */
620 bfd_session_disable(bs
);
625 void bfdd_sessions_enable_vrf(struct vrf
*vrf
)
627 struct bfd_session_observer
*bso
;
628 struct bfd_session
*bs
;
630 /* it may affect configs without interfaces */
631 TAILQ_FOREACH(bso
, &bglobal
.bg_obslist
, bso_entry
) {
634 if (bs
->vrf
&& bs
->vrf
== vrf
) {
635 if (!strmatch(bs
->key
.vrfname
, vrf
->name
))
636 bfd_session_update_vrf_name(bs
, vrf
);
640 if (bs
->key
.vrfname
[0] &&
641 strcmp(vrf
->name
, bs
->key
.vrfname
))
643 /* need to update the vrf information on
644 * bs so that callbacks are handled
647 /* Skip enabled sessions. */
650 /* Try to enable it. */
651 bfd_session_enable(bs
);
655 void bfdd_sessions_disable_vrf(struct vrf
*vrf
)
657 struct bfd_session_observer
*bso
;
658 struct bfd_session
*bs
;
660 TAILQ_FOREACH(bso
, &bglobal
.bg_obslist
, bso_entry
) {
662 if (bs
->key
.vrfname
[0] &&
663 strcmp(vrf
->name
, bs
->key
.vrfname
))
665 /* Skip disabled sessions. */
669 bfd_session_disable(bs
);
673 static int bfd_ifp_destroy(struct interface
*ifp
)
675 bfdd_sessions_disable_interface(ifp
);
680 static int bfdd_interface_vrf_update(ZAPI_CALLBACK_ARGS
)
682 struct interface
*ifp
;
685 ifp
= zebra_interface_vrf_update_read(zclient
->ibuf
, vrf_id
, &nvrfid
);
689 if_update_to_new_vrf(ifp
, nvrfid
);
694 static void bfdd_sessions_enable_address(struct connected
*ifc
)
696 struct bfd_session_observer
*bso
;
697 struct bfd_session
*bs
;
698 struct prefix prefix
;
700 TAILQ_FOREACH(bso
, &bglobal
.bg_obslist
, bso_entry
) {
701 /* Skip enabled sessions. */
707 prefix
= bso
->bso_addr
;
708 prefix
.prefixlen
= ifc
->address
->prefixlen
;
709 if (prefix_cmp(&prefix
, ifc
->address
))
712 /* Try to enable it. */
713 bfd_session_enable(bs
);
717 static int bfdd_interface_address_update(ZAPI_CALLBACK_ARGS
)
719 struct connected
*ifc
;
721 ifc
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
725 bfdd_sessions_enable_address(ifc
);
730 static int bfd_ifp_create(struct interface
*ifp
)
732 bfdd_sessions_enable_interface(ifp
);
737 void bfdd_zclient_init(struct zebra_privs_t
*bfdd_priv
)
739 if_zapi_callbacks(bfd_ifp_create
, NULL
, NULL
, bfd_ifp_destroy
);
740 zclient
= zclient_new(master
, &zclient_options_default
);
741 assert(zclient
!= NULL
);
742 zclient_init(zclient
, ZEBRA_ROUTE_BFD
, 0, bfdd_priv
);
745 * We'll receive all messages through replay, however it will
746 * contain a special field with the real command inside so we
747 * avoid having to create too many handlers.
749 zclient
->bfd_dest_replay
= bfdd_replay
;
751 /* Send replay request on zebra connect. */
752 zclient
->zebra_connected
= bfdd_zebra_connected
;
754 /* Learn about interface VRF. */
755 zclient
->interface_vrf_update
= bfdd_interface_vrf_update
;
757 /* Learn about new addresses being registered. */
758 zclient
->interface_address_add
= bfdd_interface_address_update
;
759 zclient
->interface_address_delete
= bfdd_interface_address_update
;
762 void bfdd_zclient_register(vrf_id_t vrf_id
)
764 if (!zclient
|| zclient
->sock
< 0)
766 zclient_send_reg_requests(zclient
, vrf_id
);
769 void bfdd_zclient_unregister(vrf_id_t vrf_id
)
771 if (!zclient
|| zclient
->sock
< 0)
773 zclient_send_dereg_requests(zclient
, vrf_id
);
776 void bfdd_zclient_stop(void)
778 zclient_stop(zclient
);
780 /* Clean-up and free ptm clients data memory. */
788 static struct ptm_client
*pc_lookup(uint32_t pid
)
790 struct ptm_client
*pc
;
792 TAILQ_FOREACH (pc
, &pcqueue
, pc_entry
) {
793 if (pc
->pc_pid
!= pid
)
802 static struct ptm_client
*pc_new(uint32_t pid
)
804 struct ptm_client
*pc
;
806 /* Look up first, if not found create the client. */
811 /* Allocate the client data and save it. */
812 pc
= XCALLOC(MTYPE_BFDD_CONTROL
, sizeof(*pc
));
815 TAILQ_INSERT_HEAD(&pcqueue
, pc
, pc_entry
);
819 static void pc_free(struct ptm_client
*pc
)
821 struct ptm_client_notification
*pcn
;
826 TAILQ_REMOVE(&pcqueue
, pc
, pc_entry
);
828 while (!TAILQ_EMPTY(&pc
->pc_pcnqueue
)) {
829 pcn
= TAILQ_FIRST(&pc
->pc_pcnqueue
);
833 XFREE(MTYPE_BFDD_CONTROL
, pc
);
836 static void pc_free_all(void)
838 struct ptm_client
*pc
;
840 while (!TAILQ_EMPTY(&pcqueue
)) {
841 pc
= TAILQ_FIRST(&pcqueue
);
846 static struct ptm_client_notification
*pcn_new(struct ptm_client
*pc
,
847 struct bfd_session
*bs
)
849 struct ptm_client_notification
*pcn
;
851 /* Try to find an existing pcn fist. */
852 pcn
= pcn_lookup(pc
, bs
);
856 /* Save the client notification data. */
857 pcn
= XCALLOC(MTYPE_BFDD_NOTIFICATION
, sizeof(*pcn
));
859 TAILQ_INSERT_HEAD(&pc
->pc_pcnqueue
, pcn
, pcn_entry
);
867 static struct ptm_client_notification
*pcn_lookup(struct ptm_client
*pc
,
868 struct bfd_session
*bs
)
870 struct ptm_client_notification
*pcn
;
872 TAILQ_FOREACH (pcn
, &pc
->pc_pcnqueue
, pcn_entry
) {
873 if (pcn
->pcn_bs
!= bs
)
882 static void pcn_free(struct ptm_client_notification
*pcn
)
884 struct ptm_client
*pc
;
885 struct bfd_session
*bs
;
890 /* Handle session de-registration. */
895 /* Handle ptm_client deregistration. */
898 TAILQ_REMOVE(&pc
->pc_pcnqueue
, pcn
, pcn_entry
);
900 XFREE(MTYPE_BFDD_NOTIFICATION
, pcn
);