#include <vnet/vnet.h>
#include <vnet/plugin/plugin.h>
-#include <vnet/fib/ip6_fib.h>
#include <vnet/adj/adj.h>
#include <vnet/adj/adj_mcast.h>
-#include <vnet/l2/l2_input.h>
+#include <vnet/ip/ip.h>
+#include <vnet/interface/rx_queue_funcs.h>
+#include <vnet/interface/tx_queue_funcs.h>
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_LOG_CLASS (if_default_log, static) = {
+ .class_name = "interface",
+};
+/* *INDENT-ON* */
+
+#define log_debug(fmt,...) vlib_log_debug(if_default_log.class, fmt, __VA_ARGS__)
+#define log_err(fmt,...) vlib_log_err(if_default_log.class, fmt, __VA_ARGS__)
typedef enum vnet_interface_helper_flags_t_
{
/* Serialize hardware interface classes since they may have changed.
Must do this before sending up/down flags. */
/* *INDENT-OFF* */
- pool_foreach (hif, im->hw_interfaces, ({
+ pool_foreach (hif, im->hw_interfaces) {
vnet_hw_interface_class_t * hw_class = vnet_get_hw_interface_class (vnm, hif->hw_class_index);
serialize_cstring (m, hw_class->name);
- }));
+ }
/* *INDENT-ON* */
/* Send sw/hw interface state when non-zero. */
/* *INDENT-OFF* */
- pool_foreach (sif, im->sw_interfaces, ({
+ pool_foreach (sif, im->sw_interfaces) {
if (sif->flags != 0)
{
vec_add2 (sts, st, 1);
st->sw_hw_if_index = sif->sw_if_index;
st->flags = sif->flags;
}
- }));
+ }
/* *INDENT-ON* */
vec_serialize (m, sts, serialize_vec_vnet_sw_hw_interface_state);
_vec_len (sts) = 0;
/* *INDENT-OFF* */
- pool_foreach (hif, im->hw_interfaces, ({
+ pool_foreach (hif, im->hw_interfaces) {
if (hif->flags != 0)
{
vec_add2 (sts, st, 1);
st->sw_hw_if_index = hif->hw_if_index;
st->flags = vnet_hw_interface_flags_to_sw(hif->flags);
}
- }));
+ }
/* *INDENT-ON* */
vec_serialize (m, sts, serialize_vec_vnet_sw_hw_interface_state);
clib_error_t *error;
/* *INDENT-OFF* */
- pool_foreach (hif, im->hw_interfaces, ({
+ pool_foreach (hif, im->hw_interfaces) {
unserialize_cstring (m, &class_name);
p = hash_get_mem (im->hw_interface_class_by_name, class_name);
- ASSERT (p != 0);
- error = vnet_hw_interface_set_class_helper (vnm, hif->hw_if_index, p[0], /* redistribute */ 0);
+ if (p)
+ {
+ error = vnet_hw_interface_set_class_helper
+ (vnm, hif->hw_if_index, p[0], /* redistribute */ 0);
+ }
+ else
+ error = clib_error_return (0, "hw class %s AWOL?", class_name);
+
if (error)
clib_error_report (error);
vec_free (class_name);
- }));
+ }
/* *INDENT-ON* */
}
hi->flags |= flags;
done:
+ if (error)
+ log_err ("hw_set_flags_helper: %U", format_clib_error, error);
return error;
}
}
}
- /* Do not change state for slave link of bonded interfaces */
- if (si->flags & VNET_SW_INTERFACE_FLAG_BOND_SLAVE)
- {
- error = clib_error_return
- (0, "not allowed as %U belong to a BondEthernet interface",
- format_vnet_sw_interface_name, vnm, si);
- goto done;
- }
-
/* Already in the desired state? */
if ((si->flags & mask) == flags)
goto done;
goto done;
}
- /* save the si admin up flag */
- old_flags = si->flags;
-
/* update si admin up flag in advance if we are going admin down */
if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
si->flags &= ~VNET_SW_INTERFACE_FLAG_ADMIN_UP;
hi->flags &
~VNET_HW_INTERFACE_FLAG_LINK_UP,
helper_flags);
+ vnet_hw_if_update_runtime_data (vnm, si->hw_if_index);
}
}
si->flags |= flags;
done:
+ if (error)
+ log_err ("sw_set_flags_helper: %U", format_clib_error, error);
return error;
}
vnet_hw_interface_set_flags (vnet_main_t * vnm, u32 hw_if_index,
vnet_hw_interface_flags_t flags)
{
+ log_debug ("hw_set_flags: hw_if_index %u flags 0x%x", hw_if_index, flags);
return vnet_hw_interface_set_flags_helper
(vnm, hw_if_index, flags,
VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE);
vnet_sw_interface_set_flags (vnet_main_t * vnm, u32 sw_if_index,
vnet_sw_interface_flags_t flags)
{
+ log_debug ("sw_set_flags: sw_if_index %u flags 0x%x", sw_if_index, flags);
return vnet_sw_interface_set_flags_helper
(vnm, sw_if_index, flags,
VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE);
}
+void
+vnet_sw_interface_admin_up (vnet_main_t * vnm, u32 sw_if_index)
+{
+ u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
+ log_debug ("sw_admin_up: sw_if_index %u", sw_if_index);
+
+ if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
+ {
+ flags |= VNET_SW_INTERFACE_FLAG_ADMIN_UP;
+ vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
+ }
+}
+
+void
+vnet_sw_interface_admin_down (vnet_main_t * vnm, u32 sw_if_index)
+{
+ u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
+ log_debug ("sw_admin_down: sw_if_index %u", sw_if_index);
+
+ if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
+ {
+ flags &= ~(VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+ vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
+ }
+}
+
+static void
+vnet_if_update_lookup_tables (vnet_main_t *vnm, u32 sw_if_index)
+{
+ vnet_interface_main_t *im = &vnm->interface_main;
+ vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
+
+ vec_validate_init_empty (im->hw_if_index_by_sw_if_index, sw_if_index, ~0);
+ vec_validate_init_empty (im->if_out_arc_end_next_index_by_sw_if_index,
+ sw_if_index, ~0);
+
+ im->hw_if_index_by_sw_if_index[sw_if_index] = hi->hw_if_index;
+ im->if_out_arc_end_next_index_by_sw_if_index[sw_if_index] =
+ hi->if_out_arc_end_node_next_index;
+}
+
static u32
vnet_create_sw_interface_no_callbacks (vnet_main_t * vnm,
vnet_sw_interface_t * template)
vnet_interface_counter_unlock (im);
}
+ vnet_if_update_lookup_tables (vnm, sw_if_index);
return sw_if_index;
}
vnet_create_sw_interface (vnet_main_t * vnm, vnet_sw_interface_t * template,
u32 * sw_if_index)
{
+ vnet_interface_main_t *im = &vnm->interface_main;
clib_error_t *error;
vnet_hw_interface_t *hi;
vnet_device_class_t *dev_class;
+ if (template->sub.eth.flags.two_tags == 1
+ && template->sub.eth.flags.exact_match == 1
+ && (template->sub.eth.flags.inner_vlan_id_any == 1
+ || template->sub.eth.flags.outer_vlan_id_any == 1))
+ {
+ char *str = "inner-dot1q any exact-match is unsupported";
+ error = clib_error_return (0, str);
+ log_err ("create_sw_interface: %s", str);
+ return error;
+ }
+
hi = vnet_get_sup_hw_interface (vnm, template->sup_sw_if_index);
dev_class = vnet_get_device_class (vnm, hi->dev_class_index);
if (error)
{
/* undo the work done by vnet_create_sw_interface_no_callbacks() */
- vnet_interface_main_t *im = &vnm->interface_main;
+ log_err ("create_sw_interface: set flags failed\n %U",
+ format_clib_error, error);
vnet_sw_interface_t *sw =
pool_elt_at_index (im->sw_interfaces, *sw_if_index);
pool_put (im->sw_interfaces, sw);
}
+ else
+ {
+ vnet_sw_interface_t *sw =
+ pool_elt_at_index (im->sw_interfaces, *sw_if_index);
+ log_debug ("create_sw_interface: interface %U (sw_if_index %u) created",
+ format_vnet_sw_interface_name, vnm, sw, *sw_if_index);
+ }
return error;
}
vnet_sw_interface_t *sw =
pool_elt_at_index (im->sw_interfaces, sw_if_index);
+ log_debug ("delete_sw_interface: sw_if_index %u, name '%U'",
+ sw_if_index, format_vnet_sw_if_index_name, vnm, sw_if_index);
+
/* Check if the interface has config and is removed from L2 BD or XConnect */
- vlib_main_t *vm = vlib_get_main ();
- l2_input_config_t *config;
- if (sw_if_index < vec_len (l2input_main.configs))
- {
- config = vec_elt_at_index (l2input_main.configs, sw_if_index);
- if (config->xconnect)
- set_int_l2_mode (vm, vnm, MODE_L3, config->output_sw_if_index, 0,
- L2_BD_PORT_TYPE_NORMAL, 0, 0);
- if (config->xconnect || config->bridge)
- set_int_l2_mode (vm, vnm, MODE_L3, sw_if_index, 0,
- L2_BD_PORT_TYPE_NORMAL, 0, 0);
- }
vnet_clear_sw_interface_tag (vnm, sw_if_index);
/* Bring down interface in case it is up. */
if (si->mtu[VNET_MTU_L3] != mtu)
{
si->mtu[VNET_MTU_L3] = mtu;
+ log_debug ("set_mtu: interface %U, new mtu %u",
+ format_vnet_sw_if_index_name, vnm, sw_if_index, mtu);
+
call_sw_interface_mtu_change_callbacks (vnm, sw_if_index);
}
}
}
/* Notify interested parties */
if (changed)
- call_sw_interface_mtu_change_callbacks (vnm, sw_if_index);
+ {
+ log_debug ("set_protocol_mtu: interface %U l3 %u ip4 %u ip6 %u mpls %u",
+ format_vnet_sw_if_index_name, vnm, sw_if_index,
+ mtu[VNET_MTU_L3], mtu[VNET_MTU_IP4], mtu[VNET_MTU_IP6],
+ mtu[VNET_MTU_MPLS]);
+ call_sw_interface_mtu_change_callbacks (vnm, sw_if_index);
+ }
}
void
{
vlib_node_t *n = vlib_get_node (vm, node_index);
- n->function = dev_class->tx_function;
n->format_trace = dev_class->format_tx_trace;
- vlib_register_errors (vm, node_index,
- dev_class->tx_function_n_errors,
- dev_class->tx_function_error_strings);
+ vlib_register_errors (vm, node_index, dev_class->tx_function_n_errors,
+ dev_class->tx_function_error_strings,
+ dev_class->tx_function_error_counters);
}
static void
vnet_config_main_t *cm;
u32 hw_index, i;
char *tx_node_name = NULL, *output_node_name = NULL;
+ vlib_node_t *if_out_node =
+ vlib_get_node (vm, vnet_interface_output_node.index);
pool_get (im->hw_interfaces, hw);
clib_memset (hw, 0, sizeof (*hw));
+ hw->trace_classify_table_index = ~0;
hw_index = hw - im->hw_interfaces;
hw->hw_if_index = hw_index;
- hw->default_rx_mode = VNET_HW_INTERFACE_RX_MODE_POLLING;
+ hw->default_rx_mode = VNET_HW_IF_RX_MODE_POLLING;
if (dev_class->format_device_name)
hw->name = format (0, "%U", dev_class->format_device_name, dev_instance);
hw->min_packet_bytes = 0;
vnet_sw_interface_set_mtu (vnm, hw->sw_if_index, 0);
- if (dev_class->tx_function == 0)
+ if (dev_class->tx_function == 0 && dev_class->tx_fn_registrations == 0)
goto no_output_nodes; /* No output/tx nodes to create */
tx_node_name = (char *) format (0, "%v-tx", hw->name);
vlib_node_rename (vm, hw->tx_node_index, "%v", tx_node_name);
vlib_node_rename (vm, hw->output_node_index, "%v", output_node_name);
- /* *INDENT-OFF* */
- foreach_vlib_main ({
- vnet_interface_output_runtime_t *rt;
-
- rt = vlib_node_get_runtime_data (this_vlib_main, hw->output_node_index);
- ASSERT (rt->is_deleted == 1);
- rt->is_deleted = 0;
- rt->hw_if_index = hw_index;
- rt->sw_if_index = hw->sw_if_index;
- rt->dev_instance = hw->dev_instance;
+ foreach_vlib_main ()
+ {
+ vnet_interface_output_runtime_t *rt;
- rt = vlib_node_get_runtime_data (this_vlib_main, hw->tx_node_index);
- rt->hw_if_index = hw_index;
- rt->sw_if_index = hw->sw_if_index;
- rt->dev_instance = hw->dev_instance;
- });
- /* *INDENT-ON* */
+ rt =
+ vlib_node_get_runtime_data (this_vlib_main, hw->output_node_index);
+ ASSERT (rt->is_deleted == 1);
+ rt->is_deleted = 0;
+ rt->hw_if_index = hw_index;
+ rt->sw_if_index = hw->sw_if_index;
+ rt->dev_instance = hw->dev_instance;
+
+ rt = vlib_node_get_runtime_data (this_vlib_main, hw->tx_node_index);
+ rt->hw_if_index = hw_index;
+ rt->sw_if_index = hw->sw_if_index;
+ rt->dev_instance = hw->dev_instance;
+ }
/* The new class may differ from the old one.
* Functions have to be updated. */
node = vlib_get_node (vm, hw->output_node_index);
- node->function = vnet_interface_output_node;
node->format_trace = format_vnet_interface_output_trace;
- /* *INDENT-OFF* */
- foreach_vlib_main ({
- nrt = vlib_node_get_runtime (this_vlib_main, hw->output_node_index);
- nrt->function = node->function;
- });
- /* *INDENT-ON* */
+ node->node_fn_registrations = if_out_node->node_fn_registrations;
+ node->function = if_out_node->function;
+
+ foreach_vlib_main ()
+ {
+ nrt = vlib_node_get_runtime (this_vlib_main, hw->output_node_index);
+ nrt->function = node->function;
+ vlib_node_runtime_perf_counter (this_vlib_main, nrt, 0, 0, 0,
+ VLIB_NODE_RUNTIME_PERF_RESET);
+ }
node = vlib_get_node (vm, hw->tx_node_index);
- node->function = dev_class->tx_function;
+ if (dev_class->tx_fn_registrations)
+ {
+ node->node_fn_registrations = dev_class->tx_fn_registrations;
+ node->function = vlib_node_get_preferred_node_fn_variant (
+ vm, dev_class->tx_fn_registrations);
+ }
+ else
+ node->function = dev_class->tx_function;
node->format_trace = dev_class->format_tx_trace;
- /* *INDENT-OFF* */
- foreach_vlib_main ({
- nrt = vlib_node_get_runtime (this_vlib_main, hw->tx_node_index);
- nrt->function = node->function;
- });
- /* *INDENT-ON* */
+
+ foreach_vlib_main ()
+ {
+ nrt = vlib_node_get_runtime (this_vlib_main, hw->tx_node_index);
+ nrt->function = node->function;
+ vlib_node_runtime_perf_counter (this_vlib_main, nrt, 0, 0, 0,
+ VLIB_NODE_RUNTIME_PERF_RESET);
+ }
_vec_len (im->deleted_hw_interface_nodes) -= 1;
}
r.type = VLIB_NODE_TYPE_INTERNAL;
r.runtime_data = &rt;
r.runtime_data_bytes = sizeof (rt);
- r.scalar_size = 0;
+ r.scalar_size = sizeof (vnet_hw_if_tx_frame_t);
r.vector_size = sizeof (u32);
r.flags = VLIB_NODE_FLAG_IS_OUTPUT;
r.name = tx_node_name;
- r.function = dev_class->tx_function;
+ if (dev_class->tx_fn_registrations)
+ {
+ r.function = 0;
+ r.node_fn_registrations = dev_class->tx_fn_registrations;
+ }
+ else
+ r.function = dev_class->tx_function;
hw->tx_node_index = vlib_register_node (vm, &r);
r.flags = 0;
r.name = output_node_name;
- r.function = vnet_interface_output_node;
r.format_trace = format_vnet_interface_output_trace;
+ if (if_out_node->node_fn_registrations)
+ {
+ r.function = 0;
+ r.node_fn_registrations = if_out_node->node_fn_registrations;
+ }
+ else
+ r.function = if_out_node->function;
{
static char *e[] = {
"interface is down",
"interface is deleted",
- "no buffers to segment GSO",
};
r.n_errors = ARRAY_LEN (e);
vlib_node_add_next_with_slot (vm, hw->output_node_index,
hw->tx_node_index,
VNET_INTERFACE_OUTPUT_NEXT_TX);
-
/* add interface to the list of "output-interface" feature arc start nodes
and clone nexts from 1st interface if it exists */
fcm = vnet_feature_get_config_main (im->output_feature_arc_index);
}
}
+ hw->if_out_arc_end_node_next_index = vlib_node_add_next (
+ vm, vnet_interface_output_arc_end_node.index, hw->tx_node_index);
+ vnet_if_update_lookup_tables (vnm, hw->sw_if_index);
setup_output_node (vm, hw->output_node_index, hw_class);
setup_tx_node (vm, hw->tx_node_index, dev_class);
/* Call delete callbacks. */
call_hw_interface_add_del_callbacks (vnm, hw_if_index, /* is_create */ 0);
+ /* delete rx & tx queues */
+ vnet_hw_if_unregister_all_rx_queues (vnm, hw_if_index);
+ vnet_hw_if_unregister_all_tx_queues (vnm, hw_if_index);
+ vnet_hw_if_update_runtime_data (vnm, hw_if_index);
+
/* Delete any sub-interfaces. */
{
u32 id, sw_if_index;
/* Put output/tx nodes into recycle pool */
vnet_hw_interface_nodes_t *dn;
- /* *INDENT-OFF* */
- foreach_vlib_main
- ({
+ foreach_vlib_main ()
+ {
vnet_interface_output_runtime_t *rt =
vlib_node_get_runtime_data (this_vlib_main, hw->output_node_index);
/* Mark node runtime as deleted so output node (if called)
* will drop packets. */
rt->is_deleted = 1;
- });
- /* *INDENT-ON* */
+ }
vlib_node_rename (vm, hw->output_node_index,
"interface-%d-output-deleted", hw_if_index);
hash_unset_mem (im->hw_interface_by_name, hw->name);
vec_free (hw->name);
vec_free (hw->hw_address);
- vec_free (hw->input_node_thread_index_by_queue);
- vec_free (hw->dq_runtime_index_by_queue);
-
+ vec_free (hw->output_node_thread_runtimes);
pool_put (im->hw_interfaces, hw);
}
im = &vnm->interface_main;
/* *INDENT-OFF* */
- pool_foreach (hi, im->hw_interfaces,
- ({
+ pool_foreach (hi, im->hw_interfaces)
+ {
if (WALK_STOP == fn(vnm, hi->hw_if_index, ctx))
break;
- }));
+ }
/* *INDENT-ON* */
}
im = &vnm->interface_main;
/* *INDENT-OFF* */
- pool_foreach (si, im->sw_interfaces,
+ pool_foreach (si, im->sw_interfaces)
{
if (WALK_STOP == fn (vnm, si, ctx))
break;
- });
+ }
/* *INDENT-ON* */
}
return (hc->flags & VNET_HW_INTERFACE_CLASS_FLAG_P2P);
}
+int
+vnet_sw_interface_is_nbma (vnet_main_t * vnm, u32 sw_if_index)
+{
+ vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
+ vnet_hw_interface_class_t *hc =
+ vnet_get_hw_interface_class (vnm, hw->hw_class_index);
+
+ return (hc->flags & VNET_HW_INTERFACE_CLASS_FLAG_NBMA);
+}
+
+clib_error_t *
+vnet_sw_interface_supports_addressing (vnet_main_t *vnm, u32 sw_if_index)
+{
+ if (sw_if_index == 0)
+ {
+ return clib_error_create (
+ "local0 interface doesn't support IP addressing");
+ }
+
+ if (vnet_sw_interface_is_sub (vnm, sw_if_index))
+ {
+ vnet_sw_interface_t *si;
+ si = vnet_get_sw_interface_or_null (vnm, sw_if_index);
+ if (si && si->type == VNET_SW_INTERFACE_TYPE_SUB &&
+ si->sub.eth.flags.exact_match == 0)
+ {
+ return clib_error_create (
+ "sub-interface without exact-match doesn't support IP addressing");
+ }
+ }
+ return NULL;
+}
+
clib_error_t *
vnet_interface_init (vlib_main_t * vm)
{
sizeof (b->opaque), sizeof (vnet_buffer_opaque_t));
}
- im->sw_if_counter_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
- CLIB_CACHE_LINE_BYTES);
- im->sw_if_counter_lock[0] = 1; /* should be no need */
+ clib_spinlock_init (&im->sw_if_counter_lock);
+ clib_spinlock_lock (&im->sw_if_counter_lock); /* should be no need */
vec_validate (im->sw_if_counters, VNET_N_SIMPLE_INTERFACE_COUNTER - 1);
#define _(E,n,p) \
im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_##E].stat_segment_name = "/" #p "/" #n;
foreach_combined_interface_counter_name
#undef _
- im->sw_if_counter_lock[0] = 0;
+ clib_spinlock_unlock (&im->sw_if_counter_lock);
im->device_class_by_name = hash_create_string ( /* size */ 0,
sizeof (uword));
c->index = vec_len (im->device_classes);
hash_set_mem (im->device_class_by_name, c->name, c->index);
+ /* to avoid confusion, please remove ".tx_function" statement
+ from VNET_DEVICE_CLASS() if using function candidates */
+ ASSERT (c->tx_fn_registrations == 0 || c->tx_function == 0);
+
if (c->tx_fn_registrations)
- {
- vlib_node_fn_registration_t *fnr = c->tx_fn_registrations;
- int priority = -1;
-
- /* to avoid confusion, please remove ".tx_function" statement
- from VNET_DEVICE_CLASS() if using function candidates */
- ASSERT (c->tx_function == 0);
-
- while (fnr)
- {
- if (fnr->priority > priority)
- {
- priority = fnr->priority;
- c->tx_function = fnr->function;
- }
- fnr = fnr->next_registration;
- }
- }
+ c->tx_function = vlib_node_get_preferred_node_fn_variant (
+ vm, c->tx_fn_registrations);
vec_add1 (im->device_classes, c[0]);
c = c->next_class_registration;
im->hw_interface_class_by_name = hash_create_string ( /* size */ 0,
sizeof (uword));
+ im->rxq_index_by_hw_if_index_and_queue_id =
+ hash_create_mem (0, sizeof (u64), sizeof (u32));
+ im->txq_index_by_hw_if_index_and_queue_id =
+ hash_create_mem (0, sizeof (u64), sizeof (u32));
im->sw_if_index_by_sup_and_sub = hash_create_mem (0, sizeof (u64),
sizeof (uword));
{
}
}
- im->gso_interface_count = 0;
/* init per-thread data */
vec_validate_aligned (im->per_thread_data, vlib_num_workers (),
CLIB_CACHE_LINE_BYTES);
vnm->interface_tag_by_sw_if_index = hash_create (0, sizeof (uword));
-#if VLIB_BUFFER_TRACE_TRAJECTORY > 0
- if ((error = vlib_call_init_function (vm, trajectory_trace_init)))
- return error;
-#endif
-
return 0;
}
return error;
}
+clib_error_t *
+vnet_hw_interface_add_del_mac_address (vnet_main_t * vnm,
+ u32 hw_if_index,
+ const u8 * mac_address, u8 is_add)
+{
+ clib_error_t *error = 0;
+ vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
+
+ vnet_device_class_t *dev_class =
+ vnet_get_device_class (vnm, hi->dev_class_index);
+
+ if (!hi->hw_address)
+ {
+ error =
+ clib_error_return
+ (0, "Secondary MAC Addresses not supported for interface index %u",
+ hw_if_index);
+ goto done;
+ }
+
+ if (dev_class->mac_addr_add_del_function)
+ error = dev_class->mac_addr_add_del_function (hi, mac_address, is_add);
+
+ if (!error)
+ {
+ vnet_hw_interface_class_t *hw_class;
+
+ hw_class = vnet_get_hw_interface_class (vnm, hi->hw_class_index);
+
+ if (NULL != hw_class->mac_addr_add_del_function)
+ error = hw_class->mac_addr_add_del_function (hi, mac_address, is_add);
+ }
+
+ /* If no errors, add to the list of secondary MACs on the ethernet intf */
+ if (!error)
+ ethernet_interface_add_del_address (ðernet_main, hw_if_index,
+ mac_address, is_add);
+
+done:
+ if (error)
+ log_err ("hw_add_del_mac_address: %U", format_clib_error, error);
+ return error;
+}
+
static clib_error_t *
vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm,
u32 hw_if_index,
(vnm, hw_if_index, mac_address);
}
+static int
+vnet_sw_interface_check_table_same (u32 unnumbered_sw_if_index,
+ u32 ip_sw_if_index)
+{
+ if (ip4_main.fib_index_by_sw_if_index[unnumbered_sw_if_index] !=
+ ip4_main.fib_index_by_sw_if_index[ip_sw_if_index])
+ return VNET_API_ERROR_UNEXPECTED_INTF_STATE;
+
+ if (ip4_main.mfib_index_by_sw_if_index[unnumbered_sw_if_index] !=
+ ip4_main.mfib_index_by_sw_if_index[ip_sw_if_index])
+ return VNET_API_ERROR_UNEXPECTED_INTF_STATE;
+
+ if (ip6_main.fib_index_by_sw_if_index[unnumbered_sw_if_index] !=
+ ip6_main.fib_index_by_sw_if_index[ip_sw_if_index])
+ return VNET_API_ERROR_UNEXPECTED_INTF_STATE;
+
+ if (ip6_main.mfib_index_by_sw_if_index[unnumbered_sw_if_index] !=
+ ip6_main.mfib_index_by_sw_if_index[ip_sw_if_index])
+ return VNET_API_ERROR_UNEXPECTED_INTF_STATE;
+
+ return 0;
+}
+
/* update the unnumbered state of an interface*/
-void
+int
vnet_sw_interface_update_unnumbered (u32 unnumbered_sw_if_index,
u32 ip_sw_if_index, u8 enable)
{
vnet_main_t *vnm = vnet_get_main ();
vnet_sw_interface_t *si;
u32 was_unnum;
+ int rv = 0;
si = vnet_get_sw_interface (vnm, unnumbered_sw_if_index);
was_unnum = (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED);
if (enable)
{
+ rv = vnet_sw_interface_check_table_same (unnumbered_sw_if_index,
+ ip_sw_if_index);
+ if (rv != 0)
+ return rv;
si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED;
si->unnumbered_sw_if_index = ip_sw_if_index;
}
else
{
- si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED);
- si->unnumbered_sw_if_index = (u32) ~ 0;
+ /*
+ * Unless the interface is actually unnumbered, don't
+ * smash e.g. if_address_pool_index_by_sw_if_index
+ */
+ if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
+ {
+ si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED);
+ si->unnumbered_sw_if_index = (u32) ~0;
- ip4_main.lookup_main.if_address_pool_index_by_sw_if_index
- [unnumbered_sw_if_index] = ~0;
- ip6_main.lookup_main.if_address_pool_index_by_sw_if_index
- [unnumbered_sw_if_index] = ~0;
+ ip4_main.lookup_main
+ .if_address_pool_index_by_sw_if_index[unnumbered_sw_if_index] = ~0;
+ ip6_main.lookup_main
+ .if_address_pool_index_by_sw_if_index[unnumbered_sw_if_index] = ~0;
+ }
}
if (was_unnum != (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
ip4_sw_interface_enable_disable (unnumbered_sw_if_index, enable);
ip6_sw_interface_enable_disable (unnumbered_sw_if_index, enable);
}
+
+ return 0;
}
vnet_l3_packet_type_t
}
}
+clib_error_t *
+vnet_hw_interface_set_rss_queues (vnet_main_t * vnm,
+ vnet_hw_interface_t * hi,
+ clib_bitmap_t * bitmap)
+{
+ clib_error_t *error = 0;
+ vnet_device_class_t *dev_class =
+ vnet_get_device_class (vnm, hi->dev_class_index);
+
+ if (dev_class->set_rss_queues_function)
+ {
+ if (clib_bitmap_count_set_bits (bitmap) == 0)
+ {
+ error = clib_error_return (0,
+ "must assign at least one valid rss queue");
+ goto done;
+ }
+
+ error = dev_class->set_rss_queues_function (vnm, hi, bitmap);
+ }
+ else
+ {
+ error = clib_error_return (0,
+ "setting rss queues is not supported on this interface");
+ }
+
+ if (!error)
+ {
+ clib_bitmap_free (hi->rss_queues);
+ hi->rss_queues = clib_bitmap_dup (bitmap);
+ }
+
+done:
+ if (error)
+ log_err ("hw_set_rss_queues: %U", format_clib_error, error);
+ return error;
+}
+
int collect_detailed_interface_stats_flag = 0;
void