It gets packet without virtio header and adds it if needed. Allows to
inject packets to vlan from outside. To send gracious arp for instance.
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 8e9178d..3c77b99 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -389,7 +389,7 @@ static int iov_fill(struct iovec *iov, int iovcnt, const
void *buf, int count)
}
static int receive_header(VirtIONet *n, struct iovec *iov, int iovcnt,
- const void *buf, size_t size, size_t hdr_len)
+ const void *buf, size_t size, size_t hdr_len, int
raw)
{
struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)iov[0].iov_base;
int offset = 0;
@@ -399,7 +399,11 @@ static int receive_header(VirtIONet *n, struct iovec *iov,
int iovcnt,
#ifdef TAP_VNET_HDR
if (tap_has_vnet_hdr(n->vc->vlan->first_client)) {
- memcpy(hdr, buf, sizeof(*hdr));
+ if (!raw) {
+ memcpy(hdr, buf, sizeof(*hdr));
+ } else {
+ memset(hdr, 0, sizeof(*hdr));
+ }
offset = sizeof(*hdr);
work_around_broken_dhclient(hdr, buf + offset, size - offset);
}
@@ -452,7 +456,7 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf,
int size)
return 0;
}
-static void virtio_net_receive(void *opaque, const uint8_t *buf, int size)
+static void virtio_net_receive2(void *opaque, const uint8_t *buf, int size,
int raw)
{
VirtIONet *n = opaque;
struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL;
@@ -502,7 +506,7 @@ static void virtio_net_receive(void *opaque, const uint8_t
*buf, int size)
mhdr = (struct virtio_net_hdr_mrg_rxbuf *)sg[0].iov_base;
offset += receive_header(n, sg, elem.in_num,
- buf + offset, size - offset, hdr_len);
+ buf + offset, size - offset, hdr_len,
raw);
total += hdr_len;
}
@@ -524,6 +528,16 @@ static void virtio_net_receive(void *opaque, const uint8_t
*buf, int size)
virtio_notify(&n->vdev, n->rx_vq);
}
+static void virtio_net_receive(void *opaque, const uint8_t *buf, int size)
+{
+ virtio_net_receive2(opaque, buf, size, 0);
+}
+
+static void virtio_net_receive_raw(void *opaque, const uint8_t *buf, int size)
+{
+ virtio_net_receive2(opaque, buf, size, 1);
+}
+
/* TX */
static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
{
@@ -721,6 +735,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev)
virtio_net_can_receive,
virtio_net_cleanup, n);
n->vc->link_status_changed = virtio_net_set_link_status;
+ n->vc->fd_read_raw = virtio_net_receive_raw;
qemu_format_nic_info_str(n->vc, n->mac);
diff --git a/net.c b/net.c
index 3dfc728..01e31db 100644
--- a/net.c
+++ b/net.c
@@ -456,6 +456,31 @@ int qemu_send_packet(VLANClientState *vc, const uint8_t
*buf, int size)
return ret;
}
+void qemu_send_packet_raw(VLANClientState *sender, const uint8_t *buf, int
size)
+{
+ VLANState *vlan = sender->vlan;
+ VLANClientState *vc;
+
+ if (sender->link_down)
+ return;
+
+#ifdef DEBUG_NET
+ printf("vlan %d send raw:\n", vlan->id);
+ hex_dump(stdout, buf, size);
+#endif
+ for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
+ if (vc == sender || vc->link_down) {
+ continue;
+ }
+ if (vc->fd_read_raw) {
+ vc->fd_read_raw(vc->opaque, buf, size);
+ } else {
+ vc->fd_read(vc->opaque, buf, size);
+ }
+ }
+ return;
+}
+
static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov,
int iovcnt)
{
@@ -823,6 +848,29 @@ static void tap_receive(void *opaque, const uint8_t *buf,
int size)
tap_receive_iov(opaque, iov, i);
}
+static void tap_receive_raw(void *opaque, const uint8_t *buf, int size)
+{
+ struct iovec iov[2];
+ int i = 0;
+
+#ifdef IFF_VNET_HDR
+ TAPState *s = opaque;
+ struct virtio_net_hdr hdr = { 0, };
+
+ if (s->has_vnet_hdr && s->using_vnet_hdr) {
+ iov[i].iov_base = &hdr;
+ iov[i].iov_len = sizeof(hdr);
+ i++;
+ }
+#endif
+
+ iov[i].iov_base = (char *) buf;
+ iov[i].iov_len = size;
+ i++;
+
+ tap_receive_iov(opaque, iov, i);
+}
+
static int tap_can_send(void *opaque)
{
TAPState *s = opaque;
@@ -992,6 +1040,7 @@ static TAPState *net_tap_fd_init(VLANState *vlan,
s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive,
NULL, tap_cleanup, s);
s->vc->fd_readv = tap_receive_iov;
+ s->vc->fd_read_raw = tap_receive_raw;
#ifdef TUNSETOFFLOAD
s->vc->set_offload = tap_set_offload;
tap_set_offload(s->vc, 0, 0, 0, 0);
diff --git a/net.h b/net.h
index 931133b..3d0b6f2 100644
--- a/net.h
+++ b/net.h
@@ -15,6 +15,7 @@ typedef void (SetOffload)(VLANClientState *, int, int, int,
int);
struct VLANClientState {
IOReadHandler *fd_read;
+ IOReadHandler *fd_read_raw;
IOReadvHandler *fd_readv;
/* Packets may still be sent if this returns zero. It's used to
rate-limit the slirp code. */
@@ -63,6 +64,7 @@ int qemu_can_send_packet(VLANClientState *vc);
ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov,
int iovcnt);
int qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size);
+void qemu_send_packet_raw(VLANClientState *vc, const uint8_t *buf, int size);
void qemu_format_nic_info_str(VLANClientState *vc, uint8_t macaddr[6]);
void qemu_check_nic_model(NICInfo *nd, const char *model);
void qemu_check_nic_model_list(NICInfo *nd, const char * const *models,
--
Gleb.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html