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

Version: GnuPG v1
 
 iQEcBAABAgAGBQJW3oNAAAoJEO8Ells5jWIRCNIH/iJ7ZKfnhSxQB4/dJdPNA72N
 V8QA4Ta+FTV0yiEXBgoK1QyCOgs+GsJ8Ip6jBPz3B+tPhYaQl2L7QlqS3fdn73P6
 9MwdzJp4LTB6txOw7YsxCEz3yRSNAfxPsAouIyeYROwuNnD8IOI4XxNTt7cig6Ku
 jm6KTNk5p4dacJD3HIFPzkqw63XkyyGpLzOjJWW7s3ZwafVlPKVLZCTXGIMmHE5L
 USQdR7Le5I9HsrsygdrDaXo1fopKdt56efPVm2lhpL1IJBkR21ixYqcdVGrOKwo2
 KofLtUY/cHvGtluufU0FMih5OCg1q/Pz0NdTv29afWMQ0hiIuB5GhfptRdNdHKI=
 =ozGZ
 -----END PGP SIGNATURE-----

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

# gpg: Signature made Tue 08 Mar 2016 07:46:08 GMT using RSA key ID 398D6211
# 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:
  net: check packet payload length
  filter-buffer: Add status_changed callback processing
  filter: Add 'status' property for filter object
  rocker: allow user to specify rocker world by property
  rocker: add name field into WorldOps ale let world specify its name
  rocker: return -ENOMEM in case of some world alloc fails
  rocker: forbid to change world type
  net: netmap: probe netmap interface for virtio-net header
  net: simplify net_init_tap_one logic
  MAINTAINERS: Add entries for include/net/ files
  net: filter: correctly remove filter from the list during finalization
  net: ne2000: check ring buffer control registers

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2016-03-08 10:25:50 +00:00
commit d1cc881d54
15 changed files with 185 additions and 49 deletions

View File

@ -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

View File

@ -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)

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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,

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
};

View File

@ -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;

View File

@ -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,

View File

@ -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);

View File

@ -323,30 +323,8 @@ 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;
}
static bool netmap_has_vnet_hdr(NetClientState *nc)
{
return true;
}
static bool netmap_has_vnet_hdr_len(NetClientState *nc, int len)
{
return len == 0 || len == sizeof(struct virtio_net_hdr) ||
len == sizeof(struct virtio_net_hdr_mrg_rxbuf);
}
static void netmap_using_vnet_hdr(NetClientState *nc, bool enable)
{
}
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
@ -357,10 +335,50 @@ static void netmap_set_vnet_hdr_len(NetClientState *nc, int len)
req.nr_version = NETMAP_API;
req.nr_cmd = NETMAP_BDG_VNET_HDR;
req.nr_arg1 = len;
err = ioctl(s->nmd->fd, NIOCREGIF, &req);
return ioctl(s->nmd->fd, NIOCREGIF, &req);
}
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;
}
/* 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 netmap_has_vnet_hdr_len(nc, sizeof(struct virtio_net_hdr));
}
static void netmap_using_vnet_hdr(NetClientState *nc, bool enable)
{
}
static void netmap_set_vnet_hdr_len(NetClientState *nc, int len)
{
NetmapState *s = DO_UPCAST(NetmapState, nc, nc);
int err;
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,

View File

@ -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");
}
}

View File

@ -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.