mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging
# gpg: Signature made Thu 18 Jun 2020 14:16:22 BST # gpg: using RSA key EF04965B398D6211 # gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" [marginal] # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 215D 46F4 8246 689E C77F 3562 EF04 965B 398D 6211 * remotes/jasowang/tags/net-pull-request: (33 commits) net: Drop the NetLegacy structure, always use Netdev instead net: Drop the legacy "name" parameter from the -net option hw/net/e1000e: Do not abort() on invalid PSRCTL register value colo-compare: Fix memory leak in packet_enqueue() net/colo-compare.c: Correct ordering in complete and finalize net/colo-compare.c: Check that colo-compare is active net/colo-compare.c: Only hexdump packets if tracing is enabled net/colo-compare.c: Fix deadlock in compare_chr_send chardev/char.c: Use qemu_co_sleep_ns if in coroutine net/colo-compare.c: Create event_bh with the right AioContext net: use peer when purging queue in qemu_flush_or_purge_queue_packets() net: cadence_gem: Fix RX address filtering net: cadence_gem: TX_LAST bit should be set by guest net: cadence_gem: Update the reset value for interrupt mask register net: cadnece_gem: Update irq_read_clear field of designcfg_debug1 reg net: cadence_gem: Add support for jumbo frames net: cadence_gem: Fix up code style net: cadence_gem: Move tx/rx packet buffert to CadenceGEMState net: cadence_gem: Set ISR according to queue in use net: cadence_gem: Define access permission for interrupt registers ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+6
-1
@@ -38,6 +38,7 @@
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/id.h"
|
||||
#include "qemu/coroutine.h"
|
||||
|
||||
#include "chardev/char-mux.h"
|
||||
|
||||
@@ -119,7 +120,11 @@ static int qemu_chr_write_buffer(Chardev *s,
|
||||
retry:
|
||||
res = cc->chr_write(s, buf + *offset, len - *offset);
|
||||
if (res < 0 && errno == EAGAIN && write_all) {
|
||||
g_usleep(100);
|
||||
if (qemu_in_coroutine()) {
|
||||
qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
|
||||
} else {
|
||||
g_usleep(100);
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,12 +47,6 @@ The 'file' driver for drives is no longer appropriate for character or host
|
||||
devices and will only accept regular files (S_IFREG). The correct driver
|
||||
for these file types is 'host_cdrom' or 'host_device' as appropriate.
|
||||
|
||||
``-net ...,name=``\ *name* (since 3.1)
|
||||
''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The ``name`` parameter of the ``-net`` option is a synonym
|
||||
for the ``id`` parameter, which should now be used instead.
|
||||
|
||||
``-smp`` (invalid topologies) (since 3.1)
|
||||
'''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
@@ -441,6 +435,15 @@ What follows is a record of recently removed, formerly deprecated
|
||||
features that serves as a record for users who have encountered
|
||||
trouble after a recent upgrade.
|
||||
|
||||
System emulator command line arguments
|
||||
--------------------------------------
|
||||
|
||||
``-net ...,name=``\ *name* (removed in 5.1)
|
||||
'''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The ``name`` parameter of the ``-net`` option was a synonym
|
||||
for the ``id`` parameter, which should now be used instead.
|
||||
|
||||
QEMU Machine Protocol (QMP) commands
|
||||
------------------------------------
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ obj-$(CONFIG_MILKYMIST) += milkymist-minimac2.o
|
||||
obj-$(CONFIG_PSERIES) += spapr_llan.o
|
||||
obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
|
||||
|
||||
common-obj-$(CONFIG_VIRTIO_NET) += net_rx_pkt.o
|
||||
obj-$(CONFIG_VIRTIO_NET) += virtio-net.o
|
||||
common-obj-$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET)) += vhost_net.o
|
||||
common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET))) += vhost_net-stub.o
|
||||
|
||||
+256
-196
File diff suppressed because it is too large
Load Diff
@@ -34,9 +34,9 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "net/net.h"
|
||||
#include "net/tap.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/pci/msi.h"
|
||||
#include "hw/pci/msix.h"
|
||||
#include "sysemu/runstate.h"
|
||||
@@ -2816,11 +2816,15 @@ e1000e_set_psrctl(E1000ECore *core, int index, uint32_t val)
|
||||
if (core->mac[RCTL] & E1000_RCTL_DTYP_MASK) {
|
||||
|
||||
if ((val & E1000_PSRCTL_BSIZE0_MASK) == 0) {
|
||||
hw_error("e1000e: PSRCTL.BSIZE0 cannot be zero");
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"e1000e: PSRCTL.BSIZE0 cannot be zero");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((val & E1000_PSRCTL_BSIZE1_MASK) == 0) {
|
||||
hw_error("e1000e: PSRCTL.BSIZE1 cannot be zero");
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"e1000e: PSRCTL.BSIZE1 cannot be zero");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -381,6 +381,9 @@ virtio_net_announce_notify(void) ""
|
||||
virtio_net_announce_timer(int round) "%d"
|
||||
virtio_net_handle_announce(int round) "%d"
|
||||
virtio_net_post_load_device(void)
|
||||
virtio_net_rss_disable(void)
|
||||
virtio_net_rss_error(const char *msg, uint32_t value) "%s, value 0x%08x"
|
||||
virtio_net_rss_enable(uint32_t p1, uint16_t p2, uint8_t p3) "hashes 0x%x, table of %d, key of %d"
|
||||
|
||||
# tulip.c
|
||||
tulip_reg_write(uint64_t addr, const char *name, int size, uint64_t val) "addr 0x%02"PRIx64" (%s) size %d value 0x%08"PRIx64
|
||||
|
||||
+6
-6
@@ -171,9 +171,6 @@ static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc)
|
||||
len = s->rx_frame_len;
|
||||
}
|
||||
|
||||
if (s->rx_frame_len + len > sizeof(s->rx_frame)) {
|
||||
return;
|
||||
}
|
||||
pci_dma_write(&s->dev, desc->buf_addr1, s->rx_frame +
|
||||
(s->rx_frame_size - s->rx_frame_len), len);
|
||||
s->rx_frame_len -= len;
|
||||
@@ -186,9 +183,6 @@ static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc)
|
||||
len = s->rx_frame_len;
|
||||
}
|
||||
|
||||
if (s->rx_frame_len + len > sizeof(s->rx_frame)) {
|
||||
return;
|
||||
}
|
||||
pci_dma_write(&s->dev, desc->buf_addr2, s->rx_frame +
|
||||
(s->rx_frame_size - s->rx_frame_len), len);
|
||||
s->rx_frame_len -= len;
|
||||
@@ -584,6 +578,9 @@ static int tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc)
|
||||
int len2 = (desc->control >> TDES1_BUF2_SIZE_SHIFT) & TDES1_BUF2_SIZE_MASK;
|
||||
|
||||
if (s->tx_frame_len + len1 > sizeof(s->tx_frame)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: descriptor overflow (ofs: %u, len:%d, size:%zu)\n",
|
||||
__func__, s->tx_frame_len, len1, sizeof(s->tx_frame));
|
||||
return -1;
|
||||
}
|
||||
if (len1) {
|
||||
@@ -593,6 +590,9 @@ static int tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc)
|
||||
}
|
||||
|
||||
if (s->tx_frame_len + len2 > sizeof(s->tx_frame)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: descriptor overflow (ofs: %u, len:%d, size:%zu)\n",
|
||||
__func__, s->tx_frame_len, len2, sizeof(s->tx_frame));
|
||||
return -1;
|
||||
}
|
||||
if (len2) {
|
||||
|
||||
+1
-1
@@ -211,7 +211,7 @@
|
||||
#define RDES0_RF BIT(11)
|
||||
#define RDES0_DT_SHIFT 12
|
||||
#define RDES0_DT_MASK 3
|
||||
#define RDES0_LE BIT(14)
|
||||
#define RDES0_DE BIT(14)
|
||||
#define RDES0_ES BIT(15)
|
||||
#define RDES0_FL_SHIFT 16
|
||||
#define RDES0_FL_MASK 0x3fff
|
||||
|
||||
+349
-40
File diff suppressed because it is too large
Load Diff
@@ -40,6 +40,9 @@
|
||||
#define MAX_TYPE1_SCREENERS 16
|
||||
#define MAX_TYPE2_SCREENERS 16
|
||||
|
||||
#define MAX_JUMBO_FRAME_SIZE_MASK 0x3FFF
|
||||
#define MAX_FRAME_SIZE MAX_JUMBO_FRAME_SIZE_MASK
|
||||
|
||||
typedef struct CadenceGEMState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
@@ -57,6 +60,7 @@ typedef struct CadenceGEMState {
|
||||
uint8_t num_type1_screeners;
|
||||
uint8_t num_type2_screeners;
|
||||
uint32_t revision;
|
||||
uint16_t jumbo_max_len;
|
||||
|
||||
/* GEM registers backing store */
|
||||
uint32_t regs[CADENCE_GEM_MAXREG];
|
||||
@@ -80,6 +84,8 @@ typedef struct CadenceGEMState {
|
||||
|
||||
uint8_t can_rx_state; /* Debug only */
|
||||
|
||||
uint8_t tx_packet[MAX_FRAME_SIZE];
|
||||
uint8_t rx_packet[MAX_FRAME_SIZE];
|
||||
uint32_t rx_desc[MAX_PRIORITY_QUEUES][DESC_MAX_NUM_WORDS];
|
||||
|
||||
bool sar_active[4];
|
||||
|
||||
@@ -126,6 +126,20 @@ typedef struct VirtioNetRscChain {
|
||||
/* Maximum packet size we can receive from tap device: header + 64k */
|
||||
#define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 * KiB))
|
||||
|
||||
#define VIRTIO_NET_RSS_MAX_KEY_SIZE 40
|
||||
#define VIRTIO_NET_RSS_MAX_TABLE_LEN 128
|
||||
|
||||
typedef struct VirtioNetRssData {
|
||||
bool enabled;
|
||||
bool redirect;
|
||||
bool populate_hash;
|
||||
uint32_t hash_types;
|
||||
uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
|
||||
uint16_t indirections_len;
|
||||
uint16_t *indirections_table;
|
||||
uint16_t default_queue;
|
||||
} VirtioNetRssData;
|
||||
|
||||
typedef struct VirtIONetQueue {
|
||||
VirtQueue *rx_vq;
|
||||
VirtQueue *tx_vq;
|
||||
@@ -199,6 +213,8 @@ struct VirtIONet {
|
||||
bool failover;
|
||||
DeviceListener primary_listener;
|
||||
Notifier migration_state;
|
||||
VirtioNetRssData rss_data;
|
||||
struct NetRxPkt *rx_pkt;
|
||||
};
|
||||
|
||||
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
|
||||
|
||||
@@ -432,6 +432,16 @@ extern const VMStateInfo vmstate_info_qlist;
|
||||
.offset = vmstate_offset_pointer(_state, _field, _type), \
|
||||
}
|
||||
|
||||
#define VMSTATE_VARRAY_UINT16_ALLOC(_field, _state, _field_num, _version, _info, _type) {\
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = (_version), \
|
||||
.num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
|
||||
.info = &(_info), \
|
||||
.size = sizeof(_type), \
|
||||
.flags = VMS_VARRAY_UINT16 | VMS_POINTER | VMS_ALLOC, \
|
||||
.offset = vmstate_offset_pointer(_state, _field, _type), \
|
||||
}
|
||||
|
||||
#define VMSTATE_VARRAY_UINT16_UNSAFE(_field, _state, _field_num, _version, _info, _type) {\
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = (_version), \
|
||||
|
||||
+213
-76
@@ -32,6 +32,9 @@
|
||||
#include "migration/migration.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "block/aio-wait.h"
|
||||
#include "qemu/coroutine.h"
|
||||
|
||||
#define TYPE_COLO_COMPARE "colo-compare"
|
||||
#define COLO_COMPARE(obj) \
|
||||
OBJECT_CHECK(CompareState, (obj), TYPE_COLO_COMPARE)
|
||||
@@ -51,6 +54,8 @@ static NotifierList colo_compare_notifiers =
|
||||
#define REGULAR_PACKET_CHECK_MS 3000
|
||||
#define DEFAULT_TIME_OUT_MS 3000
|
||||
|
||||
static QemuMutex colo_compare_mutex;
|
||||
static bool colo_compare_active;
|
||||
static QemuMutex event_mtx;
|
||||
static QemuCond event_complete_cond;
|
||||
static int event_unhandled_count;
|
||||
@@ -77,6 +82,23 @@ static int event_unhandled_count;
|
||||
* |packet | |packet + |packet | |packet +
|
||||
* +--------+ +--------+ +--------+ +--------+
|
||||
*/
|
||||
|
||||
typedef struct SendCo {
|
||||
Coroutine *co;
|
||||
struct CompareState *s;
|
||||
CharBackend *chr;
|
||||
GQueue send_list;
|
||||
bool notify_remote_frame;
|
||||
bool done;
|
||||
int ret;
|
||||
} SendCo;
|
||||
|
||||
typedef struct SendEntry {
|
||||
uint32_t size;
|
||||
uint32_t vnet_hdr_len;
|
||||
uint8_t *buf;
|
||||
} SendEntry;
|
||||
|
||||
typedef struct CompareState {
|
||||
Object parent;
|
||||
|
||||
@@ -91,6 +113,8 @@ typedef struct CompareState {
|
||||
SocketReadState pri_rs;
|
||||
SocketReadState sec_rs;
|
||||
SocketReadState notify_rs;
|
||||
SendCo out_sendco;
|
||||
SendCo notify_sendco;
|
||||
bool vnet_hdr;
|
||||
uint32_t compare_timeout;
|
||||
uint32_t expired_scan_cycle;
|
||||
@@ -122,12 +146,17 @@ enum {
|
||||
SECONDARY_IN,
|
||||
};
|
||||
|
||||
static const char *colo_mode[] = {
|
||||
[PRIMARY_IN] = "primary",
|
||||
[SECONDARY_IN] = "secondary",
|
||||
};
|
||||
|
||||
static int compare_chr_send(CompareState *s,
|
||||
const uint8_t *buf,
|
||||
uint8_t *buf,
|
||||
uint32_t size,
|
||||
uint32_t vnet_hdr_len,
|
||||
bool notify_remote_frame);
|
||||
bool notify_remote_frame,
|
||||
bool zero_copy);
|
||||
|
||||
static bool packet_matches_str(const char *str,
|
||||
const uint8_t *buf,
|
||||
@@ -145,7 +174,7 @@ static void notify_remote_frame(CompareState *s)
|
||||
char msg[] = "DO_CHECKPOINT";
|
||||
int ret = 0;
|
||||
|
||||
ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true);
|
||||
ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true, false);
|
||||
if (ret < 0) {
|
||||
error_report("Notify Xen COLO-frame failed");
|
||||
}
|
||||
@@ -217,6 +246,7 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
|
||||
ConnectionKey key;
|
||||
Packet *pkt = NULL;
|
||||
Connection *conn;
|
||||
int ret;
|
||||
|
||||
if (mode == PRIMARY_IN) {
|
||||
pkt = packet_new(s->pri_rs.buf,
|
||||
@@ -245,16 +275,18 @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
|
||||
}
|
||||
|
||||
if (mode == PRIMARY_IN) {
|
||||
if (!colo_insert_packet(&conn->primary_list, pkt, &conn->pack)) {
|
||||
error_report("colo compare primary queue size too big,"
|
||||
"drop packet");
|
||||
}
|
||||
ret = colo_insert_packet(&conn->primary_list, pkt, &conn->pack);
|
||||
} else {
|
||||
if (!colo_insert_packet(&conn->secondary_list, pkt, &conn->sack)) {
|
||||
error_report("colo compare secondary queue size too big,"
|
||||
"drop packet");
|
||||
}
|
||||
ret = colo_insert_packet(&conn->secondary_list, pkt, &conn->sack);
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
trace_colo_compare_drop_packet(colo_mode[mode],
|
||||
"queue size too big, drop packet");
|
||||
packet_destroy(pkt, NULL);
|
||||
pkt = NULL;
|
||||
}
|
||||
|
||||
*con = conn;
|
||||
|
||||
return 0;
|
||||
@@ -272,12 +304,13 @@ static void colo_release_primary_pkt(CompareState *s, Packet *pkt)
|
||||
pkt->data,
|
||||
pkt->size,
|
||||
pkt->vnet_hdr_len,
|
||||
false);
|
||||
false,
|
||||
true);
|
||||
if (ret < 0) {
|
||||
error_report("colo send primary packet failed");
|
||||
}
|
||||
trace_colo_compare_main("packet same and release packet");
|
||||
packet_destroy(pkt, NULL);
|
||||
packet_destroy_partial(pkt, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -459,10 +492,12 @@ sec:
|
||||
g_queue_push_head(&conn->primary_list, ppkt);
|
||||
g_queue_push_head(&conn->secondary_list, spkt);
|
||||
|
||||
qemu_hexdump((char *)ppkt->data, stderr,
|
||||
"colo-compare ppkt", ppkt->size);
|
||||
qemu_hexdump((char *)spkt->data, stderr,
|
||||
"colo-compare spkt", spkt->size);
|
||||
if (trace_event_get_state_backends(TRACE_COLO_COMPARE_MISCOMPARE)) {
|
||||
qemu_hexdump((char *)ppkt->data, stderr,
|
||||
"colo-compare ppkt", ppkt->size);
|
||||
qemu_hexdump((char *)spkt->data, stderr,
|
||||
"colo-compare spkt", spkt->size);
|
||||
}
|
||||
|
||||
colo_compare_inconsistency_notify(s);
|
||||
}
|
||||
@@ -699,65 +734,115 @@ static void colo_compare_connection(void *opaque, void *user_data)
|
||||
}
|
||||
}
|
||||
|
||||
static void coroutine_fn _compare_chr_send(void *opaque)
|
||||
{
|
||||
SendCo *sendco = opaque;
|
||||
CompareState *s = sendco->s;
|
||||
int ret = 0;
|
||||
|
||||
while (!g_queue_is_empty(&sendco->send_list)) {
|
||||
SendEntry *entry = g_queue_pop_tail(&sendco->send_list);
|
||||
uint32_t len = htonl(entry->size);
|
||||
|
||||
ret = qemu_chr_fe_write_all(sendco->chr, (uint8_t *)&len, sizeof(len));
|
||||
|
||||
if (ret != sizeof(len)) {
|
||||
g_free(entry->buf);
|
||||
g_slice_free(SendEntry, entry);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!sendco->notify_remote_frame && s->vnet_hdr) {
|
||||
/*
|
||||
* We send vnet header len make other module(like filter-redirector)
|
||||
* know how to parse net packet correctly.
|
||||
*/
|
||||
len = htonl(entry->vnet_hdr_len);
|
||||
|
||||
ret = qemu_chr_fe_write_all(sendco->chr,
|
||||
(uint8_t *)&len,
|
||||
sizeof(len));
|
||||
|
||||
if (ret != sizeof(len)) {
|
||||
g_free(entry->buf);
|
||||
g_slice_free(SendEntry, entry);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ret = qemu_chr_fe_write_all(sendco->chr,
|
||||
(uint8_t *)entry->buf,
|
||||
entry->size);
|
||||
|
||||
if (ret != entry->size) {
|
||||
g_free(entry->buf);
|
||||
g_slice_free(SendEntry, entry);
|
||||
goto err;
|
||||
}
|
||||
|
||||
g_free(entry->buf);
|
||||
g_slice_free(SendEntry, entry);
|
||||
}
|
||||
|
||||
sendco->ret = 0;
|
||||
goto out;
|
||||
|
||||
err:
|
||||
while (!g_queue_is_empty(&sendco->send_list)) {
|
||||
SendEntry *entry = g_queue_pop_tail(&sendco->send_list);
|
||||
g_free(entry->buf);
|
||||
g_slice_free(SendEntry, entry);
|
||||
}
|
||||
sendco->ret = ret < 0 ? ret : -EIO;
|
||||
out:
|
||||
sendco->co = NULL;
|
||||
sendco->done = true;
|
||||
aio_wait_kick();
|
||||
}
|
||||
|
||||
static int compare_chr_send(CompareState *s,
|
||||
const uint8_t *buf,
|
||||
uint8_t *buf,
|
||||
uint32_t size,
|
||||
uint32_t vnet_hdr_len,
|
||||
bool notify_remote_frame)
|
||||
bool notify_remote_frame,
|
||||
bool zero_copy)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t len = htonl(size);
|
||||
SendCo *sendco;
|
||||
SendEntry *entry;
|
||||
|
||||
if (notify_remote_frame) {
|
||||
sendco = &s->notify_sendco;
|
||||
} else {
|
||||
sendco = &s->out_sendco;
|
||||
}
|
||||
|
||||
if (!size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (notify_remote_frame) {
|
||||
ret = qemu_chr_fe_write_all(&s->chr_notify_dev,
|
||||
(uint8_t *)&len,
|
||||
sizeof(len));
|
||||
entry = g_slice_new(SendEntry);
|
||||
entry->size = size;
|
||||
entry->vnet_hdr_len = vnet_hdr_len;
|
||||
if (zero_copy) {
|
||||
entry->buf = buf;
|
||||
} else {
|
||||
ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
|
||||
entry->buf = g_malloc(size);
|
||||
memcpy(entry->buf, buf, size);
|
||||
}
|
||||
g_queue_push_head(&sendco->send_list, entry);
|
||||
|
||||
if (ret != sizeof(len)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (s->vnet_hdr) {
|
||||
/*
|
||||
* We send vnet header len make other module(like filter-redirector)
|
||||
* know how to parse net packet correctly.
|
||||
*/
|
||||
len = htonl(vnet_hdr_len);
|
||||
|
||||
if (!notify_remote_frame) {
|
||||
ret = qemu_chr_fe_write_all(&s->chr_out,
|
||||
(uint8_t *)&len,
|
||||
sizeof(len));
|
||||
}
|
||||
|
||||
if (ret != sizeof(len)) {
|
||||
goto err;
|
||||
if (sendco->done) {
|
||||
sendco->co = qemu_coroutine_create(_compare_chr_send, sendco);
|
||||
sendco->done = false;
|
||||
qemu_coroutine_enter(sendco->co);
|
||||
if (sendco->done) {
|
||||
/* report early errors */
|
||||
return sendco->ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (notify_remote_frame) {
|
||||
ret = qemu_chr_fe_write_all(&s->chr_notify_dev,
|
||||
(uint8_t *)buf,
|
||||
size);
|
||||
} else {
|
||||
ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size);
|
||||
}
|
||||
|
||||
if (ret != size) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* assume success */
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return ret < 0 ? ret : -EIO;
|
||||
}
|
||||
|
||||
static int compare_chr_can_read(void *opaque)
|
||||
@@ -830,6 +915,12 @@ static void check_old_packet_regular(void *opaque)
|
||||
void colo_notify_compares_event(void *opaque, int event, Error **errp)
|
||||
{
|
||||
CompareState *s;
|
||||
qemu_mutex_lock(&colo_compare_mutex);
|
||||
|
||||
if (!colo_compare_active) {
|
||||
qemu_mutex_unlock(&colo_compare_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_mutex_lock(&event_mtx);
|
||||
QTAILQ_FOREACH(s, &net_compares, next) {
|
||||
@@ -843,6 +934,7 @@ void colo_notify_compares_event(void *opaque, int event, Error **errp)
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&event_mtx);
|
||||
qemu_mutex_unlock(&colo_compare_mutex);
|
||||
}
|
||||
|
||||
static void colo_compare_timer_init(CompareState *s)
|
||||
@@ -890,6 +982,7 @@ static void colo_compare_handle_event(void *opaque)
|
||||
|
||||
static void colo_compare_iothread(CompareState *s)
|
||||
{
|
||||
AioContext *ctx = iothread_get_aio_context(s->iothread);
|
||||
object_ref(OBJECT(s->iothread));
|
||||
s->worker_context = iothread_get_g_main_context(s->iothread);
|
||||
|
||||
@@ -906,7 +999,7 @@ static void colo_compare_iothread(CompareState *s)
|
||||
}
|
||||
|
||||
colo_compare_timer_init(s);
|
||||
s->event_bh = qemu_bh_new(colo_compare_handle_event, s);
|
||||
s->event_bh = aio_bh_new(ctx, colo_compare_handle_event, s);
|
||||
}
|
||||
|
||||
static char *compare_get_pri_indev(Object *obj, Error **errp)
|
||||
@@ -1062,6 +1155,7 @@ static void compare_pri_rs_finalize(SocketReadState *pri_rs)
|
||||
pri_rs->buf,
|
||||
pri_rs->packet_len,
|
||||
pri_rs->vnet_hdr_len,
|
||||
false,
|
||||
false);
|
||||
} else {
|
||||
/* compare packet in the specified connection */
|
||||
@@ -1092,7 +1186,7 @@ static void compare_notify_rs_finalize(SocketReadState *notify_rs)
|
||||
if (packet_matches_str("COLO_USERSPACE_PROXY_INIT",
|
||||
notify_rs->buf,
|
||||
notify_rs->packet_len)) {
|
||||
ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true);
|
||||
ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true, false);
|
||||
if (ret < 0) {
|
||||
error_report("Notify Xen COLO-frame INIT failed");
|
||||
}
|
||||
@@ -1196,19 +1290,38 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
|
||||
s->vnet_hdr);
|
||||
}
|
||||
|
||||
QTAILQ_INSERT_TAIL(&net_compares, s, next);
|
||||
s->out_sendco.s = s;
|
||||
s->out_sendco.chr = &s->chr_out;
|
||||
s->out_sendco.notify_remote_frame = false;
|
||||
s->out_sendco.done = true;
|
||||
g_queue_init(&s->out_sendco.send_list);
|
||||
|
||||
if (s->notify_dev) {
|
||||
s->notify_sendco.s = s;
|
||||
s->notify_sendco.chr = &s->chr_notify_dev;
|
||||
s->notify_sendco.notify_remote_frame = true;
|
||||
s->notify_sendco.done = true;
|
||||
g_queue_init(&s->notify_sendco.send_list);
|
||||
}
|
||||
|
||||
g_queue_init(&s->conn_list);
|
||||
|
||||
qemu_mutex_init(&event_mtx);
|
||||
qemu_cond_init(&event_complete_cond);
|
||||
|
||||
s->connection_track_table = g_hash_table_new_full(connection_key_hash,
|
||||
connection_key_equal,
|
||||
g_free,
|
||||
connection_destroy);
|
||||
|
||||
colo_compare_iothread(s);
|
||||
|
||||
qemu_mutex_lock(&colo_compare_mutex);
|
||||
if (!colo_compare_active) {
|
||||
qemu_mutex_init(&event_mtx);
|
||||
qemu_cond_init(&event_complete_cond);
|
||||
colo_compare_active = true;
|
||||
}
|
||||
QTAILQ_INSERT_TAIL(&net_compares, s, next);
|
||||
qemu_mutex_unlock(&colo_compare_mutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1224,8 +1337,9 @@ static void colo_flush_packets(void *opaque, void *user_data)
|
||||
pkt->data,
|
||||
pkt->size,
|
||||
pkt->vnet_hdr_len,
|
||||
false);
|
||||
packet_destroy(pkt, NULL);
|
||||
false,
|
||||
true);
|
||||
packet_destroy_partial(pkt, NULL);
|
||||
}
|
||||
while (!g_queue_is_empty(&conn->secondary_list)) {
|
||||
pkt = g_queue_pop_head(&conn->secondary_list);
|
||||
@@ -1276,6 +1390,20 @@ static void colo_compare_finalize(Object *obj)
|
||||
CompareState *s = COLO_COMPARE(obj);
|
||||
CompareState *tmp = NULL;
|
||||
|
||||
qemu_mutex_lock(&colo_compare_mutex);
|
||||
QTAILQ_FOREACH(tmp, &net_compares, next) {
|
||||
if (tmp == s) {
|
||||
QTAILQ_REMOVE(&net_compares, s, next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (QTAILQ_EMPTY(&net_compares)) {
|
||||
colo_compare_active = false;
|
||||
qemu_mutex_destroy(&event_mtx);
|
||||
qemu_cond_destroy(&event_complete_cond);
|
||||
}
|
||||
qemu_mutex_unlock(&colo_compare_mutex);
|
||||
|
||||
qemu_chr_fe_deinit(&s->chr_pri_in, false);
|
||||
qemu_chr_fe_deinit(&s->chr_sec_in, false);
|
||||
qemu_chr_fe_deinit(&s->chr_out, false);
|
||||
@@ -1289,17 +1417,23 @@ static void colo_compare_finalize(Object *obj)
|
||||
|
||||
qemu_bh_delete(s->event_bh);
|
||||
|
||||
QTAILQ_FOREACH(tmp, &net_compares, next) {
|
||||
if (tmp == s) {
|
||||
QTAILQ_REMOVE(&net_compares, s, next);
|
||||
break;
|
||||
}
|
||||
AioContext *ctx = iothread_get_aio_context(s->iothread);
|
||||
aio_context_acquire(ctx);
|
||||
AIO_WAIT_WHILE(ctx, !s->out_sendco.done);
|
||||
if (s->notify_dev) {
|
||||
AIO_WAIT_WHILE(ctx, !s->notify_sendco.done);
|
||||
}
|
||||
aio_context_release(ctx);
|
||||
|
||||
/* Release all unhandled packets after compare thead exited */
|
||||
g_queue_foreach(&s->conn_list, colo_flush_packets, s);
|
||||
AIO_WAIT_WHILE(NULL, !s->out_sendco.done);
|
||||
|
||||
g_queue_clear(&s->conn_list);
|
||||
g_queue_clear(&s->out_sendco.send_list);
|
||||
if (s->notify_dev) {
|
||||
g_queue_clear(&s->notify_sendco.send_list);
|
||||
}
|
||||
|
||||
if (s->connection_track_table) {
|
||||
g_hash_table_destroy(s->connection_track_table);
|
||||
@@ -1309,15 +1443,18 @@ static void colo_compare_finalize(Object *obj)
|
||||
object_unref(OBJECT(s->iothread));
|
||||
}
|
||||
|
||||
qemu_mutex_destroy(&event_mtx);
|
||||
qemu_cond_destroy(&event_complete_cond);
|
||||
|
||||
g_free(s->pri_indev);
|
||||
g_free(s->sec_indev);
|
||||
g_free(s->outdev);
|
||||
g_free(s->notify_dev);
|
||||
}
|
||||
|
||||
static void __attribute__((__constructor__)) colo_compare_init_globals(void)
|
||||
{
|
||||
colo_compare_active = false;
|
||||
qemu_mutex_init(&colo_compare_mutex);
|
||||
}
|
||||
|
||||
static const TypeInfo colo_compare_info = {
|
||||
.name = TYPE_COLO_COMPARE,
|
||||
.parent = TYPE_OBJECT,
|
||||
|
||||
@@ -185,6 +185,13 @@ void packet_destroy(void *opaque, void *user_data)
|
||||
g_slice_free(Packet, pkt);
|
||||
}
|
||||
|
||||
void packet_destroy_partial(void *opaque, void *user_data)
|
||||
{
|
||||
Packet *pkt = opaque;
|
||||
|
||||
g_slice_free(Packet, pkt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear hashtable, stop this hash growing really huge
|
||||
*/
|
||||
|
||||
@@ -102,5 +102,6 @@ bool connection_has_tracked(GHashTable *connection_track_table,
|
||||
void connection_hashtable_reset(GHashTable *connection_track_table);
|
||||
Packet *packet_new(const void *data, int size, int vnet_hdr_len);
|
||||
void packet_destroy(void *opaque, void *user_data);
|
||||
void packet_destroy_partial(void *opaque, void *user_data);
|
||||
|
||||
#endif /* NET_COLO_H */
|
||||
|
||||
@@ -610,7 +610,7 @@ void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge)
|
||||
qemu_notify_event();
|
||||
} else if (purge) {
|
||||
/* Unable to empty the queue, purge remaining packets */
|
||||
qemu_net_queue_purge(nc->incoming_queue, nc);
|
||||
qemu_net_queue_purge(nc->incoming_queue, nc->peer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -965,17 +965,11 @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
|
||||
};
|
||||
|
||||
|
||||
static int net_client_init1(const void *object, bool is_netdev, Error **errp)
|
||||
static int net_client_init1(const Netdev *netdev, bool is_netdev, Error **errp)
|
||||
{
|
||||
Netdev legacy = {0};
|
||||
const Netdev *netdev;
|
||||
const char *name;
|
||||
NetClientState *peer = NULL;
|
||||
|
||||
if (is_netdev) {
|
||||
netdev = object;
|
||||
name = netdev->id;
|
||||
|
||||
if (netdev->type == NET_CLIENT_DRIVER_NIC ||
|
||||
!net_client_init_fun[netdev->type]) {
|
||||
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
|
||||
@@ -983,62 +977,11 @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
const NetLegacy *net = object;
|
||||
const NetLegacyOptions *opts = net->opts;
|
||||
legacy.id = net->id;
|
||||
netdev = &legacy;
|
||||
/* missing optional values have been initialized to "all bits zero" */
|
||||
name = net->has_id ? net->id : net->name;
|
||||
|
||||
if (net->has_name) {
|
||||
warn_report("The 'name' parameter is deprecated, use 'id' instead");
|
||||
}
|
||||
|
||||
/* Map the old options to the new flat type */
|
||||
switch (opts->type) {
|
||||
case NET_LEGACY_OPTIONS_TYPE_NONE:
|
||||
if (netdev->type == NET_CLIENT_DRIVER_NONE) {
|
||||
return 0; /* nothing to do */
|
||||
case NET_LEGACY_OPTIONS_TYPE_NIC:
|
||||
legacy.type = NET_CLIENT_DRIVER_NIC;
|
||||
legacy.u.nic = opts->u.nic;
|
||||
break;
|
||||
case NET_LEGACY_OPTIONS_TYPE_USER:
|
||||
legacy.type = NET_CLIENT_DRIVER_USER;
|
||||
legacy.u.user = opts->u.user;
|
||||
break;
|
||||
case NET_LEGACY_OPTIONS_TYPE_TAP:
|
||||
legacy.type = NET_CLIENT_DRIVER_TAP;
|
||||
legacy.u.tap = opts->u.tap;
|
||||
break;
|
||||
case NET_LEGACY_OPTIONS_TYPE_L2TPV3:
|
||||
legacy.type = NET_CLIENT_DRIVER_L2TPV3;
|
||||
legacy.u.l2tpv3 = opts->u.l2tpv3;
|
||||
break;
|
||||
case NET_LEGACY_OPTIONS_TYPE_SOCKET:
|
||||
legacy.type = NET_CLIENT_DRIVER_SOCKET;
|
||||
legacy.u.socket = opts->u.socket;
|
||||
break;
|
||||
case NET_LEGACY_OPTIONS_TYPE_VDE:
|
||||
legacy.type = NET_CLIENT_DRIVER_VDE;
|
||||
legacy.u.vde = opts->u.vde;
|
||||
break;
|
||||
case NET_LEGACY_OPTIONS_TYPE_BRIDGE:
|
||||
legacy.type = NET_CLIENT_DRIVER_BRIDGE;
|
||||
legacy.u.bridge = opts->u.bridge;
|
||||
break;
|
||||
case NET_LEGACY_OPTIONS_TYPE_NETMAP:
|
||||
legacy.type = NET_CLIENT_DRIVER_NETMAP;
|
||||
legacy.u.netmap = opts->u.netmap;
|
||||
break;
|
||||
case NET_LEGACY_OPTIONS_TYPE_VHOST_USER:
|
||||
legacy.type = NET_CLIENT_DRIVER_VHOST_USER;
|
||||
legacy.u.vhost_user = opts->u.vhost_user;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
if (!net_client_init_fun[netdev->type]) {
|
||||
if (netdev->type == NET_CLIENT_DRIVER_HUBPORT ||
|
||||
!net_client_init_fun[netdev->type]) {
|
||||
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
|
||||
"a net backend type (maybe it is not compiled "
|
||||
"into this binary)");
|
||||
@@ -1047,12 +990,12 @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
|
||||
|
||||
/* Do not add to a hub if it's a nic with a netdev= parameter. */
|
||||
if (netdev->type != NET_CLIENT_DRIVER_NIC ||
|
||||
!opts->u.nic.has_netdev) {
|
||||
!netdev->u.nic.has_netdev) {
|
||||
peer = net_hub_add_port(0, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (net_client_init_fun[netdev->type](netdev, name, peer, errp) < 0) {
|
||||
if (net_client_init_fun[netdev->type](netdev, netdev->id, peer, errp) < 0) {
|
||||
/* FIXME drop when all init functions store an Error */
|
||||
if (errp && !*errp) {
|
||||
error_setg(errp, QERR_DEVICE_INIT_FAILED,
|
||||
@@ -1108,7 +1051,7 @@ static void show_netdevs(void)
|
||||
static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp)
|
||||
{
|
||||
gchar **substrings = NULL;
|
||||
void *object = NULL;
|
||||
Netdev *object = NULL;
|
||||
Error *err = NULL;
|
||||
int ret = -1;
|
||||
Visitor *v = opts_visitor_new(opts);
|
||||
@@ -1151,21 +1094,19 @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
if (is_netdev) {
|
||||
visit_type_Netdev(v, NULL, (Netdev **)&object, &err);
|
||||
} else {
|
||||
visit_type_NetLegacy(v, NULL, (NetLegacy **)&object, &err);
|
||||
/* Create an ID for -net if the user did not specify one */
|
||||
if (!is_netdev && !qemu_opts_id(opts)) {
|
||||
static int idx;
|
||||
qemu_opts_set_id(opts, g_strdup_printf("__org.qemu.net%i", idx++));
|
||||
}
|
||||
|
||||
visit_type_Netdev(v, NULL, &object, &err);
|
||||
|
||||
if (!err) {
|
||||
ret = net_client_init1(object, is_netdev, &err);
|
||||
}
|
||||
|
||||
if (is_netdev) {
|
||||
qapi_free_Netdev(object);
|
||||
} else {
|
||||
qapi_free_NetLegacy(object);
|
||||
}
|
||||
qapi_free_Netdev(object);
|
||||
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
|
||||
@@ -254,7 +254,8 @@ static void tap_set_vnet_hdr_len(NetClientState *nc, int len)
|
||||
|
||||
assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
|
||||
assert(len == sizeof(struct virtio_net_hdr_mrg_rxbuf) ||
|
||||
len == sizeof(struct virtio_net_hdr));
|
||||
len == sizeof(struct virtio_net_hdr) ||
|
||||
len == sizeof(struct virtio_net_hdr_v1_hash));
|
||||
|
||||
tap_fd_set_vnet_hdr_len(s->fd, len);
|
||||
s->host_vnet_hdr_len = len;
|
||||
|
||||
@@ -12,6 +12,7 @@ colo_proxy_main(const char *chr) ": %s"
|
||||
|
||||
# colo-compare.c
|
||||
colo_compare_main(const char *chr) ": %s"
|
||||
colo_compare_drop_packet(const char *queue, const char *chr) ": %s: %s"
|
||||
colo_compare_udp_miscompare(const char *sta, int size) ": %s = %d"
|
||||
colo_compare_icmp_miscompare(const char *sta, int size) ": %s = %d"
|
||||
colo_compare_ip_info(int psize, const char *sta, const char *stb, int ssize, const char *stc, const char *std) "ppkt size = %d, ip_src = %s, ip_dst = %s, spkt size = %d, ip_src = %s, ip_dst = %s"
|
||||
|
||||
@@ -467,55 +467,6 @@
|
||||
'netmap': 'NetdevNetmapOptions',
|
||||
'vhost-user': 'NetdevVhostUserOptions' } }
|
||||
|
||||
##
|
||||
# @NetLegacy:
|
||||
#
|
||||
# Captures the configuration of a network device; legacy.
|
||||
#
|
||||
# @id: identifier for monitor commands
|
||||
#
|
||||
# @name: identifier for monitor commands, ignored if @id is present
|
||||
#
|
||||
# @opts: device type specific properties (legacy)
|
||||
#
|
||||
# Since: 1.2
|
||||
##
|
||||
{ 'struct': 'NetLegacy',
|
||||
'data': {
|
||||
'*id': 'str',
|
||||
'*name': 'str',
|
||||
'opts': 'NetLegacyOptions' } }
|
||||
|
||||
##
|
||||
# @NetLegacyOptionsType:
|
||||
#
|
||||
# Since: 1.2
|
||||
##
|
||||
{ 'enum': 'NetLegacyOptionsType',
|
||||
'data': ['none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde',
|
||||
'bridge', 'netmap', 'vhost-user'] }
|
||||
|
||||
##
|
||||
# @NetLegacyOptions:
|
||||
#
|
||||
# Like Netdev, but for use only by the legacy command line options
|
||||
#
|
||||
# Since: 1.2
|
||||
##
|
||||
{ 'union': 'NetLegacyOptions',
|
||||
'base': { 'type': 'NetLegacyOptionsType' },
|
||||
'discriminator': 'type',
|
||||
'data': {
|
||||
'nic': 'NetLegacyNicOptions',
|
||||
'user': 'NetdevUserOptions',
|
||||
'tap': 'NetdevTapOptions',
|
||||
'l2tpv3': 'NetdevL2TPv3Options',
|
||||
'socket': 'NetdevSocketOptions',
|
||||
'vde': 'NetdevVdeOptions',
|
||||
'bridge': 'NetdevBridgeOptions',
|
||||
'netmap': 'NetdevNetmapOptions',
|
||||
'vhost-user': 'NetdevVhostUserOptions' } }
|
||||
|
||||
##
|
||||
# @NetFilterDirection:
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user