diff options
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, @@ -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 Binary files differindex ec0e642b06..44374e3f57 100644 --- a/tests/acpi-test-data/pc/DSDT +++ b/tests/acpi-test-data/pc/DSDT diff --git a/tests/acpi-test-data/pc/DSDT.bridge b/tests/acpi-test-data/pc/DSDT.bridge Binary files differindex 7b1c14b529..c9a6230983 100644 --- a/tests/acpi-test-data/pc/DSDT.bridge +++ b/tests/acpi-test-data/pc/DSDT.bridge diff --git a/tests/acpi-test-data/q35/DSDT b/tests/acpi-test-data/q35/DSDT Binary files differindex b492f04b88..a90c52a4c3 100644 --- a/tests/acpi-test-data/q35/DSDT +++ b/tests/acpi-test-data/q35/DSDT diff --git a/tests/acpi-test-data/q35/DSDT.bridge b/tests/acpi-test-data/q35/DSDT.bridge Binary files differindex 3b72e250fa..6fd2ef308b 100644 --- a/tests/acpi-test-data/q35/DSDT.bridge +++ b/tests/acpi-test-data/q35/DSDT.bridge |