/* * Copyright (c) 2011-2016 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * @brief BFD CLI implementation */ #include #include #include #include #include #include #include #include static u8 * format_bfd_session_cli (u8 * s, va_list * args) { vlib_main_t *vm = va_arg (*args, vlib_main_t *); bfd_main_t *bm = va_arg (*args, bfd_main_t *); bfd_session_t *bs = va_arg (*args, bfd_session_t *); switch (bs->transport) { case BFD_TRANSPORT_UDP4: s = format (s, "%=10u %-32s %20U %20U\n", bs->bs_idx, "IPv4 address", format_ip4_address, bs->udp.key.local_addr.ip4.as_u8, format_ip4_address, bs->udp.key.peer_addr.ip4.as_u8); break; case BFD_TRANSPORT_UDP6: s = format (s, "%=10u %-32s %20U %20U\n", bs->bs_idx, "IPv6 address", format_ip6_address, &bs->udp.key.local_addr.ip6, format_ip6_address, &bs->udp.key.peer_addr.ip6); break; } s = format (s, "%10s %-32s %20s %20s\n", "", "Session state", bfd_state_string (bs->local_state), bfd_state_string (bs->remote_state)); s = format (s, "%10s %-32s %20s %20s\n", "", "Diagnostic code", bfd_diag_code_string (bs->local_diag), bfd_diag_code_string (bs->remote_diag)); s = format (s, "%10s %-32s %20u %20u\n", "", "Detect multiplier", bs->local_detect_mult, bs->remote_detect_mult); s = format (s, "%10s %-32s %20u %20llu\n", "", "Required Min Rx Interval (usec)", bs->config_required_min_rx_usec, bs->remote_min_rx_usec); s = format (s, "%10s %-32s %20u %20u\n", "", "Desired Min Tx Interval (usec)", bs->config_desired_min_tx_usec, bfd_clocks_to_usec (bm, bs->remote_desired_min_tx_clocks)); s = format (s, "%10s %-32s %20u\n", "", "Transmit interval", bfd_clocks_to_usec (bm, bs->transmit_interval_clocks)); u64 now = clib_cpu_time_now (); u8 *tmp = NULL; if (bs->last_tx_clocks > 0) { tmp = format (tmp, "%.2fs ago", (now - bs->last_tx_clocks) * vm->clib_time.seconds_per_clock); s = format (s, "%10s %-32s %20v\n", "", "Last control frame tx", tmp); vec_reset_length (tmp); } if (bs->last_rx_clocks) { tmp = format (tmp, "%.2fs ago", (now - bs->last_rx_clocks) * vm->clib_time.seconds_per_clock); s = format (s, "%10s %-32s %20v\n", "", "Last control frame rx", tmp); vec_reset_length (tmp); } s = format (s, "%10s %-32s %20u %20llu\n", "", "Min Echo Rx Interval (usec)", 1, bs->remote_min_echo_rx_usec); if (bs->echo) { s = format (s, "%10s %-32s %20u\n", "", "Echo transmit interval", bfd_clocks_to_usec (bm, bs->echo_transmit_interval_clocks)); tmp = format (tmp, "%.2fs ago", (now - bs->echo_last_tx_clocks) * vm->clib_time.seconds_per_clock); s = format (s, "%10s %-32s %20v\n", "", "Last echo frame tx", tmp); vec_reset_length (tmp); tmp = format (tmp, "%.6fs", (bs->echo_last_rx_clocks - bs->echo_last_tx_clocks) * vm->clib_time.seconds_per_clock); s = format (s, "%10s %-32s %20v\n", "", "Last echo frame roundtrip time", tmp); } vec_free (tmp); tmp = NULL; s = format (s, "%10s %-32s %20s %20s\n", "", "Demand mode", "no", bs->remote_demand ? "yes" : "no"); s = format (s, "%10s %-32s %20s\n", "", "Poll state", bfd_poll_state_string (bs->poll_state)); if (bs->auth.curr_key) { s = format (s, "%10s %-32s %20u\n", "", "Authentication config key ID", bs->auth.curr_key->conf_key_id); s = format (s, "%10s %-32s %20u\n", "", "Authentication BFD key ID", bs->auth.curr_bfd_key_id); s = format (s, "%10s %-32s %20u %20u\n", "", "Sequence number", bs->auth.local_seq_number, bs->auth.remote_seq_number); } return s; } static clib_error_t * show_bfd (vlib_main_t * vm, unformat_input_t * input, CLIB_UNUSED (vlib_cli_command_t * lmd)) { bfd_main_t *bm = &bfd_main; bfd_session_t *bs = NULL; unformat_input_t _line_input, *line_input = &_line_input; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return 0; if (unformat (line_input, "keys")) { bfd_auth_key_t *key = NULL; u8 *s = format (NULL, "%=10s %=25s %=10s\n", "Configuration Key ID", "Type", "Use Count"); /* *INDENT-OFF* */ pool_foreach (key, bm->auth_keys, { s = format (s, "%10u %-25s %10u\n", key->conf_key_id, bfd_auth_type_str (key->auth_type), key->use_count); }); /* *INDENT-ON* */ vlib_cli_output (vm, "%v\n", s); vec_free (s); vlib_cli_output (vm, "Number of configured BFD keys: %lu\n", (u64) pool_elts (bm->auth_keys)); } else if (unformat (line_input, "sessions")) { u8 *s = format (NULL, "%=10s %=32s %=20s %=20s\n", "Index", "Property", "Local value", "Remote value"); /* *INDENT-OFF* */ pool_foreach (bs, bm->sessions, { s = format (s, "%U", format_bfd_session_cli, vm, bm, bs); }); /* *INDENT-ON* */ vlib_cli_output (vm, "%v", s); vec_free (s); vlib_cli_output (vm, "Number of configured BFD sessions: %lu\n", (u64) pool_elts (bm->sessions)); } else if (unformat (line_input, "echo-source")) { int is_set; u32 sw_if_index; int have_usable_ip4; ip4_address_t ip4; int have_usable_ip6; ip6_address_t ip6; bfd_udp_get_echo_source (&is_set, &sw_if_index, &have_usable_ip4, &ip4, &have_usable_ip6, &ip6); if (is_set) { vnet_sw_interface_t *sw_if = vnet_get_sw_interface_safe (&vnet_main, sw_if_index); vnet_hw_interface_t *hw_if = vnet_get_hw_interface (&vnet_main, sw_if->hw_if_index); u8 *s = format (NULL, "UDP echo source is: %v\n", hw_if->name); s = format (s, "IPv4 address usable as echo source: "); if (have_usable_ip4) { s = format (s, "%U\n", format_ip4_address, &ip4); } else { s = format (s, "none\n"); } s = format (s, "IPv6 address usable as echo source: "); if (have_usable_ip6) { s = format (s, "%U\n", format_ip6_address, &ip6); } else { s = format (s, "none\n"); } vlib_cli_output (vm, "%v", s); vec_free (s); } else { vlib_cli_output (vm, "UDP echo source is not set.\n"); } } else { vlib_cli_output (vm, "Number of configured BFD sessions: %lu\n", (u64) pool_elts (bm->sessions)); vlib_cli_output (vm, "Number of configured BFD keys: %lu\n", (u64) pool_elts (bm->auth_keys)); } return 0; } /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_bfd_command, static) = { .path = "show bfd", .short_help = "show bfd [keys|sessions|echo-source]", .function = show_bfd, }; /* *INDENT-ON* */ static clib_error_t * bfd_cli_key_add (vlib_main_t * vm, unformat_input_t * input, CLIB_UNUSED (vlib_cli_command_t * lmd)) { clib_error_t *ret = NULL; int have_key_id = 0; u32 key_id = 0; u8 *vec_auth_type = NULL; bfd_auth_type_e auth_type = BFD_AUTH_TYPE_reserved; u8 *secret = NULL; unformat_input_t _line_input, *line_input = &_line_input; static const u8 keyed_sha1[] = "keyed-sha1"; static const u8 meticulous_keyed_sha1[] = "meticulous-keyed-sha1"; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return 0; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (unformat (line_input, "conf-key-id %u", &key_id)) { have_key_id = 1; } else if (unformat (line_input, "type %U", unformat_token, "a-zA-Z0-9-", &vec_auth_type)) { if (vec_len (vec_auth_type) == sizeof (keyed_sha1) - 1 && 0 == memcmp (vec_auth_type, keyed_sha1, sizeof (keyed_sha1) - 1)) { auth_type = BFD_AUTH_TYPE_keyed_sha1; } else if (vec_len (vec_auth_type) == sizeof (meticulous_keyed_sha1) - 1 && 0 == memcmp (vec_auth_type, meticulous_keyed_sha1, sizeof (meticulous_keyed_sha1) - 1)) { auth_type = BFD_AUTH_TYPE_meticulous_keyed_sha1; } else { ret = clib_error_return (0, "invalid type `%v'", vec_auth_type); goto out; } } else if (unformat (line_input, "secret %U", unformat_hex_string, &secret)) { /* nothing to do here */ } else { ret = clib_error_return (0, "Unknown input `%U'", format_unformat_error, line_input); goto out; } } if (!have_key_id) { ret = clib_error_return (0, "required parameter missing: `conf-key-id'"); goto out; } if (!vec_auth_type) { ret = clib_error_return (0, "required parameter missing: `type'"); goto out; } if (!secret) { ret = clib_error_return (0, "required parameter missing: `secret'"); goto out; } vnet_api_error_t rv = bfd_auth_set_key (key_id, auth_type, vec_len (secret), secret); if (rv) { ret = clib_error_return (0, "`bfd_auth_set_key' API call failed, rv=%d:%U", (int) rv, format_vnet_api_errno, rv); } out: vec_free (vec_auth_type); return ret; } /* *INDENT-OFF* */ VLIB_CLI_COMMAND (bfd_cli_key_add_command, static) = { .path = "bfd key set", .short_help = "bfd key set" " conf-key-id " " type " " secret ", .function = bfd_cli_key_add, }; /* *INDENT-ON* */ static clib_error_t * bfd_cli_key_del (vlib_main_t * vm, unformat_input_t * input, CLIB_UNUSED (vlib_cli_command_t * lmd)) { clib_error_t *ret = NULL; u32 key_id = 0; unformat_input_t _line_input, *line_input = &_line_input; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return 0; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (!unformat (line_input, "conf-key-id %u", &key_id)) { ret = clib_error_return (0, "Unknown input `%U'", format_unformat_error, line_input); goto out; } } vnet_api_error_t rv = bfd_auth_del_key (key_id); if (rv) { ret = clib_error_return (0, "`bfd_auth_del_key' API call failed, rv=%d:%U", (int) rv, format_vnet_api_errno, rv); } out: return ret; } /* *INDENT-OFF* */ VLIB_CLI_COMMAND (bfd_cli_key_del_command, static) = { .path = "bfd key del", .short_help = "bfd key del conf-key-id ", .function = bfd_cli_key_del, }; /* *INDENT-ON* */ #define INTERFACE_STR "interface" #define LOCAL_ADDR_STR "local-addr" #define PEER_ADDR_STR "peer-addr" #define CONF_KEY_ID_STR "conf-key-id" #define BFD_KEY_ID_STR "bfd-key-id" #define DESIRED_MIN_TX_STR "desired-min-tx" #define REQUIRED_MIN_RX_STR "required-min-rx" #define DETECT_MULT_STR "detect-mult" #define ADMIN_STR "admin" #define DELAYED_STR "delayed" static const unsigned mandatory = 1; static const unsigned optional = 0; #define DECLARE(t, n, s, r, ...) \ int have_##n = 0; \ t n; #define UNFORMAT(t, n, s, r, ...) \ if (unformat (line_input, s " " __VA_ARGS__, &n)) \ { \ something_parsed = 1; \ have_##n = 1; \ } #define CHECK_MANDATORY(t, n, s, r, ...) \ WARN_OFF(tautological-compare) \ if (mandatory == r && !have_##n) \ { \ WARN_ON(tautological-compare) \ ret = clib_error_return (0, "Required parameter `%s' missing.", s); \ goto out; \ } static clib_error_t * bfd_cli_udp_session_add (vlib_main_t * vm, unformat_input_t * input, CLIB_UNUSED (vlib_cli_command_t * lmd)) { clib_error_t *ret = NULL; unformat_input_t _line_input, *line_input = &_line_input; #define foreach_bfd_cli_udp_session_add_cli_param(F) \ F (u32, sw_if_index, INTERFACE_STR, mandatory, "%U", \ unformat_vnet_sw_interface, &vnet_main) \ F (ip46_address_t, local_addr, LOCAL_ADDR_STR, mandatory, "%U", \ unformat_ip46_address) \ F (ip46_address_t, peer_addr, PEER_ADDR_STR, mandatory, "%U", \ unformat_ip46_address) \ F (u32, desired_min_tx, DESIRED_MIN_TX_STR, mandatory, "%u") \ F (u32, required_min_rx, REQUIRED_MIN_RX_STR, mandatory, "%u") \ F (u32, detect_mult, DETECT_MULT_STR, mandatory, "%u") \ F (u32, conf_key_id, CONF_KEY_ID_STR, optional, "%u") \ F (u32, bfd_key_id, BFD_KEY_ID_STR, optional, "%u") foreach_bfd_cli_udp_session_add_cli_param (DECLARE); /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return 0; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { int something_parsed = 0; foreach_bfd_cli_udp_session_add_cli_param (UNFORMAT); if (!something_parsed) { ret = clib_error_return (0, "Unknown input `%U'", format_unformat_error, line_input); goto out; } } foreach_bfd_cli_udp_session_add_cli_param (CHECK_MANDATORY); if (1 == have_conf_key_id + have_bfd_key_id) { ret = clib_error_return (0, "Incompatible parameter combination, `%s' " "and `%s' must be either both specified or none", CONF_KEY_ID_STR, BFD_KEY_ID_STR); goto out; } if (detect_mult > 255) { ret = clib_error_return (0, "%s value `%u' out of range <1,255>", DETECT_MULT_STR, detect_mult); goto out; } if (have_bfd_key_id && bfd_key_id > 255) { ret = clib_error_return (0, "%s value `%u' out of range <1,255>", BFD_KEY_ID_STR, bfd_key_id); goto out; } vnet_api_error_t rv = bfd_udp_add_session (sw_if_index, &local_addr, &peer_addr, desired_min_tx, required_min_rx, detect_mult, have_conf_key_id, conf_key_id, bfd_key_id); if (rv) { ret = clib_error_return (0, "`bfd_add_add_session' API call failed, rv=%d:%U", (int) rv, format_vnet_api_errno, rv); goto out; } out: return ret; } /* *INDENT-OFF* */ VLIB_CLI_COMMAND (bfd_cli_udp_session_add_command, static) = { .path = "bfd udp session add", .short_help = "bfd udp session add" " interface " " local-addr " " peer-addr " " desired-min-tx " " required-min-rx " " detect-mult " "[" " conf-key-id " " bfd-key-id " "]", .function = bfd_cli_udp_session_add, }; /* *INDENT-ON* */ static clib_error_t * bfd_cli_udp_session_mod (vlib_main_t * vm, unformat_input_t * input, CLIB_UNUSED (vlib_cli_command_t * lmd)) { clib_error_t *ret = NULL; unformat_input_t _line_input, *line_input = &_line_input; #define foreach_bfd_cli_udp_session_mod_cli_param(F) \ F (u32, sw_if_index, INTERFACE_STR, mandatory, "%U", \ unformat_vnet_sw_interface, &vnet_main) \ F (ip46_address_t, local_addr, LOCAL_ADDR_STR, mandatory, "%U", \ unformat_ip46_address) \ F (ip46_address_t, peer_addr, PEER_ADDR_STR, mandatory, "%U", \ unformat_ip46_address) \ F (u32, desired_min_tx, DESIRED_MIN_TX_STR, mandatory, "%u") \ F (u32, required_min_rx, REQUIRED_MIN_RX_STR, mandatory, "%u") \ F (u32, detect_mult, DETECT_MULT_STR, mandatory, "%u") foreach_bfd_cli_udp_session_mod_cli_param (DECLARE); /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return 0; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { int something_parsed = 0; foreach_bfd_cli_udp_session_mod_cli_param (UNFORMAT); if (!something_parsed) { ret = clib_error_return (0, "Unknown input `%U'", format_unformat_error, line_input); goto out; } } foreach_bfd_cli_udp_session_mod_cli_param (CHECK_MANDATORY); if (detect_mult > 255) { ret = clib_error_return (0, "%s value `%u' out of range <1,255>", DETECT_MULT_STR, detect_mult); goto out; } vnet_api_error_t rv = bfd_udp_mod_session (sw_if_index, &local_addr, &peer_addr, desired_min_tx, required_min_rx, detect_mult); if (rv) { ret = clib_error_return (0, "`bfd_udp_mod_session' API call failed, rv=%d:%U", (int) rv, format_vnet_api_errno, rv); goto out; } out: return ret; } /* *INDENT-OFF* */ VLIB_CLI_COMMAND (bfd_cli_udp_session_mod_command, static) = { .path = "bfd udp session mod", .short_help = "bfd udp session mod interface" " local-addr" " peer-addr" " desired-min-tx" " required-min-rx" " detect-mult" " ", .function = bfd_cli_udp_session_mod, }; /* *INDENT-ON* */ static clib_error_t * bfd_cli_udp_session_del (vlib_main_t * vm, unformat_input_t * input, CLIB_UNUSED (vlib_cli_command_t * lmd)) { clib_error_t *ret = NULL; unformat_input_t _line_input, *line_input = &_line_input; #define foreach_bfd_cli_udp_session_del_cli_param(F) \ F (u32, sw_if_index, INTERFACE_STR, mandatory, "%U", \ unformat_vnet_sw_interface, &vnet_main) \ F (ip46_address_t, local_addr, LOCAL_ADDR_STR, mandatory, "%U", \ unformat_ip46_address) \ F (ip46_address_t, peer_addr, PEER_ADDR_STR, mandatory, "%U", \ unformat_ip46_address) foreach_bfd_cli_udp_session_del_cli_param (DECLARE); /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return 0; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { int something_parsed = 0; foreach_bfd_cli_udp_session_del_cli_param (UNFORMAT); if (!something_parsed) { ret = clib_error_return (0, "Unknown input `%U'", format_unformat_error, line_input); goto out; } } foreach_bfd_cli_udp_session_del_cli_param (CHECK_MANDATORY); vnet_api_error_t rv = bfd_udp_del_session (sw_if_index, &local_addr, &peer_addr); if (rv) { ret = clib_error_return (0, "`bfd_udp_del_session' API call failed, rv=%d:%U", (int) rv, format_vnet_api_errno, rv); goto out; } out: return ret; } /* *INDENT-OFF* */ VLIB_CLI_COMMAND (bfd_cli_udp_session_del_command, static) = { .path = "bfd udp session del", .short_help = "bfd udp session del interface" " local-addr" " peer-addr" " ", .function = bfd_cli_udp_session_del, }; /* *INDENT-ON* */ static clib_error_t * bfd_cli_udp_session_set_flags (vlib_main_t * vm, unformat_input_t * input, CLIB_UNUSED (vlib_cli_command_t * lmd)) { clib_error_t *ret = NULL; unformat_input_t _line_input, *line_input = &_line_input; #define foreach_bfd_cli_udp_session_set_flags_cli_param(F) \ F (u32, sw_if_index, INTERFACE_STR, mandatory, "%U", \ unformat_vnet_sw_interface, &vnet_main) \ F (ip46_address_t, local_addr, LOCAL_ADDR_STR, mandatory, "%U", \ unformat_ip46_address) \ F (ip46_address_t, peer_addr, PEER_ADDR_STR, mandatory, "%U", \ unformat_ip46_address) \ F (u8 *, admin_up_down_token, ADMIN_STR, mandatory, "%v", \ &admin_up_down_token) foreach_bfd_cli_udp_session_set_flags_cli_param (DECLARE); /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return 0; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { int something_parsed = 0; foreach_bfd_cli_udp_session_set_flags_cli_param (UNFORMAT); if (!something_parsed) { ret = clib_error_return (0, "Unknown input `%U'", format_unformat_error, line_input); goto out; } } foreach_bfd_cli_udp_session_set_flags_cli_param (CHECK_MANDATORY); u8 admin_up_down; static const char up[] = "up"; static const char down[] = "down"; }
/*
 * Copyright (c) 2015 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
  Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus

  Permission is hereby granted, free of charge, to any person obtaining
  a copy of this software and associated documentation files (the
  "Software"), to deal in the Software without restriction, including
  without limitation the rights to use, copy, modify, merge, publish,
  distribute, sublicense, and/or sell copies of the Software, and to
  permit persons to whom the Software is furnished to do so, subject to
  the following conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef included_clib_vec_bootstrap_h
#define included_clib_vec_bootstrap_h

/** \file
    Vector bootstrap header file
*/

/* Bootstrap include so that #include <vppinfra/mem.h> can include e.g.
   <vppinfra/mheap.h> which depends on <vppinfra/vec.h>. */

/** \brief vector header structure

   Bookkeeping header preceding vector elements in memory.
   User header information may preceed standard vec header.
   If you change u32 len -> u64 len, single vectors can
   exceed 2**32 elements. Clib heaps are vectors. */

typedef struct
{
  u32 len; /**< Number of elements in vector (NOT its allocated length). */
  u8 numa_id; /**< NUMA id */
  u8 vpad[3]; /**< pad to 8 bytes */
  u8 vector_data[0];  /**< Vector data . */
} vec_header_t;

#define VEC_NUMA_UNSPECIFIED (0xFF)

/** \brief Find the vector header

    Given the user's pointer to a vector, find the corresponding
    vector header

    @param v pointer to a vector
    @return pointer to the vector's vector_header_t
*/
#define _vec_find(v)	((vec_header_t *) (v) - 1)

#define _vec_round_size(s) \
  (((s) + sizeof (uword) - 1) &~ (sizeof (uword) - 1))

always_inline uword
vec_header_bytes (uword header_bytes)
{
  return round_pow2 (header_bytes + sizeof (vec_header_t),
		     sizeof (vec_header_t));
}

/** \brief Find a user vector header

    Finds the user header of a vector with unspecified alignment given
    the user pointer to the vector.
*/

always_inline void *
vec_header (void *v, uword header_bytes)
{
  return v - vec_header_bytes (header_bytes);
}

/** \brief Find the end of user vector header

    Finds the end of the user header of a vector with unspecified
    alignment given the user pointer to the vector.
*/

always_inline void *
vec_header_end (void *v, uword header_bytes)
{
  return v + vec_header_bytes (header_bytes);
}

always_inline uword
vec_aligned_header_bytes (uword header_bytes, uword align)
{
  return round_pow2 (header_bytes + sizeof (vec_header_t), align);
}

always_inline void *
vec_aligned_header (void *v, uword header_bytes, uword align)
{
  return v - vec_aligned_header_bytes (header_bytes, align);
}

always_inline void *
vec_aligned_header_end (void *v,