1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * This header is BSD licensed so anyone can use the definitions to implement 5 * compatible drivers/servers. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of IBM nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #ifndef _VIRTIO_NET_H 32 #define _VIRTIO_NET_H 33 34 /* The feature bitmap for virtio net */ 35 #define VIRTIO_NET_F_CSUM (1ULL << 0) /* Host handles pkts w/ partial csum */ 36 #define VIRTIO_NET_F_GUEST_CSUM (1ULL << 1) /* Guest handles pkts w/ partial csum*/ 37 #define VIRTIO_NET_F_CTRL_GUEST_OFFLOADS (1ULL << 2) /* Dynamic offload configuration. */ 38 #define VIRTIO_NET_F_MTU (1ULL << 3) /* Initial MTU advice */ 39 #define VIRTIO_NET_F_MAC (1ULL << 5) /* Host has given MAC address. */ 40 #define VIRTIO_NET_F_GSO (1ULL << 6) /* Host handles pkts w/ any GSO type */ 41 #define VIRTIO_NET_F_GUEST_TSO4 (1ULL << 7) /* Guest can handle TSOv4 in. */ 42 #define VIRTIO_NET_F_GUEST_TSO6 (1ULL << 8) /* Guest can handle TSOv6 in. */ 43 #define VIRTIO_NET_F_GUEST_ECN (1ULL << 9) /* Guest can handle TSO[6] w/ ECN in. */ 44 #define VIRTIO_NET_F_GUEST_UFO (1ULL << 10) /* Guest can handle UFO in. */ 45 #define VIRTIO_NET_F_HOST_TSO4 (1ULL << 11) /* Host can handle TSOv4 in. */ 46 #define VIRTIO_NET_F_HOST_TSO6 (1ULL << 12) /* Host can handle TSOv6 in. */ 47 #define VIRTIO_NET_F_HOST_ECN (1ULL << 13) /* Host can handle TSO[6] w/ ECN in. */ 48 #define VIRTIO_NET_F_HOST_UFO (1ULL << 14) /* Host can handle UFO in. */ 49 #define VIRTIO_NET_F_MRG_RXBUF (1ULL << 15) /* Host can merge receive buffers. */ 50 #define VIRTIO_NET_F_STATUS (1ULL << 16) /* virtio_net_config.status available*/ 51 #define VIRTIO_NET_F_CTRL_VQ (1ULL << 17) /* Control channel available */ 52 #define VIRTIO_NET_F_CTRL_RX (1ULL << 18) /* Control channel RX mode support */ 53 #define VIRTIO_NET_F_CTRL_VLAN (1ULL << 19) /* Control channel VLAN filtering */ 54 #define VIRTIO_NET_F_CTRL_RX_EXTRA (1ULL << 20) /* Extra RX mode control support */ 55 #define VIRTIO_NET_F_GUEST_ANNOUNCE (1ULL << 21) /* Announce device on network */ 56 #define VIRTIO_NET_F_MQ (1ULL << 22) /* Device supports Receive Flow Steering */ 57 #define VIRTIO_NET_F_CTRL_MAC_ADDR (1ULL << 23) /* Set MAC address */ 58 #define VIRTIO_NET_F_SPEED_DUPLEX (1ULL << 63) /* Device set linkspeed and duplex */ 59 60 /* virtio net feature flag descriptions for use with printf(9) %b identifier. */ 61 #define VIRTIO_NET_FEATURE_BITS \ 62 "\20\200CSUM\201GUEST_CSUM\202CTRL_GUEST_OFFLOADS\203MTU\205MAC\206GSO" \ 63 "\207GUEST_TSO4\210GUEST_TSO6\211GUEST_ECN\212GUEST_UFO\213HOST_TSO4" \ 64 "\214HOST_TSO6\215HOST_ECN\216HOST_UFO\217MRG_RXBUF\220STATUS\221CTRL_VQ" \ 65 "\222CTRL_RX\223CTRL_VLAN\224CTRL_RX_EXTRA\225GUEST_ANNOUNCE\226MQ" \ 66 "\227CTRL_MAC_ADDR\277SPEED_DUPLEX" 67 68 #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ 69 #define VIRTIO_NET_S_ANNOUNCE 2 /* Announcement is needed */ 70 71 struct virtio_net_config { 72 /* The config defining mac address (if VIRTIO_NET_F_MAC) */ 73 uint8_t mac[ETHER_ADDR_LEN]; 74 /* See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above */ 75 uint16_t status; 76 /* Maximum number of each of transmit and receive queues; 77 * see VIRTIO_NET_F_MQ and VIRTIO_NET_CTRL_MQ. 78 * Legal values are between 1 and 0x8000. 79 */ 80 uint16_t max_virtqueue_pairs; 81 /* Default maximum transmit unit advice */ 82 uint16_t mtu; 83 /* 84 * speed, in units of 1Mb. All values 0 to INT_MAX are legal. 85 * Any other value stands for unknown. 86 */ 87 uint32_t speed; 88 /* 89 * 0x00 - half duplex 90 * 0x01 - full duplex 91 * Any other value stands for unknown. 92 */ 93 uint8_t duplex; 94 } __packed; 95 96 /* 97 * This header comes first in the scatter-gather list. If you don't 98 * specify GSO or CSUM features, you can simply ignore the header. 99 * 100 * This is bitwise-equivalent to the legacy struct virtio_net_hdr_mrg_rxbuf, 101 * only flattened. 102 */ 103 struct virtio_net_hdr_v1 { 104 #define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 /* Use csum_start, csum_offset */ 105 #define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */ 106 uint8_t flags; 107 #define VIRTIO_NET_HDR_GSO_NONE 0 /* Not a GSO frame */ 108 #define VIRTIO_NET_HDR_GSO_TCPV4 1 /* GSO frame, IPv4 TCP (TSO) */ 109 #define VIRTIO_NET_HDR_GSO_UDP 3 /* GSO frame, IPv4 UDP (UFO) */ 110 #define VIRTIO_NET_HDR_GSO_TCPV6 4 /* GSO frame, IPv6 TCP */ 111 #define VIRTIO_NET_HDR_GSO_ECN 0x80 /* TCP has ECN set */ 112 uint8_t gso_type; 113 uint16_t hdr_len; /* Ethernet + IP + tcp/udp hdrs */ 114 uint16_t gso_size; /* Bytes to append to hdr_len per frame */ 115 uint16_t csum_start; /* Position to start checksumming from */ 116 uint16_t csum_offset; /* Offset after that to place checksum */ 117 uint16_t num_buffers; /* Number of merged rx buffers */ 118 }; 119 120 /* 121 * This header comes first in the scatter-gather list. 122 * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, it must 123 * be the first element of the scatter-gather list. If you don't 124 * specify GSO or CSUM features, you can simply ignore the header. 125 */ 126 struct virtio_net_hdr { 127 /* See VIRTIO_NET_HDR_F_* */ 128 uint8_t flags; 129 /* See VIRTIO_NET_HDR_GSO_* */ 130 uint8_t gso_type; 131 uint16_t hdr_len; /* Ethernet + IP + tcp/udp hdrs */ 132 uint16_t gso_size; /* Bytes to append to hdr_len per frame */ 133 uint16_t csum_start; /* Position to start checksumming from */ 134 uint16_t csum_offset; /* Offset after that to place checksum */ 135 }; 136 137 /* 138 * This is the version of the header to use when the MRG_RXBUF 139 * feature has been negotiated. 140 */ 141 struct virtio_net_hdr_mrg_rxbuf { 142 struct virtio_net_hdr hdr; 143 uint16_t num_buffers; /* Number of merged rx buffers */ 144 }; 145 146 /* 147 * Control virtqueue data structures 148 * 149 * The control virtqueue expects a header in the first sg entry 150 * and an ack/status response in the last entry. Data for the 151 * command goes in between. 152 */ 153 struct virtio_net_ctrl_hdr { 154 uint8_t class; 155 uint8_t cmd; 156 } __packed; 157 158 #define VIRTIO_NET_OK 0 159 #define VIRTIO_NET_ERR 1 160 161 /* 162 * Control the RX mode, ie. promiscuous, allmulti, etc... 163 * All commands require an "out" sg entry containing a 1 byte 164 * state value, zero = disable, non-zero = enable. Commands 165 * 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature. 166 * Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA. 167 */ 168 #define VIRTIO_NET_CTRL_RX 0 169 #define VIRTIO_NET_CTRL_RX_PROMISC 0 170 #define VIRTIO_NET_CTRL_RX_ALLMULTI 1 171 #define VIRTIO_NET_CTRL_RX_ALLUNI 2 172 #define VIRTIO_NET_CTRL_RX_NOMULTI 3 173 #define VIRTIO_NET_CTRL_RX_NOUNI 4 174 #define VIRTIO_NET_CTRL_RX_NOBCAST 5 175 176 /* 177 * Control the MAC filter table. 178 * 179 * The MAC filter table is managed by the hypervisor, the guest should 180 * assume the size is infinite. Filtering should be considered 181 * non-perfect, ie. based on hypervisor resources, the guest may 182 * received packets from sources not specified in the filter list. 183 * 184 * In addition to the class/cmd header, the TABLE_SET command requires 185 * two out scatterlists. Each contains a 4 byte count of entries followed 186 * by a concatenated byte stream of the ETH_ALEN MAC addresses. The 187 * first sg list contains unicast addresses, the second is for multicast. 188 * This functionality is present if the VIRTIO_NET_F_CTRL_RX feature 189 * is available. 190 * 191 * The ADDR_SET command requests one out scatterlist, it contains a 192 * 6 bytes MAC address. This functionality is present if the 193 * VIRTIO_NET_F_CTRL_MAC_ADDR feature is available. 194 */ 195 struct virtio_net_ctrl_mac { 196 uint32_t entries; 197 uint8_t macs[][ETHER_ADDR_LEN]; 198 } __packed; 199 200 #define VIRTIO_NET_CTRL_MAC 1 201 #define VIRTIO_NET_CTRL_MAC_TABLE_SET 0 202 #define VIRTIO_NET_CTRL_MAC_ADDR_SET 1 203 204 /* 205 * Control VLAN filtering 206 * 207 * The VLAN filter table is controlled via a simple ADD/DEL interface. 208 * VLAN IDs not added may be filtered by the hypervisor. Del is the 209 * opposite of add. Both commands expect an out entry containing a 2 210 * byte VLAN ID. VLAN filtering is available with the 211 * VIRTIO_NET_F_CTRL_VLAN feature bit. 212 */ 213 #define VIRTIO_NET_CTRL_VLAN 2 214 #define VIRTIO_NET_CTRL_VLAN_ADD 0 215 #define VIRTIO_NET_CTRL_VLAN_DEL 1 216 217 /* 218 * Control link announce acknowledgement 219 * 220 * The command VIRTIO_NET_CTRL_ANNOUNCE_ACK is used to indicate that 221 * driver has received the notification; device would clear the 222 * VIRTIO_NET_S_ANNOUNCE bit in the status field after it receives 223 * this command. 224 */ 225 #define VIRTIO_NET_CTRL_ANNOUNCE 3 226 #define VIRTIO_NET_CTRL_ANNOUNCE_ACK 0 227 228 /* 229 * Control Receive Flow Steering 230 * 231 * The command VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET enables Receive Flow 232 * Steering, specifying the number of the transmit and receive queues 233 * that will be used. After the command is consumed and acked by the 234 * device, the device will not steer new packets on receive virtqueues 235 * other than specified nor read from transmit virtqueues other than 236 * specified. Accordingly, driver should not transmit new packets on 237 * virtqueues other than specified. 238 */ 239 struct virtio_net_ctrl_mq { 240 uint16_t virtqueue_pairs; 241 } __packed; 242 243 #define VIRTIO_NET_CTRL_MQ 4 244 #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET 0 245 #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN 1 246 #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX 0x8000 247 248 /* 249 * Control network offloads 250 * 251 * Reconfigures the network offloads that Guest can handle. 252 * 253 * Available with the VIRTIO_NET_F_CTRL_GUEST_OFFLOADS feature bit. 254 * 255 * Command data format matches the feature bit mask exactly. 256 * 257 * See VIRTIO_NET_F_GUEST_* for the list of offloads 258 * that can be enabled/disabled. 259 */ 260 #define VIRTIO_NET_CTRL_GUEST_OFFLOADS 5 261 #define VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET 0 262 263 /* 264 * Use the checksum offset in the VirtIO header to set the 265 * correct CSUM_* flags. 266 */ 267 static inline int 268 virtio_net_rx_csum_by_offset(struct mbuf *m, uint16_t eth_type, int ip_start, 269 struct virtio_net_hdr *hdr) 270 { 271 #if defined(INET) || defined(INET6) 272 int offset = hdr->csum_start + hdr->csum_offset; 273 #endif 274 275 /* Only do a basic sanity check on the offset. */ 276 switch (eth_type) { 277 #if defined(INET) 278 case ETHERTYPE_IP: 279 if (__predict_false(offset < ip_start + sizeof(struct ip))) 280 return (1); 281 break; 282 #endif 283 #if defined(INET6) 284 case ETHERTYPE_IPV6: 285 if (__predict_false(offset < ip_start + sizeof(struct ip6_hdr))) 286 return (1); 287 break; 288 #endif 289 default: 290 /* Here we should increment the rx_csum_bad_ethtype counter. */ 291 return (1); 292 } 293 294 /* 295 * Use the offset to determine the appropriate CSUM_* flags. This is 296 * a bit dirty, but we can get by with it since the checksum offsets 297 * happen to be different. We assume the host host does not do IPv4 298 * header checksum offloading. 299 */ 300 switch (hdr->csum_offset) { 301 case offsetof(struct udphdr, uh_sum): 302 case offsetof(struct tcphdr, th_sum): 303 m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 304 m->m_pkthdr.csum_data = 0xFFFF; 305 break; 306 default: 307 /* Here we should increment the rx_csum_bad_offset counter. */ 308 return (1); 309 } 310 311 return (0); 312 } 313 314 static inline int 315 virtio_net_rx_csum_by_parse(struct mbuf *m, uint16_t eth_type, int ip_start, 316 struct virtio_net_hdr *hdr) 317 { 318 int offset, proto; 319 320 switch (eth_type) { 321 #if defined(INET) 322 case ETHERTYPE_IP: { 323 struct ip *ip; 324 if (__predict_false(m->m_len < ip_start + sizeof(struct ip))) 325 return (1); 326 ip = (struct ip *)(m->m_data + ip_start); 327 proto = ip->ip_p; 328 offset = ip_start + (ip->ip_hl << 2); 329 break; 330 } 331 #endif 332 #if defined(INET6) 333 case ETHERTYPE_IPV6: 334 if (__predict_false(m->m_len < ip_start + 335 sizeof(struct ip6_hdr))) 336 return (1); 337 offset = ip6_lasthdr(m, ip_start, IPPROTO_IPV6, &proto); 338 if (__predict_false(offset < 0)) 339 return (1); 340 break; 341 #endif 342 default: 343 /* Here we should increment the rx_csum_bad_ethtype counter. */ 344 return (1); 345 } 346 347 switch (proto) { 348 case IPPROTO_TCP: 349 if (__predict_false(m->m_len < offset + sizeof(struct tcphdr))) 350 return (1); 351 m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 352 m->m_pkthdr.csum_data = 0xFFFF; 353 break; 354 case IPPROTO_UDP: 355 if (__predict_false(m->m_len < offset + sizeof(struct udphdr))) 356 return (1); 357 m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 358 m->m_pkthdr.csum_data = 0xFFFF; 359 break; 360 default: 361 /* 362 * For the remaining protocols, FreeBSD does not support 363 * checksum offloading, so the checksum will be recomputed. 364 */ 365 #if 0 366 if_printf(ifp, "cksum offload of unsupported " 367 "protocol eth_type=%#x proto=%d csum_start=%d " 368 "csum_offset=%d\n", __func__, eth_type, proto, 369 hdr->csum_start, hdr->csum_offset); 370 #endif 371 break; 372 } 373 374 return (0); 375 } 376 377 /* 378 * Set the appropriate CSUM_* flags. Unfortunately, the information 379 * provided is not directly useful to us. The VirtIO header gives the 380 * offset of the checksum, which is all Linux needs, but this is not 381 * how FreeBSD does things. We are forced to peek inside the packet 382 * a bit. 383 * 384 * It would be nice if VirtIO gave us the L4 protocol or if FreeBSD 385 * could accept the offsets and let the stack figure it out. 386 */ 387 static inline int 388 virtio_net_rx_csum(struct mbuf *m, struct virtio_net_hdr *hdr) 389 { 390 struct ether_header *eh; 391 struct ether_vlan_header *evh; 392 uint16_t eth_type; 393 int offset, error; 394 395 if ((hdr->flags & (VIRTIO_NET_HDR_F_NEEDS_CSUM | 396 VIRTIO_NET_HDR_F_DATA_VALID)) == 0) { 397 return (0); 398 } 399 400 eh = mtod(m, struct ether_header *); 401 eth_type = ntohs(eh->ether_type); 402 if (eth_type == ETHERTYPE_VLAN) { 403 /* BMV: We should handle nested VLAN tags too. */ 404 evh = mtod(m, struct ether_vlan_header *); 405 eth_type = ntohs(evh->evl_proto); 406 offset = sizeof(struct ether_vlan_header); 407 } else 408 offset = sizeof(struct ether_header); 409 410 if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) 411 error = virtio_net_rx_csum_by_offset(m, eth_type, offset, hdr); 412 else 413 error = virtio_net_rx_csum_by_parse(m, eth_type, offset, hdr); 414 415 return (error); 416 } 417 418 static inline int 419 virtio_net_tx_offload_ctx(struct mbuf *m, int *etype, int *proto, int *start) 420 { 421 struct ether_vlan_header *evh; 422 #if defined(INET) || defined(INET6) 423 int offset; 424 #endif 425 426 evh = mtod(m, struct ether_vlan_header *); 427 if (evh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 428 /* BMV: We should handle nested VLAN tags too. */ 429 *etype = ntohs(evh->evl_proto); 430 #if defined(INET) || defined(INET6) 431 offset = sizeof(struct ether_vlan_header); 432 #endif 433 } else { 434 *etype = ntohs(evh->evl_encap_proto); 435 #if defined(INET) || defined(INET6) 436 offset = sizeof(struct ether_header); 437 #endif 438 } 439 440 switch (*etype) { 441 #if defined(INET) 442 case ETHERTYPE_IP: { 443 struct ip *ip, iphdr; 444 if (__predict_false(m->m_len < offset + sizeof(struct ip))) { 445 m_copydata(m, offset, sizeof(struct ip), 446 (caddr_t) &iphdr); 447 ip = &iphdr; 448 } else 449 ip = (struct ip *)(m->m_data + offset); 450 *proto = ip->ip_p; 451 *start = offset + (ip->ip_hl << 2); 452 break; 453 } 454 #endif 455 #if defined(INET6) 456 case ETHERTYPE_IPV6: 457 *proto = -1; 458 *start = ip6_lasthdr(m, offset, IPPROTO_IPV6, proto); 459 /* Assert the network stack sent us a valid packet. */ 460 KASSERT(*start > offset, 461 ("%s: mbuf %p start %d offset %d proto %d", __func__, m, 462 *start, offset, *proto)); 463 break; 464 #endif 465 default: 466 /* Here we should increment the tx_csum_bad_ethtype counter. */ 467 return (EINVAL); 468 } 469 470 return (0); 471 } 472 473 static inline int 474 virtio_net_tx_offload_tso(if_t ifp, struct mbuf *m, int eth_type, 475 int offset, bool allow_ecn, struct virtio_net_hdr *hdr) 476 { 477 static struct timeval lastecn; 478 static int curecn; 479 struct tcphdr *tcp, tcphdr; 480 481 if (__predict_false(m->m_len < offset + sizeof(struct tcphdr))) { 482 m_copydata(m, offset, sizeof(struct tcphdr), (caddr_t) &tcphdr); 483 tcp = &tcphdr; 484 } else 485 tcp = (struct tcphdr *)(m->m_data + offset); 486 487 hdr->hdr_len = offset + (tcp->th_off << 2); 488 hdr->gso_size = m->m_pkthdr.tso_segsz; 489 hdr->gso_type = eth_type == ETHERTYPE_IP ? VIRTIO_NET_HDR_GSO_TCPV4 : 490 VIRTIO_NET_HDR_GSO_TCPV6; 491 492 if (tcp_get_flags(tcp) & TH_CWR) { 493 /* 494 * Drop if VIRTIO_NET_F_HOST_ECN was not negotiated. In FreeBSD, 495 * ECN support is not on a per-interface basis, but globally via 496 * the net.inet.tcp.ecn.enable sysctl knob. The default is off. 497 */ 498 if (!allow_ecn) { 499 if (ppsratecheck(&lastecn, &curecn, 1)) 500 if_printf(ifp, 501 "TSO with ECN not negotiated with host\n"); 502 return (ENOTSUP); 503 } 504 hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN; 505 } 506 507 /* Here we should increment tx_tso counter. */ 508 509 return (0); 510 } 511 512 static inline struct mbuf * 513 virtio_net_tx_offload(if_t ifp, struct mbuf *m, bool allow_ecn, 514 struct virtio_net_hdr *hdr) 515 { 516 int flags, etype, csum_start, proto, error; 517 518 flags = m->m_pkthdr.csum_flags; 519 520 error = virtio_net_tx_offload_ctx(m, &etype, &proto, &csum_start); 521 if (error) 522 goto drop; 523 524 if ((etype == ETHERTYPE_IP && (flags & (CSUM_TCP | CSUM_UDP))) || 525 (etype == ETHERTYPE_IPV6 && 526 (flags & (CSUM_TCP_IPV6 | CSUM_UDP_IPV6)))) { 527 /* 528 * We could compare the IP protocol vs the CSUM_ flag too, 529 * but that really should not be necessary. 530 */ 531 hdr->flags |= VIRTIO_NET_HDR_F_NEEDS_CSUM; 532 hdr->csum_start = csum_start; 533 hdr->csum_offset = m->m_pkthdr.csum_data; 534 /* Here we should increment the tx_csum counter. */ 535 } 536 537 if (flags & CSUM_TSO) { 538 if (__predict_false(proto != IPPROTO_TCP)) { 539 /* Likely failed to correctly parse the mbuf. 540 * Here we should increment the tx_tso_not_tcp 541 * counter. */ 542 goto drop; 543 } 544 545 KASSERT(hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM, 546 ("%s: mbuf %p TSO without checksum offload %#x", 547 __func__, m, flags)); 548 549 error = virtio_net_tx_offload_tso(ifp, m, etype, csum_start, 550 allow_ecn, hdr); 551 if (error) 552 goto drop; 553 } 554 555 return (m); 556 557 drop: 558 m_freem(m); 559 return (NULL); 560 } 561 562 #endif /* _VIRTIO_NET_H */ 563