+static_always_inline void
+vmxnet3_handle_offload (vmxnet3_rx_comp * rx_comp, vlib_buffer_t * hb,
+ u16 * next, u16 gso_size)
+{
+ u8 l4_hdr_sz = 0;
+
+ if (gso_size)
+ {
+ if (rx_comp->flags & VMXNET3_RXCF_TCP)
+ {
+ tcp_header_t *tcp =
+ (tcp_header_t *) (hb->data + vnet_buffer (hb)->l4_hdr_offset);
+ l4_hdr_sz = tcp_header_bytes (tcp);
+ }
+ else if (rx_comp->flags & VMXNET3_RXCF_UDP)
+ {
+ udp_header_t *udp =
+ (udp_header_t *) (hb->data + vnet_buffer (hb)->l4_hdr_offset);
+ l4_hdr_sz = sizeof (*udp);
+ }
+ }
+
+ if (rx_comp->flags & VMXNET3_RXCF_IP4)
+ {
+ ip4_header_t *ip4 = (ip4_header_t *) (hb->data +
+ sizeof (ethernet_header_t));
+
+ vnet_buffer (hb)->l2_hdr_offset = 0;
+ vnet_buffer (hb)->l3_hdr_offset = sizeof (ethernet_header_t);
+ vnet_buffer (hb)->l4_hdr_offset = sizeof (ethernet_header_t) +
+ ip4_header_bytes (ip4);
+ hb->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
+ VNET_BUFFER_F_L3_HDR_OFFSET_VALID |
+ VNET_BUFFER_F_L4_HDR_OFFSET_VALID | VNET_BUFFER_F_IS_IP4;
+ next[0] = VNET_DEVICE_INPUT_NEXT_IP4_NCS_INPUT;
+
+ /* checksum offload */
+ if (!(rx_comp->index & VMXNET3_RXCI_CNC))
+ {
+ if (!(rx_comp->flags & VMXNET3_RXCF_IPC))
+ {
+ hb->flags |= VNET_BUFFER_F_OFFLOAD_IP_CKSUM;
+ ip4->checksum = 0;
+ }
+ if (!(rx_comp->flags & VMXNET3_RXCF_TUC))
+ {
+ if (rx_comp->flags & VMXNET3_RXCF_TCP)
+ {
+ tcp_header_t *tcp =
+ (tcp_header_t *) (hb->data +
+ vnet_buffer (hb)->l4_hdr_offset);
+ hb->flags |= VNET_BUFFER_F_OFFLOAD_TCP_CKSUM;
+ tcp->checksum = 0;
+ }
+ else if (rx_comp->flags & VMXNET3_RXCF_UDP)
+ {
+ udp_header_t *udp =
+ (udp_header_t *) (hb->data +
+ vnet_buffer (hb)->l4_hdr_offset);
+ hb->flags |= VNET_BUFFER_F_OFFLOAD_UDP_CKSUM;
+ udp->checksum = 0;
+ }
+ }
+ }
+
+ if (gso_size)
+ {
+ vnet_buffer2 (hb)->gso_size = gso_size;
+ vnet_buffer2 (hb)->gso_l4_hdr_sz = l4_hdr_sz;
+ hb->flags |= VNET_BUFFER_F_GSO;
+ }
+ vlib_buffer_advance (hb, device_input_next_node_advance[next[0]]);
+ }
+ else if (rx_comp->flags & VMXNET3_RXCF_IP6)
+ {
+ vnet_buffer (hb)->l2_hdr_offset = 0;
+ vnet_buffer (hb)->l3_hdr_offset = sizeof (ethernet_header_t);
+ vnet_buffer (hb)->l4_hdr_offset = sizeof (ethernet_header_t) +
+ sizeof (ip6_header_t);
+ hb->flags |= VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
+ VNET_BUFFER_F_L3_HDR_OFFSET_VALID |
+ VNET_BUFFER_F_L4_HDR_OFFSET_VALID | VNET_BUFFER_F_IS_IP6;
+ next[0] = VNET_DEVICE_INPUT_NEXT_IP6_INPUT;
+
+ /* checksum offload */
+ if (!(rx_comp->index & VMXNET3_RXCI_CNC))
+ {
+ if (!(rx_comp->flags & VMXNET3_RXCF_TUC))
+ {
+ if (rx_comp->flags & VMXNET3_RXCF_TCP)
+ {
+ tcp_header_t *tcp =
+ (tcp_header_t *) (hb->data +
+ vnet_buffer (hb)->l4_hdr_offset);
+ hb->flags |= VNET_BUFFER_F_OFFLOAD_TCP_CKSUM;
+ tcp->checksum = 0;
+ }
+ else if (rx_comp->flags & VMXNET3_RXCF_UDP)
+ {
+ udp_header_t *udp =
+ (udp_header_t *) (hb->data +
+ vnet_buffer (hb)->l4_hdr_offset);
+ hb->flags |= VNET_BUFFER_F_OFFLOAD_UDP_CKSUM;
+ udp->checksum = 0;
+ }
+ }
+ }
+
+ if (gso_size)
+ {
+ vnet_buffer2 (hb)->gso_size = gso_size;
+ vnet_buffer2 (hb)->gso_l4_hdr_sz = l4_hdr_sz;
+ hb->flags |= VNET_BUFFER_F_GSO;
+ }
+ vlib_buffer_advance (hb, device_input_next_node_advance[next[0]]);
+ }
+ else
+ next[0] = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
+}
+