interface: add multi tx-queues support for new tx infra

Type: feature

Change-Id: I231f782b3c56dc2b10321e4569ac7acdad1c11da
Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
This commit is contained in:
Mohsin Kazmi
2021-11-09 17:44:10 +00:00
committed by Damjan Marion
parent 5d5f85f5e4
commit 0d05c0d214
15 changed files with 870 additions and 139 deletions

View File

@ -855,10 +855,10 @@ memif_delete_if (vlib_main_t * vm, memif_if_t * mif)
}
/* *INDENT-OFF* */
VNET_HW_INTERFACE_CLASS (memif_ip_hw_if_class, static) =
{
VNET_HW_INTERFACE_CLASS (memif_ip_hw_if_class, static) = {
.name = "memif-ip",
.flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
.tx_hash_fn_type = VNET_HASH_FN_TYPE_IP,
};
/* *INDENT-ON* */

View File

@ -58,13 +58,11 @@ tap_main_t tap_main;
goto error; \
}
/* *INDENT-OFF* */
VNET_HW_INTERFACE_CLASS (tun_device_hw_interface_class, static) =
{
VNET_HW_INTERFACE_CLASS (tun_device_hw_interface_class, static) = {
.name = "tun-device",
.flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
.tx_hash_fn_type = VNET_HASH_FN_TYPE_IP,
};
/* *INDENT-ON* */
#define TUN_MAX_PACKET_BYTES 65355
#define TUN_MIN_PACKET_BYTES 64

View File

@ -313,6 +313,7 @@ ethernet_mac_change (vnet_hw_interface_t * hi,
/* *INDENT-OFF* */
VNET_HW_INTERFACE_CLASS (ethernet_hw_interface_class) = {
.name = "Ethernet",
.tx_hash_fn_type = VNET_HASH_FN_TYPE_ETHERNET,
.format_address = format_ethernet_address,
.format_header = format_ethernet_header_with_length,
.unformat_hw_address = unformat_ethernet_address,

View File

@ -458,6 +458,29 @@ autoreply define sw_interface_set_rx_placement
bool is_main;
};
/** \brief Set an interface's tx-placement
Tx-Queue placement on specific thread is operational for only hardware
interface. It will not set queue - thread placement for sub-interfaces,
p2p and pipe interfaces.
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param sw_if_index - the interface whose tx-placement will be set
@param queue_id - the queue number whose tx-placement will be set.
@param array_size - the size of the thread indexes array
@param threads - the thread indexes of main and worker(s) threads
whom tx-placement will be at.
*/
autoendian autoreply define sw_interface_set_tx_placement
{
u32 client_index;
u32 context;
vl_api_interface_index_t sw_if_index;
u32 queue_id;
u32 array_size;
u32 threads[array_size];
option vat_help = "<interface | sw_if_index <index>> queue <n> [threads <list> | mask <hex>]";
};
/** \brief Set custom interface name
Set custom interface name for the interface.
@param client_index - opaque cookie to identify the sender
@ -512,6 +535,60 @@ define sw_interface_rx_placement_details
vl_api_rx_mode_t mode;
};
service {
rpc sw_interface_tx_placement_get returns sw_interface_tx_placement_get_reply
stream sw_interface_tx_placement_details;
};
/** \brief get the tx queue placement of interface(s)
@param cursor - optional, it allows client to continue a dump
@param sw_if_index - optional interface index for which queue placement to
be requested. sw_if_index = ~0 will get the placement information for all
interfaces. It will not get information related to sub-interfaces, p2p
and pipe interfaces.
*/
autoendian define sw_interface_tx_placement_get
{
u32 client_index;
u32 context;
u32 cursor;
vl_api_interface_index_t sw_if_index;
option vat_help = "[interface | sw_if_index <index>]";
};
autoendian define sw_interface_tx_placement_get_reply
{
u32 context;
i32 retval;
u32 cursor;
};
/** \brief show the interface's queue - thread placement
This api is used to display the interface and queue worker
thread placement. One message per tx-queue per interface will
be sent to client.
Each message will contain information about tx-queue id of an
interface, interface index, thread on which this tx-queue is
placed and mode of tx-queue.
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param sw_if_index - the interface whose tx-placement will be dumped
@param queue_id - the queue id
@param shared - the queue is shared on other threads
@param array_size - the size of the threads array
@param threads - the main and worker(s) thread index(es) whom tx-placement are at.
*/
autoendian define sw_interface_tx_placement_details
{
u32 client_index;
u32 context;
vl_api_interface_index_t sw_if_index;
u32 queue_id;
u8 shared;
u32 array_size;
u32 threads[array_size];
};
/* Gross kludge, DGMS */
autoreply define interface_name_renumber
{

View File

@ -863,6 +863,10 @@ vnet_register_interface (vnet_main_t * vnm,
hw->hw_if_index = hw_index;
hw->default_rx_mode = VNET_HW_IF_RX_MODE_POLLING;
if (hw_class->tx_hash_fn_type == VNET_HASH_FN_TYPE_ETHERNET ||
hw_class->tx_hash_fn_type == VNET_HASH_FN_TYPE_IP)
hw->hf = vnet_hash_default_function (hw_class->tx_hash_fn_type);
if (dev_class->format_device_name)
hw->name = format (0, "%U", dev_class->format_device_name, dev_instance);
else if (hw_class->format_interface_name)
@ -1020,6 +1024,7 @@ vnet_register_interface (vnet_main_t * vnm,
static char *e[] = {
"interface is down",
"interface is deleted",
"no tx queue available",
};
r.n_errors = ARRAY_LEN (e);

View File

@ -44,6 +44,7 @@
#include <vppinfra/pcap.h>
#include <vnet/l3_types.h>
#include <vppinfra/lock.h>
#include <vnet/hash/hash.h>
struct vnet_main_t;
struct vnet_hw_interface_t;
@ -410,6 +411,9 @@ typedef struct _vnet_hw_interface_class
/* Flags */
vnet_hw_interface_class_flags_t flags;
/* tx hash type for interfaces of this hw class */
vnet_hash_fn_type_t tx_hash_fn_type;
/* Function to call when hardware interface is added/deleted. */
vnet_interface_function_t *interface_add_del_function;
@ -641,8 +645,9 @@ typedef struct
typedef struct
{
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
vnet_hw_if_tx_frame_t frame;
u32 n_threads;
vnet_hw_if_tx_frame_t *frame;
u32 *lookup_table;
u32 n_queues;
} vnet_hw_if_output_node_runtime_t;
/* Hardware-interface. This corresponds to a physical wire
@ -696,6 +701,9 @@ typedef struct vnet_hw_interface_t
used by node function vnet_per_buffer_interface_output() */
u32 output_node_next_index;
/* called when hw interface is using transmit side packet steering */
vnet_hash_fn_t hf;
/* Maximum transmit rate for this interface in bits/sec. */
f64 max_rate_bits_per_sec;

View File

@ -184,39 +184,73 @@ vnet_hw_if_update_runtime_data (vnet_main_t *vnm, u32 hw_if_index)
}
}
new_out_runtimes =
vec_dup_aligned (hi->output_node_thread_runtimes, CLIB_CACHE_LINE_BYTES);
vec_validate_aligned (new_out_runtimes, n_threads - 1,
CLIB_CACHE_LINE_BYTES);
if (vec_len (hi->output_node_thread_runtimes) != vec_len (new_out_runtimes))
something_changed_on_tx = 1;
for (int i = 0; i < vec_len (hi->tx_queue_indices); i++)
if (vec_len (hi->tx_queue_indices) > 0)
{
u32 thread_index;
u32 queue_index = hi->tx_queue_indices[i];
vnet_hw_if_tx_queue_t *txq = vnet_hw_if_get_tx_queue (vnm, queue_index);
uword n_threads = clib_bitmap_count_set_bits (txq->threads);
new_out_runtimes = vec_dup_aligned (hi->output_node_thread_runtimes,
CLIB_CACHE_LINE_BYTES);
vec_validate_aligned (new_out_runtimes, n_threads - 1,
CLIB_CACHE_LINE_BYTES);
clib_bitmap_foreach (thread_index, txq->threads)
for (u32 i = 0; i < vec_len (new_out_runtimes); i++)
{
vnet_hw_if_output_node_runtime_t *rt;
rt = vec_elt_at_index (new_out_runtimes, thread_index);
if ((rt->frame.queue_id != txq->queue_id) ||
(rt->n_threads != n_threads))
rt = vec_elt_at_index (new_out_runtimes, i);
u32 n_queues = 0, total_queues = vec_len (hi->tx_queue_indices);
rt->frame = 0;
rt->lookup_table = 0;
for (u32 j = 0; j < total_queues; j++)
{
u32 queue_index = hi->tx_queue_indices[j];
vnet_hw_if_tx_frame_t frame = { .shared_queue = 0,
.hints = 7,
.queue_id = ~0 };
vnet_hw_if_tx_queue_t *txq =
vnet_hw_if_get_tx_queue (vnm, queue_index);
if (!clib_bitmap_get (txq->threads, i))
continue;
log_debug ("tx queue data changed for interface %v, thread %u "
"(queue_id %u -> %u, n_threads %u -> %u)",
hi->name, thread_index, rt->frame.queue_id,
txq->queue_id, rt->n_threads, n_threads);
"(queue_id %u)",
hi->name, i, txq->queue_id);
something_changed_on_tx = 1;
rt->frame.queue_id = txq->queue_id;
rt->frame.shared_queue = txq->shared_queue;
rt->n_threads = n_threads;
frame.queue_id = txq->queue_id;
frame.shared_queue = txq->shared_queue;
vec_add1 (rt->frame, frame);
n_queues++;
}
// don't initialize rt->n_queues above
if (rt->n_queues != n_queues)
{
something_changed_on_tx = 1;
rt->n_queues = n_queues;
}
/*
* It is only used in case of multiple txq.
*/
if (rt->n_queues > 0)
{
if (!is_pow2 (n_queues))
n_queues = max_pow2 (n_queues);
vec_validate_aligned (rt->lookup_table, n_queues - 1,
CLIB_CACHE_LINE_BYTES);
for (u32 k = 0; k < vec_len (rt->lookup_table); k++)
{
rt->lookup_table[k] = rt->frame[k % rt->n_queues].queue_id;
log_debug ("tx queue lookup table changed for interface %v, "
"(lookup table [%u]=%u)",
hi->name, k, rt->lookup_table[k]);
}
}
}
}
else
/* interface deleted */
something_changed_on_tx = 1;
if (something_changed_on_rx || something_changed_on_tx)
{
@ -303,6 +337,11 @@ vnet_hw_if_update_runtime_data (vnet_main_t *vnm, u32 hw_if_index)
{
vec_free (d[i]);
vec_free (a[i]);
if (new_out_runtimes)
{
vec_free (new_out_runtimes[i].frame);
vec_free (new_out_runtimes[i].lookup_table);
}
}
vec_free (d);

View File

@ -27,3 +27,20 @@ vnet_hw_if_get_tx_queue (vnet_main_t *vnm, u32 queue_index)
return 0;
return pool_elt_at_index (im->hw_if_tx_queues, queue_index);
}
static_always_inline int
vnet_hw_if_txq_cmp_cli_api (vnet_hw_if_tx_queue_t **a,
vnet_hw_if_tx_queue_t **b)
{
if (*a == *b)
return 0;
if (a[0]->hw_if_index != b[0]->hw_if_index)
return 2 * (a[0]->hw_if_index > b[0]->hw_if_index) - 1;
if (a[0]->queue_id != b[0]->queue_id)
return 2 * (a[0]->queue_id > b[0]->queue_id) - 1;
ASSERT (0);
return ~0;
}

View File

@ -22,6 +22,7 @@
#include <vnet/interface.h>
#include <vnet/interface/rx_queue_funcs.h>
#include <vnet/interface/tx_queue_funcs.h>
#include <vnet/api_errno.h>
#include <vnet/ethernet/ethernet.h>
#include <vnet/ip/ip.h>
@ -56,7 +57,9 @@ vpe_api_main_t vpe_api_main;
_ (SW_INTERFACE_ADD_DEL_ADDRESS, sw_interface_add_del_address) \
_ (SW_INTERFACE_SET_RX_MODE, sw_interface_set_rx_mode) \
_ (SW_INTERFACE_RX_PLACEMENT_DUMP, sw_interface_rx_placement_dump) \
_ (SW_INTERFACE_TX_PLACEMENT_GET, sw_interface_tx_placement_get) \
_ (SW_INTERFACE_SET_RX_PLACEMENT, sw_interface_set_rx_placement) \
_ (SW_INTERFACE_SET_TX_PLACEMENT, sw_interface_set_tx_placement) \
_ (SW_INTERFACE_SET_TABLE, sw_interface_set_table) \
_ (SW_INTERFACE_GET_TABLE, sw_interface_get_table) \
_ (SW_INTERFACE_SET_UNNUMBERED, sw_interface_set_unnumbered) \
@ -1215,6 +1218,168 @@ out:
REPLY_MACRO (VL_API_SW_INTERFACE_SET_RX_PLACEMENT_REPLY);
}
static void
send_interface_tx_placement_details (vnet_hw_if_tx_queue_t **all_queues,
u32 index, vl_api_registration_t *rp,
u32 context)
{
vnet_main_t *vnm = vnet_get_main ();
vl_api_sw_interface_tx_placement_details_t *rmp;
u32 n_bits = 0, v = ~0;
vnet_hw_if_tx_queue_t **q = vec_elt_at_index (all_queues, index);
uword *bitmap = q[0]->threads;
u32 hw_if_index = q[0]->hw_if_index;
vnet_hw_interface_t *hw_if = vnet_get_hw_interface (vnm, hw_if_index);
n_bits = clib_bitmap_count_set_bits (bitmap);
u32 n = n_bits * sizeof (u32);
/*
* FIXME: Use the REPLY_MACRO_DETAILS5_END once endian handler is registered
* and available.
*/
REPLY_MACRO_DETAILS5 (
VL_API_SW_INTERFACE_TX_PLACEMENT_DETAILS, n, rp, context, ({
rmp->sw_if_index = clib_host_to_net_u32 (hw_if->sw_if_index);
rmp->queue_id = clib_host_to_net_u32 (q[0]->queue_id);
rmp->shared = q[0]->shared_queue;
rmp->array_size = clib_host_to_net_u32 (n_bits);
v = clib_bitmap_first_set (bitmap);
for (u32 i = 0; i < n_bits; i++)
{
rmp->threads[i] = clib_host_to_net_u32 (v);
v = clib_bitmap_next_set (bitmap, v + 1);
}
}));
}
static void
vl_api_sw_interface_tx_placement_get_t_handler (
vl_api_sw_interface_tx_placement_get_t *mp)
{
vnet_main_t *vnm = vnet_get_main ();
vl_api_sw_interface_tx_placement_get_reply_t *rmp = 0;
vnet_hw_if_tx_queue_t **all_queues = 0;
vnet_hw_if_tx_queue_t *q;
u32 sw_if_index = mp->sw_if_index;
i32 rv = 0;
if (pool_elts (vnm->interface_main.hw_if_tx_queues) == 0)
{
rv = VNET_API_ERROR_NO_SUCH_ENTRY;
goto err;
}
if (sw_if_index == ~0)
{
pool_foreach (q, vnm->interface_main.hw_if_tx_queues)
vec_add1 (all_queues, q);
vec_sort_with_function (all_queues, vnet_hw_if_txq_cmp_cli_api);
}
else
{
u32 qi = ~0;
vnet_sw_interface_t *si;
if (!vnet_sw_if_index_is_api_valid (sw_if_index))
{
clib_warning ("sw_if_index %u does not exist", sw_if_index);
rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
goto err;
}
si = vnet_get_sw_interface (vnm, sw_if_index);
if (si->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
{
clib_warning ("interface type is not HARDWARE! P2P, PIPE and SUB"
" interfaces are not supported");
rv = VNET_API_ERROR_INVALID_INTERFACE;
goto err;
}
vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, si->hw_if_index);
for (qi = 0; qi < vec_len (hw->tx_queue_indices); qi++)
{
q = vnet_hw_if_get_tx_queue (vnm, hw->tx_queue_indices[qi]);
vec_add1 (all_queues, q);
}
}
REPLY_AND_DETAILS_VEC_MACRO_END (VL_API_SW_INTERFACE_TX_PLACEMENT_GET_REPLY,
all_queues, mp, rmp, rv, ({
send_interface_tx_placement_details (
all_queues, cursor, rp, mp->context);
}));
vec_free (all_queues);
return;
err:
REPLY_MACRO_END (VL_API_SW_INTERFACE_TX_PLACEMENT_GET_REPLY);
}
static void
vl_api_sw_interface_set_tx_placement_t_handler (
vl_api_sw_interface_set_tx_placement_t *mp)
{
vl_api_sw_interface_set_tx_placement_reply_t *rmp;
vnet_main_t *vnm = vnet_get_main ();
u32 sw_if_index = mp->sw_if_index;
vnet_sw_interface_t *si;
uword *bitmap = 0;
u32 queue_id = ~0;
u32 size = 0;
clib_error_t *error = 0;
int rv = 0;
VALIDATE_SW_IF_INDEX_END (mp);
si = vnet_get_sw_interface (vnm, sw_if_index);
if (si->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
{
rv = VNET_API_ERROR_INVALID_VALUE;
goto bad_sw_if_index;
}
size = mp->array_size;
for (u32 i = 0; i < size; i++)
{
u32 thread_index = mp->threads[i];
bitmap = clib_bitmap_set (bitmap, thread_index, 1);
}
queue_id = mp->queue_id;
rv = set_hw_interface_tx_queue (si->hw_if_index, queue_id, bitmap);
switch (rv)
{
case VNET_API_ERROR_INVALID_VALUE:
error = clib_error_return (
0, "please specify valid thread(s) - last thread index %u",
clib_bitmap_last_set (bitmap));
break;
case VNET_API_ERROR_INVALID_QUEUE:
error = clib_error_return (
0, "unknown queue %u on interface %s", queue_id,
vnet_get_hw_interface (vnet_get_main (), si->hw_if_index)->name);
break;
default:
break;
}
if (error)
{
clib_error_report (error);
goto out;
}
BAD_SW_IF_INDEX_LABEL;
out:
REPLY_MACRO_END (VL_API_SW_INTERFACE_SET_TX_PLACEMENT_REPLY);
clib_bitmap_free (bitmap);
}
static void
vl_api_create_vlan_subif_t_handler (vl_api_create_vlan_subif_t * mp)
{
@ -1474,6 +1639,10 @@ interface_api_hookup (vlib_main_t * vm)
/* Do not replay VL_API_SW_INTERFACE_DUMP messages */
am->api_trace_cfg[VL_API_SW_INTERFACE_DUMP].replay_enable = 0;
/* Mark these APIs as autoendian */
am->is_autoendian[VL_API_SW_INTERFACE_SET_TX_PLACEMENT] = 1;
am->is_autoendian[VL_API_SW_INTERFACE_TX_PLACEMENT_GET] = 1;
/*
* Set up the (msg_name, crc, message-id) table
*/

View File

@ -53,6 +53,7 @@
#include <vnet/classify/vnet_classify.h>
#include <vnet/interface/rx_queue_funcs.h>
#include <vnet/interface/tx_queue_funcs.h>
#include <vnet/hash/hash.h>
static int
compare_interface_names (void *a1, void *a2)
{
@ -1840,28 +1841,24 @@ VLIB_CLI_COMMAND (cmd_set_if_rx_placement,static) = {
};
/* *INDENT-ON* */
clib_error_t *
int
set_hw_interface_tx_queue (u32 hw_if_index, u32 queue_id, uword *bitmap)
{
vnet_main_t *vnm = vnet_get_main ();
vnet_device_main_t *vdm = &vnet_device_main;
vnet_hw_interface_t *hw;
vlib_thread_main_t *vtm = vlib_get_thread_main ();
vnet_hw_if_tx_queue_t *txq;
u32 queue_index;
u32 thread_index;
hw = vnet_get_hw_interface (vnm, hw_if_index);
/* highest set bit in bitmap should not exceed last worker thread index */
thread_index = clib_bitmap_last_set (bitmap);
if ((thread_index != ~0) && (thread_index > vdm->last_worker_thread_index))
return clib_error_return (0, "please specify valid thread(s)");
if ((thread_index != ~0) && (thread_index >= vtm->n_vlib_mains))
return VNET_API_ERROR_INVALID_VALUE;
queue_index =
vnet_hw_if_get_tx_queue_index_by_id (vnm, hw_if_index, queue_id);
if (queue_index == ~0)
return clib_error_return (0, "unknown queue %u on interface %s", queue_id,
hw->name);
return VNET_API_ERROR_INVALID_QUEUE;
txq = vnet_hw_if_get_tx_queue (vnm, queue_index);
@ -1889,6 +1886,7 @@ set_interface_tx_queue (vlib_main_t *vm, unformat_input_t *input,
u32 hw_if_index = (u32) ~0;
u32 queue_id = (u32) 0;
uword *bitmap = 0;
int rv = 0;
if (!unformat_user (input, unformat_line_input, line_input))
return 0;
@ -1920,7 +1918,23 @@ set_interface_tx_queue (vlib_main_t *vm, unformat_input_t *input,
goto error;
}
error = set_hw_interface_tx_queue (hw_if_index, queue_id, bitmap);
rv = set_hw_interface_tx_queue (hw_if_index, queue_id, bitmap);
switch (rv)
{
case VNET_API_ERROR_INVALID_VALUE:
error = clib_error_return (
0, "please specify valid thread(s) - last thread index %u",
clib_bitmap_last_set (bitmap));
break;
case VNET_API_ERROR_INVALID_QUEUE:
error = clib_error_return (
0, "unknown queue %u on interface %s", queue_id,
vnet_get_hw_interface (vnet_get_main (), hw_if_index)->name);
break;
default:
break;
}
error:
clib_bitmap_free (bitmap);
@ -2467,6 +2481,132 @@ VLIB_CLI_COMMAND (cmd_set_if_name, static) = {
.function = set_interface_name,
.is_mp_safe = 1,
};
static clib_error_t *
set_interface_tx_hash_cmd (vlib_main_t *vm, unformat_input_t *input,
vlib_cli_command_t *cmd)
{
clib_error_t *error = 0;
unformat_input_t _line_input, *line_input = &_line_input;
vnet_main_t *vnm = vnet_get_main ();
vnet_hw_interface_t *hi;
u8 *hash_name = 0;
u32 hw_if_index = (u32) ~0;
vnet_hash_fn_t hf;
vnet_hash_fn_type_t ftype;
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, "%U", unformat_vnet_hw_interface, vnm,
&hw_if_index))
;
else if (unformat (line_input, "hash-name %s", &hash_name))
;
else
{
error = clib_error_return (0, "parse error: '%U'",
format_unformat_error, line_input);
unformat_free (line_input);
return error;
}
}
unformat_free (line_input);
if (hw_if_index == (u32) ~0)
{
error = clib_error_return (0, "please specify valid interface name");
goto error;
}
hi = vnet_get_hw_interface (vnm, hw_if_index);
ftype =
vnet_get_hw_interface_class (vnm, hi->hw_class_index)->tx_hash_fn_type;
hf = vnet_hash_function_from_name ((const char *) hash_name, ftype);
if (!hf)
{
error = clib_error_return (0, "please specify valid hash name");
goto error;
}
hi->hf = hf;
error:
vec_free (hash_name);
return (error);
}
VLIB_CLI_COMMAND (cmd_set_if_tx_hash, static) = {
.path = "set interface tx-hash",
.short_help = "set interface tx-hash <interface> hash-name <hash-name>",
.function = set_interface_tx_hash_cmd,
};
static clib_error_t *
show_tx_hash (vlib_main_t *vm, unformat_input_t *input,
vlib_cli_command_t *cmd)
{
clib_error_t *error = 0;
unformat_input_t _line_input, *line_input = &_line_input;
vnet_main_t *vnm = vnet_get_main ();
vnet_hw_interface_t *hi;
vnet_hash_function_registration_t *hash;
u32 hw_if_index = (u32) ~0;
vnet_hash_fn_type_t ftype;
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, "%U", unformat_vnet_hw_interface, vnm,
&hw_if_index))
;
else
{
error = clib_error_return (0, "parse error: '%U'",
format_unformat_error, line_input);
unformat_free (line_input);
goto error;
}
}
unformat_free (line_input);
if (hw_if_index == (u32) ~0)
{
error = clib_error_return (0, "please specify valid interface name");
goto error;
}
hi = vnet_get_hw_interface (vnm, hw_if_index);
ftype =
vnet_get_hw_interface_class (vnm, hi->hw_class_index)->tx_hash_fn_type;
if (hi->hf)
{
hash = vnet_hash_function_from_func (hi->hf, ftype);
if (hash)
vlib_cli_output (vm, "%U", format_vnet_hash, hash);
else
vlib_cli_output (vm, "no matching hash function found");
}
else
vlib_cli_output (vm, "no hashing function set");
error:
return (error);
}
VLIB_CLI_COMMAND (cmd_show_tx_hash, static) = {
.path = "show interface tx-hash",
.short_help = "show interface tx-hash [interface]",
.function = show_tx_hash,
};
/*
* fd.io coding-style-patch-verification: ON
*

View File

@ -212,6 +212,9 @@ format_vnet_hw_interface (u8 * s, va_list * args)
if (vec_len (hi->tx_queue_indices))
{
s = format (s, "\n%UTX Queues:", format_white_space, indent + 2);
s = format (
s, "\n%UTX Hash: %U", format_white_space, indent + 4, format_vnet_hash,
vnet_hash_function_from_func (hi->hf, hw_class->tx_hash_fn_type));
s = format (s, "\n%U%-6s%-7s%-15s", format_white_space, indent + 4,
"queue", "shared", "thread(s)");
for (int i = 0; i < vec_len (hi->tx_queue_indices); i++)

View File

@ -427,6 +427,8 @@ clib_error_t *set_hw_interface_change_rx_mode (vnet_main_t * vnm,
/* Set rx-placement on the interface */
clib_error_t *set_hw_interface_rx_placement (u32 hw_if_index, u32 queue_id,
u32 thread_index, u8 is_main);
/* Set tx-queue placement on the interface */
int set_hw_interface_tx_queue (u32 hw_if_index, u32 queue_id, uword *bitmap);
/* Set the MTU on the HW interface */
void vnet_hw_interface_set_mtu (vnet_main_t * vnm, u32 hw_if_index, u32 mtu);
@ -509,6 +511,7 @@ typedef enum
{
VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DOWN,
VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DELETED,
VNET_INTERFACE_OUTPUT_ERROR_NO_TX_QUEUE,
} vnet_interface_output_error_t;
/* Format for interface output traces. */

File diff suppressed because it is too large Load Diff

View File

@ -569,6 +569,63 @@ api_sw_interface_set_rx_placement (vat_main_t *vam)
return ret;
}
static int
api_sw_interface_set_tx_placement (vat_main_t *vam)
{
unformat_input_t *i = vam->input;
vl_api_sw_interface_set_tx_placement_t *mp;
u32 sw_if_index;
u8 sw_if_index_set = 0;
int ret;
uword *bitmap = 0;
u32 queue_id, n_bits = 0;
u32 v;
/* Parse args required to build the message */
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "queue %d", &queue_id))
;
else if (unformat (i, "threads %U", unformat_bitmap_list, &bitmap))
;
else if (unformat (i, "mask %U", unformat_bitmap_mask, &bitmap))
;
else if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
sw_if_index_set = 1;
else if (unformat (i, "sw_if_index %d", &sw_if_index))
sw_if_index_set = 1;
else
break;
}
if (sw_if_index_set == 0)
{
errmsg ("missing interface name or sw_if_index");
return -99;
}
n_bits = clib_bitmap_count_set_bits (bitmap);
/* Construct the API message */
M2 (SW_INTERFACE_SET_TX_PLACEMENT, mp, sizeof (u32) * n_bits);
mp->sw_if_index = htonl (sw_if_index);
mp->queue_id = htonl (queue_id);
mp->array_size = htonl (n_bits);
v = clib_bitmap_first_set (bitmap);
for (u32 j = 0; j < n_bits; j++)
{
mp->threads[j] = htonl (v);
v = clib_bitmap_next_set (bitmap, v + 1);
}
/* send it... */
S (mp);
/* Wait for a reply, return the good/bad news... */
W (ret);
clib_bitmap_free (bitmap);
return ret;
}
static int
api_interface_name_renumber (vat_main_t *vam)
{
@ -844,6 +901,25 @@ vl_api_sw_interface_rx_placement_details_t_handler (
((mp->mode == 2) ? "interrupt" : "adaptive"));
}
static __clib_unused void
vl_api_sw_interface_tx_placement_details_t_handler (
vl_api_sw_interface_tx_placement_details_t *mp)
{
vat_main_t *vam = interface_test_main.vat_main;
u32 size = ntohl (mp->array_size);
uword *bitmap = 0;
for (u32 i = 0; i < size; i++)
{
u32 thread_index = ntohl (mp->threads[i]);
bitmap = clib_bitmap_set (bitmap, thread_index, 1);
}
print (vam->ofp, "\n%-11d %-6d %-7s %U", ntohl (mp->sw_if_index),
ntohl (mp->queue_id), (mp->shared == 1) ? "yes" : "no",
format_bitmap_list, bitmap);
}
static void
vl_api_create_vlan_subif_reply_t_handler (vl_api_create_vlan_subif_reply_t *mp)
{
@ -960,6 +1036,52 @@ api_sw_interface_rx_placement_dump (vat_main_t *vam)
return ret;
}
static int
api_sw_interface_tx_placement_get (vat_main_t *vam)
{
unformat_input_t *i = vam->input;
vl_api_sw_interface_tx_placement_get_t *mp;
vl_api_control_ping_t *mp_ping;
int ret;
u32 sw_if_index;
u8 sw_if_index_set = 0;
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
sw_if_index_set++;
else if (unformat (i, "sw_if_index %d", &sw_if_index))
sw_if_index_set++;
else
break;
}
fformat (vam->ofp, "\n%-11s %-6s %-7s %-11s", "sw_if_index", "queue",
"shared", "threads");
/* Dump Interface tx placement */
M (SW_INTERFACE_TX_PLACEMENT_GET, mp);
if (sw_if_index_set)
mp->sw_if_index = htonl (sw_if_index);
else
mp->sw_if_index = ~0;
S (mp);
/* Use a control ping for synchronization */
PING (&interface_test_main, mp_ping);
S (mp_ping);
W (ret);
return ret;
}
static void
vl_api_sw_interface_tx_placement_get_reply_t_handler ()
{
}
static int
api_sw_interface_clear_stats (vat_main_t *vam)
{

View File

@ -245,6 +245,7 @@ VNET_HW_INTERFACE_CLASS (pg_tun_hw_interface_class) = {
.build_rewrite = NULL,
//.update_adjacency = gre_update_adj,
.flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
.tx_hash_fn_type = VNET_HASH_FN_TYPE_IP,
};
u32