Example #1
0
static void
vnic_poll(VLANClientState *ncp, bool enable)
{
	VNICState *vsp = DO_UPCAST(VNICState, vns_nc, ncp);
	vnic_read_poll(vsp, 1);
	vnic_write_poll(vsp, 1);
}
Example #2
0
/*
 * Because this is a single packet API, just read(2). If QEMU's net backend were
 * better we could send more packets at once.
 */
static int
vnic_read_packet(VNICState *vsp, uint8_t *buf, int len)
{
	int ret;

	do {
		ret = read(vsp->vns_fd, buf, len);
	} while (ret == -1 && errno == EINTR);

	if (ret == -1 && errno == EAGAIN) {
		vnic_read_poll(vsp, 1);
		return (0);
	}

	return (ret);
}
Example #3
0
/* outside world -> VM */
static void
vnic_send(void *opaque)
{
	VNICState *vsp = opaque;
	int ret;

	do {
		ret = vnic_read_packet(vsp, vsp->vns_buf,
		    sizeof (vsp->vns_buf));
		if (ret <= 0)
			break;

		ret = qemu_send_packet_async(&vsp->vns_nc, vsp->vns_buf, ret,
		    vnic_send_completed);

		if (ret == 0)
			vnic_read_poll(vsp, 0);

	} while (ret > 0 && qemu_can_send_packet(&vsp->vns_nc));
}
Example #4
0
/* VM -> outside world */
static ssize_t
vnic_receive(VLANClientState *ncp, const uint8_t *buf, size_t size)
{
	VNICState *vsp = DO_UPCAST(VNICState, vns_nc, ncp);

	if (vsp->vns_ds.vnds_enabled && is_dhcp_request(buf, size)) {
		int ret;

		ret = create_dhcp_response(buf, size, &vsp->vns_ds);
		if (!ret)
			return size;

		ret = qemu_send_packet_async(&vsp->vns_nc,
		    vsp->vns_ds.vnds_buf, ret, vnic_send_completed);
		if (ret == 0)
			vnic_read_poll(vsp, 0);

		return size;
	}

	return (vnic_write_packet(vsp, buf, size));
}
Example #5
0
int
net_init_vnic(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan)
{
	int fd, len, vnderr, syserr;
	const char *ifname, *mac;
	uchar_t *macaddr;
	VLANClientState *ncp;
	VNICState *vsp;
	vnd_prop_buf_t vib;

	if ((ifname = qemu_opt_get(opts, "ifname")) == NULL) {
		error_report("missing ifname required for vnic\n");
		return (-1);
	}

	mac = qemu_opt_get(opts, "macaddr");

	if (mac != NULL) {
		macaddr = _link_aton(mac, &len);
		if (macaddr == NULL || len != ETHERADDRL) {
			error_report("invalid macaddr for vnic: %s\n", mac);
			return (-1);
		}
	}

	ncp = qemu_new_net_client(&net_vnic_info, vlan, NULL, "vnic", name);
	vsp = DO_UPCAST(VNICState, vns_nc, ncp);


	vsp->vns_hdl = vnd_open(NULL, ifname, &vnderr, &syserr);
	if (vsp->vns_hdl == NULL) {
		const char *err = vnderr != VND_E_SYS ?
		    vnd_strerror(vnderr) : vnd_strsyserror(syserr);
		error_report("vnic: failed to open interface %s - %s\n",
		    ifname, err);
		return (-1);
	}

	vib.vpb_size = 1024 * 1024 * 4; 	/* 4 MB */
	if (vnd_prop_set(vsp->vns_hdl, VND_PROP_RXBUF, &vib,
	    sizeof (vib)) != 0) {
		const char *err = vnderr != VND_E_SYS ?
		    vnd_strerror(vnderr) : vnd_strsyserror(syserr);
		error_report("failed to change rx buf size: %s\n", err);
		return (-1);
	}

	vib.vpb_size = 1024 * 1024 * 4; 	/* 4 MB */
	if (vnd_prop_set(vsp->vns_hdl, VND_PROP_TXBUF, &vib,
	    sizeof (vib)) != 0) {
		const char *err = vnderr != VND_E_SYS ?
		    vnd_strerror(vnderr) : vnd_strsyserror(syserr);
		error_report("failed to change tx buf size: %s\n", err);
		return (-1);
	}


	fd = vnd_pollfd(vsp->vns_hdl);
	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
		error_report("vnic: failed to set fd on interface %s to "
		    "non-blocking: %s\n", ifname, strerror(errno));
		return (-1);
	}

	vsp->vns_fd = fd;

	snprintf(vsp->vns_nc.info_str, sizeof (vsp->vns_nc.info_str), "ifname=%s",
	    qemu_opt_get(opts, "ifname"));

	if (vnic_dhcp_init(&vsp->vns_ds, opts) == 0)
		return (-1);

	if (vnic_frameio_init(vsp) != 0) {
		error_report("vnic: failed initialize frameio: %s\n",
		    strerror(errno));
		return (-1);
	}

	/* We have to manually intialize the polling for read */
	vnic_read_poll(vsp, 1);

	return (0);
}
Example #6
0
static ssize_t
vnic_receive_iov(VLANClientState *ncp, const struct iovec *iov,
    int iovcnt)
{
	int ret, fvec, i;
	size_t total;
	VNICState *vsp = DO_UPCAST(VNICState, vns_nc, ncp);

	assert(iovcnt <= FRAMEIO_NVECS_MAX);
	/*
	 * Copy the iovcs to our write frameio. Also, check if any of these is
	 * valid dhcp and handle it immediately.
	 */
	for (i = 0, fvec = 0; i < iovcnt; i++, iov++) {

		if (vsp->vns_ds.vnds_enabled &&
		    is_dhcp_request(iov->iov_base, iov->iov_len)) {
			/*
			 * Basically drop the packet because we can't send a
			 * reply at this time. It's unfortunate, but we don't
			 * really have the proper infrastructure to do something
			 * else with this at this time.
			 */
			if (!vnic_can_send(vsp))
				continue;
			ret = create_dhcp_response(iov->iov_base,
			    iov->iov_len, &vsp->vns_ds);
			/* This failed, drop it and continue */
			if (ret == 0)
				continue;

			ret = qemu_send_packet_async(&vsp->vns_nc,
			    vsp->vns_ds.vnds_buf, ret, vnic_send_completed);
			/*
			 * qemu has told us that it can't receive any more data
			 * at this time for the guest (host->guest traffic) so
			 * turn off our read poll until we get that the send has
			 * completed.
			 */
			if (ret == 0)
				vnic_read_poll(vsp, 0);
			continue;
		}
		vsp->vns_wfio->fio_vecs[fvec].fv_buf = iov->iov_base;
		vsp->vns_wfio->fio_vecs[fvec].fv_buflen = iov->iov_len;
		fvec++;
	}

	vsp->vns_wfio->fio_nvecs = fvec;
	do {
		ret = vnd_frameio_write(vsp->vns_hdl, vsp->vns_wfio);
	} while (ret == -1 && errno == EINTR);

	if (ret == -1 && errno == EAGAIN) {
		vnic_write_poll(vsp, 1);
		return (0);
	}

	total = 0;
	for (i = 0; i < vsp->vns_wfio->fio_nvecs; i++) {
		if (vsp->vns_wfio->fio_vecs[i].fv_actlen == 0 &&
		    vsp->vns_wfio->fio_vecs[i].fv_buflen == 0)
			break;

		total += vsp->vns_wfio->fio_vecs[i].fv_actlen;
	}

	return (total);
}
Example #7
0
static void
vnic_send_completed(VLANClientState *nc, ssize_t len)
{
	VNICState *vsp = DO_UPCAST(VNICState, vns_nc, nc);
	vnic_read_poll(vsp, 1);
}
Example #8
0
static ssize_t
vnic_receive_iov(VLANClientState *ncp, const struct iovec *iov,
    int iovcnt)
{
	int ret, i;
	size_t total, altsize;
	VNICState *vsp = DO_UPCAST(VNICState, vns_nc, ncp);

	for (total = 0, i = 0; i < iovcnt; i++) {
		total += (iov + i)->iov_len;
	}

	if (vsp->vns_ds.vnds_enabled &&
	    is_dhcp_requestv(iov, iovcnt)) {
		/*
		 * Basically drop the packet because we can't send a
		 * reply at this time. It's unfortunate, but we don't
		 * really have the proper infrastructure to do something
		 * else with this at this time.
		 */
		if (!vnic_can_send(vsp))
			return (total);
		ret = create_dhcp_responsev(iov, iovcnt, &vsp->vns_ds);
		/* This failed, drop it and continue */
		if (ret == 0)
			return (total);

		ret = qemu_send_packet_async(&vsp->vns_nc,
		    vsp->vns_ds.vnds_buf, ret, vnic_send_completed);
		/*
		 * qemu has told us that it can't receive any more data
		 * at this time for the guest (host->guest traffic) so
		 * turn off our read poll until we get that the send has
		 * completed.
		 */
		if (ret == 0)
			vnic_read_poll(vsp, 0);
		return (total);
	}

	/*
	 * Copy the iovcs to our write frameio. Be on the lookout for someone
	 * giving us more vectors than we support in frameio. In that case,
	 * let's go ahead and just simply concat the rest.
	 */
	for (i = 0; i < MIN(iovcnt, FRAMEIO_NVECS_MAX - 1); i++, iov++) {
		vsp->vns_wfio->fio_vecs[i].fv_buf = iov->iov_base;
		vsp->vns_wfio->fio_vecs[i].fv_buflen = iov->iov_len;
	}

	altsize = 0;
	for (i = MIN(iovcnt, FRAMEIO_NVECS_MAX - 1); i != iovcnt; i++, iov++) {
		/*
		 * The packet is too large. We're goin to silently drop it...
		 */
		if (altsize + iov->iov_len > VNIC_BUFSIZE)
			return (total);

		bcopy(iov->iov_base, vsp->vns_txbuf + altsize, iov->iov_len);
		altsize += iov->iov_len;
	}
	if (altsize != 0) {
		vsp->vns_wfio->fio_vecs[FRAMEIO_NVECS_MAX-1].fv_buf =
		    vsp->vns_txbuf;
		vsp->vns_wfio->fio_vecs[FRAMEIO_NVECS_MAX-1].fv_buflen =
		    altsize;
	}

	vsp->vns_wfio->fio_nvecs = MIN(iovcnt, FRAMEIO_NVECS_MAX);
	vsp->vns_wfio->fio_nvpf = MIN(iovcnt, FRAMEIO_NVECS_MAX);
	do {
		ret = vnd_frameio_write(vsp->vns_hdl, vsp->vns_wfio);
	} while (ret == -1 && errno == EINTR);

	if (ret == -1 && errno == EAGAIN) {
		vnic_write_poll(vsp, 1);
		return (0);
	} else if (ret == -1) {
		abort();
	}

	total = 0;
	for (i = 0; i < vsp->vns_wfio->fio_nvecs; i++) {
		if (vsp->vns_wfio->fio_vecs[i].fv_actlen == 0 &&
		    vsp->vns_wfio->fio_vecs[i].fv_buflen == 0)
			break;

		total += vsp->vns_wfio->fio_vecs[i].fv_actlen;
	}

	return (total);
}