The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/virtio/network/virtio_net.h

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 7161e610e777b24adb97345c9e419066


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.