#include <vlib/unix/unix.h>
#include <vnet/ip/ip.h>
+#include <vnet/fib/fib_table.h>
#include <vnet/ethernet/ethernet.h>
#include <vnet/devices/devices.h>
} subif_address_t;
/**
- * @brief TUNTAP node main state
+ * @brief TUNTAP per thread struct
*/
-typedef struct {
- /** Vector of iovecs for readv/writev calls. */
- struct iovec * iovecs;
-
+typedef struct
+{
/** Vector of VLIB rx buffers to use. We allocate them in blocks
of VLIB_FRAME_SIZE (256). */
u32 * rx_buffers;
+ /** Vector of iovecs for readv/writev calls. */
+ struct iovec * iovecs;
+} tuntap_per_thread_t;
+
+/**
+ * @brief TUNTAP node main state
+ */
+typedef struct {
+ /** per thread variables */
+ tuntap_per_thread_t * threads;
+
/** File descriptors for /dev/net/tun and provisioning socket. */
int dev_net_tun_fd, dev_tap_fd;
mhash_t subif_mhash;
/** Unix file index */
- u32 unix_file_index;
+ u32 clib_file_index;
/** For the "normal" interface, if configured */
u32 hw_if_index, sw_if_index;
vnet_interface_main_t *im = &vnm->interface_main;
u32 n_bytes = 0;
int i;
+ u16 thread_index = vlib_get_thread_index ();
for (i = 0; i < n_packets; i++)
{
}
/* Re-set iovecs if present. */
- if (tm->iovecs)
- _vec_len (tm->iovecs) = 0;
+ if (tm->threads[thread_index].iovecs)
+ _vec_len (tm->threads[thread_index].iovecs) = 0;
/** VLIB buffer chain -> Unix iovec(s). */
- vec_add2 (tm->iovecs, iov, 1);
+ vec_add2 (tm->threads[thread_index].iovecs, iov, 1);
iov->iov_base = b->data + b->current_data;
iov->iov_len = l = b->current_length;
do {
b = vlib_get_buffer (vm, b->next_buffer);
- vec_add2 (tm->iovecs, iov, 1);
+ vec_add2 (tm->threads[thread_index].iovecs, iov, 1);
iov->iov_base = b->data + b->current_data;
iov->iov_len = b->current_length;
} while (b->flags & VLIB_BUFFER_NEXT_PRESENT);
}
- if (writev (tm->dev_net_tun_fd, tm->iovecs, vec_len (tm->iovecs)) < l)
+ if (writev (tm->dev_net_tun_fd, tm->threads[thread_index].iovecs,
+ vec_len (tm->threads[thread_index].iovecs)) < l)
clib_unix_warning ("writev");
n_bytes += l;
/* Update tuntap interface output stats. */
vlib_increment_combined_counter (im->combined_sw_if_counters
+ VNET_INTERFACE_COUNTER_TX,
- vm->cpu_index,
+ vm->thread_index,
tm->sw_if_index, n_packets, n_bytes);
vlib_buffer_t * b;
u32 bi;
const uword buffer_size = VLIB_BUFFER_DATA_SIZE;
+ u16 thread_index = vlib_get_thread_index ();
/** Make sure we have some RX buffers. */
{
- uword n_left = vec_len (tm->rx_buffers);
+ uword n_left = vec_len (tm->threads[thread_index].rx_buffers);
uword n_alloc;
if (n_left < VLIB_FRAME_SIZE / 2)
{
- if (! tm->rx_buffers)
- vec_alloc (tm->rx_buffers, VLIB_FRAME_SIZE);
+ if (! tm->threads[thread_index].rx_buffers)
+ vec_alloc (tm->threads[thread_index].rx_buffers, VLIB_FRAME_SIZE);
- n_alloc = vlib_buffer_alloc (vm, tm->rx_buffers + n_left, VLIB_FRAME_SIZE - n_left);
- _vec_len (tm->rx_buffers) = n_left + n_alloc;
+ n_alloc = vlib_buffer_alloc (vm, tm->threads[thread_index].rx_buffers + n_left, VLIB_FRAME_SIZE - n_left);
+ _vec_len (tm->threads[thread_index].rx_buffers) = n_left + n_alloc;
}
}
/** Allocate RX buffers from end of rx_buffers.
Turn them into iovecs to pass to readv. */
{
- uword i_rx = vec_len (tm->rx_buffers) - 1;
+ uword i_rx = vec_len (tm->threads[thread_index].rx_buffers) - 1;
vlib_buffer_t * b;
word i, n_bytes_left, n_bytes_in_packet;
/** We should have enough buffers left for an MTU sized packet. */
- ASSERT (vec_len (tm->rx_buffers) >= tm->mtu_buffers);
+ ASSERT (vec_len (tm->threads[thread_index].rx_buffers) >= tm->mtu_buffers);
- vec_validate (tm->iovecs, tm->mtu_buffers - 1);
+ vec_validate (tm->threads[thread_index].iovecs, tm->mtu_buffers - 1);
for (i = 0; i < tm->mtu_buffers; i++)
{
- b = vlib_get_buffer (vm, tm->rx_buffers[i_rx - i]);
- tm->iovecs[i].iov_base = b->data;
- tm->iovecs[i].iov_len = buffer_size;
+ b = vlib_get_buffer (vm, tm->threads[thread_index].rx_buffers[i_rx - i]);
+ tm->threads[thread_index].iovecs[i].iov_base = b->data;
+ tm->threads[thread_index].iovecs[i].iov_len = buffer_size;
}
- n_bytes_left = readv (tm->dev_net_tun_fd, tm->iovecs, tm->mtu_buffers);
+ n_bytes_left = readv (tm->dev_net_tun_fd, tm->threads[thread_index].iovecs,
+ tm->mtu_buffers);
n_bytes_in_packet = n_bytes_left;
if (n_bytes_left <= 0)
{
return 0;
}
- bi = tm->rx_buffers[i_rx];
+ bi = tm->threads[thread_index].rx_buffers[i_rx];
while (1)
{
- b = vlib_get_buffer (vm, tm->rx_buffers[i_rx]);
+ b = vlib_get_buffer (vm, tm->threads[thread_index].rx_buffers[i_rx]);
b->flags = 0;
b->current_data = 0;
b->current_length = n_bytes_left < buffer_size ? n_bytes_left : buffer_size;
i_rx--;
b->flags |= VLIB_BUFFER_NEXT_PRESENT;
- b->next_buffer = tm->rx_buffers[i_rx];
+ b->next_buffer = tm->threads[thread_index].rx_buffers[i_rx];
}
/** Interface counters for tuntap interface. */
vlib_increment_combined_counter
(vnet_main.interface_main.combined_sw_if_counters
+ VNET_INTERFACE_COUNTER_RX,
- os_get_cpu_number(),
+ thread_index,
tm->sw_if_index,
1, n_bytes_in_packet);
- _vec_len (tm->rx_buffers) = i_rx;
+ _vec_len (tm->threads[thread_index].rx_buffers) = i_rx;
}
b = vlib_get_buffer (vm, bi);
next_index = VNET_DEVICE_INPUT_NEXT_DROP;
}
- vnet_feature_start_device_input_x1 (tm->sw_if_index, &next_index, b, 0);
+ vnet_feature_start_device_input_x1 (tm->sw_if_index, &next_index, b);
vlib_set_next_frame_buffer (vm, node, next_index, bi);
/**
* @brief Gets called when file descriptor is ready from epoll.
*
- * @param *uf - unix_file_t
+ * @param *uf - clib_file_t
*
* @return error - clib_error_t
*/
-static clib_error_t * tuntap_read_ready (unix_file_t * uf)
+static clib_error_t * tuntap_read_ready (clib_file_t * uf)
{
vlib_main_t * vm = vlib_get_main();
vlib_node_set_interrupt_pending (vm, tuntap_rx_node.index);
}
{
- unix_file_t template = {0};
+ clib_file_t template = {0};
template.read_function = tuntap_read_ready;
template.file_descriptor = tm->dev_net_tun_fd;
- tm->unix_file_index = unix_file_add (&unix_main, &template);
+ tm->clib_file_index = clib_file_add (&file_main, &template);
}
done:
if (tm->have_normal_interface || tm->dev_tap_fd < 0)
return;
+ /* if the address is being applied to an interface that is not in
+ * the same table/VRF as this tap, then ignore it.
+ * If we don't do this overlapping address spaces in the diferent tables
+ * breaks the linux host's routing tables */
+ if (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
+ sw_if_index) !=
+ fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP4,
+ tm->sw_if_index))
+ return;
+
/** See if we already know about this subif */
memset (&subif_addr, 0, sizeof (subif_addr));
subif_addr.sw_if_index = sw_if_index;
if (tm->have_normal_interface || tm->dev_tap_fd < 0)
return;
+ /* if the address is being applied to an interface that is not in
+ * the same table/VRF as this tap, then ignore it.
+ * If we don't do this overlapping address spaces in the diferent tables
+ * breaks the linux host's routing tables */
+ if (fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP6,
+ sw_if_index) !=
+ fib_table_get_index_for_sw_if_index(FIB_PROTOCOL_IP6,
+ tm->sw_if_index))
+ return;
+
/* See if we already know about this subif */
memset (&subif_addr, 0, sizeof (subif_addr));
subif_addr.sw_if_index = sw_if_index;
ip4_add_del_interface_address_callback_t cb4;
ip6_add_del_interface_address_callback_t cb6;
tuntap_main_t * tm = &tuntap_main;
+ vlib_thread_main_t * m = vlib_get_thread_main ();
error = vlib_call_init_function (vm, ip4_init);
if (error)
cb6.function = tuntap_ip6_add_del_interface_address;
cb6.function_opaque = 0;
vec_add1 (im6->add_del_interface_address_callbacks, cb6);
+ vec_validate_aligned (tm->threads, m->n_vlib_mains - 1,
+ CLIB_CACHE_LINE_BYTES);
return 0;
}