-----BEGIN PGP SIGNATURE-----

Version: GnuPG v1
 
 iQEcBAABAgAGBQJZsfnCAAoJEO8Ells5jWIRF9kH+wTT8+958CsD9hixjGQlPClv
 g7jY/EyKDe/6568nRDX/TZrGOJjgqYnXyIewyzNjxMp5gptapvTjkgGjhdKU8ZJC
 Z9RGfYTL30WZDQHZKBdhKpR7BAwRLuzu2kDGpj4c30kQFScjfamhkOyGO8Ej1vW+
 bYQkROfSb/jwhgfxHeOwIH50RBfXU6uhr41UeWuGHS9OL8NarTsa6GuPdH4pTxXa
 aXWZoGPuQAYd0DRuqM8FbxDuSTlaWHFZpQ55eJoRimDfc0JQyrq93si9DjZ3EenT
 doPF038qjPN4c0MuPLhILOHFD0IL41wol7k3WxT/LSJE7aVnnXzbjd5zbQvgUQE=
 =SIPv
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging

# gpg: Signature made Fri 08 Sep 2017 03:00:34 BST
# gpg:                using RSA key 0xEF04965B398D6211
# gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>"
# 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:
  colo-compare: Update the COLO document to add the IOThread configuration
  colo-compare: Use IOThread to Check old packet regularly and Process pactkets of the primary
  qemu-iothread: IOThread supports the GMainContext event loop
  net/colo-compare.c: Fix comments and scheme
  net/colo-compare.c: Adjust net queue pop order for performance
  net/colo-compare.c: Optimize unpredictable tcp options comparison
  e1000: Rename the SEC symbol to SEQEC
  net/socket: Improve -net socket error reporting
  net/net: Convert parse_host_port() to Error
  net/socket: Convert several helper functions to Error
  net/socket: Don't treat odd socket type as SOCK_STREAM
  MAINTAINERS: Update mail address for COLO Proxy
  net: rtl8139: do not use old_mmio accesses
  net/rocker: Fix the unusual macro name
  net/rocker: Convert to realize()
  net/rocker: Plug memory leak in pci_rocker_init()
  net/rocker: Remove the dead error handling
  net/filter-rewriter.c: Fix rewirter checksum bug when use virtio-net

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-09-08 12:57:28 +01:00
commit 74bbfe024d
19 changed files with 305 additions and 324 deletions

View File

@ -1577,7 +1577,7 @@ F: include/migration/failover.h
F: docs/COLO-FT.txt
COLO Proxy
M: Zhang Chen <zhangchen.fnst@cn.fujitsu.com>
M: Zhang Chen <zhangckid@gmail.com>
M: Li Zhijian <lizhijian@cn.fujitsu.com>
S: Supported
F: docs/colo-proxy.txt

View File

@ -170,10 +170,11 @@ Primary(ip:3.3.3.3):
-chardev socket,id=compare0-0,host=3.3.3.3,port=9001
-chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait
-chardev socket,id=compare_out0,host=3.3.3.3,port=9005
-object iothread,id=iothread1
-object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0
-object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out
-object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0
-object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0
-object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0,iothread=iothread1
Secondary(ip:3.3.3.8):
-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down script=/etc/qemu-ifdown

View File

@ -1127,7 +1127,7 @@ static uint32_t (*macreg_readops[])(E1000State *, int) = {
getreg(TADV), getreg(ITR), getreg(FCRUC), getreg(IPAV),
getreg(WUC), getreg(WUS), getreg(SCC), getreg(ECOL),
getreg(MCC), getreg(LATECOL), getreg(COLC), getreg(DC),
getreg(TNCRS), getreg(SEC), getreg(CEXTERR), getreg(RLEC),
getreg(TNCRS), getreg(SEQEC), getreg(CEXTERR), getreg(RLEC),
getreg(XONRXC), getreg(XONTXC), getreg(XOFFRXC), getreg(XOFFTXC),
getreg(RFC), getreg(RJC), getreg(RNBC), getreg(TSCTFC),
getreg(MGTPRC), getreg(MGTPDC), getreg(MGTPTC), getreg(GORCL),
@ -1223,7 +1223,7 @@ static const uint8_t mac_reg_access[0x8000] = {
[FFLT] = markflag(MAC), [FFMT] = markflag(MAC),
[SCC] = markflag(MAC), [FCRUC] = markflag(MAC),
[LATECOL] = markflag(MAC), [COLC] = markflag(MAC),
[SEC] = markflag(MAC), [CEXTERR] = markflag(MAC),
[SEQEC] = markflag(MAC), [CEXTERR] = markflag(MAC),
[XONTXC] = markflag(MAC), [XOFFRXC] = markflag(MAC),
[RJC] = markflag(MAC), [RNBC] = markflag(MAC),
[MGTPDC] = markflag(MAC), [MGTPTC] = markflag(MAC),

View File

@ -260,7 +260,7 @@
#define E1000_COLC 0x04028 /* Collision Count - R/clr */
#define E1000_DC 0x04030 /* Defer Count - R/clr */
#define E1000_TNCRS 0x04034 /* TX-No CRS - R/clr */
#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */
#define E1000_SEQEC 0x04038 /* Sequence Error Count - R/clr */
#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */
#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */
#define E1000_XONRXC 0x04048 /* XON RX Count - R/clr */

View File

@ -2855,7 +2855,7 @@ static uint32_t (*e1000e_macreg_readops[])(E1000ECore *, int) = {
e1000e_getreg(RDLEN0),
e1000e_getreg(RDH1),
e1000e_getreg(LATECOL),
e1000e_getreg(SEC),
e1000e_getreg(SEQEC),
e1000e_getreg(XONTXC),
e1000e_getreg(WUS),
e1000e_getreg(GORCL),

View File

@ -40,7 +40,7 @@ enum {
defreg(VFTA), defreg(VET), defreg(RDTR), defreg(RADV),
defreg(TADV), defreg(ITR), defreg(SCC), defreg(ECOL),
defreg(MCC), defreg(LATECOL), defreg(COLC), defreg(DC),
defreg(TNCRS), defreg(SEC), defreg(CEXTERR), defreg(RLEC),
defreg(TNCRS), defreg(SEQEC), defreg(CEXTERR), defreg(RLEC),
defreg(XONRXC), defreg(XONTXC), defreg(XOFFRXC), defreg(XOFFTXC),
defreg(FCRUC), defreg(AIT), defreg(TDFH), defreg(TDFT),
defreg(TDFHS), defreg(TDFTS), defreg(TDFPC), defreg(WUC),

View File

@ -69,10 +69,10 @@ struct rocker {
QLIST_ENTRY(rocker) next;
};
#define ROCKER "rocker"
#define TYPE_ROCKER "rocker"
#define to_rocker(obj) \
OBJECT_CHECK(Rocker, (obj), ROCKER)
#define ROCKER(obj) \
OBJECT_CHECK(Rocker, (obj), TYPE_ROCKER)
static QLIST_HEAD(, rocker) rockers;
@ -239,10 +239,6 @@ static int tx_consume(Rocker *r, DescInfo *info)
}
iov[iovcnt].iov_len = frag_len;
iov[iovcnt].iov_base = g_malloc(frag_len);
if (!iov[iovcnt].iov_base) {
err = -ROCKER_ENOMEM;
goto err_no_mem;
}
pci_dma_read(dev, frag_addr, iov[iovcnt].iov_base,
iov[iovcnt].iov_len);
@ -259,7 +255,6 @@ static int tx_consume(Rocker *r, DescInfo *info)
err = fp_port_eg(r->fp_port[port], iov, iovcnt);
err_too_many_frags:
err_no_mem:
err_bad_attr:
for (i = 0; i < ROCKER_TX_FRAGS_MAX; i++) {
g_free(iov[i].iov_base);
@ -671,10 +666,7 @@ int rx_produce(World *world, uint32_t pport,
*/
data = g_malloc(data_size);
if (!data) {
err = -ROCKER_ENOMEM;
goto out;
}
iov_to_buf(iov, iovcnt, 0, data, data_size);
pci_dma_write(dev, frag_addr, data, data_size);
g_free(data);
@ -719,11 +711,6 @@ static void rocker_test_dma_ctrl(Rocker *r, uint32_t val)
buf = g_malloc(r->test_dma_size);
if (!buf) {
DPRINTF("test dma buffer alloc failed");
return;
}
switch (val) {
case ROCKER_TEST_DMA_CTRL_CLEAR:
memset(buf, 0, r->test_dma_size);
@ -1249,20 +1236,18 @@ rollback:
return err;
}
static int rocker_msix_init(Rocker *r)
static int rocker_msix_init(Rocker *r, Error **errp)
{
PCIDevice *dev = PCI_DEVICE(r);
int err;
Error *local_err = NULL;
err = msix_init(dev, ROCKER_MSIX_VEC_COUNT(r->fp_ports),
&r->msix_bar,
ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_TABLE_OFFSET,
&r->msix_bar,
ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_PBA_OFFSET,
0, &local_err);
0, errp);
if (err) {
error_report_err(local_err);
return err;
}
@ -1298,9 +1283,9 @@ static World *rocker_world_type_by_name(Rocker *r, const char *name)
return NULL;
}
static int pci_rocker_init(PCIDevice *dev)
static void pci_rocker_realize(PCIDevice *dev, Error **errp)
{
Rocker *r = to_rocker(dev);
Rocker *r = ROCKER(dev);
const MACAddr zero = { .a = { 0, 0, 0, 0, 0, 0 } };
const MACAddr dflt = { .a = { 0x52, 0x54, 0x00, 0x12, 0x35, 0x01 } };
static int sw_index;
@ -1310,23 +1295,15 @@ static int pci_rocker_init(PCIDevice *dev)
r->worlds[ROCKER_WORLD_TYPE_OF_DPA] = of_dpa_world_alloc(r);
for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
if (!r->worlds[i]) {
err = -ENOMEM;
goto err_world_alloc;
}
}
if (!r->world_name) {
r->world_name = g_strdup(world_name(r->worlds[ROCKER_WORLD_TYPE_OF_DPA]));
}
r->world_dflt = rocker_world_type_by_name(r, r->world_name);
if (!r->world_dflt) {
fprintf(stderr,
"rocker: requested world \"%s\" does not exist\n",
error_setg(errp,
"invalid argument requested world %s does not exist",
r->world_name);
err = -EINVAL;
goto err_world_type_by_name;
}
@ -1346,7 +1323,7 @@ static int pci_rocker_init(PCIDevice *dev)
/* MSI-X init */
err = rocker_msix_init(r);
err = rocker_msix_init(r, errp);
if (err) {
goto err_msix_init;
}
@ -1354,11 +1331,11 @@ static int pci_rocker_init(PCIDevice *dev)
/* validate switch properties */
if (!r->name) {
r->name = g_strdup(ROCKER);
r->name = g_strdup(TYPE_ROCKER);
}
if (rocker_find(r->name)) {
err = -EEXIST;
error_setg(errp, "%s already exists", r->name);
goto err_duplicate;
}
@ -1372,10 +1349,10 @@ static int pci_rocker_init(PCIDevice *dev)
#define ROCKER_IFNAMSIZ 16
#define MAX_ROCKER_NAME_LEN (ROCKER_IFNAMSIZ - 1 - 3 - 3)
if (strlen(r->name) > MAX_ROCKER_NAME_LEN) {
fprintf(stderr,
"rocker: name too long; please shorten to at most %d chars\n",
error_setg(errp,
"name too long; please shorten to at most %d chars",
MAX_ROCKER_NAME_LEN);
return -EINVAL;
goto err_name_too_long;
}
if (memcmp(&r->fp_start_macaddr, &zero, sizeof(zero)) == 0) {
@ -1393,9 +1370,6 @@ static int pci_rocker_init(PCIDevice *dev)
}
r->rings = g_new(DescRing *, rocker_pci_ring_count(r));
if (!r->rings) {
goto err_rings_alloc;
}
/* Rings are ordered like this:
* - command ring
@ -1407,14 +1381,9 @@ static int pci_rocker_init(PCIDevice *dev)
* .....
*/
err = -ENOMEM;
for (i = 0; i < rocker_pci_ring_count(r); i++) {
DescRing *ring = desc_ring_alloc(r, i);
if (!ring) {
goto err_ring_alloc;
}
if (i == ROCKER_RING_CMD) {
desc_ring_set_consume(ring, cmd_consume, ROCKER_MSIX_VEC_CMD);
} else if (i == ROCKER_RING_EVENT) {
@ -1434,48 +1403,31 @@ static int pci_rocker_init(PCIDevice *dev)
fp_port_alloc(r, r->name, &r->fp_start_macaddr,
i, &r->fp_ports_peers[i]);
if (!port) {
goto err_port_alloc;
}
r->fp_port[i] = port;
fp_port_set_world(port, r->world_dflt);
}
QLIST_INSERT_HEAD(&rockers, r, next);
return 0;
return;
err_port_alloc:
for (--i; i >= 0; i--) {
FpPort *port = r->fp_port[i];
fp_port_free(port);
}
i = rocker_pci_ring_count(r);
err_ring_alloc:
for (--i; i >= 0; i--) {
desc_ring_free(r->rings[i]);
}
g_free(r->rings);
err_rings_alloc:
err_name_too_long:
err_duplicate:
rocker_msix_uninit(r);
err_msix_init:
object_unparent(OBJECT(&r->msix_bar));
object_unparent(OBJECT(&r->mmio));
err_world_type_by_name:
err_world_alloc:
for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
if (r->worlds[i]) {
world_free(r->worlds[i]);
}
}
return err;
}
static void pci_rocker_uninit(PCIDevice *dev)
{
Rocker *r = to_rocker(dev);
Rocker *r = ROCKER(dev);
int i;
QLIST_REMOVE(r, next);
@ -1508,7 +1460,7 @@ static void pci_rocker_uninit(PCIDevice *dev)
static void rocker_reset(DeviceState *dev)
{
Rocker *r = to_rocker(dev);
Rocker *r = ROCKER(dev);
int i;
for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
@ -1546,7 +1498,7 @@ static Property rocker_properties[] = {
};
static const VMStateDescription rocker_vmsd = {
.name = ROCKER,
.name = TYPE_ROCKER,
.unmigratable = 1,
};
@ -1555,7 +1507,7 @@ static void rocker_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->init = pci_rocker_init;
k->realize = pci_rocker_realize;
k->exit = pci_rocker_uninit;
k->vendor_id = PCI_VENDOR_ID_REDHAT;
k->device_id = PCI_DEVICE_ID_REDHAT_ROCKER;
@ -1569,7 +1521,7 @@ static void rocker_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo rocker_info = {
.name = ROCKER,
.name = TYPE_ROCKER,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(Rocker),
.class_init = rocker_class_init,

View File

@ -65,10 +65,6 @@ char *desc_get_buf(DescInfo *info, bool read_only)
info->buf_size = size;
}
if (!info->buf) {
return NULL;
}
pci_dma_read(dev, le64_to_cpu(info->desc.buf_addr), info->buf, size);
return info->buf;
@ -142,9 +138,6 @@ bool desc_ring_set_size(DescRing *ring, uint32_t size)
ring->head = ring->tail = 0;
ring->info = g_renew(DescInfo, ring->info, size);
if (!ring->info) {
return false;
}
memset(ring->info, 0, size * sizeof(DescInfo));
@ -345,9 +338,6 @@ DescRing *desc_ring_alloc(Rocker *r, int index)
DescRing *ring;
ring = g_new0(DescRing, 1);
if (!ring) {
return NULL;
}
ring->r = r;
ring->index = index;

View File

@ -226,10 +226,6 @@ FpPort *fp_port_alloc(Rocker *r, char *sw_name,
{
FpPort *port = g_new0(FpPort, 1);
if (!port) {
return NULL;
}
port->r = r;
port->index = index;
port->pport = index + 1;

View File

@ -368,9 +368,6 @@ static OfDpaFlow *of_dpa_flow_alloc(uint64_t cookie)
int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) / 1000;
flow = g_new0(OfDpaFlow, 1);
if (!flow) {
return NULL;
}
flow->cookie = cookie;
flow->mask.tbl_id = 0xffffffff;
@ -813,10 +810,6 @@ static OfDpaGroup *of_dpa_group_alloc(uint32_t id)
{
OfDpaGroup *group = g_new0(OfDpaGroup, 1);
if (!group) {
return NULL;
}
group->id = id;
return group;
@ -1867,9 +1860,6 @@ static int of_dpa_cmd_flow_add(OfDpa *of_dpa, uint64_t cookie,
}
flow = of_dpa_flow_alloc(cookie);
if (!flow) {
return -ROCKER_ENOMEM;
}
err = of_dpa_cmd_flow_add_mod(of_dpa, flow, flow_tlvs);
if (err) {
@ -2040,17 +2030,10 @@ static int of_dpa_cmd_add_l2_flood(OfDpa *of_dpa, OfDpaGroup *group,
rocker_tlv_get_le16(group_tlvs[ROCKER_TLV_OF_DPA_GROUP_COUNT]);
tlvs = g_new0(RockerTlv *, group->l2_flood.group_count + 1);
if (!tlvs) {
return -ROCKER_ENOMEM;
}
g_free(group->l2_flood.group_ids);
group->l2_flood.group_ids =
g_new0(uint32_t, group->l2_flood.group_count);
if (!group->l2_flood.group_ids) {
err = -ROCKER_ENOMEM;
goto err_out;
}
rocker_tlv_parse_nested(tlvs, group->l2_flood.group_count,
group_tlvs[ROCKER_TLV_OF_DPA_GROUP_IDS]);
@ -2157,9 +2140,6 @@ static int of_dpa_cmd_group_add(OfDpa *of_dpa, uint32_t group_id,
}
group = of_dpa_group_alloc(group_id);
if (!group) {
return -ROCKER_ENOMEM;
}
err = of_dpa_cmd_group_do(of_dpa, group_id, group, group_tlvs);
if (err) {

View File

@ -51,13 +51,11 @@ World *world_alloc(Rocker *r, size_t sizeof_private,
{
World *w = g_malloc0(sizeof(World) + sizeof_private);
if (w) {
w->r = r;
w->type = type;
w->ops = ops;
if (w->ops->init) {
w->ops->init(w);
}
w->r = r;
w->type = type;
w->ops = ops;
if (w->ops->init) {
w->ops->init(w);
}
return w;

View File

@ -3132,38 +3132,6 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr)
/* */
static void rtl8139_mmio_writeb(void *opaque, hwaddr addr, uint32_t val)
{
rtl8139_io_writeb(opaque, addr & 0xFF, val);
}
static void rtl8139_mmio_writew(void *opaque, hwaddr addr, uint32_t val)
{
rtl8139_io_writew(opaque, addr & 0xFF, val);
}
static void rtl8139_mmio_writel(void *opaque, hwaddr addr, uint32_t val)
{
rtl8139_io_writel(opaque, addr & 0xFF, val);
}
static uint32_t rtl8139_mmio_readb(void *opaque, hwaddr addr)
{
return rtl8139_io_readb(opaque, addr & 0xFF);
}
static uint32_t rtl8139_mmio_readw(void *opaque, hwaddr addr)
{
uint32_t val = rtl8139_io_readw(opaque, addr & 0xFF);
return val;
}
static uint32_t rtl8139_mmio_readl(void *opaque, hwaddr addr)
{
uint32_t val = rtl8139_io_readl(opaque, addr & 0xFF);
return val;
}
static int rtl8139_post_load(void *opaque, int version_id)
{
RTL8139State* s = opaque;
@ -3344,22 +3312,6 @@ static const MemoryRegionOps rtl8139_io_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
static const MemoryRegionOps rtl8139_mmio_ops = {
.old_mmio = {
.read = {
rtl8139_mmio_readb,
rtl8139_mmio_readw,
rtl8139_mmio_readl,
},
.write = {
rtl8139_mmio_writeb,
rtl8139_mmio_writew,
rtl8139_mmio_writel,
},
},
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void rtl8139_timer(void *opaque)
{
RTL8139State *s = opaque;
@ -3422,8 +3374,9 @@ static void pci_rtl8139_realize(PCIDevice *dev, Error **errp)
memory_region_init_io(&s->bar_io, OBJECT(s), &rtl8139_io_ops, s,
"rtl8139", 0x100);
memory_region_init_io(&s->bar_mem, OBJECT(s), &rtl8139_mmio_ops, s,
"rtl8139", 0x100);
memory_region_init_alias(&s->bar_mem, OBJECT(s), "rtl8139-mem", &s->bar_io,
0, 0x100);
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->bar_io);
pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar_mem);

View File

@ -45,7 +45,8 @@ void socket_listen_cleanup(int fd, Error **errp);
int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp);
/* Old, ipv4 only bits. Don't use for new code. */
int parse_host_port(struct sockaddr_in *saddr, const char *str);
int parse_host_port(struct sockaddr_in *saddr, const char *str,
Error **errp);
int socket_init(void);
/**

View File

@ -24,6 +24,9 @@ typedef struct {
QemuThread thread;
AioContext *ctx;
GMainContext *worker_context;
GMainLoop *main_loop;
GOnce once;
QemuMutex init_done_lock;
QemuCond init_done_cond; /* is thread initialization done? */
bool stopping;
@ -41,5 +44,6 @@ typedef struct {
char *iothread_get_id(IOThread *iothread);
AioContext *iothread_get_aio_context(IOThread *iothread);
void iothread_stop_all(void);
GMainContext *iothread_get_g_main_context(IOThread *iothread);
#endif /* IOTHREAD_H */

View File

@ -57,6 +57,23 @@ static void *iothread_run(void *opaque)
while (!atomic_read(&iothread->stopping)) {
aio_poll(iothread->ctx, true);
if (atomic_read(&iothread->worker_context)) {
GMainLoop *loop;
g_main_context_push_thread_default(iothread->worker_context);
iothread->main_loop =
g_main_loop_new(iothread->worker_context, TRUE);
loop = iothread->main_loop;
g_main_loop_run(iothread->main_loop);
iothread->main_loop = NULL;
g_main_loop_unref(loop);
g_main_context_pop_thread_default(iothread->worker_context);
g_main_context_unref(iothread->worker_context);
iothread->worker_context = NULL;
}
}
rcu_unregister_thread();
@ -73,6 +90,9 @@ static int iothread_stop(Object *object, void *opaque)
}
iothread->stopping = true;
aio_notify(iothread->ctx);
if (atomic_read(&iothread->main_loop)) {
g_main_loop_quit(iothread->main_loop);
}
qemu_thread_join(&iothread->thread);
return 0;
}
@ -125,6 +145,7 @@ static void iothread_complete(UserCreatable *obj, Error **errp)
qemu_mutex_init(&iothread->init_done_lock);
qemu_cond_init(&iothread->init_done_cond);
iothread->once = (GOnce) G_ONCE_INIT;
/* This assumes we are called from a thread with useful CPU affinity for us
* to inherit.
@ -309,3 +330,27 @@ void iothread_stop_all(void)
object_child_foreach(container, iothread_stop, NULL);
}
static gpointer iothread_g_main_context_init(gpointer opaque)
{
AioContext *ctx;
IOThread *iothread = opaque;
GSource *source;
iothread->worker_context = g_main_context_new();
ctx = iothread_get_aio_context(iothread);
source = aio_get_g_source(ctx);
g_source_attach(source, iothread->worker_context);
g_source_unref(source);
aio_notify(iothread->ctx);
return NULL;
}
GMainContext *iothread_get_g_main_context(IOThread *iothread)
{
g_once(&iothread->once, iothread_g_main_context_init, iothread);
return iothread->worker_context;
}

View File

@ -29,6 +29,7 @@
#include "qemu/sockets.h"
#include "qapi-visit.h"
#include "net/colo.h"
#include "sysemu/iothread.h"
#define TYPE_COLO_COMPARE "colo-compare"
#define COLO_COMPARE(obj) \
@ -41,27 +42,27 @@
#define REGULAR_PACKET_CHECK_MS 3000
/*
+ CompareState ++
| |
+---------------+ +---------------+ +---------------+
|conn list +--->conn +--------->conn |
+---------------+ +---------------+ +---------------+
| | | | | |
+---------------+ +---v----+ +---v----+ +---v----+ +---v----+
|primary | |secondary |primary | |secondary
|packet | |packet + |packet | |packet +
+--------+ +--------+ +--------+ +--------+
| | | |
+---v----+ +---v----+ +---v----+ +---v----+
|primary | |secondary |primary | |secondary
|packet | |packet + |packet | |packet +
+--------+ +--------+ +--------+ +--------+
| | | |
+---v----+ +---v----+ +---v----+ +---v----+
|primary | |secondary |primary | |secondary
|packet | |packet + |packet | |packet +
+--------+ +--------+ +--------+ +--------+
*/
* + CompareState ++
* | |
* +---------------+ +---------------+ +---------------+
* | conn list + - > conn + ------- > conn + -- > ......
* +---------------+ +---------------+ +---------------+
* | | | | | |
* +---------------+ +---v----+ +---v----+ +---v----+ +---v----+
* |primary | |secondary |primary | |secondary
* |packet | |packet + |packet | |packet +
* +--------+ +--------+ +--------+ +--------+
* | | | |
* +---v----+ +---v----+ +---v----+ +---v----+
* |primary | |secondary |primary | |secondary
* |packet | |packet + |packet | |packet +
* +--------+ +--------+ +--------+ +--------+
* | | | |
* +---v----+ +---v----+ +---v----+ +---v----+
* |primary | |secondary |primary | |secondary
* |packet | |packet + |packet | |packet +
* +--------+ +--------+ +--------+ +--------+
*/
typedef struct CompareState {
Object parent;
@ -75,18 +76,17 @@ typedef struct CompareState {
SocketReadState sec_rs;
bool vnet_hdr;
/* connection list: the connections belonged to this NIC could be found
* in this list.
* element type: Connection
/*
* Record the connection that through the NIC
* Element type: Connection
*/
GQueue conn_list;
/* hashtable to save connection */
/* Record the connection without repetition */
GHashTable *connection_track_table;
/* compare thread, a thread for each NIC */
QemuThread thread;
IOThread *iothread;
GMainContext *worker_context;
GMainLoop *compare_loop;
QEMUTimer *packet_check_timer;
} CompareState;
typedef struct CompareClass {
@ -186,7 +186,10 @@ static int packet_enqueue(CompareState *s, int mode)
* return: 0 means packet same
* > 0 || < 0 means packet different
*/
static int colo_packet_compare_common(Packet *ppkt, Packet *spkt, int offset)
static int colo_packet_compare_common(Packet *ppkt,
Packet *spkt,
int poffset,
int soffset)
{
if (trace_event_get_state_backends(TRACE_COLO_COMPARE_MISCOMPARE)) {
char pri_ip_src[20], pri_ip_dst[20], sec_ip_src[20], sec_ip_dst[20];
@ -201,12 +204,13 @@ static int colo_packet_compare_common(Packet *ppkt, Packet *spkt, int offset)
sec_ip_src, sec_ip_dst);
}
offset = ppkt->vnet_hdr_len + offset;
poffset = ppkt->vnet_hdr_len + poffset;
soffset = ppkt->vnet_hdr_len + soffset;
if (ppkt->size == spkt->size) {
return memcmp(ppkt->data + offset,
spkt->data + offset,
spkt->size - offset);
if (ppkt->size - poffset == spkt->size - soffset) {
return memcmp(ppkt->data + poffset,
spkt->data + soffset,
spkt->size - soffset);
} else {
trace_colo_compare_main("Net packet size are not the same");
return -1;
@ -263,13 +267,22 @@ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt)
* so we just need skip this field.
*/
if (ptcp->th_off > 5) {
ptrdiff_t tcp_offset;
ptrdiff_t ptcp_offset, stcp_offset;
tcp_offset = ppkt->transport_header - (uint8_t *)ppkt->data
+ (ptcp->th_off * 4) - ppkt->vnet_hdr_len;
res = colo_packet_compare_common(ppkt, spkt, tcp_offset);
ptcp_offset = ppkt->transport_header - (uint8_t *)ppkt->data
+ (ptcp->th_off * 4) - ppkt->vnet_hdr_len;
stcp_offset = spkt->transport_header - (uint8_t *)spkt->data
+ (stcp->th_off * 4) - spkt->vnet_hdr_len;
/*
* When network is busy, some tcp options(like sack) will unpredictable
* occur in primary side or secondary side. it will make packet size
* not same, but the two packet's payload is identical. colo just
* care about packet payload, so we skip the option field.
*/
res = colo_packet_compare_common(ppkt, spkt, ptcp_offset, stcp_offset);
} else if (ptcp->th_sum == stcp->th_sum) {
res = colo_packet_compare_common(ppkt, spkt, ETH_HLEN);
res = colo_packet_compare_common(ppkt, spkt, ETH_HLEN, ETH_HLEN);
} else {
res = -1;
}
@ -330,6 +343,7 @@ static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
* the ip payload here.
*/
ret = colo_packet_compare_common(ppkt, spkt,
network_header_length + ETH_HLEN,
network_header_length + ETH_HLEN);
if (ret) {
@ -367,6 +381,7 @@ static int colo_packet_compare_icmp(Packet *spkt, Packet *ppkt)
* the ip payload here.
*/
if (colo_packet_compare_common(ppkt, spkt,
network_header_length + ETH_HLEN,
network_header_length + ETH_HLEN)) {
trace_colo_compare_icmp_miscompare("primary pkt size",
ppkt->size);
@ -404,7 +419,7 @@ static int colo_packet_compare_other(Packet *spkt, Packet *ppkt)
sec_ip_src, sec_ip_dst);
}
return colo_packet_compare_common(ppkt, spkt, 0);
return colo_packet_compare_common(ppkt, spkt, 0, 0);
}
static int colo_old_packet_check_one(Packet *pkt, int64_t *check_time)
@ -430,8 +445,11 @@ static int colo_old_packet_check_one_conn(Connection *conn,
(GCompareFunc)colo_old_packet_check_one);
if (result) {
/* do checkpoint will flush old packet */
/* TODO: colo_notify_checkpoint();*/
/* Do checkpoint will flush old packet */
/*
* TODO: Notify colo frame to do checkpoint.
* colo_compare_inconsistent_notify();
*/
return 0;
}
@ -469,7 +487,7 @@ static void colo_compare_connection(void *opaque, void *user_data)
while (!g_queue_is_empty(&conn->primary_list) &&
!g_queue_is_empty(&conn->secondary_list)) {
pkt = g_queue_pop_tail(&conn->primary_list);
pkt = g_queue_pop_head(&conn->primary_list);
switch (conn->ip_proto) {
case IPPROTO_TCP:
result = g_queue_find_custom(&conn->secondary_list,
@ -507,7 +525,7 @@ static void colo_compare_connection(void *opaque, void *user_data)
* until next comparison.
*/
trace_colo_compare_main("packet different");
g_queue_push_tail(&conn->primary_list, pkt);
g_queue_push_head(&conn->primary_list, pkt);
/* TODO: colo_notify_checkpoint();*/
break;
}
@ -597,22 +615,40 @@ static void compare_sec_chr_in(void *opaque, const uint8_t *buf, int size)
* Check old packet regularly so it can watch for any packets
* that the secondary hasn't produced equivalents of.
*/
static gboolean check_old_packet_regular(void *opaque)
static void check_old_packet_regular(void *opaque)
{
CompareState *s = opaque;
/* if have old packet we will notify checkpoint */
colo_old_packet_check(s);
return TRUE;
timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
REGULAR_PACKET_CHECK_MS);
}
static void *colo_compare_thread(void *opaque)
static void colo_compare_timer_init(CompareState *s)
{
CompareState *s = opaque;
GSource *timeout_source;
AioContext *ctx = iothread_get_aio_context(s->iothread);
s->worker_context = g_main_context_new();
s->packet_check_timer = aio_timer_new(ctx, QEMU_CLOCK_VIRTUAL,
SCALE_MS, check_old_packet_regular,
s);
timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
REGULAR_PACKET_CHECK_MS);
}
static void colo_compare_timer_del(CompareState *s)
{
if (s->packet_check_timer) {
timer_del(s->packet_check_timer);
timer_free(s->packet_check_timer);
s->packet_check_timer = NULL;
}
}
static void colo_compare_iothread(CompareState *s)
{
object_ref(OBJECT(s->iothread));
s->worker_context = iothread_get_g_main_context(s->iothread);
qemu_chr_fe_set_handlers(&s->chr_pri_in, compare_chr_can_read,
compare_pri_chr_in, NULL, NULL,
@ -621,20 +657,7 @@ static void *colo_compare_thread(void *opaque)
compare_sec_chr_in, NULL, NULL,
s, s->worker_context, true);
s->compare_loop = g_main_loop_new(s->worker_context, FALSE);
/* To kick any packets that the secondary doesn't match */
timeout_source = g_timeout_source_new(REGULAR_PACKET_CHECK_MS);
g_source_set_callback(timeout_source,
(GSourceFunc)check_old_packet_regular, s, NULL);
g_source_attach(timeout_source, s->worker_context);
g_main_loop_run(s->compare_loop);
g_source_unref(timeout_source);
g_main_loop_unref(s->compare_loop);
g_main_context_unref(s->worker_context);
return NULL;
colo_compare_timer_init(s);
}
static char *compare_get_pri_indev(Object *obj, Error **errp)
@ -759,12 +782,10 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
{
CompareState *s = COLO_COMPARE(uc);
Chardev *chr;
char thread_name[64];
static int compare_id;
if (!s->pri_indev || !s->sec_indev || !s->outdev) {
if (!s->pri_indev || !s->sec_indev || !s->outdev || !s->iothread) {
error_setg(errp, "colo compare needs 'primary_in' ,"
"'secondary_in','outdev' property set");
"'secondary_in','outdev','iothread' property set");
return;
} else if (!strcmp(s->pri_indev, s->outdev) ||
!strcmp(s->sec_indev, s->outdev) ||
@ -799,12 +820,7 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
g_free,
connection_destroy);
sprintf(thread_name, "colo-compare %d", compare_id);
qemu_thread_create(&s->thread, thread_name,
colo_compare_thread, s,
QEMU_THREAD_JOINABLE);
compare_id++;
colo_compare_iothread(s);
return;
}
@ -848,6 +864,10 @@ static void colo_compare_init(Object *obj)
object_property_add_str(obj, "outdev",
compare_get_outdev, compare_set_outdev,
NULL);
object_property_add_link(obj, "iothread", TYPE_IOTHREAD,
(Object **)&s->iothread,
object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
s->vnet_hdr = false;
object_property_add_bool(obj, "vnet_hdr_support", compare_get_vnet_hdr,
@ -861,16 +881,21 @@ static void colo_compare_finalize(Object *obj)
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);
g_main_loop_quit(s->compare_loop);
qemu_thread_join(&s->thread);
if (s->iothread) {
colo_compare_timer_del(s);
}
/* Release all unhandled packets after compare thead exited */
g_queue_foreach(&s->conn_list, colo_flush_packets, s);
g_queue_clear(&s->conn_list);
g_hash_table_destroy(s->connection_track_table);
if (s->connection_track_table) {
g_hash_table_destroy(s->connection_track_table);
}
if (s->iothread) {
object_unref(OBJECT(s->iothread));
}
g_free(s->pri_indev);
g_free(s->sec_indev);
g_free(s->outdev);

View File

@ -99,7 +99,8 @@ static int handle_primary_tcp_pkt(NetFilterState *nf,
/* handle packets to the secondary from the primary */
tcp_pkt->th_ack = htonl(ntohl(tcp_pkt->th_ack) + conn->offset);
net_checksum_calculate((uint8_t *)pkt->data, pkt->size);
net_checksum_calculate((uint8_t *)pkt->data + pkt->vnet_hdr_len,
pkt->size - pkt->vnet_hdr_len);
}
}
@ -138,7 +139,8 @@ static int handle_secondary_tcp_pkt(NetFilterState *nf,
/* handle packets to the primary from the secondary*/
tcp_pkt->th_seq = htonl(ntohl(tcp_pkt->th_seq) - conn->offset);
net_checksum_calculate((uint8_t *)pkt->data, pkt->size);
net_checksum_calculate((uint8_t *)pkt->data + pkt->vnet_hdr_len,
pkt->size - pkt->vnet_hdr_len);
}
}

View File

@ -100,7 +100,8 @@ static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
return 0;
}
int parse_host_port(struct sockaddr_in *saddr, const char *str)
int parse_host_port(struct sockaddr_in *saddr, const char *str,
Error **errp)
{
char buf[512];
struct hostent *he;
@ -108,24 +109,35 @@ int parse_host_port(struct sockaddr_in *saddr, const char *str)
int port;
p = str;
if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
error_setg(errp, "host address '%s' doesn't contain ':' "
"separating host from port", str);
return -1;
}
saddr->sin_family = AF_INET;
if (buf[0] == '\0') {
saddr->sin_addr.s_addr = 0;
} else {
if (qemu_isdigit(buf[0])) {
if (!inet_aton(buf, &saddr->sin_addr))
if (!inet_aton(buf, &saddr->sin_addr)) {
error_setg(errp, "host address '%s' is not a valid "
"IPv4 address", buf);
return -1;
}
} else {
if ((he = gethostbyname(buf)) == NULL)
he = gethostbyname(buf);
if (he == NULL) {
error_setg(errp, "can't resolve host address '%s'", buf);
return - 1;
}
saddr->sin_addr = *(struct in_addr *)he->h_addr;
}
}
port = strtol(p, (char **)&r, 0);
if (r == p)
if (r == p) {
error_setg(errp, "port number '%s' is invalid", p);
return -1;
}
saddr->sin_port = htons(port);
return 0;
}

View File

@ -209,7 +209,9 @@ static void net_socket_send_dgram(void *opaque)
}
}
static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr *localaddr)
static int net_socket_mcast_create(struct sockaddr_in *mcastaddr,
struct in_addr *localaddr,
Error **errp)
{
struct ip_mreq imr;
int fd;
@ -221,16 +223,16 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
#endif
if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) "
"does not contain a multicast address\n",
inet_ntoa(mcastaddr->sin_addr),
(int)ntohl(mcastaddr->sin_addr.s_addr));
error_setg(errp, "specified mcastaddr %s (0x%08x) "
"does not contain a multicast address",
inet_ntoa(mcastaddr->sin_addr),
(int)ntohl(mcastaddr->sin_addr.s_addr));
return -1;
}
fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
perror("socket(PF_INET, SOCK_DGRAM)");
error_setg_errno(errp, errno, "can't create datagram socket");
return -1;
}
@ -242,13 +244,15 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
val = 1;
ret = qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
if (ret < 0) {
perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
error_setg_errno(errp, errno,
"can't set socket option SO_REUSEADDR");
goto fail;
}
ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
if (ret < 0) {
perror("bind");
error_setg_errno(errp, errno, "can't bind ip=%s to socket",
inet_ntoa(mcastaddr->sin_addr));
goto fail;
}
@ -263,7 +267,9 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
ret = qemu_setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&imr, sizeof(struct ip_mreq));
if (ret < 0) {
perror("setsockopt(IP_ADD_MEMBERSHIP)");
error_setg_errno(errp, errno,
"can't add socket to multicast group %s",
inet_ntoa(imr.imr_multiaddr));
goto fail;
}
@ -272,7 +278,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
&loop, sizeof(loop));
if (ret < 0) {
perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
error_setg_errno(errp, errno,
"can't force multicast message to loopback");
goto fail;
}
@ -281,7 +288,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
localaddr, sizeof(*localaddr));
if (ret < 0) {
perror("setsockopt(IP_MULTICAST_IF)");
error_setg_errno(errp, errno,
"can't set the default network send interface");
goto fail;
}
}
@ -321,7 +329,8 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
const char *model,
const char *name,
int fd, int is_connected,
const char *mcast)
const char *mcast,
Error **errp)
{
struct sockaddr_in saddr;
int newfd;
@ -334,22 +343,17 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
*/
if (is_connected && mcast != NULL) {
if (parse_host_port(&saddr, mcast) < 0) {
fprintf(stderr,
"qemu: error: init_dgram: fd=%d failed parse_host_port()\n",
fd);
if (parse_host_port(&saddr, mcast, errp) < 0) {
goto err;
}
/* must be bound */
if (saddr.sin_addr.s_addr == 0) {
fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, "
"cannot setup multicast dst addr\n", fd);
error_setg(errp, "can't setup multicast destination address");
goto err;
}
/* clone dgram socket */
newfd = net_socket_mcast_create(&saddr, NULL);
newfd = net_socket_mcast_create(&saddr, NULL, errp);
if (newfd < 0) {
/* error already reported by net_socket_mcast_create() */
goto err;
}
/* clone newfd to fd, close newfd */
@ -431,26 +435,27 @@ static NetSocketState *net_socket_fd_init_stream(NetClientState *peer,
static NetSocketState *net_socket_fd_init(NetClientState *peer,
const char *model, const char *name,
int fd, int is_connected, const char *mc)
int fd, int is_connected,
const char *mc, Error **errp)
{
int so_type = -1, optlen=sizeof(so_type);
if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
(socklen_t *)&optlen)< 0) {
fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n",
fd);
error_setg(errp, "can't get socket option SO_TYPE");
closesocket(fd);
return NULL;
}
switch(so_type) {
case SOCK_DGRAM:
return net_socket_fd_init_dgram(peer, model, name, fd, is_connected, mc);
return net_socket_fd_init_dgram(peer, model, name, fd, is_connected,
mc, errp);
case SOCK_STREAM:
return net_socket_fd_init_stream(peer, model, name, fd, is_connected);
default:
/* who knows ... this could be a eg. a pty, do warn and continue as stream */
fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
return net_socket_fd_init_stream(peer, model, name, fd, is_connected);
error_report("socket type=%d for fd=%d must be either"
" SOCK_DGRAM or SOCK_STREAM", so_type, fd);
closesocket(fd);
}
return NULL;
}
@ -484,19 +489,21 @@ static void net_socket_accept(void *opaque)
static int net_socket_listen_init(NetClientState *peer,
const char *model,
const char *name,
const char *host_str)
const char *host_str,
Error **errp)
{
NetClientState *nc;
NetSocketState *s;
struct sockaddr_in saddr;
int fd, ret;
if (parse_host_port(&saddr, host_str) < 0)
if (parse_host_port(&saddr, host_str, errp) < 0) {
return -1;
}
fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0) {
perror("socket");
error_setg_errno(errp, errno, "can't create stream socket");
return -1;
}
qemu_set_nonblock(fd);
@ -505,13 +512,14 @@ static int net_socket_listen_init(NetClientState *peer,
ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
if (ret < 0) {
perror("bind");
error_setg_errno(errp, errno, "can't bind ip=%s to socket",
inet_ntoa(saddr.sin_addr));
closesocket(fd);
return -1;
}
ret = listen(fd, 0);
if (ret < 0) {
perror("listen");
error_setg_errno(errp, errno, "can't listen on socket");
closesocket(fd);
return -1;
}
@ -530,18 +538,20 @@ static int net_socket_listen_init(NetClientState *peer,
static int net_socket_connect_init(NetClientState *peer,
const char *model,
const char *name,
const char *host_str)
const char *host_str,
Error **errp)
{
NetSocketState *s;
int fd, connected, ret;
struct sockaddr_in saddr;
if (parse_host_port(&saddr, host_str) < 0)
if (parse_host_port(&saddr, host_str, errp) < 0) {
return -1;
}
fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0) {
perror("socket");
error_setg_errno(errp, errno, "can't create stream socket");
return -1;
}
qemu_set_nonblock(fd);
@ -557,7 +567,7 @@ static int net_socket_connect_init(NetClientState *peer,
errno == EINVAL) {
break;
} else {
perror("connect");
error_setg_errno(errp, errno, "can't connect socket");
closesocket(fd);
return -1;
}
@ -566,9 +576,11 @@ static int net_socket_connect_init(NetClientState *peer,
break;
}
}
s = net_socket_fd_init(peer, model, name, fd, connected, NULL);
if (!s)
s = net_socket_fd_init(peer, model, name, fd, connected, NULL, errp);
if (!s) {
return -1;
}
snprintf(s->nc.info_str, sizeof(s->nc.info_str),
"socket: connect to %s:%d",
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
@ -579,31 +591,38 @@ static int net_socket_mcast_init(NetClientState *peer,
const char *model,
const char *name,
const char *host_str,
const char *localaddr_str)
const char *localaddr_str,
Error **errp)
{
NetSocketState *s;
int fd;
struct sockaddr_in saddr;
struct in_addr localaddr, *param_localaddr;
if (parse_host_port(&saddr, host_str) < 0)
if (parse_host_port(&saddr, host_str, errp) < 0) {
return -1;
}
if (localaddr_str != NULL) {
if (inet_aton(localaddr_str, &localaddr) == 0)
if (inet_aton(localaddr_str, &localaddr) == 0) {
error_setg(errp, "localaddr '%s' is not a valid IPv4 address",
localaddr_str);
return -1;
}
param_localaddr = &localaddr;
} else {
param_localaddr = NULL;
}
fd = net_socket_mcast_create(&saddr, param_localaddr);
if (fd < 0)
fd = net_socket_mcast_create(&saddr, param_localaddr, errp);
if (fd < 0) {
return -1;
}
s = net_socket_fd_init(peer, model, name, fd, 0, NULL);
if (!s)
s = net_socket_fd_init(peer, model, name, fd, 0, NULL, errp);
if (!s) {
return -1;
}
s->dgram_dst = saddr;
@ -618,40 +637,44 @@ static int net_socket_udp_init(NetClientState *peer,
const char *model,
const char *name,
const char *rhost,
const char *lhost)
const char *lhost,
Error **errp)
{
NetSocketState *s;
int fd, ret;
struct sockaddr_in laddr, raddr;
if (parse_host_port(&laddr, lhost) < 0) {
if (parse_host_port(&laddr, lhost, errp) < 0) {
return -1;
}
if (parse_host_port(&raddr, rhost) < 0) {
if (parse_host_port(&raddr, rhost, errp) < 0) {
return -1;
}
fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
perror("socket(PF_INET, SOCK_DGRAM)");
error_setg_errno(errp, errno, "can't create datagram socket");
return -1;
}
ret = socket_set_fast_reuse(fd);
if (ret < 0) {
error_setg_errno(errp, errno,
"can't set socket option SO_REUSEADDR");
closesocket(fd);
return -1;
}
ret = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr));
if (ret < 0) {
perror("bind");
error_setg_errno(errp, errno, "can't bind ip=%s to socket",
inet_ntoa(laddr.sin_addr));
closesocket(fd);
return -1;
}
qemu_set_nonblock(fd);
s = net_socket_fd_init(peer, model, name, fd, 0, NULL);
s = net_socket_fd_init(peer, model, name, fd, 0, NULL, errp);
if (!s) {
return -1;
}
@ -667,8 +690,6 @@ static int net_socket_udp_init(NetClientState *peer,
int net_init_socket(const Netdev *netdev, const char *name,
NetClientState *peer, Error **errp)
{
/* FIXME error_setg(errp, ...) on failure */
Error *err = NULL;
const NetdevSocketOptions *sock;
assert(netdev->type == NET_CLIENT_DRIVER_SOCKET);
@ -676,41 +697,42 @@ int net_init_socket(const Netdev *netdev, const char *name,
if (sock->has_listen + sock->has_connect + sock->has_mcast +
sock->has_udp > 1) {
error_report("exactly one of listen=, connect=, mcast= or udp="
" is required");
error_setg(errp, "exactly one of listen=, connect=, mcast= or udp="
" is required");
return -1;
}
if (sock->has_localaddr && !sock->has_mcast && !sock->has_udp) {
error_report("localaddr= is only valid with mcast= or udp=");
error_setg(errp, "localaddr= is only valid with mcast= or udp=");
return -1;
}
if (sock->has_fd) {
int fd;
fd = monitor_fd_param(cur_mon, sock->fd, &err);
fd = monitor_fd_param(cur_mon, sock->fd, errp);
if (fd == -1) {
error_report_err(err);
return -1;
}
qemu_set_nonblock(fd);
if (!net_socket_fd_init(peer, "socket", name, fd, 1, sock->mcast)) {
if (!net_socket_fd_init(peer, "socket", name, fd, 1, sock->mcast,
errp)) {
return -1;
}
return 0;
}
if (sock->has_listen) {
if (net_socket_listen_init(peer, "socket", name, sock->listen) == -1) {
if (net_socket_listen_init(peer, "socket", name, sock->listen, errp)
< 0) {
return -1;
}
return 0;
}
if (sock->has_connect) {
if (net_socket_connect_init(peer, "socket", name, sock->connect) ==
-1) {
if (net_socket_connect_init(peer, "socket", name, sock->connect, errp)
< 0) {
return -1;
}
return 0;
@ -720,7 +742,7 @@ int net_init_socket(const Netdev *netdev, const char *name,
/* if sock->localaddr is missing, it has been initialized to "all bits
* zero" */
if (net_socket_mcast_init(peer, "socket", name, sock->mcast,
sock->localaddr) == -1) {
sock->localaddr, errp) < 0) {
return -1;
}
return 0;
@ -728,11 +750,11 @@ int net_init_socket(const Netdev *netdev, const char *name,
assert(sock->has_udp);
if (!sock->has_localaddr) {
error_report("localaddr= is mandatory with udp=");
error_setg(errp, "localaddr= is mandatory with udp=");
return -1;
}
if (net_socket_udp_init(peer, "socket", name, sock->udp, sock->localaddr) ==
-1) {
if (net_socket_udp_init(peer, "socket", name, sock->udp, sock->localaddr,
errp) < 0) {
return -1;
}
return 0;