static int
read__(vpi_interface_mmap_t* vi, char* data, int len)
{
    ring_control_t* rc;
    frame_control_t* fc;
    struct tpacket2_hdr* hdr;
    int size;
    bool tagged = false;
    void* copy_start;

    rc = &vi->rx_ring;
    fc = &rc->frames[rc->current_frame];
    hdr = (struct tpacket2_hdr*)fc->base;

    /* check min buffer size */
    if(len < 64) {
        return -1;
    }

    /* not ready */
    if(!(hdr->tp_status & TP_STATUS_USER)) {
        return 0;
    }

    size = hdr->tp_snaplen;
    /* check vlan tag */
    if((hdr->tp_status & TP_STATUS_VLAN_VALID) &&
       (hdr->tp_status & TP_STATUS_VLAN_TPID_VALID)) {
        size += 4;
        tagged = true;
    }

    size = (len < size) ? len : size;
    copy_start = (void*)hdr + hdr->tp_mac;
    if(tagged) {
        /* convert to network order */
        uint16_t tpid = htons(hdr->tp_vlan_tpid);
        uint16_t vlan = htons(hdr->tp_vlan_tci);

        /* L2 src and dst */
        VPI_MEMCPY(data, copy_start, 12);
        /* TPID */
        VPI_MEMCPY(data + 12, &tpid, 2);
        /* VLAN */
        VPI_MEMCPY(data + 14, &vlan, 2);
        /* Rest of packet */
        VPI_MEMCPY(data + 16, copy_start + 12, size - 16);
    } else {
        VPI_MEMCPY(data, copy_start, size);
    }
    VPI_INFO(vi, "packet received: %d bytes read", size);

    /* advance and flush */
    rc->current_frame = (rc->current_frame + 1)%NUM_FRAMES;
    hdr->tp_status = TP_STATUS_KERNEL;

    return size;
}
/**************************************************************************//**
 *
 * Receive packet data on our socket. Assumes no fragmentation.
 *
 *
 *****************************************************************************/
static int
read__(vpi_interface_veth_t* vi, char* data, int len)
{
    int rv;
    if((rv = read(vi->fd, data, len)) < 0) {
        VPI_ERROR(vi, "read() failed: %s", strerror(errno));
        return -1;
    }
    else {
        VPI_INFO(vi, "packet received");
    }
    return rv;
}
int
vpi_mmap_interface_create(vpi_interface_t** vi, char* args[], int flags,
                       const char* vpi_name_ptr)
{
    struct sockaddr_ll sockaddr;
    struct packet_mreq sockparams;
    struct tpacket_req treq;
    struct ifreq ifreq;
    vpi_interface_mmap_t* nvi = aim_zmalloc(sizeof(*nvi));
    char** arg = args;
    int version;
    int i;
    frame_control_t* fc;

    AIM_REFERENCE(flags);

    if(nvi == NULL) {
        VPI_MERROR("interface allocation failed for %s.",
                   vpi_name_ptr);
        return -1;
    }

    /*
     * Point our log_string to our name so we can use it immediately
     * in log messages.
     */
    nvi->log_string = vpi_name_ptr;


    /*
     * The first argument is the type -- skip for now
     */
    arg++;

    aim_strlcpy(nvi->interface_name, *arg, sizeof(nvi->interface_name));

    /* Create RAW socket */
    if((nvi->fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
        VPI_ERROR(nvi, "socket() failed: %s\n", strerror(errno));
        aim_free(nvi);
        return -1;
    }

    /* Set version */
    version = TPACKET_V2;
    if(setsockopt(nvi->fd, SOL_PACKET, PACKET_VERSION,
                  &version, sizeof(version)) < 0) {
        VPI_ERROR(nvi, "setsockopt() version failed: %s\n", strerror(errno));
        aim_free(nvi);
        return -1;
    }

    /*
     * Get the interface index for the requested interface, as specified
     * in the current argument.
     */
    VPI_MEMSET(&ifreq, 0, sizeof(ifreq));
    aim_strlcpy(ifreq.ifr_name, nvi->interface_name, IFNAMSIZ);
    if(ioctl(nvi->fd, SIOCGIFINDEX, &ifreq) < 0) {
        VPI_ERROR(nvi, "ioctl() failed: %s", strerror(errno));
        close(nvi->fd);
        aim_free(nvi);
        return -1;
    }
    nvi->ifindex = ifreq.ifr_ifindex;
    VPI_INFO(nvi, "ifndex is %d", nvi->ifindex);

    /* Set promisc */
    VPI_MEMSET(&sockparams, 0, sizeof(sockparams));
    sockparams.mr_type = PACKET_MR_PROMISC;
    sockparams.mr_ifindex = nvi->ifindex;
    if(setsockopt(nvi->fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
                  (void *)&sockparams, sizeof(sockparams)) < 0) {
        VPI_ERROR(nvi, "setsockopt() promisc failed. %s\n", strerror(errno));
        close(nvi->fd);
        aim_free(nvi);
        return -1;
    }

    /* Set up rx_ring buffer */
    VPI_MEMSET(&treq, 0, sizeof(treq));
    treq.tp_block_size = BLOCK_SIZE;
    treq.tp_frame_size = FRAME_SIZE;
    treq.tp_block_nr = NUM_BLOCKS;
    treq.tp_frame_nr = NUM_FRAMES;;
    if(setsockopt(nvi->fd, SOL_PACKET, PACKET_RX_RING,
                  (void*)&treq , sizeof(treq)) < 0) {
        VPI_ERROR(nvi, "setsockopt() rx_ring failed. %s\n", strerror(errno));
        close(nvi->fd);
        aim_free(nvi);
        return -1;
    }

    /* If num blocks change, bail! */
    if(treq.tp_block_nr != NUM_BLOCKS) {
        AIM_DIE("Unhandled: RX_RING block number changed!\n");
    }

    /* Set up rx_ring */
    nvi->rx_ring.buf = mmap(NULL, BLOCK_SIZE*NUM_BLOCKS,
                            PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED,
                            nvi->fd, 0);
    if(nvi->rx_ring.buf == MAP_FAILED) {
        VPI_ERROR(nvi, "mmap() failed.\n");
        close(nvi->fd);
        aim_free(nvi);
        return -1;
    }

    /* Set up rx_ring and frame controls */
    nvi->rx_ring.current_frame = 0;
    for(i = 0; i < NUM_FRAMES; i++) {
        fc = &nvi->rx_ring.frames[i];
        fc->base = nvi->rx_ring.buf + (i*FRAME_SIZE);
    }

    /* Bind */
    VPI_MEMSET(&sockaddr, 0, sizeof(sockaddr));
    sockaddr.sll_family = AF_PACKET;
    sockaddr.sll_protocol = htons(ETH_P_ALL);
    sockaddr.sll_ifindex = nvi->ifindex;
    if(bind(nvi->fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
        VPI_ERROR(nvi, "bind() failed.\n");
        close(nvi->fd);
        aim_free(nvi);
        return -1;
    }

    nvi->interface.send = vpi_mmap_interface_send;
    nvi->interface.recv = vpi_mmap_interface_recv;
    nvi->interface.recv_ready = vpi_mmap_interface_recv_ready;
    nvi->interface.destroy = vpi_mmap_interface_destroy;
    nvi->interface.descriptor = vpi_mmap_interface_descriptor;

    *vi = (vpi_interface_t*)nvi;
    return 0;
}
int
vpi_veth_interface_create(vpi_interface_t** vi, char* args[], int flags,
                       const char* vpi_name_ptr)
{
    struct sockaddr_ll sockaddr;
    struct ifreq ifreq;
    vpi_interface_veth_t* nvi = aim_zmalloc(sizeof(*nvi));
    char** arg = args;

    AIM_REFERENCE(flags);

    if(nvi == NULL) {
        VPI_MERROR("interface allocation failed for %s.",
                   vpi_name_ptr);
        return -1;
    }

    /*
     * Point our log_string to our name so we can use it immediately
     * in log messages.
     */
    nvi->log_string = vpi_name_ptr;


    /*
     * The first argument is the type -- skip for now
     */
    arg++;

    aim_strlcpy(nvi->interface_name, *arg, sizeof(nvi->interface_name));

    /* Create RAW socket */
    if((nvi->fd = socket(PF_PACKET, SOCK_RAW, 0)) < 0) {
        VPI_ERROR(nvi, "socket() failed: %s\n", strerror(errno));
        aim_free(nvi);
        return -1;
    }

    /*
     * Get the interface index for the requested interface, as specified
     * in the current argument.
     */

    VPI_MEMSET(&ifreq, 0, sizeof(ifreq));
    aim_strlcpy(ifreq.ifr_name, nvi->interface_name, IFNAMSIZ);

    if(ioctl(nvi->fd, SIOCGIFINDEX, &ifreq) < 0) {
        VPI_ERROR(nvi, "ioctl() failed: %s", strerror(errno));
        close(nvi->fd);
        aim_free(nvi);
        return -1;
    }
    nvi->ifindex = ifreq.ifr_ifindex;

    VPI_INFO(nvi, "ifndex is %d", nvi->ifindex);

    VPI_MEMSET(&sockaddr, 0, sizeof(sockaddr));
    sockaddr.sll_family=AF_PACKET;
    sockaddr.sll_protocol = htons(ETH_P_ALL);
    sockaddr.sll_ifindex = ifreq.ifr_ifindex;

    if(bind(nvi->fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
        VPI_ERROR(nvi, "bind() failed");
        return -1;
    }

    nvi->interface.send = vpi_veth_interface_send;
    nvi->interface.recv = vpi_veth_interface_recv;
    nvi->interface.recv_ready = vpi_veth_interface_recv_ready;
    nvi->interface.destroy = vpi_veth_interface_destroy;
    nvi->interface.descriptor = vpi_veth_interface_descriptor;

    *vi = (vpi_interface_t*)nvi;
    return 0;
}