X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Flibrte_vhost%2Fvirtio_net.c;h=751c1f37337d6a47008f20e947dc921f1010532b;hb=4a4ca46ae29efc602d7e7f45a5221b0b74668796;hp=37c47c7dc0641cdd119e75d6fc3a93b748067853;hpb=cdf1dc5e6a361df17d081e3e975cc586a4b7d68d;p=dpdk.git diff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c index 37c47c7dc0..751c1f3733 100644 --- a/lib/librte_vhost/virtio_net.c +++ b/lib/librte_vhost/virtio_net.c @@ -43,6 +43,36 @@ is_valid_virt_queue_idx(uint32_t idx, int is_tx, uint32_t nr_vring) return (is_tx ^ (idx & 1)) == 0 && idx < nr_vring; } +static inline void +do_data_copy_enqueue(struct virtio_net *dev, struct vhost_virtqueue *vq) +{ + struct batch_copy_elem *elem = vq->batch_copy_elems; + uint16_t count = vq->batch_copy_nb_elems; + int i; + + for (i = 0; i < count; i++) { + rte_memcpy(elem[i].dst, elem[i].src, elem[i].len); + vhost_log_cache_write_iova(dev, vq, elem[i].log_addr, + elem[i].len); + PRINT_PACKET(dev, (uintptr_t)elem[i].dst, elem[i].len, 0); + } + + vq->batch_copy_nb_elems = 0; +} + +static inline void +do_data_copy_dequeue(struct vhost_virtqueue *vq) +{ + struct batch_copy_elem *elem = vq->batch_copy_elems; + uint16_t count = vq->batch_copy_nb_elems; + int i; + + for (i = 0; i < count; i++) + rte_memcpy(elem[i].dst, elem[i].src, elem[i].len); + + vq->batch_copy_nb_elems = 0; +} + static __rte_always_inline void do_flush_shadow_used_ring_split(struct virtio_net *dev, struct vhost_virtqueue *vq, @@ -77,11 +107,10 @@ flush_shadow_used_ring_split(struct virtio_net *dev, struct vhost_virtqueue *vq) } vq->last_used_idx += vq->shadow_used_idx; - rte_smp_wmb(); - vhost_log_cache_sync(dev, vq); - *(volatile uint16_t *)&vq->used->idx += vq->shadow_used_idx; + __atomic_add_fetch(&vq->used->idx, vq->shadow_used_idx, + __ATOMIC_RELEASE); vq->shadow_used_idx = 0; vhost_log_used_vring(dev, vq, offsetof(struct vring_used, idx), sizeof(vq->used->idx)); @@ -186,6 +215,11 @@ vhost_flush_enqueue_batch_packed(struct virtio_net *dev, uint16_t i; uint16_t flags; + if (vq->shadow_used_idx) { + do_data_copy_enqueue(dev, vq); + vhost_flush_enqueue_shadow_packed(dev, vq); + } + flags = PACKED_DESC_ENQUEUE_USED_FLAG(vq->used_wrap_counter); vhost_for_each_try_unroll(i, 0, PACKED_BATCH_SIZE) { @@ -325,36 +359,6 @@ vhost_shadow_dequeue_single_packed_inorder(struct vhost_virtqueue *vq, vq_inc_last_used_packed(vq, count); } -static inline void -do_data_copy_enqueue(struct virtio_net *dev, struct vhost_virtqueue *vq) -{ - struct batch_copy_elem *elem = vq->batch_copy_elems; - uint16_t count = vq->batch_copy_nb_elems; - int i; - - for (i = 0; i < count; i++) { - rte_memcpy(elem[i].dst, elem[i].src, elem[i].len); - vhost_log_cache_write_iova(dev, vq, elem[i].log_addr, - elem[i].len); - PRINT_PACKET(dev, (uintptr_t)elem[i].dst, elem[i].len, 0); - } - - vq->batch_copy_nb_elems = 0; -} - -static inline void -do_data_copy_dequeue(struct vhost_virtqueue *vq) -{ - struct batch_copy_elem *elem = vq->batch_copy_elems; - uint16_t count = vq->batch_copy_nb_elems; - int i; - - for (i = 0; i < count; i++) - rte_memcpy(elem[i].dst, elem[i].src, elem[i].len); - - vq->batch_copy_nb_elems = 0; -} - static __rte_always_inline void vhost_shadow_enqueue_single_packed(struct virtio_net *dev, struct vhost_virtqueue *vq, @@ -382,25 +386,6 @@ vhost_shadow_enqueue_single_packed(struct virtio_net *dev, } } -static __rte_always_inline void -vhost_flush_dequeue_packed(struct virtio_net *dev, - struct vhost_virtqueue *vq) -{ - int shadow_count; - if (!vq->shadow_used_idx) - return; - - shadow_count = vq->last_used_idx - vq->shadow_last_used_idx; - if (shadow_count <= 0) - shadow_count += vq->size; - - if ((uint32_t)shadow_count >= (vq->size - MAX_PKT_BURST)) { - do_data_copy_dequeue(vq); - vhost_flush_dequeue_shadow_packed(dev, vq); - vhost_vring_call_packed(dev, vq); - } -} - /* avoid write operation when necessary, to lessen cache issues */ #define ASSIGN_UNLESS_EQUAL(var, val) do { \ if ((var) != (val)) \ @@ -992,13 +977,11 @@ virtio_dev_rx_split(struct virtio_net *dev, struct vhost_virtqueue *vq, struct buf_vector buf_vec[BUF_VECTOR_MAX]; uint16_t avail_head; - avail_head = *((volatile uint16_t *)&vq->avail->idx); - /* * The ordering between avail index and * desc reads needs to be enforced. */ - rte_smp_rmb(); + avail_head = __atomic_load_n(&vq->avail->idx, __ATOMIC_ACQUIRE); rte_prefetch0(&vq->avail->ring[vq->last_avail_idx & (vq->size - 1)]); @@ -1086,6 +1069,8 @@ virtio_dev_rx_batch_packed(struct virtio_net *dev, VHOST_ACCESS_RW); vhost_for_each_try_unroll(i, 0, PACKED_BATCH_SIZE) { + if (unlikely(!desc_addrs[i])) + return -1; if (unlikely(lens[i] != descs[avail_idx + i].len)) return -1; } @@ -1688,6 +1673,8 @@ virtio_dev_tx_split(struct virtio_net *dev, struct vhost_virtqueue *vq, { uint16_t i; uint16_t free_entries; + uint16_t dropped = 0; + static bool allocerr_warned; if (unlikely(dev->dequeue_zero_copy)) { struct zcopy_mbuf *zmbuf, *next; @@ -1713,16 +1700,14 @@ virtio_dev_tx_split(struct virtio_net *dev, struct vhost_virtqueue *vq, } } - free_entries = *((volatile uint16_t *)&vq->avail->idx) - - vq->last_avail_idx; - if (free_entries == 0) - return 0; - /* * The ordering between avail index and * desc reads needs to be enforced. */ - rte_smp_rmb(); + free_entries = __atomic_load_n(&vq->avail->idx, __ATOMIC_ACQUIRE) - + vq->last_avail_idx; + if (free_entries == 0) + return 0; rte_prefetch0(&vq->avail->ring[vq->last_avail_idx & (vq->size - 1)]); @@ -1751,13 +1736,35 @@ virtio_dev_tx_split(struct virtio_net *dev, struct vhost_virtqueue *vq, update_shadow_used_ring_split(vq, head_idx, 0); pkts[i] = virtio_dev_pktmbuf_alloc(dev, mbuf_pool, buf_len); - if (unlikely(pkts[i] == NULL)) + if (unlikely(pkts[i] == NULL)) { + /* + * mbuf allocation fails for jumbo packets when external + * buffer allocation is not allowed and linear buffer + * is required. Drop this packet. + */ + if (!allocerr_warned) { + VHOST_LOG_DATA(ERR, + "Failed mbuf alloc of size %d from %s on %s.\n", + buf_len, mbuf_pool->name, dev->ifname); + allocerr_warned = true; + } + dropped += 1; + i++; break; + } err = copy_desc_to_mbuf(dev, vq, buf_vec, nr_vec, pkts[i], mbuf_pool); if (unlikely(err)) { rte_pktmbuf_free(pkts[i]); + if (!allocerr_warned) { + VHOST_LOG_DATA(ERR, + "Failed to copy desc to mbuf on %s.\n", + dev->ifname); + allocerr_warned = true; + } + dropped += 1; + i++; break; } @@ -1767,6 +1774,8 @@ virtio_dev_tx_split(struct virtio_net *dev, struct vhost_virtqueue *vq, zmbuf = get_zmbuf(vq); if (!zmbuf) { rte_pktmbuf_free(pkts[i]); + dropped += 1; + i++; break; } zmbuf->mbuf = pkts[i]; @@ -1796,7 +1805,7 @@ virtio_dev_tx_split(struct virtio_net *dev, struct vhost_virtqueue *vq, } } - return i; + return (i - dropped); } static __rte_always_inline int @@ -1841,6 +1850,8 @@ vhost_reserve_avail_batch_packed(struct virtio_net *dev, } vhost_for_each_try_unroll(i, 0, PACKED_BATCH_SIZE) { + if (unlikely(!desc_addrs[i])) + return -1; if (unlikely((lens[i] != descs[avail_idx + i].len))) return -1; } @@ -1928,6 +1939,7 @@ vhost_dequeue_single_packed(struct virtio_net *dev, uint32_t buf_len; uint16_t nr_vec = 0; int err; + static bool allocerr_warned; if (unlikely(fill_vec_buf_packed(dev, vq, vq->last_avail_idx, desc_count, @@ -1938,14 +1950,24 @@ vhost_dequeue_single_packed(struct virtio_net *dev, *pkts = virtio_dev_pktmbuf_alloc(dev, mbuf_pool, buf_len); if (unlikely(*pkts == NULL)) { - VHOST_LOG_DATA(ERR, - "Failed to allocate memory for mbuf.\n"); + if (!allocerr_warned) { + VHOST_LOG_DATA(ERR, + "Failed mbuf alloc of size %d from %s on %s.\n", + buf_len, mbuf_pool->name, dev->ifname); + allocerr_warned = true; + } return -1; } err = copy_desc_to_mbuf(dev, vq, buf_vec, nr_vec, *pkts, mbuf_pool); if (unlikely(err)) { + if (!allocerr_warned) { + VHOST_LOG_DATA(ERR, + "Failed to copy desc to mbuf on %s.\n", + dev->ifname); + allocerr_warned = true; + } rte_pktmbuf_free(*pkts); return -1; } @@ -1960,21 +1982,24 @@ virtio_dev_tx_single_packed(struct virtio_net *dev, struct rte_mbuf **pkts) { - uint16_t buf_id, desc_count; + uint16_t buf_id, desc_count = 0; + int ret; - if (vhost_dequeue_single_packed(dev, vq, mbuf_pool, pkts, &buf_id, - &desc_count)) - return -1; + ret = vhost_dequeue_single_packed(dev, vq, mbuf_pool, pkts, &buf_id, + &desc_count); - if (virtio_net_is_inorder(dev)) - vhost_shadow_dequeue_single_packed_inorder(vq, buf_id, - desc_count); - else - vhost_shadow_dequeue_single_packed(vq, buf_id, desc_count); + if (likely(desc_count > 0)) { + if (virtio_net_is_inorder(dev)) + vhost_shadow_dequeue_single_packed_inorder(vq, buf_id, + desc_count); + else + vhost_shadow_dequeue_single_packed(vq, buf_id, + desc_count); - vq_inc_last_avail_packed(vq, desc_count); + vq_inc_last_avail_packed(vq, desc_count); + } - return 0; + return ret; } static __rte_always_inline int @@ -2004,7 +2029,7 @@ virtio_dev_tx_batch_packed_zmbuf(struct virtio_net *dev, vhost_for_each_try_unroll(i, 0, PACKED_BATCH_SIZE) { zmbufs[i]->mbuf = pkts[i]; - zmbufs[i]->desc_idx = avail_idx + i; + zmbufs[i]->desc_idx = ids[i]; zmbufs[i]->desc_count = 1; } @@ -2045,7 +2070,7 @@ virtio_dev_tx_single_packed_zmbuf(struct virtio_net *dev, return -1; } zmbuf->mbuf = *pkts; - zmbuf->desc_idx = vq->last_avail_idx; + zmbuf->desc_idx = buf_id; zmbuf->desc_count = desc_count; rte_mbuf_refcnt_update(*pkts, 1); @@ -2133,20 +2158,6 @@ virtio_dev_tx_packed_zmbuf(struct virtio_net *dev, return pkt_idx; } -static __rte_always_inline bool -next_desc_is_avail(const struct vhost_virtqueue *vq) -{ - bool wrap_counter = vq->avail_wrap_counter; - uint16_t next_used_idx = vq->last_used_idx + 1; - - if (next_used_idx >= vq->size) { - next_used_idx -= vq->size; - wrap_counter ^= 1; - } - - return desc_is_avail(&vq->desc_packed[next_used_idx], wrap_counter); -} - static __rte_noinline uint16_t virtio_dev_tx_packed(struct virtio_net *dev, struct vhost_virtqueue *vq, @@ -2163,7 +2174,6 @@ virtio_dev_tx_packed(struct virtio_net *dev, if (remained >= PACKED_BATCH_SIZE) { if (!virtio_dev_tx_batch_packed(dev, vq, mbuf_pool, &pkts[pkt_idx])) { - vhost_flush_dequeue_packed(dev, vq); pkt_idx += PACKED_BATCH_SIZE; remained -= PACKED_BATCH_SIZE; continue; @@ -2173,7 +2183,6 @@ virtio_dev_tx_packed(struct virtio_net *dev, if (virtio_dev_tx_single_packed(dev, vq, mbuf_pool, &pkts[pkt_idx])) break; - vhost_flush_dequeue_packed(dev, vq); pkt_idx++; remained--; @@ -2182,15 +2191,8 @@ virtio_dev_tx_packed(struct virtio_net *dev, if (vq->shadow_used_idx) { do_data_copy_dequeue(vq); - if (remained && !next_desc_is_avail(vq)) { - /* - * The guest may be waiting to TX some buffers to - * enqueue more to avoid bufferfloat, so we try to - * reduce latency here. - */ - vhost_flush_dequeue_shadow_packed(dev, vq); - vhost_vring_call_packed(dev, vq); - } + vhost_flush_dequeue_shadow_packed(dev, vq); + vhost_vring_call_packed(dev, vq); } return pkt_idx; @@ -2203,6 +2205,7 @@ rte_vhost_dequeue_burst(int vid, uint16_t queue_id, struct virtio_net *dev; struct rte_mbuf *rarp_mbuf = NULL; struct vhost_virtqueue *vq; + int16_t success = 1; dev = get_device(vid); if (!dev) @@ -2249,16 +2252,17 @@ rte_vhost_dequeue_burst(int vid, uint16_t queue_id, * * broadcast_rarp shares a cacheline in the virtio_net structure * with some fields that are accessed during enqueue and - * rte_atomic16_cmpset() causes a write if using cmpxchg. This could - * result in false sharing between enqueue and dequeue. + * __atomic_compare_exchange_n causes a write if performed compare + * and exchange. This could result in false sharing between enqueue + * and dequeue. * * Prevent unnecessary false sharing by reading broadcast_rarp first - * and only performing cmpset if the read indicates it is likely to - * be set. + * and only performing compare and exchange if the read indicates it + * is likely to be set. */ - if (unlikely(rte_atomic16_read(&dev->broadcast_rarp) && - rte_atomic16_cmpset((volatile uint16_t *) - &dev->broadcast_rarp.cnt, 1, 0))) { + if (unlikely(__atomic_load_n(&dev->broadcast_rarp, __ATOMIC_ACQUIRE) && + __atomic_compare_exchange_n(&dev->broadcast_rarp, + &success, 0, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED))) { rarp_mbuf = rte_net_make_rarp_packet(mbuf_pool, &dev->mac); if (rarp_mbuf == NULL) {