+ if ((vring->used->flags & VRING_USED_F_NO_NOTIFY) == 0)
+ {
+ virtio_kick (vm, vring, vif);
+ }
+ goto more;
+}
+
+static_always_inline void
+virtio_refill_vring_packed (vlib_main_t * vm, virtio_if_t * vif,
+ virtio_if_type_t type, virtio_vring_t * vring,
+ const int hdr_sz, u32 node_index)
+{
+ u16 used, next, n_slots, n_refill, flags = 0, first_desc_flags;
+ u16 sz = vring->size;
+
+more:
+ used = vring->desc_in_use;
+
+ if (sz == used)
+ return;
+
+ /* deliver free buffers in chunks of 64 */
+ n_refill = clib_min (sz - used, 64);
+
+ next = vring->desc_next;
+ first_desc_flags = vring->packed_desc[next].flags;
+ n_slots =
+ vlib_buffer_alloc_to_ring_from_pool (vm, vring->buffers, next,
+ sz, n_refill,
+ vring->buffer_pool_index);
+
+ if (PREDICT_FALSE (n_slots != n_refill))
+ {
+ vlib_error_count (vm, node_index,
+ VIRTIO_INPUT_ERROR_BUFFER_ALLOC, n_refill - n_slots);
+ if (n_slots == 0)
+ return;
+ }
+
+ while (n_slots)
+ {
+ vring_packed_desc_t *d = &vring->packed_desc[next];
+ vlib_buffer_t *b = vlib_get_buffer (vm, vring->buffers[next]);
+ /*
+ * current_data may not be initialized with 0 and may contain
+ * previous offset. Here we want to make sure, it should be 0
+ * initialized.
+ */
+ b->current_data = -hdr_sz;
+ memset (vlib_buffer_get_current (b), 0, hdr_sz);
+ d->addr =
+ ((type == VIRTIO_IF_TYPE_PCI) ? vlib_buffer_get_current_pa (vm,
+ b) :
+ pointer_to_uword (vlib_buffer_get_current (b)));
+ d->len = vlib_buffer_get_default_data_size (vm) + hdr_sz;
+
+ if (vring->avail_wrap_counter)
+ flags = (VRING_DESC_F_AVAIL | VRING_DESC_F_WRITE);
+ else
+ flags = (VRING_DESC_F_USED | VRING_DESC_F_WRITE);
+
+ d->id = next;
+ if (vring->desc_next == next)
+ first_desc_flags = flags;
+ else
+ d->flags = flags;
+
+ next++;
+ if (next >= sz)
+ {
+ next = 0;
+ vring->avail_wrap_counter ^= 1;
+ }
+ n_slots--;
+ used++;
+ }
+ CLIB_MEMORY_STORE_BARRIER ();
+ vring->packed_desc[vring->desc_next].flags = first_desc_flags;
+ vring->desc_next = next;
+ vring->desc_in_use = used;
+ CLIB_MEMORY_BARRIER ();
+ if (vring->device_event->flags != VRING_EVENT_F_DISABLE)
+ {
+ virtio_kick (vm, vring, vif);
+ }
+
+ goto more;
+}
+
+static_always_inline void
+virtio_needs_csum (vlib_buffer_t * b0, virtio_net_hdr_v1_t * hdr,
+ u8 * l4_proto, u8 * l4_hdr_sz, virtio_if_type_t type)
+{
+ if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)
+ {
+ u16 ethertype = 0, l2hdr_sz = 0;
+
+ if (type == VIRTIO_IF_TYPE_TUN)
+ {
+ switch (b0->data[0] & 0xf0)
+ {
+ case 0x40:
+ ethertype = ETHERNET_TYPE_IP4;
+ break;
+ case 0x60:
+ ethertype = ETHERNET_TYPE_IP6;
+ break;
+ }
+ }
+ else
+ {
+ ethernet_header_t *eh =
+ (ethernet_header_t *) vlib_buffer_get_current (b0);
+ ethertype = clib_net_to_host_u16 (eh->type);
+ l2hdr_sz = sizeof (ethernet_header_t);
+
+ if (ethernet_frame_is_tagged (ethertype))
+ {
+ ethernet_vlan_header_t *vlan =
+ (ethernet_vlan_header_t *) (eh + 1);
+
+ ethertype = clib_net_to_host_u16 (vlan->type);
+ l2hdr_sz += sizeof (*vlan);
+ if (ethertype == ETHERNET_TYPE_VLAN)
+ {
+ vlan++;
+ ethertype = clib_net_to_host_u16 (vlan->type);
+ l2hdr_sz += sizeof (*vlan);
+ }
+ }
+ }
+
+ vnet_buffer (b0)->l2_hdr_offset = 0;
+ vnet_buffer (b0)->l3_hdr_offset = l2hdr_sz;
+
+ if (PREDICT_TRUE (ethertype == ETHERNET_TYPE_IP4))
+ {
+ ip4_header_t *ip4 =
+ (ip4_header_t *) (vlib_buffer_get_current (b0) + l2hdr_sz);
+ vnet_buffer (b0)->l4_hdr_offset = l2hdr_sz + ip4_header_bytes (ip4);
+ *l4_proto = ip4->protocol;
+ b0->flags |=
+ (VNET_BUFFER_F_IS_IP4 | VNET_BUFFER_F_OFFLOAD_IP_CKSUM);
+ b0->flags |=
+ (VNET_BUFFER_F_L2_HDR_OFFSET_VALID
+ | VNET_BUFFER_F_L3_HDR_OFFSET_VALID |
+ VNET_BUFFER_F_L4_HDR_OFFSET_VALID);
+ }
+ else if (PREDICT_TRUE (ethertype == ETHERNET_TYPE_IP6))
+ {
+ ip6_header_t *ip6 =
+ (ip6_header_t *) (vlib_buffer_get_current (b0) + l2hdr_sz);
+ vnet_buffer (b0)->l4_hdr_offset = l2hdr_sz + sizeof (ip6_header_t);
+ /* FIXME IPv6 EH traversal */
+ *l4_proto = ip6->protocol;
+ b0->flags |= (VNET_BUFFER_F_IS_IP6 |
+ VNET_BUFFER_F_L2_HDR_OFFSET_VALID
+ | VNET_BUFFER_F_L3_HDR_OFFSET_VALID |
+ VNET_BUFFER_F_L4_HDR_OFFSET_VALID);
+ }
+ if (*l4_proto == IP_PROTOCOL_TCP)
+ {
+ b0->flags |= VNET_BUFFER_F_OFFLOAD_TCP_CKSUM;
+ tcp_header_t *tcp = (tcp_header_t *) (vlib_buffer_get_current (b0) +
+ vnet_buffer
+ (b0)->l4_hdr_offset);
+ *l4_hdr_sz = tcp_header_bytes (tcp);
+ }
+ else if (*l4_proto == IP_PROTOCOL_UDP)
+ {
+ b0->flags |= VNET_BUFFER_F_OFFLOAD_UDP_CKSUM;
+ udp_header_t *udp = (udp_header_t *) (vlib_buffer_get_current (b0) +
+ vnet_buffer
+ (b0)->l4_hdr_offset);
+ *l4_hdr_sz = sizeof (*udp);
+ }
+ }
+}
+
+static_always_inline void
+fill_gso_buffer_flags (vlib_buffer_t * b0, virtio_net_hdr_v1_t * hdr,
+ u8 l4_proto, u8 l4_hdr_sz)
+{
+ if (hdr->gso_type == VIRTIO_NET_HDR_GSO_TCPV4)