1*f0ea3689SLuigi Rizzo /* 2*f0ea3689SLuigi Rizzo * Copyright (C) 2014 Vincenzo Maffione. All rights reserved. 3*f0ea3689SLuigi Rizzo * 4*f0ea3689SLuigi Rizzo * Redistribution and use in source and binary forms, with or without 5*f0ea3689SLuigi Rizzo * modification, are permitted provided that the following conditions 6*f0ea3689SLuigi Rizzo * are met: 7*f0ea3689SLuigi Rizzo * 1. Redistributions of source code must retain the above copyright 8*f0ea3689SLuigi Rizzo * notice, this list of conditions and the following disclaimer. 9*f0ea3689SLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 10*f0ea3689SLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 11*f0ea3689SLuigi Rizzo * documentation and/or other materials provided with the distribution. 12*f0ea3689SLuigi Rizzo * 13*f0ea3689SLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14*f0ea3689SLuigi Rizzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15*f0ea3689SLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16*f0ea3689SLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17*f0ea3689SLuigi Rizzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18*f0ea3689SLuigi Rizzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19*f0ea3689SLuigi Rizzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20*f0ea3689SLuigi Rizzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21*f0ea3689SLuigi Rizzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22*f0ea3689SLuigi Rizzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23*f0ea3689SLuigi Rizzo * SUCH DAMAGE. 24*f0ea3689SLuigi Rizzo */ 25*f0ea3689SLuigi Rizzo 26*f0ea3689SLuigi Rizzo /* $FreeBSD$ */ 27*f0ea3689SLuigi Rizzo 28*f0ea3689SLuigi Rizzo #if defined(__FreeBSD__) 29*f0ea3689SLuigi Rizzo #include <sys/cdefs.h> /* prerequisite */ 30*f0ea3689SLuigi Rizzo 31*f0ea3689SLuigi Rizzo #include <sys/types.h> 32*f0ea3689SLuigi Rizzo #include <sys/errno.h> 33*f0ea3689SLuigi Rizzo #include <sys/param.h> /* defines used in kernel.h */ 34*f0ea3689SLuigi Rizzo #include <sys/kernel.h> /* types used in module initialization */ 35*f0ea3689SLuigi Rizzo #include <sys/sockio.h> 36*f0ea3689SLuigi Rizzo #include <sys/socketvar.h> /* struct socket */ 37*f0ea3689SLuigi Rizzo #include <sys/socket.h> /* sockaddrs */ 38*f0ea3689SLuigi Rizzo #include <net/if.h> 39*f0ea3689SLuigi Rizzo #include <net/if_var.h> 40*f0ea3689SLuigi Rizzo #include <machine/bus.h> /* bus_dmamap_* */ 41*f0ea3689SLuigi Rizzo #include <sys/endian.h> 42*f0ea3689SLuigi Rizzo 43*f0ea3689SLuigi Rizzo #elif defined(linux) 44*f0ea3689SLuigi Rizzo 45*f0ea3689SLuigi Rizzo #include "bsd_glue.h" 46*f0ea3689SLuigi Rizzo 47*f0ea3689SLuigi Rizzo #elif defined(__APPLE__) 48*f0ea3689SLuigi Rizzo 49*f0ea3689SLuigi Rizzo #warning OSX support is only partial 50*f0ea3689SLuigi Rizzo #include "osx_glue.h" 51*f0ea3689SLuigi Rizzo 52*f0ea3689SLuigi Rizzo #else 53*f0ea3689SLuigi Rizzo 54*f0ea3689SLuigi Rizzo #error Unsupported platform 55*f0ea3689SLuigi Rizzo 56*f0ea3689SLuigi Rizzo #endif /* unsupported */ 57*f0ea3689SLuigi Rizzo 58*f0ea3689SLuigi Rizzo #include <net/netmap.h> 59*f0ea3689SLuigi Rizzo #include <dev/netmap/netmap_kern.h> 60*f0ea3689SLuigi Rizzo 61*f0ea3689SLuigi Rizzo 62*f0ea3689SLuigi Rizzo 63*f0ea3689SLuigi Rizzo /* This routine is called by bdg_mismatch_datapath() when it finishes 64*f0ea3689SLuigi Rizzo * accumulating bytes for a segment, in order to fix some fields in the 65*f0ea3689SLuigi Rizzo * segment headers (which still contain the same content as the header 66*f0ea3689SLuigi Rizzo * of the original GSO packet). 'buf' points to the beginning (e.g. 67*f0ea3689SLuigi Rizzo * the ethernet header) of the segment, and 'len' is its length. 68*f0ea3689SLuigi Rizzo */ 69*f0ea3689SLuigi Rizzo static void gso_fix_segment(uint8_t *buf, size_t len, u_int idx, 70*f0ea3689SLuigi Rizzo u_int segmented_bytes, u_int last_segment, 71*f0ea3689SLuigi Rizzo u_int tcp, u_int iphlen) 72*f0ea3689SLuigi Rizzo { 73*f0ea3689SLuigi Rizzo struct nm_iphdr *iph = (struct nm_iphdr *)(buf + 14); 74*f0ea3689SLuigi Rizzo struct nm_ipv6hdr *ip6h = (struct nm_ipv6hdr *)(buf + 14); 75*f0ea3689SLuigi Rizzo uint16_t *check = NULL; 76*f0ea3689SLuigi Rizzo uint8_t *check_data = NULL; 77*f0ea3689SLuigi Rizzo 78*f0ea3689SLuigi Rizzo if (iphlen == 20) { 79*f0ea3689SLuigi Rizzo /* Set the IPv4 "Total Length" field. */ 80*f0ea3689SLuigi Rizzo iph->tot_len = htobe16(len-14); 81*f0ea3689SLuigi Rizzo ND("ip total length %u", be16toh(ip->tot_len)); 82*f0ea3689SLuigi Rizzo 83*f0ea3689SLuigi Rizzo /* Set the IPv4 "Identification" field. */ 84*f0ea3689SLuigi Rizzo iph->id = htobe16(be16toh(iph->id) + idx); 85*f0ea3689SLuigi Rizzo ND("ip identification %u", be16toh(iph->id)); 86*f0ea3689SLuigi Rizzo 87*f0ea3689SLuigi Rizzo /* Compute and insert the IPv4 header checksum. */ 88*f0ea3689SLuigi Rizzo iph->check = 0; 89*f0ea3689SLuigi Rizzo iph->check = nm_csum_ipv4(iph); 90*f0ea3689SLuigi Rizzo ND("IP csum %x", be16toh(iph->check)); 91*f0ea3689SLuigi Rizzo } else {/* if (iphlen == 40) */ 92*f0ea3689SLuigi Rizzo /* Set the IPv6 "Payload Len" field. */ 93*f0ea3689SLuigi Rizzo ip6h->payload_len = htobe16(len-14-iphlen); 94*f0ea3689SLuigi Rizzo } 95*f0ea3689SLuigi Rizzo 96*f0ea3689SLuigi Rizzo if (tcp) { 97*f0ea3689SLuigi Rizzo struct nm_tcphdr *tcph = (struct nm_tcphdr *)(buf + 14 + iphlen); 98*f0ea3689SLuigi Rizzo 99*f0ea3689SLuigi Rizzo /* Set the TCP sequence number. */ 100*f0ea3689SLuigi Rizzo tcph->seq = htobe32(be32toh(tcph->seq) + segmented_bytes); 101*f0ea3689SLuigi Rizzo ND("tcp seq %u", be32toh(tcph->seq)); 102*f0ea3689SLuigi Rizzo 103*f0ea3689SLuigi Rizzo /* Zero the PSH and FIN TCP flags if this is not the last 104*f0ea3689SLuigi Rizzo segment. */ 105*f0ea3689SLuigi Rizzo if (!last_segment) 106*f0ea3689SLuigi Rizzo tcph->flags &= ~(0x8 | 0x1); 107*f0ea3689SLuigi Rizzo ND("last_segment %u", last_segment); 108*f0ea3689SLuigi Rizzo 109*f0ea3689SLuigi Rizzo check = &tcph->check; 110*f0ea3689SLuigi Rizzo check_data = (uint8_t *)tcph; 111*f0ea3689SLuigi Rizzo } else { /* UDP */ 112*f0ea3689SLuigi Rizzo struct nm_udphdr *udph = (struct nm_udphdr *)(buf + 14 + iphlen); 113*f0ea3689SLuigi Rizzo 114*f0ea3689SLuigi Rizzo /* Set the UDP 'Length' field. */ 115*f0ea3689SLuigi Rizzo udph->len = htobe16(len-14-iphlen); 116*f0ea3689SLuigi Rizzo 117*f0ea3689SLuigi Rizzo check = &udph->check; 118*f0ea3689SLuigi Rizzo check_data = (uint8_t *)udph; 119*f0ea3689SLuigi Rizzo } 120*f0ea3689SLuigi Rizzo 121*f0ea3689SLuigi Rizzo /* Compute and insert TCP/UDP checksum. */ 122*f0ea3689SLuigi Rizzo *check = 0; 123*f0ea3689SLuigi Rizzo if (iphlen == 20) 124*f0ea3689SLuigi Rizzo nm_csum_tcpudp_ipv4(iph, check_data, len-14-iphlen, check); 125*f0ea3689SLuigi Rizzo else 126*f0ea3689SLuigi Rizzo nm_csum_tcpudp_ipv6(ip6h, check_data, len-14-iphlen, check); 127*f0ea3689SLuigi Rizzo 128*f0ea3689SLuigi Rizzo ND("TCP/UDP csum %x", be16toh(*check)); 129*f0ea3689SLuigi Rizzo } 130*f0ea3689SLuigi Rizzo 131*f0ea3689SLuigi Rizzo 132*f0ea3689SLuigi Rizzo /* The VALE mismatch datapath implementation. */ 133*f0ea3689SLuigi Rizzo void bdg_mismatch_datapath(struct netmap_vp_adapter *na, 134*f0ea3689SLuigi Rizzo struct netmap_vp_adapter *dst_na, 135*f0ea3689SLuigi Rizzo struct nm_bdg_fwd *ft_p, struct netmap_ring *ring, 136*f0ea3689SLuigi Rizzo u_int *j, u_int lim, u_int *howmany) 137*f0ea3689SLuigi Rizzo { 138*f0ea3689SLuigi Rizzo struct netmap_slot *slot = NULL; 139*f0ea3689SLuigi Rizzo struct nm_vnet_hdr *vh = NULL; 140*f0ea3689SLuigi Rizzo /* Number of source slots to process. */ 141*f0ea3689SLuigi Rizzo u_int frags = ft_p->ft_frags; 142*f0ea3689SLuigi Rizzo struct nm_bdg_fwd *ft_end = ft_p + frags; 143*f0ea3689SLuigi Rizzo 144*f0ea3689SLuigi Rizzo /* Source and destination pointers. */ 145*f0ea3689SLuigi Rizzo uint8_t *dst, *src; 146*f0ea3689SLuigi Rizzo size_t src_len, dst_len; 147*f0ea3689SLuigi Rizzo 148*f0ea3689SLuigi Rizzo u_int j_start = *j; 149*f0ea3689SLuigi Rizzo u_int dst_slots = 0; 150*f0ea3689SLuigi Rizzo 151*f0ea3689SLuigi Rizzo /* If the source port uses the offloadings, while destination doesn't, 152*f0ea3689SLuigi Rizzo * we grab the source virtio-net header and do the offloadings here. 153*f0ea3689SLuigi Rizzo */ 154*f0ea3689SLuigi Rizzo if (na->virt_hdr_len && !dst_na->virt_hdr_len) { 155*f0ea3689SLuigi Rizzo vh = (struct nm_vnet_hdr *)ft_p->ft_buf; 156*f0ea3689SLuigi Rizzo } 157*f0ea3689SLuigi Rizzo 158*f0ea3689SLuigi Rizzo /* Init source and dest pointers. */ 159*f0ea3689SLuigi Rizzo src = ft_p->ft_buf; 160*f0ea3689SLuigi Rizzo src_len = ft_p->ft_len; 161*f0ea3689SLuigi Rizzo slot = &ring->slot[*j]; 162*f0ea3689SLuigi Rizzo dst = BDG_NMB(&dst_na->up, slot); 163*f0ea3689SLuigi Rizzo dst_len = src_len; 164*f0ea3689SLuigi Rizzo 165*f0ea3689SLuigi Rizzo /* We are processing the first input slot and there is a mismatch 166*f0ea3689SLuigi Rizzo * between source and destination virt_hdr_len (SHL and DHL). 167*f0ea3689SLuigi Rizzo * When the a client is using virtio-net headers, the header length 168*f0ea3689SLuigi Rizzo * can be: 169*f0ea3689SLuigi Rizzo * - 10: the header corresponds to the struct nm_vnet_hdr 170*f0ea3689SLuigi Rizzo * - 12: the first 10 bytes correspond to the struct 171*f0ea3689SLuigi Rizzo * virtio_net_hdr, and the last 2 bytes store the 172*f0ea3689SLuigi Rizzo * "mergeable buffers" info, which is an optional 173*f0ea3689SLuigi Rizzo * hint that can be zeroed for compability 174*f0ea3689SLuigi Rizzo * 175*f0ea3689SLuigi Rizzo * The destination header is therefore built according to the 176*f0ea3689SLuigi Rizzo * following table: 177*f0ea3689SLuigi Rizzo * 178*f0ea3689SLuigi Rizzo * SHL | DHL | destination header 179*f0ea3689SLuigi Rizzo * ----------------------------- 180*f0ea3689SLuigi Rizzo * 0 | 10 | zero 181*f0ea3689SLuigi Rizzo * 0 | 12 | zero 182*f0ea3689SLuigi Rizzo * 10 | 0 | doesn't exist 183*f0ea3689SLuigi Rizzo * 10 | 12 | first 10 bytes are copied from source header, last 2 are zero 184*f0ea3689SLuigi Rizzo * 12 | 0 | doesn't exist 185*f0ea3689SLuigi Rizzo * 12 | 10 | copied from the first 10 bytes of source header 186*f0ea3689SLuigi Rizzo */ 187*f0ea3689SLuigi Rizzo bzero(dst, dst_na->virt_hdr_len); 188*f0ea3689SLuigi Rizzo if (na->virt_hdr_len && dst_na->virt_hdr_len) 189*f0ea3689SLuigi Rizzo memcpy(dst, src, sizeof(struct nm_vnet_hdr)); 190*f0ea3689SLuigi Rizzo /* Skip the virtio-net headers. */ 191*f0ea3689SLuigi Rizzo src += na->virt_hdr_len; 192*f0ea3689SLuigi Rizzo src_len -= na->virt_hdr_len; 193*f0ea3689SLuigi Rizzo dst += dst_na->virt_hdr_len; 194*f0ea3689SLuigi Rizzo dst_len = dst_na->virt_hdr_len + src_len; 195*f0ea3689SLuigi Rizzo 196*f0ea3689SLuigi Rizzo /* Here it could be dst_len == 0 (which implies src_len == 0), 197*f0ea3689SLuigi Rizzo * so we avoid passing a zero length fragment. 198*f0ea3689SLuigi Rizzo */ 199*f0ea3689SLuigi Rizzo if (dst_len == 0) { 200*f0ea3689SLuigi Rizzo ft_p++; 201*f0ea3689SLuigi Rizzo src = ft_p->ft_buf; 202*f0ea3689SLuigi Rizzo src_len = ft_p->ft_len; 203*f0ea3689SLuigi Rizzo dst_len = src_len; 204*f0ea3689SLuigi Rizzo } 205*f0ea3689SLuigi Rizzo 206*f0ea3689SLuigi Rizzo if (vh && vh->gso_type != VIRTIO_NET_HDR_GSO_NONE) { 207*f0ea3689SLuigi Rizzo u_int gso_bytes = 0; 208*f0ea3689SLuigi Rizzo /* Length of the GSO packet header. */ 209*f0ea3689SLuigi Rizzo u_int gso_hdr_len = 0; 210*f0ea3689SLuigi Rizzo /* Pointer to the GSO packet header. Assume it is in a single fragment. */ 211*f0ea3689SLuigi Rizzo uint8_t *gso_hdr = NULL; 212*f0ea3689SLuigi Rizzo /* Index of the current segment. */ 213*f0ea3689SLuigi Rizzo u_int gso_idx = 0; 214*f0ea3689SLuigi Rizzo /* Payload data bytes segmented so far (e.g. TCP data bytes). */ 215*f0ea3689SLuigi Rizzo u_int segmented_bytes = 0; 216*f0ea3689SLuigi Rizzo /* Length of the IP header (20 if IPv4, 40 if IPv6). */ 217*f0ea3689SLuigi Rizzo u_int iphlen = 0; 218*f0ea3689SLuigi Rizzo /* Is this a TCP or an UDP GSO packet? */ 219*f0ea3689SLuigi Rizzo u_int tcp = ((vh->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) 220*f0ea3689SLuigi Rizzo == VIRTIO_NET_HDR_GSO_UDP) ? 0 : 1; 221*f0ea3689SLuigi Rizzo 222*f0ea3689SLuigi Rizzo /* Segment the GSO packet contained into the input slots (frags). */ 223*f0ea3689SLuigi Rizzo while (ft_p != ft_end) { 224*f0ea3689SLuigi Rizzo size_t copy; 225*f0ea3689SLuigi Rizzo 226*f0ea3689SLuigi Rizzo /* Grab the GSO header if we don't have it. */ 227*f0ea3689SLuigi Rizzo if (!gso_hdr) { 228*f0ea3689SLuigi Rizzo uint16_t ethertype; 229*f0ea3689SLuigi Rizzo 230*f0ea3689SLuigi Rizzo gso_hdr = src; 231*f0ea3689SLuigi Rizzo 232*f0ea3689SLuigi Rizzo /* Look at the 'Ethertype' field to see if this packet 233*f0ea3689SLuigi Rizzo * is IPv4 or IPv6. 234*f0ea3689SLuigi Rizzo */ 235*f0ea3689SLuigi Rizzo ethertype = be16toh(*((uint16_t *)(gso_hdr + 12))); 236*f0ea3689SLuigi Rizzo if (ethertype == 0x0800) 237*f0ea3689SLuigi Rizzo iphlen = 20; 238*f0ea3689SLuigi Rizzo else /* if (ethertype == 0x86DD) */ 239*f0ea3689SLuigi Rizzo iphlen = 40; 240*f0ea3689SLuigi Rizzo ND(3, "type=%04x", ethertype); 241*f0ea3689SLuigi Rizzo 242*f0ea3689SLuigi Rizzo /* Compute gso_hdr_len. For TCP we need to read the 243*f0ea3689SLuigi Rizzo * content of the 'Data Offset' field. 244*f0ea3689SLuigi Rizzo */ 245*f0ea3689SLuigi Rizzo if (tcp) { 246*f0ea3689SLuigi Rizzo struct nm_tcphdr *tcph = 247*f0ea3689SLuigi Rizzo (struct nm_tcphdr *)&gso_hdr[14+iphlen]; 248*f0ea3689SLuigi Rizzo 249*f0ea3689SLuigi Rizzo gso_hdr_len = 14 + iphlen + 4*(tcph->doff >> 4); 250*f0ea3689SLuigi Rizzo } else 251*f0ea3689SLuigi Rizzo gso_hdr_len = 14 + iphlen + 8; /* UDP */ 252*f0ea3689SLuigi Rizzo 253*f0ea3689SLuigi Rizzo ND(3, "gso_hdr_len %u gso_mtu %d", gso_hdr_len, 254*f0ea3689SLuigi Rizzo dst_na->mfs); 255*f0ea3689SLuigi Rizzo 256*f0ea3689SLuigi Rizzo /* Advance source pointers. */ 257*f0ea3689SLuigi Rizzo src += gso_hdr_len; 258*f0ea3689SLuigi Rizzo src_len -= gso_hdr_len; 259*f0ea3689SLuigi Rizzo if (src_len == 0) { 260*f0ea3689SLuigi Rizzo ft_p++; 261*f0ea3689SLuigi Rizzo if (ft_p == ft_end) 262*f0ea3689SLuigi Rizzo break; 263*f0ea3689SLuigi Rizzo src = ft_p->ft_buf; 264*f0ea3689SLuigi Rizzo src_len = ft_p->ft_len; 265*f0ea3689SLuigi Rizzo continue; 266*f0ea3689SLuigi Rizzo } 267*f0ea3689SLuigi Rizzo } 268*f0ea3689SLuigi Rizzo 269*f0ea3689SLuigi Rizzo /* Fill in the header of the current segment. */ 270*f0ea3689SLuigi Rizzo if (gso_bytes == 0) { 271*f0ea3689SLuigi Rizzo memcpy(dst, gso_hdr, gso_hdr_len); 272*f0ea3689SLuigi Rizzo gso_bytes = gso_hdr_len; 273*f0ea3689SLuigi Rizzo } 274*f0ea3689SLuigi Rizzo 275*f0ea3689SLuigi Rizzo /* Fill in data and update source and dest pointers. */ 276*f0ea3689SLuigi Rizzo copy = src_len; 277*f0ea3689SLuigi Rizzo if (gso_bytes + copy > dst_na->mfs) 278*f0ea3689SLuigi Rizzo copy = dst_na->mfs - gso_bytes; 279*f0ea3689SLuigi Rizzo memcpy(dst + gso_bytes, src, copy); 280*f0ea3689SLuigi Rizzo gso_bytes += copy; 281*f0ea3689SLuigi Rizzo src += copy; 282*f0ea3689SLuigi Rizzo src_len -= copy; 283*f0ea3689SLuigi Rizzo 284*f0ea3689SLuigi Rizzo /* A segment is complete or we have processed all the 285*f0ea3689SLuigi Rizzo the GSO payload bytes. */ 286*f0ea3689SLuigi Rizzo if (gso_bytes >= dst_na->mfs || 287*f0ea3689SLuigi Rizzo (src_len == 0 && ft_p + 1 == ft_end)) { 288*f0ea3689SLuigi Rizzo /* After raw segmentation, we must fix some header 289*f0ea3689SLuigi Rizzo * fields and compute checksums, in a protocol dependent 290*f0ea3689SLuigi Rizzo * way. */ 291*f0ea3689SLuigi Rizzo gso_fix_segment(dst, gso_bytes, gso_idx, 292*f0ea3689SLuigi Rizzo segmented_bytes, 293*f0ea3689SLuigi Rizzo src_len == 0 && ft_p + 1 == ft_end, 294*f0ea3689SLuigi Rizzo tcp, iphlen); 295*f0ea3689SLuigi Rizzo 296*f0ea3689SLuigi Rizzo ND("frame %u completed with %d bytes", gso_idx, (int)gso_bytes); 297*f0ea3689SLuigi Rizzo slot->len = gso_bytes; 298*f0ea3689SLuigi Rizzo slot->flags = 0; 299*f0ea3689SLuigi Rizzo segmented_bytes += gso_bytes - gso_hdr_len; 300*f0ea3689SLuigi Rizzo 301*f0ea3689SLuigi Rizzo dst_slots++; 302*f0ea3689SLuigi Rizzo 303*f0ea3689SLuigi Rizzo /* Next destination slot. */ 304*f0ea3689SLuigi Rizzo *j = nm_next(*j, lim); 305*f0ea3689SLuigi Rizzo slot = &ring->slot[*j]; 306*f0ea3689SLuigi Rizzo dst = BDG_NMB(&dst_na->up, slot); 307*f0ea3689SLuigi Rizzo 308*f0ea3689SLuigi Rizzo gso_bytes = 0; 309*f0ea3689SLuigi Rizzo gso_idx++; 310*f0ea3689SLuigi Rizzo } 311*f0ea3689SLuigi Rizzo 312*f0ea3689SLuigi Rizzo /* Next input slot. */ 313*f0ea3689SLuigi Rizzo if (src_len == 0) { 314*f0ea3689SLuigi Rizzo ft_p++; 315*f0ea3689SLuigi Rizzo if (ft_p == ft_end) 316*f0ea3689SLuigi Rizzo break; 317*f0ea3689SLuigi Rizzo src = ft_p->ft_buf; 318*f0ea3689SLuigi Rizzo src_len = ft_p->ft_len; 319*f0ea3689SLuigi Rizzo } 320*f0ea3689SLuigi Rizzo } 321*f0ea3689SLuigi Rizzo ND(3, "%d bytes segmented", segmented_bytes); 322*f0ea3689SLuigi Rizzo 323*f0ea3689SLuigi Rizzo } else { 324*f0ea3689SLuigi Rizzo /* Address of a checksum field into a destination slot. */ 325*f0ea3689SLuigi Rizzo uint16_t *check = NULL; 326*f0ea3689SLuigi Rizzo /* Accumulator for an unfolded checksum. */ 327*f0ea3689SLuigi Rizzo rawsum_t csum = 0; 328*f0ea3689SLuigi Rizzo 329*f0ea3689SLuigi Rizzo /* Process a non-GSO packet. */ 330*f0ea3689SLuigi Rizzo 331*f0ea3689SLuigi Rizzo /* Init 'check' if necessary. */ 332*f0ea3689SLuigi Rizzo if (vh && (vh->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)) { 333*f0ea3689SLuigi Rizzo if (unlikely(vh->csum_offset + vh->csum_start > src_len)) 334*f0ea3689SLuigi Rizzo D("invalid checksum request"); 335*f0ea3689SLuigi Rizzo else 336*f0ea3689SLuigi Rizzo check = (uint16_t *)(dst + vh->csum_start + 337*f0ea3689SLuigi Rizzo vh->csum_offset); 338*f0ea3689SLuigi Rizzo } 339*f0ea3689SLuigi Rizzo 340*f0ea3689SLuigi Rizzo while (ft_p != ft_end) { 341*f0ea3689SLuigi Rizzo /* Init/update the packet checksum if needed. */ 342*f0ea3689SLuigi Rizzo if (vh && (vh->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)) { 343*f0ea3689SLuigi Rizzo if (!dst_slots) 344*f0ea3689SLuigi Rizzo csum = nm_csum_raw(src + vh->csum_start, 345*f0ea3689SLuigi Rizzo src_len - vh->csum_start, 0); 346*f0ea3689SLuigi Rizzo else 347*f0ea3689SLuigi Rizzo csum = nm_csum_raw(src, src_len, csum); 348*f0ea3689SLuigi Rizzo } 349*f0ea3689SLuigi Rizzo 350*f0ea3689SLuigi Rizzo /* Round to a multiple of 64 */ 351*f0ea3689SLuigi Rizzo src_len = (src_len + 63) & ~63; 352*f0ea3689SLuigi Rizzo 353*f0ea3689SLuigi Rizzo if (ft_p->ft_flags & NS_INDIRECT) { 354*f0ea3689SLuigi Rizzo if (copyin(src, dst, src_len)) { 355*f0ea3689SLuigi Rizzo /* Invalid user pointer, pretend len is 0. */ 356*f0ea3689SLuigi Rizzo dst_len = 0; 357*f0ea3689SLuigi Rizzo } 358*f0ea3689SLuigi Rizzo } else { 359*f0ea3689SLuigi Rizzo memcpy(dst, src, (int)src_len); 360*f0ea3689SLuigi Rizzo } 361*f0ea3689SLuigi Rizzo slot->len = dst_len; 362*f0ea3689SLuigi Rizzo 363*f0ea3689SLuigi Rizzo dst_slots++; 364*f0ea3689SLuigi Rizzo 365*f0ea3689SLuigi Rizzo /* Next destination slot. */ 366*f0ea3689SLuigi Rizzo *j = nm_next(*j, lim); 367*f0ea3689SLuigi Rizzo slot = &ring->slot[*j]; 368*f0ea3689SLuigi Rizzo dst = BDG_NMB(&dst_na->up, slot); 369*f0ea3689SLuigi Rizzo 370*f0ea3689SLuigi Rizzo /* Next source slot. */ 371*f0ea3689SLuigi Rizzo ft_p++; 372*f0ea3689SLuigi Rizzo src = ft_p->ft_buf; 373*f0ea3689SLuigi Rizzo dst_len = src_len = ft_p->ft_len; 374*f0ea3689SLuigi Rizzo 375*f0ea3689SLuigi Rizzo } 376*f0ea3689SLuigi Rizzo 377*f0ea3689SLuigi Rizzo /* Finalize (fold) the checksum if needed. */ 378*f0ea3689SLuigi Rizzo if (check && vh && (vh->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)) { 379*f0ea3689SLuigi Rizzo *check = nm_csum_fold(csum); 380*f0ea3689SLuigi Rizzo } 381*f0ea3689SLuigi Rizzo ND(3, "using %u dst_slots", dst_slots); 382*f0ea3689SLuigi Rizzo 383*f0ea3689SLuigi Rizzo /* A second pass on the desitations slots to set the slot flags, 384*f0ea3689SLuigi Rizzo * using the right number of destination slots. 385*f0ea3689SLuigi Rizzo */ 386*f0ea3689SLuigi Rizzo while (j_start != *j) { 387*f0ea3689SLuigi Rizzo slot = &ring->slot[j_start]; 388*f0ea3689SLuigi Rizzo slot->flags = (dst_slots << 8)| NS_MOREFRAG; 389*f0ea3689SLuigi Rizzo j_start = nm_next(j_start, lim); 390*f0ea3689SLuigi Rizzo } 391*f0ea3689SLuigi Rizzo /* Clear NS_MOREFRAG flag on last entry. */ 392*f0ea3689SLuigi Rizzo slot->flags = (dst_slots << 8); 393*f0ea3689SLuigi Rizzo } 394*f0ea3689SLuigi Rizzo 395*f0ea3689SLuigi Rizzo /* Update howmany. */ 396*f0ea3689SLuigi Rizzo if (unlikely(dst_slots > *howmany)) { 397*f0ea3689SLuigi Rizzo dst_slots = *howmany; 398*f0ea3689SLuigi Rizzo D("Slot allocation error: Should never happen"); 399*f0ea3689SLuigi Rizzo } 400*f0ea3689SLuigi Rizzo *howmany -= dst_slots; 401*f0ea3689SLuigi Rizzo } 402