aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS2
-rw-r--r--backends/rng-egd.c9
-rw-r--r--backends/rng-random.c6
-rw-r--r--backends/rng.c17
-rw-r--r--docs/specs/fw_cfg.txt9
-rw-r--r--hw/arm/virt-acpi-build.c15
-rw-r--r--hw/i386/acpi-build.c29
-rw-r--r--hw/i386/pc.c5
-rw-r--r--hw/net/ne2000.c4
-rw-r--r--hw/net/rocker/rocker.c38
-rw-r--r--hw/net/rocker/rocker_fp.c5
-rw-r--r--hw/net/rocker/rocker_fp.h1
-rw-r--r--hw/net/rocker/rocker_of_dpa.c1
-rw-r--r--hw/net/rocker/rocker_world.c7
-rw-r--r--hw/net/rocker/rocker_world.h1
-rw-r--r--hw/nvram/fw_cfg.c4
-rw-r--r--include/hw/i386/pc.h2
-rw-r--r--include/hw/nvram/fw_cfg.h3
-rw-r--r--include/net/filter.h4
-rw-r--r--include/sysemu/rng.h3
-rw-r--r--net/checksum.c10
-rw-r--r--net/filter-buffer.c34
-rw-r--r--net/filter.c44
-rw-r--r--net/netmap.c59
-rw-r--r--net/tap.c4
-rw-r--r--qemu-options.hx4
-rw-r--r--tests/acpi-test-data/pc/DSDTbin5478 -> 5538 bytes
-rw-r--r--tests/acpi-test-data/pc/DSDT.bridgebin7337 -> 7397 bytes
-rw-r--r--tests/acpi-test-data/q35/DSDTbin8321 -> 8381 bytes
-rw-r--r--tests/acpi-test-data/q35/DSDT.bridgebin8338 -> 8398 bytes
30 files changed, 259 insertions, 61 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 9d0255c72c..c47709d860 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1123,6 +1123,7 @@ Network device backends
M: Jason Wang <jasowang@redhat.com>
S: Maintained
F: net/
+F: include/net/
T: git git://github.com/jasowang/qemu.git net
Netmap network backend
@@ -1222,6 +1223,7 @@ M: Jan Kiszka <jan.kiszka@siemens.com>
S: Maintained
F: slirp/
F: net/slirp.c
+F: include/net/slirp.h
T: git git://git.kiszka.org/qemu.git queues/slirp
Tracing
diff --git a/backends/rng-egd.c b/backends/rng-egd.c
index 30332edb81..6e0ba22241 100644
--- a/backends/rng-egd.c
+++ b/backends/rng-egd.c
@@ -49,11 +49,10 @@ static void rng_egd_request_entropy(RngBackend *b, RngRequest *req)
static int rng_egd_chr_can_read(void *opaque)
{
RngEgd *s = RNG_EGD(opaque);
- GSList *i;
+ RngRequest *req;
int size = 0;
- for (i = s->parent.requests; i; i = i->next) {
- RngRequest *req = i->data;
+ QSIMPLEQ_FOREACH(req, &s->parent.requests, next) {
size += req->size - req->offset;
}
@@ -65,8 +64,8 @@ static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size)
RngEgd *s = RNG_EGD(opaque);
size_t buf_offset = 0;
- while (size > 0 && s->parent.requests) {
- RngRequest *req = s->parent.requests->data;
+ while (size > 0 && !QSIMPLEQ_EMPTY(&s->parent.requests)) {
+ RngRequest *req = QSIMPLEQ_FIRST(&s->parent.requests);
int len = MIN(size, req->size - req->offset);
memcpy(req->data + req->offset, buf + buf_offset, len);
diff --git a/backends/rng-random.c b/backends/rng-random.c
index a6cb3858e3..122e8d494d 100644
--- a/backends/rng-random.c
+++ b/backends/rng-random.c
@@ -35,8 +35,8 @@ static void entropy_available(void *opaque)
{
RndRandom *s = RNG_RANDOM(opaque);
- while (s->parent.requests != NULL) {
- RngRequest *req = s->parent.requests->data;
+ while (!QSIMPLEQ_EMPTY(&s->parent.requests)) {
+ RngRequest *req = QSIMPLEQ_FIRST(&s->parent.requests);
ssize_t len;
len = read(s->fd, req->data, req->size);
@@ -58,7 +58,7 @@ static void rng_random_request_entropy(RngBackend *b, RngRequest *req)
{
RndRandom *s = RNG_RANDOM(b);
- if (s->parent.requests == NULL) {
+ if (QSIMPLEQ_EMPTY(&s->parent.requests)) {
/* If there are no pending requests yet, we need to
* install our fd handler. */
qemu_set_fd_handler(s->fd, entropy_available, NULL, s);
diff --git a/backends/rng.c b/backends/rng.c
index 277a41bb0f..e57e2b4b52 100644
--- a/backends/rng.c
+++ b/backends/rng.c
@@ -33,7 +33,7 @@ void rng_backend_request_entropy(RngBackend *s, size_t size,
k->request_entropy(s, req);
- s->requests = g_slist_append(s->requests, req);
+ QSIMPLEQ_INSERT_TAIL(&s->requests, req, next);
}
}
@@ -83,24 +83,27 @@ static void rng_backend_free_request(RngRequest *req)
static void rng_backend_free_requests(RngBackend *s)
{
- GSList *i;
+ RngRequest *req, *next;
- for (i = s->requests; i; i = i->next) {
- rng_backend_free_request(i->data);
+ QSIMPLEQ_FOREACH_SAFE(req, &s->requests, next, next) {
+ rng_backend_free_request(req);
}
- g_slist_free(s->requests);
- s->requests = NULL;
+ QSIMPLEQ_INIT(&s->requests);
}
void rng_backend_finalize_request(RngBackend *s, RngRequest *req)
{
- s->requests = g_slist_remove(s->requests, req);
+ QSIMPLEQ_REMOVE(&s->requests, req, RngRequest, next);
rng_backend_free_request(req);
}
static void rng_backend_init(Object *obj)
{
+ RngBackend *s = RNG_BACKEND(obj);
+
+ QSIMPLEQ_INIT(&s->requests);
+
object_property_add_bool(obj, "opened",
rng_backend_prop_get_opened,
rng_backend_prop_set_opened,
diff --git a/docs/specs/fw_cfg.txt b/docs/specs/fw_cfg.txt
index 2099ad9a4d..5414140f33 100644
--- a/docs/specs/fw_cfg.txt
+++ b/docs/specs/fw_cfg.txt
@@ -84,6 +84,15 @@ Selector Register address: Base + 8 (2 bytes)
Data Register address: Base + 0 (8 bytes)
DMA Address address: Base + 16 (8 bytes)
+== ACPI Interface ==
+
+The fw_cfg device is defined with ACPI ID "QEMU0002". Since we expect
+ACPI tables to be passed into the guest through the fw_cfg device itself,
+the guest-side firmware can not use ACPI to find fw_cfg. However, once the
+firmware is finished setting up ACPI tables and hands control over to the
+guest kernel, the latter can use the fw_cfg ACPI node for a more accurate
+inventory of in-use IOport or MMIO regions.
+
== Firmware Configuration Items ==
=== Signature (Key 0x0000, FW_CFG_SIGNATURE) ===
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index b8b3ece8ca..6a86b2ca2c 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -81,6 +81,20 @@ static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
aml_append(scope, dev);
}
+static void acpi_dsdt_add_fw_cfg(Aml *scope, const MemMapEntry *fw_cfg_memmap)
+{
+ Aml *dev = aml_device("FWCF");
+ aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002")));
+ /* device present, functioning, decoding, not shown in UI */
+ aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
+
+ Aml *crs = aml_resource_template();
+ aml_append(crs, aml_memory32_fixed(fw_cfg_memmap->base,
+ fw_cfg_memmap->size, AML_READ_WRITE));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(scope, dev);
+}
+
static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap)
{
Aml *dev, *crs;
@@ -549,6 +563,7 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],
(irqmap[VIRT_UART] + ARM_SPI_BASE));
acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
+ acpi_dsdt_add_fw_cfg(scope, &memmap[VIRT_FW_CFG]);
acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],
(irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE),
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 52c9470a54..b888008839 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -2190,6 +2190,35 @@ build_dsdt(GArray *table_data, GArray *linker,
aml_append(scope, aml_name_decl("_S5", pkg));
aml_append(dsdt, scope);
+ /* create fw_cfg node, unconditionally */
+ {
+ /* when using port i/o, the 8-bit data register *always* overlaps
+ * with half of the 16-bit control register. Hence, the total size
+ * of the i/o region used is FW_CFG_CTL_SIZE; when using DMA, the
+ * DMA control register is located at FW_CFG_DMA_IO_BASE + 4 */
+ uint8_t io_size = object_property_get_bool(OBJECT(pcms->fw_cfg),
+ "dma_enabled", NULL) ?
+ ROUND_UP(FW_CFG_CTL_SIZE, 4) + sizeof(dma_addr_t) :
+ FW_CFG_CTL_SIZE;
+
+ scope = aml_scope("\\_SB.PCI0");
+ dev = aml_device("FWCF");
+
+ aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002")));
+
+ /* device present, functioning, decoding, not shown in UI */
+ aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
+
+ crs = aml_resource_template();
+ aml_append(crs,
+ aml_io(AML_DECODE16, FW_CFG_IO_BASE, FW_CFG_IO_BASE, 0x01, io_size)
+ );
+ aml_append(dev, aml_name_decl("_CRS", crs));
+
+ aml_append(scope, dev);
+ aml_append(dsdt, scope);
+ }
+
if (misc->applesmc_io_base) {
scope = aml_scope("\\_SB.PCI0.ISA");
dev = aml_device("SMC");
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 0aeefd2c0d..56ec6cd6c6 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -78,7 +78,6 @@
#define DPRINTF(fmt, ...)
#endif
-#define BIOS_CFG_IOPORT 0x510
#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
@@ -756,7 +755,7 @@ static FWCfgState *bochs_bios_init(AddressSpace *as)
int i, j;
unsigned int apic_id_limit = pc_apic_id_limit(max_cpus);
- fw_cfg = fw_cfg_init_io_dma(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 4, as);
+ fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as);
/* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
*
@@ -1258,7 +1257,7 @@ void xen_load_linux(PCMachineState *pcms)
assert(MACHINE(pcms)->kernel_filename != NULL);
- fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT);
+ fw_cfg = fw_cfg_init_io(FW_CFG_IO_BASE);
rom_set_fw(fw_cfg);
load_linux(pcms, fw_cfg);
diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c
index e408083a58..f0feaf96b0 100644
--- a/hw/net/ne2000.c
+++ b/hw/net/ne2000.c
@@ -155,6 +155,10 @@ static int ne2000_buffer_full(NE2000State *s)
{
int avail, index, boundary;
+ if (s->stop <= s->start) {
+ return 1;
+ }
+
index = s->curpag << 8;
boundary = s->boundary << 8;
if (index < boundary)
diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c
index f3e994d563..30f2ce417b 100644
--- a/hw/net/rocker/rocker.c
+++ b/hw/net/rocker/rocker.c
@@ -43,6 +43,7 @@ struct rocker {
/* switch configuration */
char *name; /* switch name */
+ char *world_name; /* world name */
uint32_t fp_ports; /* front-panel port count */
NICPeers *fp_ports_peers;
MACAddr fp_start_macaddr; /* front-panel port 0 mac addr */
@@ -400,7 +401,13 @@ static int cmd_set_port_settings(Rocker *r,
if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]) {
mode = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]);
- fp_port_set_world(fp_port, r->worlds[mode]);
+ if (mode >= ROCKER_WORLD_TYPE_MAX) {
+ return -ROCKER_EINVAL;
+ }
+ /* We don't support world change. */
+ if (!fp_port_check_world(fp_port, r->worlds[mode])) {
+ return -ROCKER_EINVAL;
+ }
}
if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING]) {
@@ -1280,6 +1287,18 @@ static void rocker_msix_uninit(Rocker *r)
rocker_msix_vectors_unuse(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports));
}
+static World *rocker_world_type_by_name(Rocker *r, const char *name)
+{
+ int i;
+
+ for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
+ if (strcmp(name, world_name(r->worlds[i])) == 0) {
+ return r->worlds[i];
+ }
+ }
+ return NULL;
+}
+
static int pci_rocker_init(PCIDevice *dev)
{
Rocker *r = to_rocker(dev);
@@ -1291,14 +1310,27 @@ static int pci_rocker_init(PCIDevice *dev)
/* allocate worlds */
r->worlds[ROCKER_WORLD_TYPE_OF_DPA] = of_dpa_world_alloc(r);
- r->world_dflt = r->worlds[ROCKER_WORLD_TYPE_OF_DPA];
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",
+ r->world_name);
+ err = -EINVAL;
+ goto err_world_type_by_name;
+ }
+
/* set up memory-mapped region at BAR0 */
memory_region_init_io(&r->mmio, OBJECT(r), &rocker_mmio_ops, r,
@@ -1432,6 +1464,7 @@ err_duplicate:
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]) {
@@ -1503,6 +1536,7 @@ static void rocker_reset(DeviceState *dev)
static Property rocker_properties[] = {
DEFINE_PROP_STRING("name", Rocker, name),
+ DEFINE_PROP_STRING("world", Rocker, world_name),
DEFINE_PROP_MACADDR("fp_start_macaddr", Rocker,
fp_start_macaddr),
DEFINE_PROP_UINT64("switch_id", Rocker,
diff --git a/hw/net/rocker/rocker_fp.c b/hw/net/rocker/rocker_fp.c
index af37fefc0a..0149899c62 100644
--- a/hw/net/rocker/rocker_fp.c
+++ b/hw/net/rocker/rocker_fp.c
@@ -186,6 +186,11 @@ void fp_port_set_world(FpPort *port, World *world)
port->world = world;
}
+bool fp_port_check_world(FpPort *port, World *world)
+{
+ return port->world == world;
+}
+
bool fp_port_enabled(FpPort *port)
{
return port->enabled;
diff --git a/hw/net/rocker/rocker_fp.h b/hw/net/rocker/rocker_fp.h
index ab80fd833c..04592bbfd2 100644
--- a/hw/net/rocker/rocker_fp.h
+++ b/hw/net/rocker/rocker_fp.h
@@ -40,6 +40,7 @@ int fp_port_set_settings(FpPort *port, uint32_t speed,
bool fp_port_from_pport(uint32_t pport, uint32_t *port);
World *fp_port_get_world(FpPort *port);
void fp_port_set_world(FpPort *port, World *world);
+bool fp_port_check_world(FpPort *port, World *world);
bool fp_port_enabled(FpPort *port);
void fp_port_enable(FpPort *port);
void fp_port_disable(FpPort *port);
diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c
index da3fc541d8..0a134ebca8 100644
--- a/hw/net/rocker/rocker_of_dpa.c
+++ b/hw/net/rocker/rocker_of_dpa.c
@@ -2614,6 +2614,7 @@ RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name,
}
static WorldOps of_dpa_ops = {
+ .name = "ofdpa",
.init = of_dpa_init,
.uninit = of_dpa_uninit,
.ig = of_dpa_ig,
diff --git a/hw/net/rocker/rocker_world.c b/hw/net/rocker/rocker_world.c
index 1ed0fcd163..89777e9684 100644
--- a/hw/net/rocker/rocker_world.c
+++ b/hw/net/rocker/rocker_world.c
@@ -98,10 +98,5 @@ enum rocker_world_type world_type(World *world)
const char *world_name(World *world)
{
- switch (world->type) {
- case ROCKER_WORLD_TYPE_OF_DPA:
- return "OF_DPA";
- default:
- return "unknown";
- }
+ return world->ops->name;
}
diff --git a/hw/net/rocker/rocker_world.h b/hw/net/rocker/rocker_world.h
index 18d277b927..58ade47335 100644
--- a/hw/net/rocker/rocker_world.h
+++ b/hw/net/rocker/rocker_world.h
@@ -33,6 +33,7 @@ typedef int (world_cmd)(World *world, DescInfo *info,
RockerTlv *cmd_info_tlv);
typedef struct world_ops {
+ const char *name;
world_init *init;
world_uninit *uninit;
world_ig *ig;
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index f3acb47bd4..7866248b93 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -32,7 +32,6 @@
#include "qemu/error-report.h"
#include "qemu/config-file.h"
-#define FW_CFG_CTL_SIZE 2
#define FW_CFG_NAME "fw_cfg"
#define FW_CFG_PATH "/machine/" FW_CFG_NAME
@@ -886,6 +885,9 @@ static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
FWCfgIoState *s = FW_CFG_IO(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ /* when using port i/o, the 8-bit data register ALWAYS overlaps
+ * with half of the 16-bit control register. Hence, the total size
+ * of the i/o region used is FW_CFG_CTL_SIZE */
memory_region_init_io(&s->comb_iomem, OBJECT(s), &fw_cfg_comb_mem_ops,
FW_CFG(s), "fwcfg", FW_CFG_CTL_SIZE);
sysbus_add_io(sbd, s->iobase, &s->comb_iomem);
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 8b3546ed5c..79ffe5b3ee 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -266,6 +266,8 @@ void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name);
ISADevice *pc_find_fdc0(void);
+#define FW_CFG_IO_BASE 0x510
+
/* acpi_piix.c */
I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
index 5d19975df5..4315f4e582 100644
--- a/include/hw/nvram/fw_cfg.h
+++ b/include/hw/nvram/fw_cfg.h
@@ -44,6 +44,9 @@
#define FW_CFG_INVALID 0xffff
+/* width in bytes of fw_cfg control register */
+#define FW_CFG_CTL_SIZE 0x02
+
#define FW_CFG_MAX_FILE_PATH 56
#ifndef NO_QEMU_PROTOS
diff --git a/include/net/filter.h b/include/net/filter.h
index 56399763cc..cfb11728df 100644
--- a/include/net/filter.h
+++ b/include/net/filter.h
@@ -36,12 +36,15 @@ typedef ssize_t (FilterReceiveIOV)(NetFilterState *nc,
int iovcnt,
NetPacketSent *sent_cb);
+typedef void (FilterStatusChanged) (NetFilterState *nf, Error **errp);
+
typedef struct NetFilterClass {
ObjectClass parent_class;
/* optional */
FilterSetup *setup;
FilterCleanup *cleanup;
+ FilterStatusChanged *status_changed;
/* mandatory */
FilterReceiveIOV *receive_iov;
} NetFilterClass;
@@ -55,6 +58,7 @@ struct NetFilterState {
char *netdev_id;
NetClientState *netdev;
NetFilterDirection direction;
+ bool on;
QTAILQ_ENTRY(NetFilterState) next;
};
diff --git a/include/sysemu/rng.h b/include/sysemu/rng.h
index 4fffd681a6..45629c4c53 100644
--- a/include/sysemu/rng.h
+++ b/include/sysemu/rng.h
@@ -39,6 +39,7 @@ struct RngRequest
void *opaque;
size_t offset;
size_t size;
+ QSIMPLEQ_ENTRY(RngRequest) next;
};
struct RngBackendClass
@@ -56,7 +57,7 @@ struct RngBackend
/*< protected >*/
bool opened;
- GSList *requests;
+ QSIMPLEQ_HEAD(requests, RngRequest) requests;
};
diff --git a/net/checksum.c b/net/checksum.c
index b5016ab40c..d0fa424cc1 100644
--- a/net/checksum.c
+++ b/net/checksum.c
@@ -60,6 +60,11 @@ void net_checksum_calculate(uint8_t *data, int length)
int hlen, plen, proto, csum_offset;
uint16_t csum;
+ /* Ensure data has complete L2 & L3 headers. */
+ if (length < 14 + 20) {
+ return;
+ }
+
if ((data[14] & 0xf0) != 0x40)
return; /* not IPv4 */
hlen = (data[14] & 0x0f) * 4;
@@ -77,8 +82,9 @@ void net_checksum_calculate(uint8_t *data, int length)
return;
}
- if (plen < csum_offset+2)
- return;
+ if (plen < csum_offset + 2 || 14 + hlen + plen > length) {
+ return;
+ }
data[14+hlen+csum_offset] = 0;
data[14+hlen+csum_offset+1] = 0;
diff --git a/net/filter-buffer.c b/net/filter-buffer.c
index 12ad2e30d4..972177b453 100644
--- a/net/filter-buffer.c
+++ b/net/filter-buffer.c
@@ -100,6 +100,19 @@ static void filter_buffer_cleanup(NetFilterState *nf)
}
}
+static void filter_buffer_setup_timer(NetFilterState *nf)
+{
+ FilterBufferState *s = FILTER_BUFFER(nf);
+
+ if (s->interval) {
+ timer_init_us(&s->release_timer, QEMU_CLOCK_VIRTUAL,
+ filter_buffer_release_timer, nf);
+ /* Timer armed to fire in s->interval microseconds. */
+ timer_mod(&s->release_timer,
+ qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + s->interval);
+ }
+}
+
static void filter_buffer_setup(NetFilterState *nf, Error **errp)
{
FilterBufferState *s = FILTER_BUFFER(nf);
@@ -115,12 +128,20 @@ static void filter_buffer_setup(NetFilterState *nf, Error **errp)
}
s->incoming_queue = qemu_new_net_queue(qemu_netfilter_pass_to_next, nf);
- if (s->interval) {
- timer_init_us(&s->release_timer, QEMU_CLOCK_VIRTUAL,
- filter_buffer_release_timer, nf);
- /* Timer armed to fire in s->interval microseconds. */
- timer_mod(&s->release_timer,
- qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + s->interval);
+ filter_buffer_setup_timer(nf);
+}
+
+static void filter_buffer_status_changed(NetFilterState *nf, Error **errp)
+{
+ FilterBufferState *s = FILTER_BUFFER(nf);
+
+ if (!nf->on) {
+ if (s->interval) {
+ timer_del(&s->release_timer);
+ }
+ filter_buffer_flush(nf);
+ } else {
+ filter_buffer_setup_timer(nf);
}
}
@@ -131,6 +152,7 @@ static void filter_buffer_class_init(ObjectClass *oc, void *data)
nfc->setup = filter_buffer_setup;
nfc->cleanup = filter_buffer_cleanup;
nfc->receive_iov = filter_buffer_receive_iov;
+ nfc->status_changed = filter_buffer_status_changed;
}
static void filter_buffer_get_interval(Object *obj, Visitor *v,
diff --git a/net/filter.c b/net/filter.c
index d2a514eb8d..a08ef68ae6 100644
--- a/net/filter.c
+++ b/net/filter.c
@@ -17,6 +17,11 @@
#include "qom/object_interfaces.h"
#include "qemu/iov.h"
+static inline bool qemu_can_skip_netfilter(NetFilterState *nf)
+{
+ return !nf->on;
+}
+
ssize_t qemu_netfilter_receive(NetFilterState *nf,
NetFilterDirection direction,
NetClientState *sender,
@@ -25,6 +30,9 @@ ssize_t qemu_netfilter_receive(NetFilterState *nf,
int iovcnt,
NetPacketSent *sent_cb)
{
+ if (qemu_can_skip_netfilter(nf)) {
+ return 0;
+ }
if (nf->direction == direction ||
nf->direction == NET_FILTER_DIRECTION_ALL) {
return NETFILTER_GET_CLASS(OBJECT(nf))->receive_iov(
@@ -134,8 +142,38 @@ static void netfilter_set_direction(Object *obj, int direction, Error **errp)
nf->direction = direction;
}
+static char *netfilter_get_status(Object *obj, Error **errp)
+{
+ NetFilterState *nf = NETFILTER(obj);
+
+ return nf->on ? g_strdup("on") : g_strdup("off");
+}
+
+static void netfilter_set_status(Object *obj, const char *str, Error **errp)
+{
+ NetFilterState *nf = NETFILTER(obj);
+ NetFilterClass *nfc = NETFILTER_GET_CLASS(obj);
+
+ if (strcmp(str, "on") && strcmp(str, "off")) {
+ error_setg(errp, "Invalid value for netfilter status, "
+ "should be 'on' or 'off'");
+ return;
+ }
+ if (nf->on == !strcmp(str, "on")) {
+ return;
+ }
+ nf->on = !nf->on;
+ if (nfc->status_changed) {
+ nfc->status_changed(nf, errp);
+ }
+}
+
static void netfilter_init(Object *obj)
{
+ NetFilterState *nf = NETFILTER(obj);
+
+ nf->on = true;
+
object_property_add_str(obj, "netdev",
netfilter_get_netdev_id, netfilter_set_netdev_id,
NULL);
@@ -143,6 +181,9 @@ static void netfilter_init(Object *obj)
NetFilterDirection_lookup,
netfilter_get_direction, netfilter_set_direction,
NULL);
+ object_property_add_str(obj, "status",
+ netfilter_get_status, netfilter_set_status,
+ NULL);
}
static void netfilter_complete(UserCreatable *uc, Error **errp)
@@ -196,7 +237,8 @@ static void netfilter_finalize(Object *obj)
nfc->cleanup(nf);
}
- if (nf->netdev && !QTAILQ_EMPTY(&nf->netdev->filters)) {
+ if (nf->netdev && !QTAILQ_EMPTY(&nf->netdev->filters) &&
+ nf->next.tqe_prev) {
QTAILQ_REMOVE(&nf->netdev->filters, nf, next);
}
g_free(nf->netdev_id);
diff --git a/net/netmap.c b/net/netmap.c
index 971032120c..1b427287a7 100644
--- a/net/netmap.c
+++ b/net/netmap.c
@@ -323,20 +323,47 @@ static void netmap_cleanup(NetClientState *nc)
}
/* Offloading manipulation support callbacks. */
-static bool netmap_has_ufo(NetClientState *nc)
+static int netmap_fd_set_vnet_hdr_len(NetmapState *s, int len)
{
- return true;
+ struct nmreq req;
+
+ /* Issue a NETMAP_BDG_VNET_HDR command to change the virtio-net header
+ * length for the netmap adapter associated to 's->ifname'.
+ */
+ memset(&req, 0, sizeof(req));
+ pstrcpy(req.nr_name, sizeof(req.nr_name), s->ifname);
+ req.nr_version = NETMAP_API;
+ req.nr_cmd = NETMAP_BDG_VNET_HDR;
+ req.nr_arg1 = len;
+
+ return ioctl(s->nmd->fd, NIOCREGIF, &req);
}
-static bool netmap_has_vnet_hdr(NetClientState *nc)
+static bool netmap_has_vnet_hdr_len(NetClientState *nc, int len)
{
+ NetmapState *s = DO_UPCAST(NetmapState, nc, nc);
+ int prev_len = s->vnet_hdr_len;
+
+ /* Check that we can set the new length. */
+ if (netmap_fd_set_vnet_hdr_len(s, len)) {
+ return false;
+ }
+
+ /* Restore the previous length. */
+ if (netmap_fd_set_vnet_hdr_len(s, prev_len)) {
+ error_report("Failed to restore vnet-hdr length %d on %s: %s",
+ prev_len, s->ifname, strerror(errno));
+ abort();
+ }
+
return true;
}
-static bool netmap_has_vnet_hdr_len(NetClientState *nc, int len)
+/* A netmap interface that supports virtio-net headers always
+ * supports UFO, so we use this callback also for the has_ufo hook. */
+static bool netmap_has_vnet_hdr(NetClientState *nc)
{
- return len == 0 || len == sizeof(struct virtio_net_hdr) ||
- len == sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ return netmap_has_vnet_hdr_len(nc, sizeof(struct virtio_net_hdr));
}
static void netmap_using_vnet_hdr(NetClientState *nc, bool enable)
@@ -347,20 +374,11 @@ static void netmap_set_vnet_hdr_len(NetClientState *nc, int len)
{
NetmapState *s = DO_UPCAST(NetmapState, nc, nc);
int err;
- struct nmreq req;
- /* Issue a NETMAP_BDG_VNET_HDR command to change the virtio-net header
- * length for the netmap adapter associated to 's->ifname'.
- */
- memset(&req, 0, sizeof(req));
- pstrcpy(req.nr_name, sizeof(req.nr_name), s->ifname);
- req.nr_version = NETMAP_API;
- req.nr_cmd = NETMAP_BDG_VNET_HDR;
- req.nr_arg1 = len;
- err = ioctl(s->nmd->fd, NIOCREGIF, &req);
+ err = netmap_fd_set_vnet_hdr_len(s, len);
if (err) {
- error_report("Unable to execute NETMAP_BDG_VNET_HDR on %s: %s",
- s->ifname, strerror(errno));
+ error_report("Unable to set vnet-hdr length %d on %s: %s",
+ len, s->ifname, strerror(errno));
} else {
/* Keep track of the current length. */
s->vnet_hdr_len = len;
@@ -373,8 +391,7 @@ static void netmap_set_offload(NetClientState *nc, int csum, int tso4, int tso6,
NetmapState *s = DO_UPCAST(NetmapState, nc, nc);
/* Setting a virtio-net header length greater than zero automatically
- * enables the offloadings.
- */
+ * enables the offloadings. */
if (!s->vnet_hdr_len) {
netmap_set_vnet_hdr_len(nc, sizeof(struct virtio_net_hdr));
}
@@ -388,7 +405,7 @@ static NetClientInfo net_netmap_info = {
.receive_iov = netmap_receive_iov,
.poll = netmap_poll,
.cleanup = netmap_cleanup,
- .has_ufo = netmap_has_ufo,
+ .has_ufo = netmap_has_vnet_hdr,
.has_vnet_hdr = netmap_has_vnet_hdr,
.has_vnet_hdr_len = netmap_has_vnet_hdr_len,
.using_vnet_hdr = netmap_using_vnet_hdr,
diff --git a/net/tap.c b/net/tap.c
index cfb6831988..cd7a7fc860 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -662,7 +662,7 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
options.backend_type = VHOST_BACKEND_TYPE_KERNEL;
options.net_backend = &s->nc;
- if (tap->has_vhostfd || tap->has_vhostfds) {
+ if (vhostfdname) {
vhostfd = monitor_fd_param(cur_mon, vhostfdname, &err);
if (vhostfd == -1) {
error_propagate(errp, err);
@@ -684,7 +684,7 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
"vhost-net requested but could not be initialized");
return;
}
- } else if (tap->has_vhostfd || tap->has_vhostfds) {
+ } else if (vhostfdname) {
error_setg(errp, "vhostfd= is not valid without vhost");
}
}
diff --git a/qemu-options.hx b/qemu-options.hx
index 2aa6577c14..2b3ed86849 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3788,11 +3788,13 @@ version by providing the @var{passwordid} parameter. This provides
the ID of a previously created @code{secret} object containing the
password for decryption.
-@item -object filter-buffer,id=@var{id},netdev=@var{netdevid},interval=@var{t}[,queue=@var{all|rx|tx}]
+@item -object filter-buffer,id=@var{id},netdev=@var{netdevid},interval=@var{t}[,queue=@var{all|rx|tx}][,status=@var{on|off}]
Interval @var{t} can't be 0, this filter batches the packet delivery: all
packets arriving in a given interval on netdev @var{netdevid} are delayed
until the end of the interval. Interval is in microseconds.
+@option{status} is optional that indicate whether the netfilter is
+on (enabled) or off (disabled), the default status for netfilter will be 'on'.
queue @var{all|rx|tx} is an option that can be applied to any netfilter.
diff --git a/tests/acpi-test-data/pc/DSDT b/tests/acpi-test-data/pc/DSDT
index ec0e642b06..44374e3f57 100644
--- a/tests/acpi-test-data/pc/DSDT
+++ b/tests/acpi-test-data/pc/DSDT
Binary files differ
diff --git a/tests/acpi-test-data/pc/DSDT.bridge b/tests/acpi-test-data/pc/DSDT.bridge
index 7b1c14b529..c9a6230983 100644
--- a/tests/acpi-test-data/pc/DSDT.bridge
+++ b/tests/acpi-test-data/pc/DSDT.bridge
Binary files differ
diff --git a/tests/acpi-test-data/q35/DSDT b/tests/acpi-test-data/q35/DSDT
index b492f04b88..a90c52a4c3 100644
--- a/tests/acpi-test-data/q35/DSDT
+++ b/tests/acpi-test-data/q35/DSDT
Binary files differ
diff --git a/tests/acpi-test-data/q35/DSDT.bridge b/tests/acpi-test-data/q35/DSDT.bridge
index 3b72e250fa..6fd2ef308b 100644
--- a/tests/acpi-test-data/q35/DSDT.bridge
+++ b/tests/acpi-test-data/q35/DSDT.bridge
Binary files differ