vmxnet_rx_pkt.c 4.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
/*
 * QEMU VMWARE VMXNET* paravirtual NICs - RX packets abstractions
 *
 * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
 *
 * Developed by Daynix Computing LTD (http://www.daynix.com)
 *
 * Authors:
 * Dmitry Fleytman <dmitry@daynix.com>
 * Tamir Shomer <tamirs@daynix.com>
 * Yan Vugenfirer <yan@daynix.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 * See the COPYING file in the top-level directory.
 *
 */

#include "vmxnet_rx_pkt.h"
#include "net/eth.h"
#include "qemu-common.h"
#include "qemu/iov.h"
#include "net/checksum.h"
#include "net/tap.h"

/*
 * RX packet may contain up to 2 fragments - rebuilt eth header
 * in case of VLAN tag stripping
 * and payload received from QEMU - in any case
 */
#define VMXNET_MAX_RX_PACKET_FRAGMENTS (2)

struct VmxnetRxPkt {
    struct virtio_net_hdr virt_hdr;
    uint8_t ehdr_buf[ETH_MAX_L2_HDR_LEN];
    struct iovec vec[VMXNET_MAX_RX_PACKET_FRAGMENTS];
    uint16_t vec_len;
    uint32_t tot_len;
    uint16_t tci;
    bool vlan_stripped;
    bool has_virt_hdr;
    eth_pkt_types_e packet_type;

    /* Analysis results */
    bool isip4;
    bool isip6;
    bool isudp;
    bool istcp;
};

void vmxnet_rx_pkt_init(struct VmxnetRxPkt **pkt, bool has_virt_hdr)
{
    struct VmxnetRxPkt *p = g_malloc0(sizeof *p);
    p->has_virt_hdr = has_virt_hdr;
    *pkt = p;
}

void vmxnet_rx_pkt_uninit(struct VmxnetRxPkt *pkt)
{
    g_free(pkt);
}

struct virtio_net_hdr *vmxnet_rx_pkt_get_vhdr(struct VmxnetRxPkt *pkt)
{
    assert(pkt);
    return &pkt->virt_hdr;
}

void vmxnet_rx_pkt_attach_data(struct VmxnetRxPkt *pkt, const void *data,
                               size_t len, bool strip_vlan)
{
    uint16_t tci = 0;
    uint16_t ploff;
    assert(pkt);
    pkt->vlan_stripped = false;

    if (strip_vlan) {
        pkt->vlan_stripped = eth_strip_vlan(data, pkt->ehdr_buf, &ploff, &tci);
    }

    if (pkt->vlan_stripped) {
        pkt->vec[0].iov_base = pkt->ehdr_buf;
        pkt->vec[0].iov_len = ploff - sizeof(struct vlan_header);
        pkt->vec[1].iov_base = (uint8_t *) data + ploff;
        pkt->vec[1].iov_len = len - ploff;
        pkt->vec_len = 2;
        pkt->tot_len = len - ploff + sizeof(struct eth_header);
    } else {
        pkt->vec[0].iov_base = (void *)data;
        pkt->vec[0].iov_len = len;
        pkt->vec_len = 1;
        pkt->tot_len = len;
    }

    pkt->tci = tci;

    eth_get_protocols(data, len, &pkt->isip4, &pkt->isip6,
        &pkt->isudp, &pkt->istcp);
}

void vmxnet_rx_pkt_dump(struct VmxnetRxPkt *pkt)
{
#ifdef VMXNET_RX_PKT_DEBUG
    VmxnetRxPkt *pkt = (VmxnetRxPkt *)pkt;
    assert(pkt);

    printf("RX PKT: tot_len: %d, vlan_stripped: %d, vlan_tag: %d\n",
              pkt->tot_len, pkt->vlan_stripped, pkt->tci);
#endif
}

void vmxnet_rx_pkt_set_packet_type(struct VmxnetRxPkt *pkt,
    eth_pkt_types_e packet_type)
{
    assert(pkt);

    pkt->packet_type = packet_type;

}

eth_pkt_types_e vmxnet_rx_pkt_get_packet_type(struct VmxnetRxPkt *pkt)
{
    assert(pkt);

    return pkt->packet_type;
}

size_t vmxnet_rx_pkt_get_total_len(struct VmxnetRxPkt *pkt)
{
    assert(pkt);

    return pkt->tot_len;
}

void vmxnet_rx_pkt_get_protocols(struct VmxnetRxPkt *pkt,
                                 bool *isip4, bool *isip6,
                                 bool *isudp, bool *istcp)
{
    assert(pkt);

    *isip4 = pkt->isip4;
    *isip6 = pkt->isip6;
    *isudp = pkt->isudp;
    *istcp = pkt->istcp;
}

struct iovec *vmxnet_rx_pkt_get_iovec(struct VmxnetRxPkt *pkt)
{
    assert(pkt);

    return pkt->vec;
}

void vmxnet_rx_pkt_set_vhdr(struct VmxnetRxPkt *pkt,
                            struct virtio_net_hdr *vhdr)
{
    assert(pkt);

    memcpy(&pkt->virt_hdr, vhdr, sizeof pkt->virt_hdr);
}

bool vmxnet_rx_pkt_is_vlan_stripped(struct VmxnetRxPkt *pkt)
{
    assert(pkt);

    return pkt->vlan_stripped;
}

bool vmxnet_rx_pkt_has_virt_hdr(struct VmxnetRxPkt *pkt)
{
    assert(pkt);

    return pkt->has_virt_hdr;
}

uint16_t vmxnet_rx_pkt_get_num_frags(struct VmxnetRxPkt *pkt)
{
    assert(pkt);

    return pkt->vec_len;
}

uint16_t vmxnet_rx_pkt_get_vlan_tag(struct VmxnetRxPkt *pkt)
{
    assert(pkt);

    return pkt->tci;
}