From 7cd468a3d7dee7d6c92f69a0bb7061ae208ec727 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 19 Dec 2016 23:05:39 +0100 Subject: Reorganize source tree to use single autotools instance Change-Id: I7b51f88292e057c6443b12224486f2d0c9f8ae23 Signed-off-by: Damjan Marion --- src/vnet/devices/af_packet/device.c | 250 ++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 src/vnet/devices/af_packet/device.c (limited to 'src/vnet/devices/af_packet/device.c') diff --git a/src/vnet/devices/af_packet/device.c b/src/vnet/devices/af_packet/device.c new file mode 100644 index 00000000..1fb4000f --- /dev/null +++ b/src/vnet/devices/af_packet/device.c @@ -0,0 +1,250 @@ +/* + *------------------------------------------------------------------ + * af_packet.c - linux kernel packet interface + * + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include + +#include +#include +#include +#include + +#include + +#define foreach_af_packet_tx_func_error \ +_(FRAME_NOT_READY, "tx frame not ready") \ +_(TXRING_EAGAIN, "tx sendto temporary failure") \ +_(TXRING_FATAL, "tx sendto fatal failure") \ +_(TXRING_OVERRUN, "tx ring overrun") + +typedef enum +{ +#define _(f,s) AF_PACKET_TX_ERROR_##f, + foreach_af_packet_tx_func_error +#undef _ + AF_PACKET_TX_N_ERROR, +} af_packet_tx_func_error_t; + +static char *af_packet_tx_func_error_strings[] = { +#define _(n,s) s, + foreach_af_packet_tx_func_error +#undef _ +}; + + +static u8 * +format_af_packet_device_name (u8 * s, va_list * args) +{ + u32 i = va_arg (*args, u32); + af_packet_main_t *apm = &af_packet_main; + af_packet_if_t *apif = pool_elt_at_index (apm->interfaces, i); + + s = format (s, "host-%s", apif->host_if_name); + return s; +} + +static u8 * +format_af_packet_device (u8 * s, va_list * args) +{ + s = format (s, "Linux PACKET socket interface"); + return s; +} + +static u8 * +format_af_packet_tx_trace (u8 * s, va_list * args) +{ + s = format (s, "Unimplemented..."); + return s; +} + +static uword +af_packet_interface_tx (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + af_packet_main_t *apm = &af_packet_main; + u32 *buffers = vlib_frame_args (frame); + u32 n_left = frame->n_vectors; + u32 n_sent = 0; + vnet_interface_output_runtime_t *rd = (void *) node->runtime_data; + af_packet_if_t *apif = + pool_elt_at_index (apm->interfaces, rd->dev_instance); + int block = 0; + u32 block_size = apif->tx_req->tp_block_size; + u32 frame_size = apif->tx_req->tp_frame_size; + u32 frame_num = apif->tx_req->tp_frame_nr; + u8 *block_start = apif->tx_ring + block * block_size; + u32 tx_frame = apif->next_tx_frame; + struct tpacket2_hdr *tph; + u32 frame_not_ready = 0; + + while (n_left > 0) + { + u32 len; + u32 offset = 0; + vlib_buffer_t *b0; + n_left--; + u32 bi = buffers[0]; + buffers++; + + tph = (struct tpacket2_hdr *) (block_start + tx_frame * frame_size); + + if (PREDICT_FALSE + (tph->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING))) + { + frame_not_ready++; + goto next; + } + + do + { + b0 = vlib_get_buffer (vm, bi); + len = b0->current_length; + clib_memcpy ((u8 *) tph + + TPACKET_ALIGN (sizeof (struct tpacket2_hdr)) + offset, + vlib_buffer_get_current (b0), len); + offset += len; + } + while ((bi = b0->next_buffer)); + + tph->tp_len = tph->tp_snaplen = offset; + tph->tp_status = TP_STATUS_SEND_REQUEST; + n_sent++; + next: + /* check if we've exhausted the ring */ + if (PREDICT_FALSE (frame_not_ready + n_sent == frame_num)) + break; + + tx_frame = (tx_frame + 1) % frame_num; + } + + CLIB_MEMORY_BARRIER (); + + if (PREDICT_TRUE (n_sent)) + { + apif->next_tx_frame = tx_frame; + + if (PREDICT_FALSE (sendto (apif->fd, NULL, 0, + MSG_DONTWAIT, NULL, 0) == -1)) + { + /* Uh-oh, drop & move on, but count whether it was fatal or not. + * Note that we have no reliable way to properly determine the + * disposition of the packets we just enqueued for delivery. + */ + vlib_error_count (vm, node->node_index, + unix_error_is_fatal (errno) ? + AF_PACKET_TX_ERROR_TXRING_FATAL : + AF_PACKET_TX_ERROR_TXRING_EAGAIN, n_sent); + } + } + + if (PREDICT_FALSE (frame_not_ready)) + vlib_error_count (vm, node->node_index, + AF_PACKET_TX_ERROR_FRAME_NOT_READY, frame_not_ready); + + if (PREDICT_FALSE (frame_not_ready + n_sent == frame_num)) + vlib_error_count (vm, node->node_index, AF_PACKET_TX_ERROR_TXRING_OVERRUN, + n_left); + + vlib_buffer_free (vm, vlib_frame_args (frame), frame->n_vectors); + return frame->n_vectors; +} + +static void +af_packet_set_interface_next_node (vnet_main_t * vnm, u32 hw_if_index, + u32 node_index) +{ + af_packet_main_t *apm = &af_packet_main; + vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); + af_packet_if_t *apif = + pool_elt_at_index (apm->interfaces, hw->dev_instance); + + /* Shut off redirection */ + if (node_index == ~0) + { + apif->per_interface_next_index = node_index; + return; + } + + apif->per_interface_next_index = + vlib_node_add_next (vlib_get_main (), af_packet_input_node.index, + node_index); +} + +static void +af_packet_clear_hw_interface_counters (u32 instance) +{ + /* Nothing for now */ +} + +static clib_error_t * +af_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, + u32 flags) +{ + af_packet_main_t *apm = &af_packet_main; + vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); + af_packet_if_t *apif = + pool_elt_at_index (apm->interfaces, hw->dev_instance); + u32 hw_flags; + + apif->is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0; + + if (apif->is_admin_up) + hw_flags = VNET_HW_INTERFACE_FLAG_LINK_UP; + else + hw_flags = 0; + + vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags); + + return 0; +} + +static clib_error_t * +af_packet_subif_add_del_function (vnet_main_t * vnm, + u32 hw_if_index, + struct vnet_sw_interface_t *st, int is_add) +{ + /* Nothing for now */ + return 0; +} + +/* *INDENT-OFF* */ +VNET_DEVICE_CLASS (af_packet_device_class) = { + .name = "af-packet", + .tx_function = af_packet_interface_tx, + .format_device_name = format_af_packet_device_name, + .format_device = format_af_packet_device, + .format_tx_trace = format_af_packet_tx_trace, + .tx_function_n_errors = AF_PACKET_TX_N_ERROR, + .tx_function_error_strings = af_packet_tx_func_error_strings, + .rx_redirect_to_node = af_packet_set_interface_next_node, + .clear_counters = af_packet_clear_hw_interface_counters, + .admin_up_down_function = af_packet_interface_admin_up_down, + .subif_add_del_function = af_packet_subif_add_del_function, +}; + +VLIB_DEVICE_TX_FUNCTION_MULTIARCH (af_packet_device_class, + af_packet_interface_tx) +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg From cf751ec70df21affb19c77b2c51e3c231b8202ad Mon Sep 17 00:00:00 2001 From: Mohsin KAZMI Date: Wed, 18 Jan 2017 11:59:45 +0100 Subject: af_packet: multithreading support This patch adds multithreading support for af_packet interfaces. Change-Id: Ief5d1117e7ffeaa59dbc2831e583d5d8e8d4fa7a Signed-off-by: Mohsin KAZMI --- src/vnet/devices/af_packet/af_packet.c | 55 ++++++++++++++++++++++++++++++++++ src/vnet/devices/af_packet/af_packet.h | 7 +++++ src/vnet/devices/af_packet/device.c | 9 ++++++ src/vnet/devices/af_packet/node.c | 26 +++++++++------- 4 files changed, 86 insertions(+), 11 deletions(-) (limited to 'src/vnet/devices/af_packet/device.c') diff --git a/src/vnet/devices/af_packet/af_packet.c b/src/vnet/devices/af_packet/af_packet.c index 91c3988b..e491ba47 100644 --- a/src/vnet/devices/af_packet/af_packet.c +++ b/src/vnet/devices/af_packet/af_packet.c @@ -171,6 +171,31 @@ error: return ret; } +static void +af_packet_worker_thread_enable () +{ + /* If worker threads are enabled, switch to polling mode */ + foreach_vlib_main (( + { + vlib_node_set_state (this_vlib_main, + af_packet_input_node.index, + VLIB_NODE_STATE_POLLING); + })); + +} + +static void +af_packet_worker_thread_disable () +{ + foreach_vlib_main (( + { + vlib_node_set_state (this_vlib_main, + af_packet_input_node.index, + VLIB_NODE_STATE_INTERRUPT); + })); + +} + int af_packet_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set, u32 * sw_if_index) @@ -184,6 +209,7 @@ af_packet_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set, u8 hw_addr[6]; clib_error_t *error; vnet_sw_interface_t *sw; + vlib_thread_main_t *tm = vlib_get_thread_main (); vnet_main_t *vnm = vnet_get_main (); uword *p; uword if_index; @@ -226,6 +252,13 @@ af_packet_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set, apif->next_tx_frame = 0; apif->next_rx_frame = 0; + if (tm->n_vlib_mains > 1) + { + apif->lockp = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, + CLIB_CACHE_LINE_BYTES); + memset ((void *) apif->lockp, 0, CLIB_CACHE_LINE_BYTES); + } + { unix_file_t template = { 0 }; template.read_function = af_packet_fd_read_ready; @@ -273,6 +306,10 @@ af_packet_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set, 0); if (sw_if_index) *sw_if_index = apif->sw_if_index; + + if (tm->n_vlib_mains > 1 && pool_elts (apm->interfaces) == 1) + af_packet_worker_thread_enable (); + return 0; error: @@ -286,6 +323,7 @@ int af_packet_delete_if (vlib_main_t * vm, u8 * host_if_name) { vnet_main_t *vnm = vnet_get_main (); + vlib_thread_main_t *tm = vlib_get_thread_main (); af_packet_main_t *apm = &af_packet_main; af_packet_if_t *apif; uword *p; @@ -335,6 +373,8 @@ af_packet_delete_if (vlib_main_t * vm, u8 * host_if_name) ethernet_delete_interface (vnm, apif->hw_if_index); pool_put (apm->interfaces, apif); + if (tm->n_vlib_mains > 1 && pool_elts (apm->interfaces) == 0) + af_packet_worker_thread_disable (); return 0; } @@ -344,9 +384,24 @@ af_packet_init (vlib_main_t * vm) { af_packet_main_t *apm = &af_packet_main; vlib_thread_main_t *tm = vlib_get_thread_main (); + vlib_thread_registration_t *tr; + uword *p; memset (apm, 0, sizeof (af_packet_main_t)); + apm->input_cpu_first_index = 0; + apm->input_cpu_count = 1; + + /* find out which cpus will be used for input */ + p = hash_get_mem (tm->thread_registrations_by_name, "workers"); + tr = p ? (vlib_thread_registration_t *) p[0] : 0; + + if (tr && tr->count > 0) + { + apm->input_cpu_first_index = tr->first_index; + apm->input_cpu_count = tr->count; + } + mhash_init_vec_string (&apm->if_index_by_host_if_name, sizeof (uword)); vec_validate_aligned (apm->rx_buffers, tm->n_vlib_mains - 1, diff --git a/src/vnet/devices/af_packet/af_packet.h b/src/vnet/devices/af_packet/af_packet.h index 19e2523d..e00e5cb4 100644 --- a/src/vnet/devices/af_packet/af_packet.h +++ b/src/vnet/devices/af_packet/af_packet.h @@ -20,6 +20,7 @@ typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); + volatile u32 *lockp; u8 *host_if_name; int fd; struct tpacket_req *rx_req; @@ -50,6 +51,12 @@ typedef struct /* hash of host interface names */ mhash_t if_index_by_host_if_name; + + /* first cpu index */ + u32 input_cpu_first_index; + + /* total cpu count */ + u32 input_cpu_count; } af_packet_main_t; af_packet_main_t af_packet_main; diff --git a/src/vnet/devices/af_packet/device.c b/src/vnet/devices/af_packet/device.c index 1fb4000f..e3bf9bbc 100644 --- a/src/vnet/devices/af_packet/device.c +++ b/src/vnet/devices/af_packet/device.c @@ -92,6 +92,12 @@ af_packet_interface_tx (vlib_main_t * vm, struct tpacket2_hdr *tph; u32 frame_not_ready = 0; + if (PREDICT_FALSE (apif->lockp != 0)) + { + while (__sync_lock_test_and_set (apif->lockp, 1)) + ; + } + while (n_left > 0) { u32 len; @@ -152,6 +158,9 @@ af_packet_interface_tx (vlib_main_t * vm, } } + if (PREDICT_FALSE (apif->lockp != 0)) + *apif->lockp = 0; + if (PREDICT_FALSE (frame_not_ready)) vlib_error_count (vm, node->node_index, AF_PACKET_TX_ERROR_FRAME_NOT_READY, frame_not_ready); diff --git a/src/vnet/devices/af_packet/node.c b/src/vnet/devices/af_packet/node.c index 72004320..476ccca9 100644 --- a/src/vnet/devices/af_packet/node.c +++ b/src/vnet/devices/af_packet/node.c @@ -108,10 +108,9 @@ buffer_add_to_chain (vlib_main_t * vm, u32 bi, u32 first_bi, u32 prev_bi) always_inline uword af_packet_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame, u32 device_idx) + vlib_frame_t * frame, af_packet_if_t * apif) { af_packet_main_t *apm = &af_packet_main; - af_packet_if_t *apif = pool_elt_at_index (apm->interfaces, device_idx); struct tpacket2_hdr *tph; u32 next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT; u32 block = 0; @@ -125,10 +124,10 @@ af_packet_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, u32 frame_num = apif->rx_req->tp_frame_nr; u8 *block_start = apif->rx_ring + block * block_size; uword n_trace = vlib_get_trace_count (vm, node); + u32 cpu_index = os_get_cpu_number (); u32 n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); u32 min_bufs = apif->rx_req->tp_frame_size / n_buffer_bytes; - int cpu_index = node->cpu_index; if (apif->per_interface_next_index != ~0) next_index = apif->per_interface_next_index; @@ -249,16 +248,18 @@ af_packet_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, { int i; u32 n_rx_packets = 0; - + u32 cpu_index = os_get_cpu_number (); af_packet_main_t *apm = &af_packet_main; + af_packet_if_t *apif; - /* *INDENT-OFF* */ - clib_bitmap_foreach (i, apm->pending_input_bitmap, - ({ - clib_bitmap_set (apm->pending_input_bitmap, i, 0); - n_rx_packets += af_packet_device_input_fn(vm, node, frame, i); - })); - /* *INDENT-ON* */ + for (i = 0; i < vec_len (apm->interfaces); i++) + { + apif = vec_elt_at_index (apm->interfaces, i); + if (apif->is_admin_up && + (i % apm->input_cpu_count) == + (cpu_index - apm->input_cpu_first_index)) + n_rx_packets += af_packet_device_input_fn (vm, node, frame, apif); + } return n_rx_packets; } @@ -270,6 +271,9 @@ VLIB_REGISTER_NODE (af_packet_input_node) = { .sibling_of = "device-input", .format_trace = format_af_packet_input_trace, .type = VLIB_NODE_TYPE_INPUT, + /** + * default state is INTERRUPT mode, switch to POLLING if worker threads are enabled + */ .state = VLIB_NODE_STATE_INTERRUPT, .n_errors = AF_PACKET_INPUT_N_ERROR, .error_strings = af_packet_input_error_strings, -- cgit 1.2.3-korg From 22db11b491f80539438418eaaa0aa864202dadf6 Mon Sep 17 00:00:00 2001 From: Jim Gibson Date: Mon, 27 Mar 2017 19:46:12 +0000 Subject: af_packet driver needs to check VLIB_BUFFER_NEXT_PRESENT flag is set when walking vlib_buffer_t next_buffer chain on transmit. On buffer allocation: - next_buffer is not and may contain a stale invalid value that should be ignored if not overwritten by a valid value. - VLIB_BUFFER_NEXT_PRESENT flag is cleared and only set if a valid value is written to next_buffer. Change-Id: I9b0ccdc54f4f7456f8328ce7c4a0d52d0fba8caa Signed-off-by: Jim Gibson --- src/vnet/devices/af_packet/device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/vnet/devices/af_packet/device.c') diff --git a/src/vnet/devices/af_packet/device.c b/src/vnet/devices/af_packet/device.c index e3bf9bbc..9a94fc5e 100644 --- a/src/vnet/devices/af_packet/device.c +++ b/src/vnet/devices/af_packet/device.c @@ -125,7 +125,8 @@ af_packet_interface_tx (vlib_main_t * vm, vlib_buffer_get_current (b0), len); offset += len; } - while ((bi = b0->next_buffer)); + while ((bi = + (b0->flags & VLIB_BUFFER_NEXT_PRESENT) ? b0->next_buffer : 0)); tph->tp_len = tph->tp_snaplen = offset; tph->tp_status = TP_STATUS_SEND_REQUEST; -- cgit 1.2.3-korg From 1927da29ccbe1d4cc8e59ccfa197eb41c257814f Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 27 Mar 2017 17:08:20 +0200 Subject: vppinfra: add spinlock inline functions Change-Id: I86089e9bb604adfc260a111685001be1c897ce53 Signed-off-by: Damjan Marion --- src/plugins/memif/device.c | 21 +------- src/plugins/memif/memif.c | 12 +---- src/plugins/memif/memif.h | 4 +- src/vnet/devices/af_packet/af_packet.c | 6 +-- src/vnet/devices/af_packet/af_packet.h | 4 +- src/vnet/devices/af_packet/device.c | 9 +--- src/vnet/devices/netmap/device.c | 9 +--- src/vnet/devices/netmap/netmap.c | 6 +-- src/vnet/devices/netmap/netmap.h | 4 +- src/vppinfra.am | 1 + src/vppinfra/lock.h | 97 ++++++++++++++++++++++++++++++++++ 11 files changed, 117 insertions(+), 56 deletions(-) create mode 100644 src/vppinfra/lock.h (limited to 'src/vnet/devices/af_packet/device.c') diff --git a/src/plugins/memif/device.c b/src/plugins/memif/device.c index 446537a3..4faeb055 100644 --- a/src/plugins/memif/device.c +++ b/src/plugins/memif/device.c @@ -78,23 +78,6 @@ format_memif_tx_trace (u8 * s, va_list * args) return s; } -static_always_inline void -memif_interface_lock (memif_if_t * mif) -{ - if (PREDICT_FALSE (mif->lockp != 0)) - { - while (__sync_lock_test_and_set (mif->lockp, 1)) - ; - } -} - -static_always_inline void -memif_interface_unlock (memif_if_t * mif) -{ - if (PREDICT_FALSE (mif->lockp != 0)) - *mif->lockp = 0; -} - static_always_inline void memif_prefetch_buffer_and_data (vlib_main_t * vm, u32 bi) { @@ -117,7 +100,7 @@ memif_interface_tx_inline (vlib_main_t * vm, vlib_node_runtime_t * node, u16 head, tail; u16 free_slots; - memif_interface_lock (mif); + clib_spinlock_lock_if_init (&mif->lockp); /* free consumed buffers */ @@ -210,7 +193,7 @@ memif_interface_tx_inline (vlib_main_t * vm, vlib_node_runtime_t * node, CLIB_MEMORY_STORE_BARRIER (); ring->head = head; - memif_interface_unlock (mif); + clib_spinlock_unlock (&mif->lockp); if (n_left) { diff --git a/src/plugins/memif/memif.c b/src/plugins/memif/memif.c index 7ba67c5b..cf8ca577 100644 --- a/src/plugins/memif/memif.c +++ b/src/plugins/memif/memif.c @@ -716,11 +716,7 @@ memif_close_if (memif_main_t * mm, memif_if_t * mif) } } - if (mif->lockp != 0) - { - clib_mem_free ((void *) mif->lockp); - mif->lockp = 0; - } + clib_spinlock_free (&mif->lockp); mhash_unset (&mm->if_index_by_key, &mif->key, &mif->if_index); vec_free (mif->socket_filename); @@ -783,11 +779,7 @@ memif_create_if (vlib_main_t * vm, memif_create_if_args_t * args) mif->connection.fd = mif->interrupt_line.fd = -1; if (tm->n_vlib_mains > 1) - { - mif->lockp = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, - CLIB_CACHE_LINE_BYTES); - memset ((void *) mif->lockp, 0, CLIB_CACHE_LINE_BYTES); - } + clib_spinlock_init (&mif->lockp); if (!args->hw_addr_set) { diff --git a/src/plugins/memif/memif.h b/src/plugins/memif/memif.h index a7a88e07..f57170f8 100644 --- a/src/plugins/memif/memif.h +++ b/src/plugins/memif/memif.h @@ -15,6 +15,8 @@ *------------------------------------------------------------------ */ +#include + typedef struct { u16 version; @@ -98,7 +100,7 @@ typedef struct typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); - volatile u32 *lockp; + clib_spinlock_t lockp; u32 flags; #define MEMIF_IF_FLAG_ADMIN_UP (1 << 0) #define MEMIF_IF_FLAG_IS_SLAVE (1 << 1) diff --git a/src/vnet/devices/af_packet/af_packet.c b/src/vnet/devices/af_packet/af_packet.c index 5fdc59f2..20285107 100644 --- a/src/vnet/devices/af_packet/af_packet.c +++ b/src/vnet/devices/af_packet/af_packet.c @@ -229,11 +229,7 @@ af_packet_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set, apif->next_rx_frame = 0; if (tm->n_vlib_mains > 1) - { - apif->lockp = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, - CLIB_CACHE_LINE_BYTES); - memset ((void *) apif->lockp, 0, CLIB_CACHE_LINE_BYTES); - } + clib_spinlock_init (&apif->lockp); { unix_file_t template = { 0 }; diff --git a/src/vnet/devices/af_packet/af_packet.h b/src/vnet/devices/af_packet/af_packet.h index 50ec2378..77a2c7a3 100644 --- a/src/vnet/devices/af_packet/af_packet.h +++ b/src/vnet/devices/af_packet/af_packet.h @@ -17,10 +17,12 @@ *------------------------------------------------------------------ */ +#include + typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); - volatile u32 *lockp; + clib_spinlock_t lockp; u8 *host_if_name; int fd; struct tpacket_req *rx_req; diff --git a/src/vnet/devices/af_packet/device.c b/src/vnet/devices/af_packet/device.c index 9a94fc5e..2ba3f579 100644 --- a/src/vnet/devices/af_packet/device.c +++ b/src/vnet/devices/af_packet/device.c @@ -92,11 +92,7 @@ af_packet_interface_tx (vlib_main_t * vm, struct tpacket2_hdr *tph; u32 frame_not_ready = 0; - if (PREDICT_FALSE (apif->lockp != 0)) - { - while (__sync_lock_test_and_set (apif->lockp, 1)) - ; - } + clib_spinlock_lock_if_init (&apif->lockp); while (n_left > 0) { @@ -159,8 +155,7 @@ af_packet_interface_tx (vlib_main_t * vm, } } - if (PREDICT_FALSE (apif->lockp != 0)) - *apif->lockp = 0; + clib_spinlock_unlock_if_init (&apif->lockp); if (PREDICT_FALSE (frame_not_ready)) vlib_error_count (vm, node->node_index, diff --git a/src/vnet/devices/netmap/device.c b/src/vnet/devices/netmap/device.c index 2152824f..aea9ddf4 100644 --- a/src/vnet/devices/netmap/device.c +++ b/src/vnet/devices/netmap/device.c @@ -105,11 +105,7 @@ netmap_interface_tx (vlib_main_t * vm, netmap_if_t *nif = pool_elt_at_index (nm->interfaces, rd->dev_instance); int cur_ring; - if (PREDICT_FALSE (nif->lockp != 0)) - { - while (__sync_lock_test_and_set (nif->lockp, 1)) - ; - } + clib_spinlock_lock_if_init (&nif->lockp); cur_ring = nif->first_tx_ring; @@ -165,8 +161,7 @@ netmap_interface_tx (vlib_main_t * vm, if (n_left < frame->n_vectors) ioctl (nif->fd, NIOCTXSYNC, NULL); - if (PREDICT_FALSE (nif->lockp != 0)) - *nif->lockp = 0; + clib_spinlock_unlock_if_init (&nif->lockp); if (n_left) vlib_error_count (vm, node->node_index, diff --git a/src/vnet/devices/netmap/netmap.c b/src/vnet/devices/netmap/netmap.c index 3bdb442d..09afc764 100644 --- a/src/vnet/devices/netmap/netmap.c +++ b/src/vnet/devices/netmap/netmap.c @@ -185,11 +185,7 @@ netmap_create_if (vlib_main_t * vm, u8 * if_name, u8 * hw_addr_set, nif->per_interface_next_index = ~0; if (tm->n_vlib_mains > 1) - { - nif->lockp = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, - CLIB_CACHE_LINE_BYTES); - memset ((void *) nif->lockp, 0, CLIB_CACHE_LINE_BYTES); - } + clib_spinlock_init (&nif->lockp); { unix_file_t template = { 0 }; diff --git a/src/vnet/devices/netmap/netmap.h b/src/vnet/devices/netmap/netmap.h index 39a94043..e04f045d 100644 --- a/src/vnet/devices/netmap/netmap.h +++ b/src/vnet/devices/netmap/netmap.h @@ -40,10 +40,12 @@ * SUCH DAMAGE. */ +#include + typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); - volatile u32 *lockp; + clib_spinlock_t lockp; u8 *host_if_name; uword if_index; u32 hw_if_index; diff --git a/src/vppinfra.am b/src/vppinfra.am index 4b9f0c29..fed1981e 100644 --- a/src/vppinfra.am +++ b/src/vppinfra.am @@ -180,6 +180,7 @@ nobase_include_HEADERS = \ vppinfra/graph.h \ vppinfra/hash.h \ vppinfra/heap.h \ + vppinfra/lock.h \ vppinfra/longjmp.h \ vppinfra/macros.h \ vppinfra/math.h \ diff --git a/src/vppinfra/lock.h b/src/vppinfra/lock.h new file mode 100644 index 00000000..c60ff414 --- /dev/null +++ b/src/vppinfra/lock.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef included_clib_lock_h +#define included_clib_lock_h + +#include + +typedef struct +{ + CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); + u32 lock; +#if CLIB_DEBUG > 0 + pid_t pid; + uword cpu_index; + void *frame_address; +#endif +} *clib_spinlock_t; + +static inline void +clib_spinlock_init (clib_spinlock_t * p) +{ + *p = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES); + memset ((void *) *p, 0, CLIB_CACHE_LINE_BYTES); +} + +static inline void +clib_spinlock_free (clib_spinlock_t * p) +{ + if (*p) + { + clib_mem_free ((void *) *p); + *p = 0; + } +} + +static_always_inline void +clib_spinlock_lock (clib_spinlock_t * p) +{ + while (__sync_lock_test_and_set (&(*p)->lock, 1)) +#if __x86_64__ + __builtin_ia32_pause () +#endif + ; +#if CLIB_DEBUG > 0 + (*p)->frame_address = __builtin_frame_address (0); + (*p)->pid = getpid (); + (*p)->cpu_index = os_get_cpu_number (); +#endif +} + +static_always_inline void +clib_spinlock_lock_if_init (clib_spinlock_t * p) +{ + if (PREDICT_FALSE (*p != 0)) + clib_spinlock_lock (p); +} + +static_always_inline void +clib_spinlock_unlock (clib_spinlock_t * p) +{ + (*p)->lock = 0; +#if CLIB_DEBUG > 0 + (*p)->frame_address = 0; + (*p)->pid = 0; + (*p)->cpu_index = 0; +#endif +} + +static_always_inline void +clib_spinlock_unlock_if_init (clib_spinlock_t * p) +{ + if (PREDICT_FALSE (*p != 0)) + clib_spinlock_unlock (p); +} + +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg From c855b73f785b3c4c1756927ad542de13ba193b6f Mon Sep 17 00:00:00 2001 From: Ray Kinsella Date: Fri, 21 Apr 2017 12:24:43 +0100 Subject: af_packet: reflect admin device state on host Setting the interface state in VPP on an af_packet device, was not being reflected on the host. This implied the user had to set the device state in VPP and then on the host, in order to put the interface into an 'up' state. This changes makes the device state consisent in VPP and the host. Change-Id: I6dc6aee79503e04576683db937b861337a2b375b Signed-off-by: Ray Kinsella --- src/vnet/devices/af_packet/af_packet.c | 50 ++++++++++++++++++++++++++-------- src/vnet/devices/af_packet/af_packet.h | 1 + src/vnet/devices/af_packet/device.c | 42 ++++++++++++++++++++++++++-- 3 files changed, 78 insertions(+), 15 deletions(-) (limited to 'src/vnet/devices/af_packet/device.c') diff --git a/src/vnet/devices/af_packet/af_packet.c b/src/vnet/devices/af_packet/af_packet.c index 7464d4e6..92bd1092 100644 --- a/src/vnet/devices/af_packet/af_packet.c +++ b/src/vnet/devices/af_packet/af_packet.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -82,26 +83,35 @@ af_packet_fd_read_ready (unix_file_t * uf) } static int -create_packet_v2_sock (u8 * name, tpacket_req_t * rx_req, +is_bridge (const u8 * host_if_name) +{ + u8 *s; + DIR *dir = NULL; + + s = format (0, "/sys/class/net/%s/bridge%c", host_if_name, 0); + dir = opendir ((char *) s); + vec_free (s); + + if (dir) + { + closedir (dir); + return 0; + } + + return -1; +} + +static int +create_packet_v2_sock (int host_if_index, tpacket_req_t * rx_req, tpacket_req_t * tx_req, int *fd, u8 ** ring) { int ret, err; struct sockaddr_ll sll; - uint host_if_index; int ver = TPACKET_V2; socklen_t req_sz = sizeof (struct tpacket_req); u32 ring_sz = rx_req->tp_block_size * rx_req->tp_block_nr + tx_req->tp_block_size * tx_req->tp_block_nr; - host_if_index = if_nametoindex ((const char *) name); - - if (!host_if_index) - { - DBG_SOCK ("Wrong host interface name"); - ret = VNET_API_ERROR_INVALID_INTERFACE; - goto error; - } - if ((*fd = socket (AF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) { DBG_SOCK ("Failed to create socket"); @@ -190,6 +200,7 @@ af_packet_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set, uword *p; uword if_index; u8 *host_if_name_dup = vec_dup (host_if_name); + int host_if_index = -1; p = mhash_get (&apm->if_index_by_host_if_name, host_if_name); if (p) @@ -209,15 +220,29 @@ af_packet_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set, tx_req->tp_block_nr = AF_PACKET_TX_BLOCK_NR; tx_req->tp_frame_nr = AF_PACKET_TX_FRAME_NR; - ret = create_packet_v2_sock (host_if_name, rx_req, tx_req, &fd, &ring); + host_if_index = if_nametoindex ((const char *) host_if_name); + + if (!host_if_index) + { + DBG_SOCK ("Wrong host interface name"); + return VNET_API_ERROR_INVALID_INTERFACE; + } + + ret = create_packet_v2_sock (host_if_index, rx_req, tx_req, &fd, &ring); if (ret != 0) goto error; + ret = is_bridge (host_if_name); + + if (ret == 0) /* is a bridge, ignore state */ + host_if_index = -1; + /* So far everything looks good, let's create interface */ pool_get (apm->interfaces, apif); if_index = apif - apm->interfaces; + apif->host_if_index = host_if_index; apif->fd = fd; apif->rx_ring = ring; apif->tx_ring = ring + rx_req->tp_block_size * rx_req->tp_block_nr; @@ -341,6 +366,7 @@ af_packet_delete_if (vlib_main_t * vm, u8 * host_if_name) vec_free (apif->host_if_name); apif->host_if_name = NULL; + apif->host_if_index = -1; mhash_unset (&apm->if_index_by_host_if_name, host_if_name, &if_index); diff --git a/src/vnet/devices/af_packet/af_packet.h b/src/vnet/devices/af_packet/af_packet.h index 77a2c7a3..194977f0 100644 --- a/src/vnet/devices/af_packet/af_packet.h +++ b/src/vnet/devices/af_packet/af_packet.h @@ -24,6 +24,7 @@ typedef struct CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); clib_spinlock_t lockp; u8 *host_if_name; + int host_if_index; int fd; struct tpacket_req *rx_req; struct tpacket_req *tx_req; diff --git a/src/vnet/devices/af_packet/device.c b/src/vnet/devices/af_packet/device.c index 2ba3f579..2a17e6b3 100644 --- a/src/vnet/devices/af_packet/device.c +++ b/src/vnet/devices/af_packet/device.c @@ -18,6 +18,8 @@ */ #include +#include +#include #include #include @@ -205,17 +207,51 @@ af_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, af_packet_if_t *apif = pool_elt_at_index (apm->interfaces, hw->dev_instance); u32 hw_flags; + int rv, fd = socket (AF_UNIX, SOCK_DGRAM, 0); + struct ifreq ifr; + + /* if interface is a bridge ignore */ + if (apif->host_if_index < 0) + return 0; /* no error */ + + /* use host_if_index in case host name has changed */ + ifr.ifr_ifindex = apif->host_if_index; + if ((rv = ioctl (fd, SIOCGIFNAME, &ifr)) < 0) + { + clib_unix_warning ("af_packet_%s ioctl could not retrieve eth name", + apif->host_if_name); + } apif->is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0; + if ((rv = ioctl (fd, SIOCGIFFLAGS, &ifr)) < 0) + { + clib_unix_warning ("af_packet_%s error: %d", + apif->is_admin_up ? "up" : "down", rv); + } + if (apif->is_admin_up) - hw_flags = VNET_HW_INTERFACE_FLAG_LINK_UP; + { + hw_flags = VNET_HW_INTERFACE_FLAG_LINK_UP; + ifr.ifr_flags |= IFF_UP; + } else - hw_flags = 0; + { + hw_flags = 0; + ifr.ifr_flags &= ~IFF_UP; + } + + if ((rv = ioctl (fd, SIOCSIFFLAGS, &ifr)) < 0) + { + clib_unix_warning ("af_packet_%s error: %d", + apif->is_admin_up ? "up" : "down", rv); + } vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags); - return 0; + close (fd); + + return 0; /* no error */ } static clib_error_t * -- cgit 1.2.3-korg From 2038ad010b54ea6c2252bf487837d3e72448040f Mon Sep 17 00:00:00 2001 From: Ray Kinsella Date: Thu, 18 May 2017 11:56:28 +0100 Subject: af_packet: set mac address support Added support to the interfaces mac address. Resolved an fd leak when the interface is a bridge. Change-Id: I6608c51b11a50bd0ae4aabe0dc5788c4301b5a1e Signed-off-by: Ray Kinsella --- src/vnet/devices/af_packet/device.c | 48 ++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'src/vnet/devices/af_packet/device.c') diff --git a/src/vnet/devices/af_packet/device.c b/src/vnet/devices/af_packet/device.c index 2a17e6b3..4607d888 100644 --- a/src/vnet/devices/af_packet/device.c +++ b/src/vnet/devices/af_packet/device.c @@ -18,8 +18,10 @@ */ #include +#include #include #include +#include #include #include @@ -212,7 +214,7 @@ af_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, /* if interface is a bridge ignore */ if (apif->host_if_index < 0) - return 0; /* no error */ + goto error; /* no error */ /* use host_if_index in case host name has changed */ ifr.ifr_ifindex = apif->host_if_index; @@ -220,6 +222,7 @@ af_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, { clib_unix_warning ("af_packet_%s ioctl could not retrieve eth name", apif->host_if_name); + goto error; } apif->is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0; @@ -228,6 +231,7 @@ af_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, { clib_unix_warning ("af_packet_%s error: %d", apif->is_admin_up ? "up" : "down", rv); + goto error; } if (apif->is_admin_up) @@ -245,10 +249,12 @@ af_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, { clib_unix_warning ("af_packet_%s error: %d", apif->is_admin_up ? "up" : "down", rv); + goto error; } vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags); +error: close (fd); return 0; /* no error */ @@ -263,6 +269,45 @@ af_packet_subif_add_del_function (vnet_main_t * vnm, return 0; } +static clib_error_t *af_packet_set_mac_address_function + (struct vnet_hw_interface_t *hi, char *address) +{ + af_packet_main_t *apm = &af_packet_main; + af_packet_if_t *apif = + pool_elt_at_index (apm->interfaces, hi->dev_instance); + int rv, fd = socket (AF_UNIX, SOCK_DGRAM, 0); + struct ifreq ifr; + + /* if interface is a bridge ignore */ + if (apif->host_if_index < 0) + goto error; /* no error */ + + /* use host_if_index in case host name has changed */ + ifr.ifr_ifindex = apif->host_if_index; + if ((rv = ioctl (fd, SIOCGIFNAME, &ifr)) < 0) + { + clib_unix_warning + ("af_packet_%s ioctl could not retrieve eth name, error: %d", + apif->host_if_name, rv); + goto error; + } + + clib_memcpy (ifr.ifr_hwaddr.sa_data, address, 6); + ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; + + if ((rv = ioctl (fd, SIOCSIFHWADDR, &ifr)) < 0) + { + clib_unix_warning ("af_packet_%s ioctl could not set mac, error: %d", + apif->host_if_name, rv); + goto error; + } + +error: + close (fd); + + return 0; /* no error */ +} + /* *INDENT-OFF* */ VNET_DEVICE_CLASS (af_packet_device_class) = { .name = "af-packet", @@ -276,6 +321,7 @@ VNET_DEVICE_CLASS (af_packet_device_class) = { .clear_counters = af_packet_clear_hw_interface_counters, .admin_up_down_function = af_packet_interface_admin_up_down, .subif_add_del_function = af_packet_subif_add_del_function, + .mac_addr_change_function = af_packet_set_mac_address_function, }; VLIB_DEVICE_TX_FUNCTION_MULTIARCH (af_packet_device_class, -- cgit 1.2.3-korg From e6cc9cc77c9dcefa3d52e0cd90db35435f0eb64e Mon Sep 17 00:00:00 2001 From: Ray Kinsella Date: Sat, 20 May 2017 13:42:30 +0100 Subject: af_packet: fix coverity error Fix coverity error associated with fd. Change-Id: I0648aebaf356308bc03cc7217922479bfc4e22f7 Signed-off-by: Ray Kinsella --- src/vnet/devices/af_packet/device.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'src/vnet/devices/af_packet/device.c') diff --git a/src/vnet/devices/af_packet/device.c b/src/vnet/devices/af_packet/device.c index 4607d888..e01b1c71 100644 --- a/src/vnet/devices/af_packet/device.c +++ b/src/vnet/devices/af_packet/device.c @@ -212,6 +212,13 @@ af_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, int rv, fd = socket (AF_UNIX, SOCK_DGRAM, 0); struct ifreq ifr; + if (0 > fd) + { + clib_unix_warning ("af_packet_%s could not open socket", + apif->host_if_name); + return 0; + } + /* if interface is a bridge ignore */ if (apif->host_if_index < 0) goto error; /* no error */ @@ -255,7 +262,8 @@ af_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags); error: - close (fd); + if (0 <= fd) + close (fd); return 0; /* no error */ } @@ -278,6 +286,13 @@ static clib_error_t *af_packet_set_mac_address_function int rv, fd = socket (AF_UNIX, SOCK_DGRAM, 0); struct ifreq ifr; + if (0 > fd) + { + clib_unix_warning ("af_packet_%s could not open socket", + apif->host_if_name); + return 0; + } + /* if interface is a bridge ignore */ if (apif->host_if_index < 0) goto error; /* no error */ @@ -303,7 +318,9 @@ static clib_error_t *af_packet_set_mac_address_function } error: - close (fd); + + if (0 <= fd) + close (fd); return 0; /* no error */ } -- cgit 1.2.3-korg