summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bfdd/bfd.c9
-rw-r--r--bfdd/bfdctl.h3
-rw-r--r--bfdd/ptm_adapter.c35
-rw-r--r--lib/bfd.c199
-rw-r--r--lib/bfd.h85
5 files changed, 242 insertions, 89 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
index a021b5cab..f51136e98 100644
--- a/bfdd/bfd.c
+++ b/bfdd/bfd.c
@@ -765,6 +765,15 @@ static void _bfd_session_update(struct bfd_session *bs,
*/
bs->peer_profile.admin_shutdown = bpc->bpc_shutdown;
bfd_set_shutdown(bs, bpc->bpc_shutdown);
+
+ /*
+ * Apply profile last: it also calls `bfd_set_shutdown`.
+ *
+ * There is no problem calling `shutdown` twice if the value doesn't
+ * change or if it is overriden by peer specific configuration.
+ */
+ if (bpc->bpc_has_profile)
+ bfd_profile_apply(bpc->bpc_profile, bs);
}
static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
diff --git a/bfdd/bfdctl.h b/bfdd/bfdctl.h
index 4ce23a8f2..95cfcb110 100644
--- a/bfdd/bfdctl.h
+++ b/bfdd/bfdctl.h
@@ -90,6 +90,9 @@ struct bfd_peer_cfg {
bool bpc_cbit;
+ bool bpc_has_profile;
+ char bpc_profile[64];
+
/* Status information */
enum bfd_peer_status bpc_bps;
uint32_t bpc_id;
diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c
index 25938dd9f..0abbdf3dc 100644
--- a/bfdd/ptm_adapter.c
+++ b/bfdd/ptm_adapter.c
@@ -85,6 +85,7 @@ static void debug_printbpc(const struct bfd_peer_cfg *bpc, const char *fmt, ...)
{
char timers[3][128] = {};
char addr[3][128] = {};
+ char profile[128] = {};
char cbit_str[32];
char msgbuf[256];
va_list vl;
@@ -119,13 +120,17 @@ static void debug_printbpc(const struct bfd_peer_cfg *bpc, const char *fmt, ...)
snprintf(cbit_str, sizeof(cbit_str), " cbit:0x%02x", bpc->bpc_cbit);
+ if (bpc->bpc_has_profile)
+ snprintf(profile, sizeof(profile), " profile:%s",
+ bpc->bpc_profile);
+
va_start(vl, fmt);
vsnprintf(msgbuf, sizeof(msgbuf), fmt, vl);
va_end(vl);
- zlog_debug("%s [mhop:%s %s%s%s%s%s%s%s]", msgbuf,
+ zlog_debug("%s [mhop:%s %s%s%s%s%s%s%s%s]", msgbuf,
bpc->bpc_mhop ? "yes" : "no", addr[0], addr[1], addr[2],
- timers[0], timers[1], timers[2], cbit_str);
+ timers[0], timers[1], timers[2], cbit_str, profile);
}
static int _ptm_msg_address(struct stream *msg, int family, const void *addr)
@@ -301,6 +306,8 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
* - c: ifname length
* - X bytes: interface name
* - c: bfd_cbit
+ * - c: profile name length.
+ * - X bytes: profile name.
*
* q(64), l(32), w(16), c(8)
*/
@@ -381,6 +388,14 @@ static int _ptm_msg_read(struct stream *msg, int command, vrf_id_t vrf_id,
STREAM_GETC(msg, bpc->bpc_cbit);
+ /* Handle profile names. */
+ STREAM_GETC(msg, ifnamelen);
+ bpc->bpc_has_profile = ifnamelen > 0;
+ if (bpc->bpc_has_profile) {
+ STREAM_GET(bpc->bpc_profile, msg, ifnamelen);
+ bpc->bpc_profile[ifnamelen] = 0;
+ }
+
/* Sanity check: peer and local address must match IP types. */
if (bpc->bpc_local.sa_sin.sin_family != 0
&& (bpc->bpc_local.sa_sin.sin_family
@@ -421,10 +436,18 @@ static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id)
/* Protocol created peers are 'no shutdown' by default. */
bs->peer_profile.admin_shutdown = false;
} else {
- /* Don't try to change echo/shutdown state. */
- bpc.bpc_echo = CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
- bpc.bpc_shutdown =
- CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
+ /*
+ * BFD session was already created, we are just updating the
+ * current peer.
+ *
+ * `ptm-bfd` (or `HAVE_BFDD == 0`) is the only implementation
+ * that allow users to set peer specific timers via protocol.
+ * BFD daemon (this code) on the other hand only supports
+ * changing peer configuration manually (through `peer` node)
+ * or via profiles.
+ */
+ if (bpc.bpc_has_profile)
+ bfd_profile_apply(bpc.bpc_profile, bs);
}
/* Create client peer notification register. */
diff --git a/lib/bfd.c b/lib/bfd.c
index 5f2d2f0ed..2d86acbbf 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -127,9 +127,8 @@ void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
int ttl, int multihop, int cbit, int command,
int set_flag, vrf_id_t vrf_id)
{
- struct stream *s;
- int ret;
- int len;
+ struct bfd_session_arg args = {};
+ size_t addrlen;
/* Individual reg/dereg messages are suppressed during shutdown. */
if (CHECK_FLAG(bfd_gbl.flags, BFD_GBL_FLAG_IN_SHUTDOWN)) {
@@ -150,86 +149,30 @@ void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info,
return;
}
- s = zclient->obuf;
- stream_reset(s);
- zclient_create_header(s, command, vrf_id);
-
- stream_putl(s, getpid());
-
- stream_putw(s, family);
- switch (family) {
- case AF_INET:
- stream_put_in_addr(s, (struct in_addr *)dst_ip);
- break;
- case AF_INET6:
- stream_put(s, dst_ip, 16);
- break;
- default:
- break;
- }
-
- if (command != ZEBRA_BFD_DEST_DEREGISTER) {
- stream_putl(s, bfd_info->required_min_rx);
- stream_putl(s, bfd_info->desired_min_tx);
- stream_putc(s, bfd_info->detect_mult);
- }
-
- if (multihop) {
- stream_putc(s, 1);
- /* Multi-hop destination send the source IP address to BFD */
- if (src_ip) {
- stream_putw(s, family);
- switch (family) {
- case AF_INET:
- stream_put_in_addr(s, (struct in_addr *)src_ip);
- break;
- case AF_INET6:
- stream_put(s, src_ip, 16);
- break;
- default:
- break;
- }
- }
- stream_putc(s, ttl);
- } else {
- stream_putc(s, 0);
- if ((family == AF_INET6) && (src_ip)) {
- stream_putw(s, family);
- stream_put(s, src_ip, 16);
- }
- if (if_name) {
- len = strlen(if_name);
- stream_putc(s, len);
- stream_put(s, if_name, len);
- } else {
- stream_putc(s, 0);
- }
- }
- /* cbit */
- if (cbit)
- stream_putc(s, 1);
- else
- stream_putc(s, 0);
-
- stream_putw_at(s, 0, stream_get_endp(s));
-
- ret = zclient_send_message(zclient);
-
- if (ret < 0) {
- if (bfd_debug)
- zlog_debug(
- "bfd_peer_sendmsg: zclient_send_message() failed");
- return;
- }
-
- if (set_flag) {
- if (command == ZEBRA_BFD_DEST_REGISTER)
- SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG);
- else if (command == ZEBRA_BFD_DEST_DEREGISTER)
- UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG);
- }
-
- return;
+ /* Fill in all arguments. */
+ args.ttl = ttl;
+ args.cbit = cbit;
+ args.family = family;
+ args.mhop = multihop;
+ args.vrf_id = vrf_id;
+ args.command = command;
+ args.set_flag = set_flag;
+ args.bfd_info = bfd_info;
+ args.min_rx = bfd_info->required_min_rx;
+ args.min_tx = bfd_info->desired_min_tx;
+ args.detection_multiplier = bfd_info->detect_mult;
+
+ addrlen = family == AF_INET ? sizeof(struct in_addr)
+ : sizeof(struct in6_addr);
+ memcpy(&args.dst, dst_ip, addrlen);
+ if (src_ip)
+ memcpy(&args.src, src_ip, addrlen);
+
+ if (if_name)
+ args.ifnamelen =
+ strlcpy(args.ifname, if_name, sizeof(args.ifname));
+
+ zclient_bfd_command(zclient, &args);
}
/*
@@ -478,3 +421,93 @@ void bfd_client_sendmsg(struct zclient *zclient, int command,
return;
}
+
+int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args)
+{
+ struct stream *s;
+ size_t addrlen;
+
+ /* Check socket. */
+ if (!zc || zc->sock < 0) {
+ if (bfd_debug)
+ zlog_debug("%s: zclient unavailable", __func__);
+ return -1;
+ }
+
+ s = zc->obuf;
+ stream_reset(s);
+
+ /* Create new message. */
+ zclient_create_header(s, args->command, args->vrf_id);
+ stream_putl(s, getpid());
+
+ /* Encode destination address. */
+ stream_putw(s, args->family);
+ addrlen = (args->family == AF_INET) ? sizeof(struct in_addr)
+ : sizeof(struct in6_addr);
+ stream_put(s, &args->dst, addrlen);
+
+ /* Encode timers if this is a registration message. */
+ if (args->command != ZEBRA_BFD_DEST_DEREGISTER) {
+ stream_putl(s, args->min_rx);
+ stream_putl(s, args->min_tx);
+ stream_putc(s, args->detection_multiplier);
+ }
+
+ if (args->mhop) {
+ /* Multi hop indicator. */
+ stream_putc(s, 1);
+
+ /* Multi hop always sends the source address. */
+ stream_putw(s, args->family);
+ stream_put(s, &args->src, addrlen);
+
+ /* Send the expected TTL. */
+ stream_putc(s, args->ttl);
+ } else {
+ /* Multi hop indicator. */
+ stream_putc(s, 0);
+
+ /* Single hop only sends the source address when IPv6. */
+ if (args->family == AF_INET6) {
+ stream_putw(s, args->family);
+ stream_put(s, &args->src, addrlen);
+ }
+
+ /* Send interface name if any. */
+ stream_putc(s, args->ifnamelen);
+ if (args->ifnamelen)
+ stream_put(s, args->ifname, args->ifnamelen);
+ }
+
+ /* Send the C bit indicator. */
+ stream_putc(s, args->cbit);
+
+ /* `ptm-bfd` doesn't support profiles yet. */
+#if HAVE_BFDD > 0
+ /* Send profile name if any. */
+ stream_putc(s, args->profilelen);
+ if (args->profilelen)
+ stream_put(s, args->profile, args->profilelen);
+#endif /* HAVE_BFDD */
+
+ /* Finish the message by writing the size. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ /* Send message to zebra. */
+ if (zclient_send_message(zc) == -1) {
+ if (bfd_debug)
+ zlog_debug("%s: zclient_send_message failed", __func__);
+ return -1;
+ }
+
+ /* Write registration indicator into data structure. */
+ if (args->set_flag) {
+ if (args->command == ZEBRA_BFD_DEST_REGISTER)
+ SET_FLAG(args->bfd_info->flags, BFD_FLAG_BFD_REG);
+ else if (args->command == ZEBRA_BFD_DEST_DEREGISTER)
+ UNSET_FLAG(args->bfd_info->flags, BFD_FLAG_BFD_REG);
+ }
+
+ return 0;
+}
diff --git a/lib/bfd.h b/lib/bfd.h
index 7f5d11150..d7d4b5fe3 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -56,6 +56,8 @@ struct bfd_gbl {
#define BFD_STATUS_UP (1 << 2) /* BFD session status is up */
#define BFD_STATUS_ADMIN_DOWN (1 << 3) /* BFD session is admin down */
+#define BFD_PROFILE_NAME_LEN 64
+
#define BFD_SET_CLIENT_STATUS(current_status, new_status) \
do { \
(current_status) = \
@@ -77,6 +79,7 @@ struct bfd_info {
time_t last_update;
uint8_t status;
enum bfd_sess_type type;
+ char profile[BFD_PROFILE_NAME_LEN];
};
extern struct bfd_info *bfd_info_create(void);
@@ -120,6 +123,88 @@ extern void bfd_gbl_init(void);
extern void bfd_gbl_exit(void);
+
+/*
+ * BFD new API.
+ */
+
+/**
+ * BFD session registration arguments.
+ */
+struct bfd_session_arg {
+ /**
+ * BFD command.
+ *
+ * Valid commands:
+ * - `ZEBRA_BFD_DEST_REGISTER`
+ * - `ZEBRA_BFD_DEST_DEREGISTER`
+ */
+ int32_t command;
+
+ /**
+ * BFD family type.
+ *
+ * Supported types:
+ * - `AF_INET`
+ * - `AF_INET6`.
+ */
+ uint32_t family;
+ /** Source address. */
+ struct in6_addr src;
+ /** Source address. */
+ struct in6_addr dst;
+
+ /** Multi hop indicator. */
+ uint8_t mhop;
+ /** Expected TTL. */
+ uint8_t ttl;
+ /** C bit (Control Plane Independent bit) indicator. */
+ uint8_t cbit;
+
+ /** Interface name size. */
+ uint8_t ifnamelen;
+ /** Interface name. */
+ char ifname[64];
+
+ /** Daemon or session VRF. */
+ vrf_id_t vrf_id;
+
+ /** Profile name length. */
+ uint8_t profilelen;
+ /** Profile name. */
+ char profile[BFD_PROFILE_NAME_LEN];
+
+ /*
+ * Deprecation fields: these fields should be removed once `ptm-bfd`
+ * no longer uses this interface.
+ */
+
+ /** Minimum required receive interval (in microseconds). */
+ uint32_t min_rx;
+ /** Minimum desired transmission interval (in microseconds). */
+ uint32_t min_tx;
+ /** Detection multiplier. */
+ uint32_t detection_multiplier;
+
+ /** BFD client information output. */
+ struct bfd_info *bfd_info;
+
+ /** Write registration indicator. */
+ uint8_t set_flag;
+};
+
+/**
+ * Send a message to BFD daemon through the zebra client.
+ *
+ * \param zc the zebra client context.
+ * \param arg the BFD session command arguments.
+ *
+ * \returns `-1` on failure otherwise `0`.
+ *
+ * \see bfd_session_arg.
+ */
+extern int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *arg);
+
#ifdef __cplusplus
}
#endif