return 0;
}
+static int
+pg_mac_address_cmp (const mac_address_t * m1, const mac_address_t * m2)
+{
+ return (!mac_address_cmp (m1, m2));
+}
+
+static clib_error_t *
+pg_add_del_mac_address (vnet_hw_interface_t * hi,
+ const u8 * address, u8 is_add)
+{
+ pg_main_t *pg = &pg_main;
+
+ if (ethernet_address_cast (address))
+ {
+ mac_address_t mac;
+ pg_interface_t *pi;
+
+ pi = pool_elt_at_index (pg->interfaces, hi->dev_instance);
+
+ mac_address_from_bytes (&mac, address);
+ if (is_add)
+ vec_add1 (pi->allowed_mcast_macs, mac);
+ else
+ {
+ u32 pos = vec_search_with_function (pi->allowed_mcast_macs, &mac,
+ pg_mac_address_cmp);
+ if (~0 != pos)
+ vec_del1 (pi->allowed_mcast_macs, pos);
+ }
+ }
+ return (NULL);
+}
+
/* *INDENT-OFF* */
VNET_DEVICE_CLASS (pg_dev_class) = {
.name = "pg",
.format_device_name = format_pg_interface_name,
.format_tx_trace = format_pg_output_trace,
.admin_up_down_function = pg_interface_admin_up_down,
+ .mac_addr_add_del_function = pg_add_del_mac_address,
};
/* *INDENT-ON* */
return 0;
}
+void
+pg_interface_enable_disable_coalesce (pg_interface_t * pi, u8 enable,
+ u32 tx_node_index)
+{
+ if (enable)
+ {
+ gro_flow_table_init (&pi->flow_table, 1 /* is_l2 */ ,
+ tx_node_index);
+ pi->coalesce_enabled = 1;
+ }
+ else
+ {
+ pi->coalesce_enabled = 0;
+ gro_flow_table_free (pi->flow_table);
+ }
+}
+
u32
-pg_interface_add_or_get (pg_main_t * pg, uword if_id)
+pg_interface_add_or_get (pg_main_t * pg, uword if_id, u8 gso_enabled,
+ u32 gso_size, u8 coalesce_enabled)
{
vnet_main_t *vnm = vnet_get_main ();
vlib_main_t *vm = vlib_get_main ();
rnd = (u32) (now * 1e6);
rnd = random_u32 (&rnd);
- clib_memcpy (hw_addr + 2, &rnd, sizeof (rnd));
+ clib_memcpy_fast (hw_addr + 2, &rnd, sizeof (rnd));
hw_addr[0] = 2;
hw_addr[1] = 0xfe;
ethernet_register_interface (vnm, pg_dev_class.index, i, hw_addr,
&pi->hw_if_index, pg_eth_flag_change);
hi = vnet_get_hw_interface (vnm, pi->hw_if_index);
+ if (gso_enabled)
+ {
+ hi->caps |= VNET_HW_INTERFACE_CAP_SUPPORTS_TCP_GSO;
+ pi->gso_enabled = 1;
+ pi->gso_size = gso_size;
+ if (coalesce_enabled)
+ {
+ pg_interface_enable_disable_coalesce (pi, 1, hi->tx_node_index);
+ }
+ }
pi->sw_if_index = hi->sw_if_index;
hash_set (pg->if_index_by_if_id, if_id, i);
+ vec_validate (pg->if_id_by_sw_if_index, hi->sw_if_index);
+ pg->if_id_by_sw_if_index[hi->sw_if_index] = i;
+
if (vlib_num_workers ())
{
pi->lockp = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
vec_foreach (e, g->edits) do_edit (s, g, e, /* want_commit */ 0);
- clib_memcpy (packet_data, g->fixed_packet_data,
- vec_len (g->fixed_packet_data));
- clib_memcpy (packet_data_mask, g->fixed_packet_data_mask,
- vec_len (g->fixed_packet_data_mask));
+ clib_memcpy_fast (packet_data, g->fixed_packet_data,
+ vec_len (g->fixed_packet_data));
+ clib_memcpy_fast (packet_data_mask, g->fixed_packet_data_mask,
+ vec_len (g->fixed_packet_data_mask));
}
static void
s->last_increment_packet_size = s->min_packet_bytes;
{
- pg_buffer_index_t *bi;
int n;
- s->buffer_bytes = VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES;
+ s->buffer_bytes = vlib_buffer_get_default_data_size (vm);
n = s->max_packet_bytes / s->buffer_bytes;
n += (s->max_packet_bytes % s->buffer_bytes) != 0;
vec_resize (s->buffer_indices, n);
-
- vec_foreach (bi, s->buffer_indices)
- bi->free_list_index = VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX;
}
/* Find an interface to use. */
- s->pg_if_index = pg_interface_add_or_get (pg, s->if_id);
-
- {
- pg_interface_t *pi = pool_elt_at_index (pg->interfaces, s->pg_if_index);
- vlib_rx_or_tx_t rx_or_tx;
+ s->pg_if_index =
+ pg_interface_add_or_get (pg, s->if_id, 0 /* gso_enabled */ ,
+ 0 /* gso_size */ , 0 /* coalesce_enabled */ );
- vlib_foreach_rx_tx (rx_or_tx)
+ if (s->sw_if_index[VLIB_RX] == ~0)
{
- if (s->sw_if_index[rx_or_tx] == ~0)
- s->sw_if_index[rx_or_tx] = pi->sw_if_index;
+ pg_interface_t *pi = pool_elt_at_index (pg->interfaces, s->pg_if_index);
+ /*
+ * Default the RX interface if unset. It's a bad mistake to
+ * set [VLIB_TX] prior to ip lookup, since the ip lookup code
+ * interprets [VLIB_TX] as a fib index...
+ */
+ s->sw_if_index[VLIB_RX] = pi->sw_if_index;
}
- }
/* Connect the graph. */
s->next_index = vlib_node_add_next (vm, device_input_node.index,
pool_put (pg->streams, s);
}
+void
+pg_stream_change (pg_main_t * pg, pg_stream_t * s)
+{
+ /* Determine packet size. */
+ switch (s->packet_size_edit_type)
+ {
+ case PG_EDIT_INCREMENT:
+ case PG_EDIT_RANDOM:
+ if (s->min_packet_bytes == s->max_packet_bytes)
+ s->packet_size_edit_type = PG_EDIT_FIXED;
+ case PG_EDIT_FIXED:
+ break;
+
+ default:
+ /* Get packet size from fixed edits. */
+ s->packet_size_edit_type = PG_EDIT_FIXED;
+ if (!s->replay_packet_templates)
+ s->min_packet_bytes = s->max_packet_bytes =
+ vec_len (s->fixed_packet_data);
+ break;
+ }
+
+ s->last_increment_packet_size = s->min_packet_bytes;
+}
+
/*
* fd.io coding-style-patch-verification: ON