aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDamjan Marion <damarion@cisco.com>2024-10-08 20:50:56 +0200
committerDamjan Marion <damjan.marion@gmail.com>2024-11-07 16:49:49 +0100
commit61e287b9f895fa7cd9809ec74e44efee780a5aad (patch)
tree2a1f6e6f038062940d9b04dce480ed07394c9407
parentde020ab4788d75e70f0cfea4c21f09a4716be161 (diff)
dev: secondary interfaces support
Type: feature Change-Id: I6cc4340431b8273022955fca1600061a722e3ace Signed-off-by: Damjan Marion <damarion@cisco.com>
-rw-r--r--src/vnet/dev/api.c97
-rw-r--r--src/vnet/dev/api.h23
-rw-r--r--src/vnet/dev/cli.c88
-rw-r--r--src/vnet/dev/dev.c48
-rw-r--r--src/vnet/dev/dev.h124
-rw-r--r--src/vnet/dev/dev_funcs.h98
-rw-r--r--src/vnet/dev/errors.h3
-rw-r--r--src/vnet/dev/format.c30
-rw-r--r--src/vnet/dev/handlers.c82
-rw-r--r--src/vnet/dev/port.c345
-rw-r--r--src/vnet/dev/queue.c10
11 files changed, 765 insertions, 183 deletions
diff --git a/src/vnet/dev/api.c b/src/vnet/dev/api.c
index 48ceccf3b6c..d968f66c316 100644
--- a/src/vnet/dev/api.c
+++ b/src/vnet/dev/api.c
@@ -156,6 +156,7 @@ vnet_dev_api_create_port_if (vlib_main_t *vm,
{
vnet_dev_t *dev = vnet_dev_by_index (args->dev_index);
vnet_dev_port_t *port = 0;
+ vnet_dev_port_if_create_args_t a = {};
u16 n_threads = vlib_get_n_threads ();
int default_is_intr_mode;
vnet_dev_rv_t rv;
@@ -181,7 +182,7 @@ vnet_dev_api_create_port_if (vlib_main_t *vm,
if (!port)
return VNET_DEV_ERR_INVALID_DEVICE_ID;
- if (port->interface_created)
+ if (port->interfaces)
return VNET_DEV_ERR_ALREADY_EXISTS;
if (args->args)
@@ -202,47 +203,82 @@ vnet_dev_api_create_port_if (vlib_main_t *vm,
{
if (args->num_rx_queues > port->attr.max_rx_queues)
return VNET_DEV_ERR_INVALID_NUM_RX_QUEUES;
- port->intf.num_rx_queues = args->num_rx_queues;
+ a.num_rx_queues = args->num_rx_queues;
}
else
- port->intf.num_rx_queues = clib_min (port->attr.max_tx_queues, 1);
+ a.num_rx_queues = clib_min (port->attr.max_tx_queues, 1);
if (args->num_tx_queues)
{
if (args->num_tx_queues > port->attr.max_tx_queues)
return VNET_DEV_ERR_INVALID_NUM_TX_QUEUES;
- port->intf.num_tx_queues = args->num_tx_queues;
+ a.num_tx_queues = args->num_tx_queues;
}
else
- port->intf.num_tx_queues = clib_min (port->attr.max_tx_queues, n_threads);
+ a.num_tx_queues = clib_min (port->attr.max_tx_queues, n_threads);
if (args->rx_queue_size)
{
if (!_vnet_dev_queue_size_validate (args->rx_queue_size,
port->rx_queue_config))
return VNET_DEV_ERR_INVALID_RX_QUEUE_SIZE;
- port->intf.rxq_sz = args->rx_queue_size;
+ a.rxq_sz = args->rx_queue_size;
}
else
- port->intf.rxq_sz = port->rx_queue_config.default_size;
+ a.rxq_sz = port->rx_queue_config.default_size;
if (args->tx_queue_size)
{
if (!_vnet_dev_queue_size_validate (args->tx_queue_size,
port->tx_queue_config))
return VNET_DEV_ERR_INVALID_TX_QUEUE_SIZE;
- port->intf.txq_sz = args->tx_queue_size;
+ a.txq_sz = args->tx_queue_size;
}
else
- port->intf.txq_sz = port->tx_queue_config.default_size;
+ a.txq_sz = port->tx_queue_config.default_size;
- clib_memcpy (port->intf.name, args->intf_name, sizeof (port->intf.name));
- port->intf.default_is_intr_mode = default_is_intr_mode;
- port->intf.consistent_qp =
- (args->flags.n & VNET_DEV_PORT_F_CONSISTENT_QP) != 0;
+ clib_memcpy (a.name, args->intf_name, sizeof (a.name));
+ a.default_is_intr_mode = default_is_intr_mode;
+ a.consistent_qp = (args->flags.n & VNET_DEV_PORT_F_CONSISTENT_QP) != 0;
- rv = vnet_dev_process_call_port_op (vm, port, vnet_dev_port_if_create);
- args->sw_if_index = (rv == VNET_DEV_OK) ? port->intf.sw_if_index : ~0;
+ rv = vnet_dev_process_call_port_op_with_ptr (vm, port,
+ vnet_dev_port_if_create, &a);
+ args->sw_if_index = (rv == VNET_DEV_OK) ? a.sw_if_index : ~0;
+
+ return rv;
+}
+
+vnet_dev_rv_t
+vnet_dev_api_port_add_sec_if (vlib_main_t *vm,
+ vnet_dev_api_port_add_sec_if_args_t *args)
+{
+ vnet_dev_port_t *port = 0;
+ vnet_dev_t *dev = 0;
+ vnet_dev_port_sec_if_create_args_t a = {};
+ vnet_dev_rv_t rv = VNET_DEV_OK;
+
+ port = vnet_dev_get_port_from_sw_if_index (args->primary_sw_if_index);
+ if (port == 0)
+ return VNET_DEV_ERR_NOT_FOUND;
+
+ log_debug (dev,
+ "create_port_if: primary_sw_if_index %u intf_name '%s' "
+ "args '%v'",
+ args->primary_sw_if_index, args->intf_name, args->args);
+
+ if (port->interfaces == 0)
+ return VNET_DEV_ERR_PRIMARY_INTERFACE_MISSING;
+
+ clib_memcpy (a.name, args->intf_name, sizeof (a.name));
+ a.args = args->args;
+
+ rv = vnet_dev_process_call_port_op_with_ptr (vm, port,
+ vnet_dev_port_add_sec_if, &a);
+
+ if (rv != VNET_DEV_OK)
+ args->sw_if_index = ~0;
+ else
+ args->sw_if_index = a.sw_if_index;
return rv;
}
@@ -251,9 +287,23 @@ vnet_dev_rv_t
vnet_dev_api_remove_port_if (vlib_main_t *vm,
vnet_dev_api_remove_port_if_args_t *args)
{
+ vnet_dev_port_t *port;
+
+ port = vnet_dev_get_port_from_sw_if_index (args->sw_if_index);
+
+ if (port == 0)
+ return VNET_DEV_ERR_UNKNOWN_INTERFACE;
+
+ return vnet_dev_process_call_port_op (vm, port, vnet_dev_port_if_remove);
+}
+
+vnet_dev_rv_t
+vnet_dev_api_port_del_sec_if (vlib_main_t *vm,
+ vnet_dev_api_port_del_sec_if_args_t *args)
+{
vnet_dev_main_t *dm = &vnet_dev_main;
vnet_main_t *vnm = vnet_get_main ();
- vnet_sw_interface_t *si;
+ vnet_sw_interface_t *si, *sup_si;
vnet_hw_interface_t *hi;
vnet_dev_port_t *port;
@@ -261,7 +311,14 @@ vnet_dev_api_remove_port_if (vlib_main_t *vm,
if (!si)
return VNET_DEV_ERR_UNKNOWN_INTERFACE;
- hi = vnet_get_hw_interface_or_null (vnm, si->hw_if_index);
+ if (si->sup_sw_if_index == si->sw_if_index)
+ return VNET_DEV_ERR_UNKNOWN_INTERFACE;
+
+ sup_si = vnet_get_sw_interface_or_null (vnm, si->sup_sw_if_index);
+ if (!sup_si)
+ return VNET_DEV_ERR_UNKNOWN_INTERFACE;
+
+ hi = vnet_get_hw_interface_or_null (vnm, sup_si->hw_if_index);
if (!hi)
return VNET_DEV_ERR_UNKNOWN_INTERFACE;
@@ -270,8 +327,10 @@ vnet_dev_api_remove_port_if (vlib_main_t *vm,
port = vnet_dev_get_port_from_dev_instance (hi->dev_instance);
- if (port->intf.hw_if_index != si->hw_if_index)
+ if (port->interfaces->primary_interface.hw_if_index != si->hw_if_index)
return VNET_DEV_ERR_UNKNOWN_INTERFACE;
- return vnet_dev_process_call_port_op (vm, port, vnet_dev_port_if_remove);
+ return vnet_dev_process_call_port_op_with_ptr (
+ vm, port, vnet_dev_port_del_sec_if,
+ &(vnet_dev_port_del_sec_if_args_t){ .sw_if_index = args->sw_if_index });
}
diff --git a/src/vnet/dev/api.h b/src/vnet/dev/api.h
index 1b7bf27d62a..3e552e4326e 100644
--- a/src/vnet/dev/api.h
+++ b/src/vnet/dev/api.h
@@ -65,4 +65,27 @@ vnet_dev_rv_t
vnet_dev_api_remove_port_if (vlib_main_t *,
vnet_dev_api_remove_port_if_args_t *);
+typedef struct
+{
+ u32 primary_sw_if_index;
+ vnet_dev_if_name_t intf_name;
+ u8 *args;
+
+ /* return */
+ u32 sw_if_index;
+} vnet_dev_api_port_add_sec_if_args_t;
+
+vnet_dev_rv_t
+vnet_dev_api_port_add_sec_if (vlib_main_t *,
+ vnet_dev_api_port_add_sec_if_args_t *);
+
+typedef struct
+{
+ u32 sw_if_index;
+} vnet_dev_api_port_del_sec_if_args_t;
+
+vnet_dev_rv_t
+vnet_dev_api_port_del_sec_if (vlib_main_t *,
+ vnet_dev_api_port_del_sec_if_args_t *);
+
#endif /* _VNET_DEV_API_H_ */
diff --git a/src/vnet/dev/cli.c b/src/vnet/dev/cli.c
index 608abcfd989..6002a2f0dee 100644
--- a/src/vnet/dev/cli.c
+++ b/src/vnet/dev/cli.c
@@ -223,6 +223,94 @@ VLIB_CLI_COMMAND (device_remove_if_cmd, static) = {
};
static clib_error_t *
+device_create_sec_if_cmd_fn (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ vnet_dev_api_port_add_sec_if_args_t a = {};
+ vnet_main_t *vnm = vnet_get_main ();
+ vnet_dev_rv_t rv;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (!a.intf_name[0] &&
+ unformat (input, "if-name %U", unformat_c_string_array, a.intf_name,
+ sizeof (a.intf_name)))
+ ;
+ else if (unformat (input, "primary-if-name %U",
+ unformat_vnet_sw_interface, vnm,
+ &a.primary_sw_if_index))
+ ;
+ else if (unformat (input, "primary-sw-if-index %u",
+ &a.primary_sw_if_index))
+ ;
+ else if (!a.args && unformat (input, "args %v", &a.args))
+ ;
+ else
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
+
+ rv = vnet_dev_api_port_add_sec_if (vm, &a);
+
+ vec_free (a.args);
+
+ if (rv != VNET_DEV_OK)
+ return clib_error_return (0, "unable to create secondary interface: %U",
+ format_vnet_dev_rv, rv);
+
+ return 0;
+}
+
+VLIB_CLI_COMMAND (device_create_sec_if_cmd, static) = {
+ .path = "device create-secondary-interface",
+ .short_help = "device create-secondary-interface [<interface-name> | "
+ "sw-if-index <n>] id <n> [args <sec-if-args>]",
+ .function = device_create_sec_if_cmd_fn,
+ .is_mp_safe = 1,
+};
+
+static clib_error_t *
+device_remove_sec_if_cmd_fn (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ vnet_dev_api_port_del_sec_if_args_t a = { .sw_if_index = ~0 };
+ vnet_main_t *vnm = vnet_get_main ();
+ vnet_dev_rv_t rv;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
+ &a.sw_if_index))
+ ;
+ else if (unformat (input, "sw-if-index %u", &a.sw_if_index))
+ ;
+ else
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
+
+ if (a.sw_if_index == ~0)
+ return clib_error_return (
+ 0, "please specify existing secondary interface name");
+
+ rv = vnet_dev_api_port_del_sec_if (vm, &a);
+
+ if (rv != VNET_DEV_OK)
+ return clib_error_return (0, "unable to remove secondary interface: %U",
+ format_vnet_dev_rv, rv);
+
+ return 0;
+}
+
+VLIB_CLI_COMMAND (device_remove_sec_if_cmd, static) = {
+ .path = "device remove-secondary-interface",
+ .short_help =
+ "device remove-secondary-interface [<interface-name> | sw-if-index <n>]",
+ .function = device_remove_sec_if_cmd_fn,
+ .is_mp_safe = 1,
+};
+
+static clib_error_t *
show_devices_cmd_fn (vlib_main_t *vm, unformat_input_t *input,
vlib_cli_command_t *cmd)
{
diff --git a/src/vnet/dev/dev.c b/src/vnet/dev/dev.c
index e04fa161ce2..7954707dd32 100644
--- a/src/vnet/dev/dev.c
+++ b/src/vnet/dev/dev.c
@@ -130,7 +130,7 @@ vnet_dev_deinit (vlib_main_t *vm, vnet_dev_t *dev)
vnet_dev_validate (vm, dev);
foreach_vnet_dev_port (p, dev)
- ASSERT (p->interface_created == 0);
+ ASSERT (p->interfaces == 0);
if (dev->ops.deinit)
dev->ops.deinit (vm, dev);
@@ -188,7 +188,7 @@ void
vnet_dev_detach (vlib_main_t *vm, vnet_dev_t *dev)
{
foreach_vnet_dev_port (p, dev)
- if (p->interface_created)
+ if (p->interfaces)
vnet_dev_port_if_remove (vm, p);
vnet_dev_deinit (vm, dev);
vnet_dev_free (vm, dev);
@@ -260,6 +260,8 @@ vnet_dev_feature_update_cb (u32 sw_if_index, u8 arc_index, u8 is_enable,
vnet_feature_config_main_t *cm;
vnet_dev_main_t *vdm = &vnet_dev_main;
vnet_dev_port_t *port;
+ vnet_dev_port_interface_t *intf;
+ vnet_dev_instance_t *di;
vnet_hw_interface_t *hw;
u32 current_config_index = ~0;
u32 next_index = ~0;
@@ -269,9 +271,18 @@ vnet_dev_feature_update_cb (u32 sw_if_index, u8 arc_index, u8 is_enable,
return;
hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
- port = vnet_dev_get_port_from_dev_instance (hw->dev_instance);
+ di = vnet_dev_get_dev_instance (hw->dev_instance);
- if (port == 0 || port->intf.sw_if_index != sw_if_index)
+ if (!di)
+ return;
+
+ intf = di->is_primary_if ?
+ vnet_dev_port_get_primary_if (di->port) :
+ vnet_dev_port_get_sec_if_by_index (di->port, di->sec_if_index);
+
+ port = di->port;
+
+ if (port == 0 || intf->sw_if_index != sw_if_index)
return;
if (vnet_have_features (arc_index, sw_if_index))
@@ -281,28 +292,27 @@ vnet_dev_feature_update_cb (u32 sw_if_index, u8 arc_index, u8 is_enable,
vec_elt (cm->config_index_by_sw_if_index, sw_if_index);
vnet_get_config_data (&cm->config_main, &current_config_index,
&next_index, 0);
- if (port->intf.feature_arc == 0 ||
- port->intf.rx_next_index != next_index ||
- port->intf.current_config_index != current_config_index)
+ if (intf->feature_arc == 0 || intf->rx_next_index != next_index ||
+ intf->current_config_index != current_config_index)
{
- port->intf.current_config_index = current_config_index;
- port->intf.rx_next_index = next_index;
- port->intf.feature_arc_index = arc_index;
- port->intf.feature_arc = 1;
+ intf->current_config_index = current_config_index;
+ intf->rx_next_index = next_index;
+ intf->feature_arc_index = arc_index;
+ intf->feature_arc = 1;
update_runtime = 1;
}
}
else
{
- if (port->intf.feature_arc)
+ if (intf->feature_arc)
{
- port->intf.current_config_index = 0;
- port->intf.rx_next_index =
- port->intf.redirect_to_node ?
- port->intf.redirect_to_node_next_index :
- vnet_dev_default_next_index_by_port_type[port->attr.type];
- port->intf.feature_arc_index = 0;
- port->intf.feature_arc = 0;
+ intf->current_config_index = 0;
+ intf->rx_next_index =
+ intf->redirect_to_node ?
+ intf->redirect_to_node_next_index :
+ vnet_dev_default_next_index_by_port_type[port->attr.type];
+ intf->feature_arc_index = 0;
+ intf->feature_arc = 0;
update_runtime = 1;
}
}
diff --git a/src/vnet/dev/dev.h b/src/vnet/dev/dev.h
index 76ff4f55b71..f3f7563317e 100644
--- a/src/vnet/dev/dev.h
+++ b/src/vnet/dev/dev.h
@@ -29,7 +29,8 @@ typedef enum
_ (interrupt_mode) \
_ (rss) \
_ (change_max_rx_frame_size) \
- _ (mac_filter)
+ _ (mac_filter) \
+ _ (secondary_interfaces)
#define foreach_vnet_dev_port_rx_offloads _ (ip4_cksum)
@@ -253,6 +254,8 @@ typedef struct
vnet_dev_port_op_no_rv_t *deinit;
vnet_dev_port_op_no_rv_t *free;
vnet_dev_port_op_no_rv_t *clear_counters;
+ vnet_dev_port_op_with_ptr_t *add_sec_if;
+ vnet_dev_port_op_with_ptr_t *del_sec_if;
format_function_t *format_status;
format_function_t *format_flow;
} vnet_dev_port_ops_t;
@@ -269,30 +272,41 @@ typedef union
u8 as_number;
} vnet_dev_rx_queue_rt_req_t;
+typedef struct
+{
+ vlib_buffer_template_t buffer_template;
+ u32 sw_if_index;
+ u16 next_index;
+ u16 sec_if_index;
+} vnet_dev_rx_queue_if_rt_data_t;
+
typedef struct vnet_dev_rx_queue
{
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
vnet_dev_port_t *port;
u16 rx_thread_index;
u16 index;
- vnet_dev_counter_main_t *counter_main;
- CLIB_CACHE_LINE_ALIGN_MARK (runtime0);
- vnet_dev_rx_queue_t *next_on_thread;
+ u16 size;
u8 interrupt_mode : 1;
u8 enabled : 1;
u8 started : 1;
u8 suspended : 1;
- vnet_dev_queue_id_t queue_id;
- u16 size;
- u16 next_index;
vnet_dev_rx_queue_rt_req_t runtime_request;
+ vnet_dev_counter_main_t *counter_main;
+ vnet_dev_rx_queue_t *next_on_thread;
+ vnet_dev_queue_id_t queue_id;
+ vnet_dev_rx_queue_if_rt_data_t **sec_if_rt_data;
CLIB_CACHE_LINE_ALIGN_MARK (runtime1);
- vlib_buffer_template_t buffer_template;
+ vnet_dev_rx_queue_if_rt_data_t if_rt_data;
CLIB_CACHE_LINE_ALIGN_MARK (driver_data);
u8 data[];
} vnet_dev_rx_queue_t;
+#if CLIB_CACHE_LINE_BYTES > 64
+STATIC_ASSERT_SIZEOF (vnet_dev_rx_queue_t, 2 * CLIB_CACHE_LINE_BYTES);
+#else
STATIC_ASSERT_SIZEOF (vnet_dev_rx_queue_t, 3 * CLIB_CACHE_LINE_BYTES);
+#endif
typedef struct vnet_dev_tx_queue
{
@@ -314,6 +328,38 @@ typedef struct vnet_dev_tx_queue
STATIC_ASSERT_SIZEOF (vnet_dev_tx_queue_t, 2 * CLIB_CACHE_LINE_BYTES);
+typedef struct
+{
+ vnet_dev_if_name_t name;
+ u8 interface_created : 1;
+ u8 feature_arc : 1;
+ u8 redirect_to_node : 1;
+ u8 feature_arc_index;
+ u16 rx_next_index;
+ u32 index;
+ u32 sw_if_index;
+ u32 hw_if_index;
+ u32 dev_instance;
+ u32 tx_node_index;
+ u32 next_index;
+ u32 current_config_index;
+ u16 redirect_to_node_next_index;
+ u32 user_data;
+ vnet_dev_arg_t *args;
+} vnet_dev_port_interface_t;
+
+typedef struct
+{
+ u32 rx_node_index;
+ u8 default_is_intr_mode : 1;
+ u16 num_rx_queues;
+ u16 num_tx_queues;
+ u16 txq_sz;
+ u16 rxq_sz;
+ vnet_dev_port_interface_t primary_interface;
+ vnet_dev_port_interface_t **secondary_interfaces;
+} vnet_dev_port_interfaces_t;
+
typedef struct vnet_dev_port
{
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
@@ -324,7 +370,6 @@ typedef struct vnet_dev_port
u8 started : 1;
u8 link_up : 1;
u8 promisc : 1;
- u8 interface_created : 1;
u8 rx_node_assigned : 1;
vnet_dev_counter_main_t *counter_main;
vnet_dev_queue_config_t rx_queue_config;
@@ -339,32 +384,12 @@ typedef struct vnet_dev_port
vnet_dev_tx_queue_t **tx_queues;
vnet_dev_port_ops_t port_ops;
vnet_dev_arg_t *args;
+ vnet_dev_arg_t *sec_if_args;
vnet_dev_rx_queue_ops_t rx_queue_ops;
vnet_dev_tx_queue_ops_t tx_queue_ops;
vnet_dev_node_t rx_node;
vnet_dev_node_t tx_node;
-
- struct
- {
- vnet_dev_if_name_t name;
- u32 dev_instance;
- u32 rx_node_index;
- u32 current_config_index;
- u16 rx_next_index;
- u16 redirect_to_node_next_index;
- u8 feature_arc_index;
- u8 feature_arc : 1;
- u8 redirect_to_node : 1;
- u8 default_is_intr_mode : 1;
- u8 consistent_qp : 1;
- u32 tx_node_index;
- u32 hw_if_index;
- u32 sw_if_index;
- u16 num_rx_queues;
- u16 num_tx_queues;
- u16 txq_sz;
- u16 rxq_sz;
- } intf;
+ vnet_dev_port_interfaces_t *interfaces;
CLIB_CACHE_LINE_ALIGN_MARK (data0);
u8 data[];
@@ -463,6 +488,8 @@ typedef struct
typedef struct
{
vnet_dev_port_t *port;
+ u32 sec_if_index;
+ u8 is_primary_if : 1;
} vnet_dev_instance_t;
typedef struct
@@ -493,6 +520,7 @@ typedef struct
vnet_dev_port_attr_t attr;
vnet_dev_port_ops_t ops;
vnet_dev_arg_t *args;
+ vnet_dev_arg_t *sec_if_args;
u16 data_size;
void *initial_data;
} port;
@@ -578,12 +606,44 @@ void vnet_dev_clear_hw_interface_counters (u32);
void vnet_dev_set_interface_next_node (vnet_main_t *, u32, u32);
/* port.c */
+
+typedef struct
+{
+ vnet_dev_if_name_t name;
+ u16 num_rx_queues;
+ u16 num_tx_queues;
+ u16 rxq_sz;
+ u16 txq_sz;
+ u8 default_is_intr_mode : 1;
+ u8 consistent_qp : 1;
+
+ /* return */
+ u32 sw_if_index;
+} vnet_dev_port_if_create_args_t;
+
+typedef struct
+{
+ vnet_dev_if_name_t name;
+ u8 *args;
+
+ /* return */
+ u32 sw_if_index;
+} vnet_dev_port_sec_if_create_args_t;
+
+typedef struct
+{
+ u32 sw_if_index;
+} vnet_dev_port_del_sec_if_args_t;
+
vnet_dev_port_op_t vnet_dev_port_start;
vnet_dev_port_op_t vnet_dev_port_start_all_rx_queues;
vnet_dev_port_op_t vnet_dev_port_start_all_tx_queues;
vnet_dev_port_op_no_rv_t vnet_dev_port_stop;
vnet_dev_port_op_no_rv_t vnet_dev_port_deinit;
vnet_dev_port_op_no_rv_t vnet_dev_port_free;
+vnet_dev_port_op_with_ptr_t vnet_dev_port_add_sec_if;
+vnet_dev_port_op_with_ptr_t vnet_dev_port_del_sec_if;
+
void vnet_dev_port_add_counters (vlib_main_t *, vnet_dev_port_t *,
vnet_dev_counter_t *, u16);
vnet_dev_port_op_no_rv_t vnet_dev_port_free_counters;
@@ -596,7 +656,7 @@ vnet_dev_port_cfg_change_req_validate (vlib_main_t *, vnet_dev_port_t *,
vnet_dev_port_cfg_change_req_t *);
vnet_dev_rv_t vnet_dev_port_cfg_change (vlib_main_t *, vnet_dev_port_t *,
vnet_dev_port_cfg_change_req_t *);
-vnet_dev_port_op_t vnet_dev_port_if_create;
+vnet_dev_port_op_with_ptr_t vnet_dev_port_if_create;
vnet_dev_port_op_t vnet_dev_port_if_remove;
/* queue.c */
diff --git a/src/vnet/dev/dev_funcs.h b/src/vnet/dev/dev_funcs.h
index 0531b17a009..f47344b0cea 100644
--- a/src/vnet/dev/dev_funcs.h
+++ b/src/vnet/dev/dev_funcs.h
@@ -60,6 +60,18 @@ vnet_dev_get_dev_instance (u32 dev_instance)
return pool_elt_at_index (dm->dev_instances, dev_instance);
}
+static_always_inline vnet_dev_port_interface_t *
+vnet_dev_port_get_primary_if (vnet_dev_port_t *p)
+{
+ return &p->interfaces->primary_interface;
+}
+
+static_always_inline vnet_dev_port_interface_t *
+vnet_dev_port_get_sec_if_by_index (vnet_dev_port_t *p, u32 index)
+{
+ return *pool_elt_at_index (p->interfaces->secondary_interfaces, index);
+}
+
static_always_inline vnet_dev_port_t *
vnet_dev_get_port_from_dev_instance (u32 dev_instance)
{
@@ -76,7 +88,8 @@ vnet_dev_get_port_from_hw_if_index (u32 hw_if_index)
hw = vnet_get_hw_interface (vnet_get_main (), hw_if_index);
port = vnet_dev_get_port_from_dev_instance (hw->dev_instance);
- if (!port || port->intf.hw_if_index != hw_if_index)
+ if (!port || !port->interfaces ||
+ port->interfaces->primary_interface.hw_if_index != hw_if_index)
return 0;
return port;
@@ -85,19 +98,32 @@ vnet_dev_get_port_from_hw_if_index (u32 hw_if_index)
static_always_inline u32
vnet_dev_get_rx_queue_if_sw_if_index (vnet_dev_rx_queue_t *rxq)
{
- return rxq->port->intf.sw_if_index;
+ return rxq->port->interfaces->primary_interface.sw_if_index;
}
static_always_inline u32
vnet_dev_get_rx_queue_if_hw_if_index (vnet_dev_rx_queue_t *rxq)
{
- return rxq->port->intf.hw_if_index;
+ return rxq->port->interfaces->primary_interface.hw_if_index;
}
static_always_inline u32
vnet_dev_get_port_rx_node_index (vnet_dev_port_t *port)
{
- return port->intf.rx_node_index;
+ return port->interfaces->rx_node_index;
+}
+
+static_always_inline vnet_dev_port_t *
+vnet_dev_get_port_from_sw_if_index (u32 sw_if_index)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ vnet_sw_interface_t *si;
+
+ si = vnet_get_sw_interface_or_null (vnm, sw_if_index);
+ if (!si)
+ return 0;
+
+ return vnet_dev_get_port_from_hw_if_index (si->hw_if_index);
}
static_always_inline vnet_dev_t *
@@ -219,22 +245,49 @@ vnet_dev_tx_queue_unlock_if_needed (vnet_dev_tx_queue_t *txq)
__atomic_store_n (&txq->lock, 0, __ATOMIC_RELEASE);
}
+static_always_inline vnet_dev_rx_queue_if_rt_data_t *
+vnet_dev_get_rx_queue_if_rt_data (vnet_dev_rx_queue_t *rxq)
+{
+ return &rxq->if_rt_data;
+}
+
+static_always_inline vnet_dev_rx_queue_if_rt_data_t *
+vnet_dev_get_rx_queue_sec_if_rt_data (vnet_dev_rx_queue_t *rxq,
+ u32 sec_if_index)
+{
+ return rxq->sec_if_rt_data[sec_if_index];
+}
+
static_always_inline vlib_buffer_template_t
vnet_dev_get_rx_queue_if_buffer_template (vnet_dev_rx_queue_t *rxq)
{
- return rxq->buffer_template;
+ return rxq->if_rt_data.buffer_template;
+}
+
+static_always_inline vlib_buffer_template_t
+vnet_dev_get_rx_queue_sec_if_buffer_template (vnet_dev_rx_queue_t *rxq,
+ u32 sec_if_index)
+{
+ return rxq->sec_if_rt_data[sec_if_index]->buffer_template;
}
static_always_inline u16
vnet_dev_get_rx_queue_if_next_index (vnet_dev_rx_queue_t *rxq)
{
- return rxq->next_index;
+ return rxq->if_rt_data.next_index;
+}
+
+static_always_inline u16
+vnet_dev_get_rx_queue_sec_if_next_index (vnet_dev_rx_queue_t *rxq,
+ u32 sec_if_index)
+{
+ return rxq->sec_if_rt_data[sec_if_index]->next_index;
}
static_always_inline u8
vnet_dev_get_rx_queue_buffer_pool_index (vnet_dev_rx_queue_t *rxq)
{
- return rxq->buffer_template.buffer_pool_index;
+ return rxq->if_rt_data.buffer_template.buffer_pool_index;
}
static_always_inline u32
@@ -269,8 +322,8 @@ static_always_inline vnet_dev_rx_queue_t *
foreach_vnet_dev_rx_queue_runtime_helper (vlib_node_runtime_t *node,
vnet_dev_rx_queue_t *rxq)
{
- vnet_dev_port_t *port;
vnet_dev_rx_queue_rt_req_t req;
+ vnet_dev_port_interfaces_t *ifs;
if (rxq == 0)
rxq = vnet_dev_get_rx_node_runtime (node)->first_rx_queue;
@@ -287,15 +340,34 @@ foreach_vnet_dev_rx_queue_runtime_helper (vlib_node_runtime_t *node,
req.as_number =
__atomic_exchange_n (&rxq->runtime_request.as_number, 0, __ATOMIC_ACQUIRE);
- port = rxq->port;
+ ifs = rxq->port->interfaces;
if (req.update_next_index)
- rxq->next_index = port->intf.rx_next_index;
+ {
+ vnet_dev_port_interface_t **si =
+ rxq->port->interfaces->secondary_interfaces;
+ rxq->if_rt_data.next_index = ifs->primary_interface.rx_next_index;
+ vec_foreach_pointer (rtd, rxq->sec_if_rt_data)
+ if (rtd)
+ rtd->next_index = si[rtd->sec_if_index]->next_index;
+ }
if (req.update_feature_arc)
{
- vlib_buffer_template_t *bt = &rxq->buffer_template;
- bt->current_config_index = port->intf.current_config_index;
- vnet_buffer (bt)->feature_arc_index = port->intf.feature_arc_index;
+ vnet_dev_port_interface_t **si =
+ rxq->port->interfaces->secondary_interfaces;
+ vlib_buffer_template_t *bt = &rxq->if_rt_data.buffer_template;
+ bt->current_config_index = ifs->primary_interface.current_config_index;
+ vnet_buffer (bt)->feature_arc_index =
+ ifs->primary_interface.feature_arc_index;
+ vec_foreach_pointer (rtd, rxq->sec_if_rt_data)
+ if (rtd)
+ {
+ vlib_buffer_template_t *bt = &rtd->buffer_template;
+ bt->current_config_index =
+ si[rtd->sec_if_index]->current_config_index;
+ vnet_buffer (bt)->feature_arc_index =
+ si[rtd->sec_if_index]->feature_arc_index;
+ }
}
if (req.suspend_on)
diff --git a/src/vnet/dev/errors.h b/src/vnet/dev/errors.h
index 6ececad12ec..243b10e698e 100644
--- a/src/vnet/dev/errors.h
+++ b/src/vnet/dev/errors.h
@@ -37,9 +37,12 @@
_ (TIMEOUT, "timeout") \
_ (UNKNOWN_DEVICE, "unknown device") \
_ (UNKNOWN_INTERFACE, "unknown interface") \
+ _ (NOT_PRIMARY_INTERFACE, "not primary interface") \
+ _ (PRIMARY_INTERFACE_MISSING, "primary interface missing") \
_ (UNSUPPORTED_CONFIG, "unsupported config") \
_ (UNSUPPORTED_DEVICE, "unsupported device") \
_ (UNSUPPORTED_DEVICE_VER, "unsupported device version") \
+ _ (UNSUPPORTED_INTERFACE, "unsupported interface") \
_ (ALREADY_DONE, "already done") \
_ (NO_SUCH_INTERFACE, "no such interface") \
_ (INIT_FAILED, "init failed")
diff --git a/src/vnet/dev/format.c b/src/vnet/dev/format.c
index fb46fcc47bc..ffc4a3a70b4 100644
--- a/src/vnet/dev/format.c
+++ b/src/vnet/dev/format.c
@@ -44,9 +44,15 @@ u8 *
format_vnet_dev_interface_name (u8 *s, va_list *args)
{
u32 i = va_arg (*args, u32);
- vnet_dev_port_t *port = vnet_dev_get_port_from_dev_instance (i);
+ vnet_dev_instance_t *di = vnet_dev_get_dev_instance (i);
+ vnet_dev_port_interface_t *si;
+ vnet_dev_port_t *p = di->port;
+
+ if (di->is_primary_if)
+ return format (s, "%s", p->interfaces->primary_interface.name);
- return format (s, "%s", port->intf.name);
+ si = vnet_dev_port_get_sec_if_by_index (p, di->sec_if_index);
+ return format (s, "%s", si->name);
}
u8 *
@@ -138,12 +144,22 @@ format_vnet_dev_port_info (u8 *s, va_list *args)
format_vnet_dev_args, port->args);
s = format (s, "\n%UInterface ", format_white_space, indent);
- if (port->interface_created)
+ if (port->interfaces)
{
- s = format (s, "assigned, interface name is '%U', RX node is '%U'",
- format_vnet_sw_if_index_name, vnm, port->intf.sw_if_index,
- format_vlib_node_name, vm,
- vnet_dev_get_port_rx_node_index (port));
+ s = format (
+ s, "assigned, primary interface name is '%U', RX node is '%U'",
+ format_vnet_sw_if_index_name, vnm,
+ port->interfaces->primary_interface.sw_if_index, format_vlib_node_name,
+ vm, vnet_dev_get_port_rx_node_index (port));
+ pool_foreach_pointer (sif, port->interfaces->secondary_interfaces)
+ {
+ s = format (s, "\n%USecondary interface '%U'", format_white_space,
+ indent, format_vnet_sw_if_index_name, vnm,
+ sif->sw_if_index);
+ if (sif->args)
+ s = format (s, "\n%U args '%U", format_white_space, indent,
+ format_vnet_dev_args, sif->args);
+ }
}
else
s = format (s, "not assigned");
diff --git a/src/vnet/dev/handlers.c b/src/vnet/dev/handlers.c
index 2a55affe3e3..bfacbe27c99 100644
--- a/src/vnet/dev/handlers.c
+++ b/src/vnet/dev/handlers.c
@@ -19,7 +19,8 @@ vnet_dev_port_set_max_frame_size (vnet_main_t *vnm, vnet_hw_interface_t *hw,
u32 frame_size)
{
vlib_main_t *vm = vlib_get_main ();
- vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (hw->dev_instance);
+ vnet_dev_instance_t *di = vnet_dev_get_dev_instance (hw->dev_instance);
+ vnet_dev_port_t *p;
vnet_dev_rv_t rv;
vnet_dev_port_cfg_change_req_t req = {
@@ -27,6 +28,11 @@ vnet_dev_port_set_max_frame_size (vnet_main_t *vnm, vnet_hw_interface_t *hw,
.max_rx_frame_size = frame_size,
};
+ p = di->port;
+
+ if (!di->is_primary_if)
+ return vnet_dev_port_err (vm, p, VNET_DEV_ERR_NOT_PRIMARY_INTERFACE, "");
+
log_debug (p->dev, "size %u", frame_size);
rv = vnet_dev_port_cfg_change_req_validate (vm, p, &req);
@@ -49,13 +55,17 @@ vnet_dev_port_eth_flag_change (vnet_main_t *vnm, vnet_hw_interface_t *hw,
u32 flags)
{
vlib_main_t *vm = vlib_get_main ();
- vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (hw->dev_instance);
+ vnet_dev_instance_t *di = vnet_dev_get_dev_instance (hw->dev_instance);
+ vnet_dev_port_t *p = di->port;
vnet_dev_rv_t rv;
vnet_dev_port_cfg_change_req_t req = {
.type = VNET_DEV_PORT_CFG_PROMISC_MODE,
};
+ if (!di->is_primary_if)
+ return ~0;
+
switch (flags)
{
case ETHERNET_INTERFACE_FLAG_DEFAULT_L3:
@@ -87,13 +97,17 @@ vnet_dev_port_mac_change (vnet_hw_interface_t *hi, const u8 *old,
const u8 *new)
{
vlib_main_t *vm = vlib_get_main ();
- vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (hi->dev_instance);
+ vnet_dev_instance_t *di = vnet_dev_get_dev_instance (hi->dev_instance);
+ vnet_dev_port_t *p = di->port;
vnet_dev_rv_t rv;
vnet_dev_port_cfg_change_req_t req = {
.type = VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR,
};
+ if (!di->is_primary_if)
+ return vnet_dev_port_err (vm, p, VNET_DEV_ERR_NOT_PRIMARY_INTERFACE, "");
+
vnet_dev_set_hw_addr_eth_mac (&req.addr, new);
log_debug (p->dev, "new mac %U", format_vnet_dev_hw_addr, &req.addr);
@@ -116,7 +130,8 @@ vnet_dev_add_del_mac_address (vnet_hw_interface_t *hi, const u8 *address,
u8 is_add)
{
vlib_main_t *vm = vlib_get_main ();
- vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (hi->dev_instance);
+ vnet_dev_instance_t *di = vnet_dev_get_dev_instance (hi->dev_instance);
+ vnet_dev_port_t *p = di->port;
vnet_dev_rv_t rv;
vnet_dev_port_cfg_change_req_t req = {
@@ -124,6 +139,9 @@ vnet_dev_add_del_mac_address (vnet_hw_interface_t *hi, const u8 *address,
VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR,
};
+ if (!di->is_primary_if)
+ return vnet_dev_port_err (vm, p, VNET_DEV_ERR_NOT_PRIMARY_INTERFACE, "");
+
vnet_dev_set_hw_addr_eth_mac (&req.addr, address);
log_debug (p->dev, "received (addr %U is_add %u", format_vnet_dev_hw_addr,
@@ -147,10 +165,19 @@ vnet_dev_flow_ops_fn (vnet_main_t *vnm, vnet_flow_dev_op_t op,
u32 dev_instance, u32 flow_index, uword *private_data)
{
vlib_main_t *vm = vlib_get_main ();
- vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (dev_instance);
+ vnet_dev_instance_t *di = vnet_dev_get_dev_instance (dev_instance);
+ vnet_dev_port_t *p;
vnet_dev_port_cfg_change_req_t req;
vnet_dev_rv_t rv;
+ if (!di)
+ return VNET_FLOW_ERROR_NO_SUCH_INTERFACE;
+
+ if (di->is_primary_if)
+ return VNET_FLOW_ERROR_NOT_SUPPORTED;
+
+ p = di->port;
+
switch (op)
{
case VNET_FLOW_DEV_OP_ADD_FLOW:
@@ -201,10 +228,12 @@ vnet_dev_interface_set_rss_queues (vnet_main_t *vnm, vnet_hw_interface_t *hi,
void
vnet_dev_clear_hw_interface_counters (u32 instance)
{
- vnet_dev_port_t *port = vnet_dev_get_port_from_dev_instance (instance);
+ vnet_dev_instance_t *di = vnet_dev_get_dev_instance (instance);
vlib_main_t *vm = vlib_get_main ();
- vnet_dev_process_call_port_op_no_rv (vm, port, vnet_dev_port_clear_counters);
+ if (di->is_primary_if)
+ vnet_dev_process_call_port_op_no_rv (vm, di->port,
+ vnet_dev_port_clear_counters);
}
void
@@ -213,44 +242,49 @@ vnet_dev_set_interface_next_node (vnet_main_t *vnm, u32 hw_if_index,
{
vlib_main_t *vm = vlib_get_main ();
vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
- vnet_dev_port_t *port =
- vnet_dev_get_port_from_dev_instance (hw->dev_instance);
+ vnet_dev_instance_t *di = vnet_dev_get_dev_instance (hw->dev_instance);
+ vnet_dev_port_interface_t *intf;
int runtime_update = 0;
+ if (di->is_primary_if)
+ intf = vnet_dev_port_get_primary_if (di->port);
+ else
+ intf = vnet_dev_port_get_sec_if_by_index (di->port, di->sec_if_index);
+
if (node_index == ~0)
{
- port->intf.redirect_to_node_next_index = 0;
- if (port->intf.feature_arc == 0)
+ intf->redirect_to_node_next_index = 0;
+ if (intf->feature_arc == 0)
{
- port->intf.rx_next_index =
- vnet_dev_default_next_index_by_port_type[port->attr.type];
+ intf->rx_next_index =
+ vnet_dev_default_next_index_by_port_type[di->port->attr.type];
runtime_update = 1;
}
- port->intf.redirect_to_node = 0;
+ intf->redirect_to_node = 0;
}
else
{
u16 next_index = vlib_node_add_next (vlib_get_main (),
port_rx_eth_node.index, node_index);
- port->intf.redirect_to_node_next_index = next_index;
- if (port->intf.feature_arc == 0)
+ intf->redirect_to_node_next_index = next_index;
+ if (intf->feature_arc == 0)
{
- port->intf.rx_next_index = next_index;
+ intf->rx_next_index = next_index;
runtime_update = 1;
}
- port->intf.redirect_to_node = 1;
+ intf->redirect_to_node = 1;
}
- port->intf.rx_next_index =
+ intf->rx_next_index =
node_index == ~0 ?
- vnet_dev_default_next_index_by_port_type[port->attr.type] :
- node_index;
+ vnet_dev_default_next_index_by_port_type[di->port->attr.type] :
+ node_index;
if (runtime_update)
{
- foreach_vnet_dev_port_rx_queue (rxq, port)
+ foreach_vnet_dev_port_rx_queue (rxq, di->port)
vnet_dev_rx_queue_rt_request (
vm, rxq, (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1 });
- log_debug (port->dev, "runtime update requested due to chgange in "
- "reditect-to-next configuration");
+ log_debug (di->port->dev, "runtime update requested due to chgange in "
+ "reditect-to-next configuration");
}
}
diff --git a/src/vnet/dev/port.c b/src/vnet/dev/port.c
index 5bd4edf05c1..fccedebdcf4 100644
--- a/src/vnet/dev/port.c
+++ b/src/vnet/dev/port.c
@@ -94,6 +94,7 @@ vnet_dev_port_free (vlib_main_t *vm, vnet_dev_port_t *port)
pool_free (port->rx_queues);
pool_free (port->tx_queues);
vnet_dev_arg_free (&port->args);
+ vnet_dev_arg_free (&port->sec_if_args);
pool_put_index (dev->ports, port->index);
clib_mem_free (port);
}
@@ -109,11 +110,23 @@ vnet_dev_port_update_tx_node_runtime (vlib_main_t *vm, vnet_dev_port_t *port)
clib_bitmap_foreach (ti, q->assigned_threads)
{
vlib_main_t *tvm = vlib_get_main_by_index (ti);
- vlib_node_runtime_t *nr =
- vlib_node_get_runtime (tvm, port->intf.tx_node_index);
- vnet_dev_tx_node_runtime_t *tnr = vnet_dev_get_tx_node_runtime (nr);
- tnr->hw_if_index = port->intf.hw_if_index;
+ vlib_node_runtime_t *nr;
+ vnet_dev_tx_node_runtime_t *tnr;
+ vnet_dev_port_interfaces_t *ifs = port->interfaces;
+
+ nr =
+ vlib_node_get_runtime (tvm, ifs->primary_interface.tx_node_index);
+ tnr = vnet_dev_get_tx_node_runtime (nr);
+ tnr->hw_if_index = ifs->primary_interface.hw_if_index;
tnr->tx_queue = q;
+
+ pool_foreach_pointer (sif, port->interfaces->secondary_interfaces)
+ {
+ nr = vlib_node_get_runtime (tvm, sif->tx_node_index);
+ tnr = vnet_dev_get_tx_node_runtime (nr);
+ tnr->hw_if_index = sif->hw_if_index;
+ tnr->tx_queue = q;
+ }
}
}
}
@@ -271,6 +284,11 @@ vnet_dev_port_add (vlib_main_t *vm, vnet_dev_t *dev, vnet_dev_port_id_t id,
for (vnet_dev_arg_t *a = args->port.args; a->type != VNET_DEV_ARG_END; a++)
vec_add1 (port->args, *a);
+ if (args->port.sec_if_args)
+ for (vnet_dev_arg_t *a = args->port.sec_if_args;
+ a->type != VNET_DEV_ARG_END; a++)
+ vec_add1 (port->sec_if_args, *a);
+
/* defaults out of port attributes */
port->max_rx_frame_size = args->port.attr.max_supported_rx_frame_size;
port->primary_hw_addr = args->port.attr.hw_addr;
@@ -466,25 +484,34 @@ vnet_dev_port_state_change (vlib_main_t *vm, vnet_dev_port_t *port,
vnet_dev_port_state_changes_t changes)
{
vnet_main_t *vnm = vnet_get_main ();
+ vnet_dev_port_interfaces_t *ifs = port->interfaces;
vnet_dev_port_validate (vm, port);
if (changes.change.link_speed)
{
port->speed = changes.link_speed;
- if (port->interface_created)
- vnet_hw_interface_set_link_speed (vnm, port->intf.hw_if_index,
- changes.link_speed);
+ if (port->interfaces)
+ vnet_hw_interface_set_link_speed (
+ vnm, ifs->primary_interface.hw_if_index, changes.link_speed);
log_debug (port->dev, "port speed changed to %u", changes.link_speed);
}
if (changes.change.link_state)
{
port->link_up = changes.link_state;
- if (port->interface_created)
- vnet_hw_interface_set_flags (
- vnm, port->intf.hw_if_index,
- changes.link_state ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
+ if (ifs)
+ {
+ vnet_hw_interface_set_flags (
+ vnm, ifs->primary_interface.hw_if_index,
+ changes.link_state ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
+ pool_foreach_pointer (sif, ifs->secondary_interfaces)
+ {
+ vnet_hw_interface_set_flags (
+ vnm, sif->hw_if_index,
+ changes.link_state ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
+ }
+ }
log_debug (port->dev, "port link state changed to %s",
changes.link_state ? "up" : "down");
}
@@ -510,19 +537,51 @@ vnet_dev_port_free_counters (vlib_main_t *vm, vnet_dev_port_t *port)
vnet_dev_counters_free (vm, port->counter_main);
}
+static void
+vnet_dev_port_init_if_rt_data (vlib_main_t *vm, vnet_dev_port_t *port,
+ vnet_dev_rx_queue_if_rt_data_t *rtd,
+ u32 sw_if_index)
+{
+ vnet_dev_t *dev = port->dev;
+ u8 buffer_pool_index =
+ vlib_buffer_pool_get_default_for_numa (vm, dev->numa_node);
+ vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index);
+
+ rtd->buffer_template = bp->buffer_template;
+ vnet_buffer (&rtd->buffer_template)->sw_if_index[VLIB_RX] = sw_if_index;
+ vnet_buffer (&rtd->buffer_template)->sw_if_index[VLIB_TX] = ~0;
+ rtd->next_index = ~0;
+ rtd->sw_if_index = sw_if_index;
+}
+
vnet_dev_rv_t
-vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port)
+vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port, void *ptr)
{
vnet_main_t *vnm = vnet_get_main ();
u16 n_threads = vlib_get_n_threads ();
vnet_dev_main_t *dm = &vnet_dev_main;
vnet_dev_t *dev = port->dev;
+ vnet_dev_port_if_create_args_t *a = ptr;
+ vnet_dev_port_interfaces_t *ifs = port->interfaces;
vnet_dev_instance_t *di;
vnet_dev_rv_t rv;
u16 ti = 0;
- u8 is_consistent_qp = port->intf.consistent_qp;
- if (port->intf.name[0] == 0)
+ if (ifs)
+ return VNET_DEV_ERR_ALREADY_EXISTS;
+
+ port->interfaces = ifs =
+ clib_mem_alloc (sizeof (vnet_dev_port_interfaces_t));
+
+ *(ifs) = (vnet_dev_port_interfaces_t){
+ .num_rx_queues = a->num_rx_queues,
+ .num_tx_queues = a->num_tx_queues,
+ .rxq_sz = a->rxq_sz,
+ .txq_sz = a->txq_sz,
+ .default_is_intr_mode = a->default_is_intr_mode,
+ };
+
+ if (a->name[0] == 0)
{
u8 *s;
s = format (0, "%s%u/%u",
@@ -530,36 +589,36 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port)
port->dev->index, port->index);
u32 n = vec_len (s);
- if (n >= sizeof (port->intf.name))
+ if (n >= sizeof (a->name))
{
vec_free (s);
return VNET_DEV_ERR_BUG;
}
- clib_memcpy (port->intf.name, s, n);
- port->intf.name[n] = 0;
+ clib_memcpy (ifs->primary_interface.name, s, n);
+ ifs->primary_interface.name[n] = 0;
vec_free (s);
}
+ else
+ clib_memcpy (ifs->primary_interface.name, a->name,
+ sizeof (ifs->primary_interface.name));
log_debug (
dev, "allocating %u rx queues with size %u and %u tx queues with size %u",
- port->intf.num_rx_queues, port->intf.rxq_sz, port->intf.num_tx_queues,
- port->intf.txq_sz);
+ a->num_rx_queues, a->rxq_sz, a->num_tx_queues, a->txq_sz);
- for (int i = 0; i < port->intf.num_rx_queues; i++)
- if ((rv = vnet_dev_rx_queue_alloc (vm, port, port->intf.rxq_sz)) !=
- VNET_DEV_OK)
+ for (int i = 0; i < ifs->num_rx_queues; i++)
+ if ((rv = vnet_dev_rx_queue_alloc (vm, port, ifs->rxq_sz)) != VNET_DEV_OK)
goto error;
- for (u32 i = 0; i < port->intf.num_tx_queues; i++)
- if ((rv = vnet_dev_tx_queue_alloc (vm, port, port->intf.txq_sz)) !=
- VNET_DEV_OK)
+ for (u32 i = 0; i < ifs->num_tx_queues; i++)
+ if ((rv = vnet_dev_tx_queue_alloc (vm, port, ifs->txq_sz)) != VNET_DEV_OK)
goto error;
foreach_vnet_dev_port_tx_queue (q, port)
{
/* if consistent_qp is enabled, we start by assigning queues to workers
* and we end with main */
- u16 real_ti = (ti + is_consistent_qp) % n_threads;
+ u16 real_ti = (ti + a->consistent_qp) % n_threads;
q->assigned_threads = clib_bitmap_set (q->assigned_threads, real_ti, 1);
log_debug (dev, "port %u tx queue %u assigned to thread %u",
port->port_id, q->queue_id, real_ti);
@@ -568,8 +627,9 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port)
}
pool_get (dm->dev_instances, di);
- port->intf.dev_instance = di - dm->dev_instances;
+ ifs->primary_interface.dev_instance = di - dm->dev_instances;
di->port = port;
+ di->is_primary_if = 1;
if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET)
{
@@ -578,7 +638,7 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port)
vnet_sw_interface_t *sw;
vnet_hw_interface_t *hw;
vnet_hw_if_caps_t caps = 0;
- u32 rx_node_index;
+ u32 rx_node_index, hw_if_index, sw_if_index;
driver = pool_elt_at_index (dm->drivers, dev->driver_index);
@@ -590,27 +650,28 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port)
dev_class->tx_function_n_errors = port->tx_node.n_error_counters;
/* create new interface including tx and output nodes */
- port->intf.hw_if_index = vnet_eth_register_interface (
+ hw_if_index = vnet_eth_register_interface (
vnm, &(vnet_eth_interface_registration_t){
.address = port->primary_hw_addr.eth_mac,
.max_frame_size = port->max_rx_frame_size,
.dev_class_index = driver->dev_class_index,
- .dev_instance = port->intf.dev_instance,
+ .dev_instance = ifs->primary_interface.dev_instance,
.cb.set_max_frame_size = vnet_dev_port_set_max_frame_size,
.cb.flag_change = vnet_dev_port_eth_flag_change,
});
+ ifs->primary_interface.hw_if_index = hw_if_index;
- sw = vnet_get_hw_sw_interface (vnm, port->intf.hw_if_index);
- hw = vnet_get_hw_interface (vnm, port->intf.hw_if_index);
- port->intf.sw_if_index = sw->sw_if_index;
+ sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
+ hw = vnet_get_hw_interface (vnm, hw_if_index);
+ sw_if_index = ifs->primary_interface.sw_if_index = sw->sw_if_index;
vnet_hw_interface_set_flags (
- vnm, port->intf.hw_if_index,
+ vnm, ifs->primary_interface.hw_if_index,
port->link_up ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
if (port->speed)
- vnet_hw_interface_set_link_speed (vnm, port->intf.hw_if_index,
- port->speed);
+ vnet_hw_interface_set_link_speed (
+ vnm, ifs->primary_interface.hw_if_index, port->speed);
- port->intf.tx_node_index = hw->tx_node_index;
+ ifs->primary_interface.tx_node_index = hw->tx_node_index;
caps |= port->attr.caps.interrupt_mode ? VNET_HW_IF_CAP_INT_MODE : 0;
caps |= port->attr.caps.mac_filter ? VNET_HW_IF_CAP_MAC_FILTER : 0;
@@ -618,14 +679,15 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port)
caps |= port->attr.tx_offloads.ip4_cksum ? VNET_HW_IF_CAP_TX_CKSUM : 0;
if (caps)
- vnet_hw_if_set_caps (vnm, port->intf.hw_if_index, caps);
+ vnet_hw_if_set_caps (vnm, hw_if_index, caps);
/* create / reuse rx node */
if (vec_len (dm->free_rx_node_indices))
{
vlib_node_t *n;
rx_node_index = vec_pop (dm->free_rx_node_indices);
- vlib_node_rename (vm, rx_node_index, "%s-rx", port->intf.name);
+ vlib_node_rename (vm, rx_node_index, "%s-rx",
+ port->interfaces->primary_interface.name);
n = vlib_get_node (vm, rx_node_index);
n->function = vlib_node_get_preferred_node_fn_variant (
vm, port->rx_node.registrations);
@@ -649,30 +711,28 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port)
.error_counters = port->rx_node.error_counters,
.n_errors = port->rx_node.n_error_counters,
};
- rx_node_index =
- vlib_register_node (vm, &rx_node_reg, "%s-rx", port->intf.name);
+ rx_node_index = vlib_register_node (vm, &rx_node_reg, "%s-rx",
+ ifs->primary_interface.name);
}
port->rx_node_assigned = 1;
- port->intf.rx_node_index = rx_node_index;
- port->intf.rx_next_index =
+ ifs->rx_node_index = rx_node_index;
+ ifs->primary_interface.rx_next_index =
vnet_dev_default_next_index_by_port_type[port->attr.type];
vlib_worker_thread_node_runtime_update ();
log_debug (dev,
"ethernet interface created, hw_if_index %u sw_if_index %u "
"rx_node_index %u tx_node_index %u",
- port->intf.hw_if_index, port->intf.sw_if_index,
- port->intf.rx_node_index, port->intf.tx_node_index);
+ hw_if_index, sw_if_index, rx_node_index,
+ ifs->primary_interface.tx_node_index);
}
- port->interface_created = 1;
foreach_vnet_dev_port_rx_queue (q, port)
{
- vnet_buffer (&q->buffer_template)->sw_if_index[VLIB_RX] =
- port->intf.sw_if_index;
+ vnet_dev_port_init_if_rt_data (vm, port, &q->if_rt_data,
+ ifs->primary_interface.sw_if_index);
/* poison to catch node not calling runtime update function */
- q->next_index = ~0;
- q->interrupt_mode = port->intf.default_is_intr_mode;
+ q->interrupt_mode = ifs->default_is_intr_mode;
vnet_dev_rx_queue_rt_request (
vm, q, (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1 });
}
@@ -685,6 +745,8 @@ vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port)
error:
if (rv != VNET_DEV_OK)
vnet_dev_port_if_remove (vm, port);
+ else
+ a->sw_if_index = ifs->primary_interface.sw_if_index;
return rv;
}
@@ -693,6 +755,7 @@ vnet_dev_port_if_remove (vlib_main_t *vm, vnet_dev_port_t *port)
{
vnet_dev_main_t *dm = &vnet_dev_main;
vnet_main_t *vnm = vnet_get_main ();
+ vnet_dev_port_interfaces_t *ifs = port->interfaces;
vnet_dev_port_validate (vm, port);
@@ -701,23 +764,22 @@ vnet_dev_port_if_remove (vlib_main_t *vm, vnet_dev_port_t *port)
if (port->rx_node_assigned)
{
- vlib_node_rename (vm, port->intf.rx_node_index, "deleted-%u",
- port->intf.rx_node_index);
- vec_add1 (dm->free_rx_node_indices, port->intf.rx_node_index);
+ vlib_node_rename (vm, ifs->rx_node_index, "deleted-%u",
+ ifs->rx_node_index);
+ vec_add1 (dm->free_rx_node_indices, ifs->rx_node_index);
port->rx_node_assigned = 0;
}
- if (port->interface_created)
+ if (ifs)
{
vlib_worker_thread_barrier_sync (vm);
- vnet_delete_hw_interface (vnm, port->intf.hw_if_index);
+ vnet_delete_hw_interface (vnm, ifs->primary_interface.hw_if_index);
vlib_worker_thread_barrier_release (vm);
- pool_put_index (dm->dev_instances, port->intf.dev_instance);
- port->interface_created = 0;
+ pool_put_index (dm->dev_instances, ifs->primary_interface.dev_instance);
+ clib_mem_free (port->interfaces);
+ port->interfaces = 0;
}
- port->intf = (typeof (port->intf)){};
-
if (port->port_ops.deinit)
port->port_ops.deinit (vm, port);
@@ -734,6 +796,171 @@ vnet_dev_port_if_remove (vlib_main_t *vm, vnet_dev_port_t *port)
return VNET_DEV_OK;
}
+
+vnet_dev_rv_t
+vnet_dev_port_del_sec_if_internal (vlib_main_t *vm, vnet_dev_port_t *port,
+ vnet_dev_port_interface_t *sif)
+{
+ vnet_dev_rv_t rv = VNET_DEV_OK;
+
+ if (sif && port->port_ops.add_sec_if)
+ rv = port->port_ops.add_sec_if (vm, port, sif);
+
+ if (rv != VNET_DEV_OK)
+ return rv;
+
+ foreach_vnet_dev_port_rx_queue (q, port)
+ {
+ vec_foreach_pointer (p, q->sec_if_rt_data)
+ if (p)
+ clib_mem_free (p);
+ vec_free (q->sec_if_rt_data);
+ }
+
+ if (sif->interface_created)
+ ethernet_delete_interface (vnet_get_main (), sif->hw_if_index);
+
+ pool_put_index (port->interfaces->secondary_interfaces, sif->index);
+ vnet_dev_arg_free (&sif->args);
+ clib_mem_free (sif);
+ return rv;
+}
+
+vnet_dev_rv_t
+vnet_dev_port_add_sec_if (vlib_main_t *vm, vnet_dev_port_t *port, void *ptr)
+{
+ vnet_dev_main_t *dm = &vnet_dev_main;
+ vnet_dev_port_sec_if_create_args_t *a = ptr;
+ vnet_main_t *vnm = vnet_get_main ();
+ vnet_dev_t *dev = port->dev;
+ vnet_dev_port_interface_t *sif = 0;
+ vnet_dev_port_interface_t **sip;
+ vnet_dev_rv_t rv = VNET_DEV_OK;
+
+ sif = clib_mem_alloc (sizeof (vnet_dev_port_interface_t));
+ pool_get (port->interfaces->secondary_interfaces, sip);
+ *sip = sif;
+
+ *sif = (vnet_dev_port_interface_t){
+ .index = sip - port->interfaces->secondary_interfaces,
+ .args = vec_dup (port->sec_if_args),
+ };
+
+ clib_memcpy (sif->name, a->name, sizeof (sif->name));
+
+ if (sif->args)
+ {
+ rv = vnet_dev_arg_parse (vm, dev, sif->args, a->args);
+ if (rv != VNET_DEV_OK)
+ return rv;
+ }
+
+ if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET)
+ {
+ vnet_device_class_t *dev_class;
+ vnet_dev_driver_t *driver;
+ vnet_sw_interface_t *sw;
+ vnet_hw_interface_t *hw;
+ vnet_dev_instance_t *di;
+ vnet_hw_if_caps_t caps = 0;
+
+ pool_get (dm->dev_instances, di);
+ sif->dev_instance = di - dm->dev_instances;
+ di->port = port;
+ di->sec_if_index = sip - port->interfaces->secondary_interfaces;
+
+ driver = pool_elt_at_index (dm->drivers, dev->driver_index);
+
+ /* hack to provide per-port tx node function */
+ dev_class = vnet_get_device_class (vnm, driver->dev_class_index);
+ dev_class->tx_fn_registrations = port->tx_node.registrations;
+ dev_class->format_tx_trace = port->tx_node.format_trace;
+ dev_class->tx_function_error_counters = port->tx_node.error_counters;
+ dev_class->tx_function_n_errors = port->tx_node.n_error_counters;
+
+ /* create new interface including tx and output nodes */
+ sif->hw_if_index = vnet_eth_register_interface (
+ vnm, &(vnet_eth_interface_registration_t){
+ .address = port->primary_hw_addr.eth_mac,
+ .max_frame_size = port->max_rx_frame_size,
+ .dev_class_index = driver->dev_class_index,
+ .dev_instance = sif->dev_instance,
+ .cb.set_max_frame_size = vnet_dev_port_set_max_frame_size,
+ .cb.flag_change = vnet_dev_port_eth_flag_change,
+ });
+
+ sw = vnet_get_hw_sw_interface (vnm, sif->hw_if_index);
+ hw = vnet_get_hw_interface (vnm, sif->hw_if_index);
+ sif->sw_if_index = sw->sw_if_index;
+ sif->next_index =
+ vnet_dev_default_next_index_by_port_type[port->attr.type];
+ sif->interface_created = 1;
+ vnet_dev_port_update_tx_node_runtime (vm, port);
+ vnet_hw_interface_set_flags (
+ vnm, sif->hw_if_index,
+ port->link_up ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
+ if (port->speed)
+ vnet_hw_interface_set_link_speed (vnm, sif->hw_if_index, port->speed);
+
+ sif->tx_node_index = hw->tx_node_index;
+
+ caps |= port->attr.caps.interrupt_mode ? VNET_HW_IF_CAP_INT_MODE : 0;
+ caps |= port->attr.caps.mac_filter ? VNET_HW_IF_CAP_MAC_FILTER : 0;
+ caps |= port->attr.tx_offloads.tcp_gso ? VNET_HW_IF_CAP_TCP_GSO : 0;
+ caps |= port->attr.tx_offloads.ip4_cksum ? VNET_HW_IF_CAP_TX_CKSUM : 0;
+
+ if (caps)
+ vnet_hw_if_set_caps (vnm, sif->hw_if_index, caps);
+ }
+ else
+ return VNET_DEV_ERR_NOT_SUPPORTED;
+
+ foreach_vnet_dev_port_rx_queue (q, port)
+ {
+ vnet_dev_rx_queue_if_rt_data_t *rtd;
+ vec_validate (q->sec_if_rt_data, sif->index);
+
+ rtd = clib_mem_alloc_aligned (sizeof (vnet_dev_rx_queue_if_rt_data_t),
+ CLIB_CACHE_LINE_BYTES);
+
+ q->sec_if_rt_data[sif->index] = rtd;
+
+ vnet_dev_port_init_if_rt_data (vm, port, rtd, sif->sw_if_index);
+ vnet_dev_rx_queue_rt_request (
+ vm, q, (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1 });
+ }
+
+ if (sif && port->port_ops.add_sec_if)
+ rv = port->port_ops.add_sec_if (vm, port, sif);
+
+ if (rv != VNET_DEV_OK)
+ vnet_dev_port_del_sec_if_internal (vm, port, sif);
+
+ return rv;
+}
+
+vnet_dev_rv_t
+vnet_dev_port_del_sec_if (vlib_main_t *vm, vnet_dev_port_t *port, void *ptr)
+{
+ vnet_dev_port_del_sec_if_args_t *a = ptr;
+ vnet_sw_interface_t *si;
+ vnet_hw_interface_t *hi;
+ vnet_dev_instance_t *di;
+ vnet_main_t *vnm = vnet_get_main ();
+
+ log_debug (port->dev, "%u", a->sw_if_index);
+
+ si = vnet_get_sw_interface_or_null (vnm, a->sw_if_index);
+ if (!si)
+ return VNET_DEV_ERR_UNKNOWN_INTERFACE;
+
+ hi = vnet_get_hw_interface (vnm, si->hw_if_index);
+ di = vnet_dev_get_dev_instance (hi->dev_instance);
+
+ return vnet_dev_port_del_sec_if_internal (
+ vm, port, vnet_dev_port_get_sec_if_by_index (port, di->sec_if_index));
+}
+
void
vnet_dev_port_clear_counters (vlib_main_t *vm, vnet_dev_port_t *port)
{
diff --git a/src/vnet/dev/queue.c b/src/vnet/dev/queue.c
index 7efea5f14bd..57ed3dcae3b 100644
--- a/src/vnet/dev/queue.c
+++ b/src/vnet/dev/queue.c
@@ -36,7 +36,6 @@ vnet_dev_rx_queue_alloc (vlib_main_t *vm, vnet_dev_port_t *port,
vnet_dev_t *dev = port->dev;
vnet_dev_rv_t rv = VNET_DEV_OK;
u16 n_threads = vlib_get_n_threads ();
- u8 buffer_pool_index;
vnet_dev_port_validate (vm, port);
@@ -65,15 +64,6 @@ vnet_dev_rx_queue_alloc (vlib_main_t *vm, vnet_dev_port_t *port,
dm->next_rx_queue_thread = 1;
}
- buffer_pool_index =
- vlib_buffer_pool_get_default_for_numa (vm, dev->numa_node);
- vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index);
-
- rxq->buffer_template = bp->buffer_template;
- vnet_buffer (&rxq->buffer_template)->sw_if_index[VLIB_TX] = ~0;
-
- rxq->next_index = vnet_dev_default_next_index_by_port_type[port->attr.type];
-
if (port->rx_queue_ops.alloc)
rv = port->rx_queue_ops.alloc (vm, rxq);