diff options
-rw-r--r-- | bfdd/bfd.c | 9 | ||||
-rw-r--r-- | bfdd/bfdctl.h | 3 | ||||
-rw-r--r-- | bfdd/ptm_adapter.c | 35 | ||||
-rw-r--r-- | lib/bfd.c | 199 | ||||
-rw-r--r-- | lib/bfd.h | 85 |
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. */ @@ -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; +} @@ -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 |