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

Version: GnuPG v1
 
 iQEcBAABAgAGBQJVetcwAAoJEJykq7OBq3PI+84IAMfkE0uCXdUbp3jZP9iVx68y
 ZtHbhpnZle3bmVFBkgsF8vHWsMlxMZzr2PpAl02VXrrE6z0ScTz+GmVU2V89Y5nv
 kn9DhAR4gcyKbKKgRtwjCLMoCfxsdaHTOJXfcHhsiqQP4PwdFkV6bQAymwcJegY/
 ze5wKX8XqIML6yUCnhrN41pjt6NkIQoyRneLwX5ymeRLfWg23i9YOVU4Njmm9X52
 kH7Xg0UuT6HTyyNER7iqwh61gQ33ETkfWd9UrHFGi7q70UJAr+cVXtzJjqnh08OU
 BExph/lQfxXuivpiThvjZkPvMVqISyCrsIAXrwjhXnjqwz/3nt3i6zrfvPNNPG0=
 =VdKf
 -----END PGP SIGNATURE-----

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

# gpg: Signature made Fri Jun 12 13:57:20 2015 BST using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg:                 aka "Stefan Hajnoczi <stefanha@gmail.com>"

* remotes/stefanha/tags/net-pull-request:
  qmp/hmp: add rocker device support
  rocker: bring link up/down on PHY enable/disable
  rocker: update tests using hw-derived interface names
  rocker: Add support for phys name
  iohandler: Change return type of qemu_set_fd_handler to "void"
  event-notifier: Always return 0 for posix implementation
  xen_backend: Remove unused error handling of qemu_set_fd_handler
  oss: Remove unused error handling of qemu_set_fd_handler
  alsaaudio: Remove unused error handling of qemu_set_fd_handler
  main-loop: Drop qemu_set_fd_handler2
  Change qemu_set_fd_handler2(..., NULL, ...) to qemu_set_fd_handler
  tap: Drop tap_can_send
  net/socket: Drop net_socket_can_send
  netmap: Drop netmap_can_send
  l2tpv3: Drop l2tpv3_can_send
  stubs: Add qemu_set_fd_handler

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-06-12 15:39:05 +01:00
commit 0a2df857a7
44 changed files with 1364 additions and 277 deletions

View file

@ -39,3 +39,4 @@ obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \
common-obj-$(CONFIG_ROCKER) += rocker/rocker.o rocker/rocker_fp.o \
rocker/rocker_desc.o rocker/rocker_world.o \
rocker/rocker_of_dpa.o
obj-$(call lnot,$(CONFIG_ROCKER)) += rocker/qmp-norocker.o

View file

@ -0,0 +1,50 @@
/*
* QMP Target options - Commands handled based on a target config
* versus a host config
*
* Copyright (c) 2015 David Ahern <dsahern@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "qemu-common.h"
#include "qmp-commands.h"
#include "qapi/qmp/qerror.h"
RockerSwitch *qmp_query_rocker(const char *name, Error **errp)
{
error_set(errp, QERR_FEATURE_DISABLED, "rocker");
return NULL;
};
RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
{
error_set(errp, QERR_FEATURE_DISABLED, "rocker");
return NULL;
};
RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name,
bool has_tbl_id,
uint32_t tbl_id,
Error **errp)
{
error_set(errp, QERR_FEATURE_DISABLED, "rocker");
return NULL;
};
RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name,
bool has_type,
uint8_t type,
Error **errp)
{
error_set(errp, QERR_FEATURE_DISABLED, "rocker");
return NULL;
};

View file

@ -94,6 +94,51 @@ World *rocker_get_world(Rocker *r, enum rocker_world_type type)
return NULL;
}
RockerSwitch *qmp_query_rocker(const char *name, Error **errp)
{
RockerSwitch *rocker = g_malloc0(sizeof(*rocker));
Rocker *r;
r = rocker_find(name);
if (!r) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
"rocker %s not found", name);
return NULL;
}
rocker->name = g_strdup(r->name);
rocker->id = r->switch_id;
rocker->ports = r->fp_ports;
return rocker;
}
RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
{
RockerPortList *list = NULL;
Rocker *r;
int i;
r = rocker_find(name);
if (!r) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
"rocker %s not found", name);
return NULL;
}
for (i = r->fp_ports - 1; i >= 0; i--) {
RockerPortList *info = g_malloc0(sizeof(*info));
info->value = g_malloc0(sizeof(*info->value));
struct fp_port *port = r->fp_port[i];
fp_port_get_info(port, info);
info->next = list;
list = info;
}
return list;
}
uint32_t rocker_fp_ports(Rocker *r)
{
return r->fp_ports;
@ -238,6 +283,7 @@ static int cmd_get_port_settings(Rocker *r,
uint8_t duplex;
uint8_t autoneg;
uint8_t learning;
char *phys_name;
MACAddr macaddr;
enum rocker_world_type mode;
size_t tlv_size;
@ -265,6 +311,7 @@ static int cmd_get_port_settings(Rocker *r,
fp_port_get_macaddr(fp_port, &macaddr);
mode = world_type(fp_port_get_world(fp_port));
learning = fp_port_get_learning(fp_port);
phys_name = fp_port_get_name(fp_port);
tlv_size = rocker_tlv_total_size(0) + /* nest */
rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */
@ -273,7 +320,8 @@ static int cmd_get_port_settings(Rocker *r,
rocker_tlv_total_size(sizeof(uint8_t)) + /* autoneg */
rocker_tlv_total_size(sizeof(macaddr.a)) + /* macaddr */
rocker_tlv_total_size(sizeof(uint8_t)) + /* mode */
rocker_tlv_total_size(sizeof(uint8_t)); /* learning */
rocker_tlv_total_size(sizeof(uint8_t)) + /* learning */
rocker_tlv_total_size(strlen(phys_name));
if (tlv_size > desc_buf_size(info)) {
return -ROCKER_EMSGSIZE;
@ -290,6 +338,8 @@ static int cmd_get_port_settings(Rocker *r,
rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MODE, mode);
rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING,
learning);
rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME,
strlen(phys_name), phys_name);
rocker_tlv_nest_end(buf, &pos, nest);
return desc_set_buf(info, tlv_size);
@ -1277,6 +1327,22 @@ static int pci_rocker_init(PCIDevice *dev)
goto err_duplicate;
}
/* Rocker name is passed in port name requests to OS with the intention
* that the name is used in interface names. Limit the length of the
* rocker name to avoid naming problems in the OS. Also, adding the
* port number as p# and unganged breakout b#, where # is at most 2
* digits, so leave room for it too (-1 for string terminator, -3 for
* p# and -3 for b#)
*/
#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",
MAX_ROCKER_NAME_LEN);
return -EINVAL;
}
if (memcmp(&r->fp_start_macaddr, &zero, sizeof(zero)) == 0) {
memcpy(&r->fp_start_macaddr, &dflt, sizeof(dflt));
r->fp_start_macaddr.a[4] += (sw_index++);

View file

@ -41,11 +41,26 @@ struct fp_port {
NICConf conf;
};
char *fp_port_get_name(FpPort *port)
{
return port->name;
}
bool fp_port_get_link_up(FpPort *port)
{
return !qemu_get_queue(port->nic)->link_down;
}
void fp_port_get_info(FpPort *port, RockerPortList *info)
{
info->value->name = g_strdup(port->name);
info->value->enabled = port->enabled;
info->value->link_up = fp_port_get_link_up(port);
info->value->speed = port->speed;
info->value->duplex = port->duplex;
info->value->autoneg = port->autoneg;
}
void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr)
{
memcpy(macaddr->a, port->conf.macaddr.a, sizeof(macaddr->a));
@ -173,8 +188,19 @@ bool fp_port_enabled(FpPort *port)
return port->enabled;
}
static void fp_port_set_link(FpPort *port, bool up)
{
NetClientState *nc = qemu_get_queue(port->nic);
if (up == nc->link_down) {
nc->link_down = !up;
nc->info->link_status_changed(nc);
}
}
void fp_port_enable(FpPort *port)
{
fp_port_set_link(port, true);
port->enabled = true;
DPRINTF("port %d enabled\n", port->index);
}
@ -182,6 +208,7 @@ void fp_port_enable(FpPort *port)
void fp_port_disable(FpPort *port)
{
port->enabled = false;
fp_port_set_link(port, false);
DPRINTF("port %d disabled\n", port->index);
}
@ -201,7 +228,7 @@ FpPort *fp_port_alloc(Rocker *r, char *sw_name,
/* front-panel switch port names are 1-based */
port->name = g_strdup_printf("%s.%d", sw_name, port->pport);
port->name = g_strdup_printf("%sp%d", sw_name, port->pport);
memcpy(port->conf.macaddr.a, start_mac, sizeof(port->conf.macaddr.a));
port->conf.macaddr.a[5] += index;

View file

@ -26,7 +26,9 @@ typedef struct fp_port FpPort;
int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt);
char *fp_port_get_name(FpPort *port);
bool fp_port_get_link_up(FpPort *port);
void fp_port_get_info(FpPort *port, RockerPortList *info);
void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr);
void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr);
uint8_t fp_port_get_learning(FpPort *port);

View file

@ -179,6 +179,7 @@ enum {
ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR, /* binary */
ROCKER_TLV_CMD_PORT_SETTINGS_MODE, /* u8 */
ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING, /* u8 */
ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME, /* binary */
__ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
ROCKER_TLV_CMD_PORT_SETTINGS_MAX = __ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1,

View file

@ -2302,6 +2302,318 @@ static void of_dpa_uninit(World *world)
g_hash_table_destroy(of_dpa->flow_tbl);
}
struct of_dpa_flow_fill_context {
RockerOfDpaFlowList *list;
uint32_t tbl_id;
};
static void of_dpa_flow_fill(void *cookie, void *value, void *user_data)
{
struct of_dpa_flow *flow = value;
struct of_dpa_flow_key *key = &flow->key;
struct of_dpa_flow_key *mask = &flow->mask;
struct of_dpa_flow_fill_context *flow_context = user_data;
RockerOfDpaFlowList *new;
RockerOfDpaFlow *nflow;
RockerOfDpaFlowKey *nkey;
RockerOfDpaFlowMask *nmask;
RockerOfDpaFlowAction *naction;
if (flow_context->tbl_id != -1 &&
flow_context->tbl_id != key->tbl_id) {
return;
}
new = g_malloc0(sizeof(*new));
nflow = new->value = g_malloc0(sizeof(*nflow));
nkey = nflow->key = g_malloc0(sizeof(*nkey));
nmask = nflow->mask = g_malloc0(sizeof(*nmask));
naction = nflow->action = g_malloc0(sizeof(*naction));
nflow->cookie = flow->cookie;
nflow->hits = flow->stats.hits;
nkey->priority = flow->priority;
nkey->tbl_id = key->tbl_id;
if (key->in_pport || mask->in_pport) {
nkey->has_in_pport = true;
nkey->in_pport = key->in_pport;
}
if (nkey->has_in_pport && mask->in_pport != 0xffffffff) {
nmask->has_in_pport = true;
nmask->in_pport = mask->in_pport;
}
if (key->eth.vlan_id || mask->eth.vlan_id) {
nkey->has_vlan_id = true;
nkey->vlan_id = ntohs(key->eth.vlan_id);
}
if (nkey->has_vlan_id && mask->eth.vlan_id != 0xffff) {
nmask->has_vlan_id = true;
nmask->vlan_id = ntohs(mask->eth.vlan_id);
}
if (key->tunnel_id || mask->tunnel_id) {
nkey->has_tunnel_id = true;
nkey->tunnel_id = key->tunnel_id;
}
if (nkey->has_tunnel_id && mask->tunnel_id != 0xffffffff) {
nmask->has_tunnel_id = true;
nmask->tunnel_id = mask->tunnel_id;
}
if (memcmp(key->eth.src.a, zero_mac.a, ETH_ALEN) ||
memcmp(mask->eth.src.a, zero_mac.a, ETH_ALEN)) {
nkey->has_eth_src = true;
nkey->eth_src = qemu_mac_strdup_printf(key->eth.src.a);
}
if (nkey->has_eth_src && memcmp(mask->eth.src.a, ff_mac.a, ETH_ALEN)) {
nmask->has_eth_src = true;
nmask->eth_src = qemu_mac_strdup_printf(mask->eth.src.a);
}
if (memcmp(key->eth.dst.a, zero_mac.a, ETH_ALEN) ||
memcmp(mask->eth.dst.a, zero_mac.a, ETH_ALEN)) {
nkey->has_eth_dst = true;
nkey->eth_dst = qemu_mac_strdup_printf(key->eth.dst.a);
}
if (nkey->has_eth_dst && memcmp(mask->eth.dst.a, ff_mac.a, ETH_ALEN)) {
nmask->has_eth_dst = true;
nmask->eth_dst = qemu_mac_strdup_printf(mask->eth.dst.a);
}
if (key->eth.type) {
nkey->has_eth_type = true;
nkey->eth_type = ntohs(key->eth.type);
switch (ntohs(key->eth.type)) {
case 0x0800:
case 0x86dd:
if (key->ip.proto || mask->ip.proto) {
nkey->has_ip_proto = true;
nkey->ip_proto = key->ip.proto;
}
if (nkey->has_ip_proto && mask->ip.proto != 0xff) {
nmask->has_ip_proto = true;
nmask->ip_proto = mask->ip.proto;
}
if (key->ip.tos || mask->ip.tos) {
nkey->has_ip_tos = true;
nkey->ip_tos = key->ip.tos;
}
if (nkey->has_ip_tos && mask->ip.tos != 0xff) {
nmask->has_ip_tos = true;
nmask->ip_tos = mask->ip.tos;
}
break;
}
switch (ntohs(key->eth.type)) {
case 0x0800:
if (key->ipv4.addr.dst || mask->ipv4.addr.dst) {
char *dst = inet_ntoa(*(struct in_addr *)&key->ipv4.addr.dst);
int dst_len = of_dpa_mask2prefix(mask->ipv4.addr.dst);
nkey->has_ip_dst = true;
nkey->ip_dst = g_strdup_printf("%s/%d", dst, dst_len);
}
break;
}
}
if (flow->action.goto_tbl) {
naction->has_goto_tbl = true;
naction->goto_tbl = flow->action.goto_tbl;
}
if (flow->action.write.group_id) {
naction->has_group_id = true;
naction->group_id = flow->action.write.group_id;
}
if (flow->action.apply.new_vlan_id) {
naction->has_new_vlan_id = true;
naction->new_vlan_id = flow->action.apply.new_vlan_id;
}
new->next = flow_context->list;
flow_context->list = new;
}
RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name,
bool has_tbl_id,
uint32_t tbl_id,
Error **errp)
{
struct rocker *r;
struct world *w;
struct of_dpa *of_dpa;
struct of_dpa_flow_fill_context fill_context = {
.list = NULL,
.tbl_id = tbl_id,
};
r = rocker_find(name);
if (!r) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
"rocker %s not found", name);
return NULL;
}
w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA);
if (!w) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
"rocker %s doesn't have OF-DPA world", name);
return NULL;
}
of_dpa = world_private(w);
g_hash_table_foreach(of_dpa->flow_tbl, of_dpa_flow_fill, &fill_context);
return fill_context.list;
}
struct of_dpa_group_fill_context {
RockerOfDpaGroupList *list;
uint8_t type;
};
static void of_dpa_group_fill(void *key, void *value, void *user_data)
{
struct of_dpa_group *group = value;
struct of_dpa_group_fill_context *flow_context = user_data;
RockerOfDpaGroupList *new;
RockerOfDpaGroup *ngroup;
struct uint32List *id;
int i;
if (flow_context->type != 9 &&
flow_context->type != ROCKER_GROUP_TYPE_GET(group->id)) {
return;
}
new = g_malloc0(sizeof(*new));
ngroup = new->value = g_malloc0(sizeof(*ngroup));
ngroup->id = group->id;
ngroup->type = ROCKER_GROUP_TYPE_GET(group->id);
switch (ngroup->type) {
case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
ngroup->has_vlan_id = true;
ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id);
ngroup->has_pport = true;
ngroup->pport = ROCKER_GROUP_PORT_GET(group->id);
ngroup->has_out_pport = true;
ngroup->out_pport = group->l2_interface.out_pport;
ngroup->has_pop_vlan = true;
ngroup->pop_vlan = group->l2_interface.pop_vlan;
break;
case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
ngroup->has_index = true;
ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id);
ngroup->has_group_id = true;
ngroup->group_id = group->l2_rewrite.group_id;
if (group->l2_rewrite.vlan_id) {
ngroup->has_set_vlan_id = true;
ngroup->set_vlan_id = ntohs(group->l2_rewrite.vlan_id);
}
break;
if (memcmp(group->l2_rewrite.src_mac.a, zero_mac.a, ETH_ALEN)) {
ngroup->has_set_eth_src = true;
ngroup->set_eth_src =
qemu_mac_strdup_printf(group->l2_rewrite.src_mac.a);
}
if (memcmp(group->l2_rewrite.dst_mac.a, zero_mac.a, ETH_ALEN)) {
ngroup->has_set_eth_dst = true;
ngroup->set_eth_dst =
qemu_mac_strdup_printf(group->l2_rewrite.dst_mac.a);
}
case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
ngroup->has_vlan_id = true;
ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id);
ngroup->has_index = true;
ngroup->index = ROCKER_GROUP_INDEX_GET(group->id);
for (i = 0; i < group->l2_flood.group_count; i++) {
ngroup->has_group_ids = true;
id = g_malloc0(sizeof(*id));
id->value = group->l2_flood.group_ids[i];
id->next = ngroup->group_ids;
ngroup->group_ids = id;
}
break;
case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST:
ngroup->has_index = true;
ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id);
ngroup->has_group_id = true;
ngroup->group_id = group->l3_unicast.group_id;
if (group->l3_unicast.vlan_id) {
ngroup->has_set_vlan_id = true;
ngroup->set_vlan_id = ntohs(group->l3_unicast.vlan_id);
}
if (memcmp(group->l3_unicast.src_mac.a, zero_mac.a, ETH_ALEN)) {
ngroup->has_set_eth_src = true;
ngroup->set_eth_src =
qemu_mac_strdup_printf(group->l3_unicast.src_mac.a);
}
if (memcmp(group->l3_unicast.dst_mac.a, zero_mac.a, ETH_ALEN)) {
ngroup->has_set_eth_dst = true;
ngroup->set_eth_dst =
qemu_mac_strdup_printf(group->l3_unicast.dst_mac.a);
}
if (group->l3_unicast.ttl_check) {
ngroup->has_ttl_check = true;
ngroup->ttl_check = group->l3_unicast.ttl_check;
}
break;
}
new->next = flow_context->list;
flow_context->list = new;
}
RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name,
bool has_type,
uint8_t type,
Error **errp)
{
struct rocker *r;
struct world *w;
struct of_dpa *of_dpa;
struct of_dpa_group_fill_context fill_context = {
.list = NULL,
.type = type,
};
r = rocker_find(name);
if (!r) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
"rocker %s not found", name);
return NULL;
}
w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA);
if (!w) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
"rocker %s doesn't have OF-DPA world", name);
return NULL;
}
of_dpa = world_private(w);
g_hash_table_foreach(of_dpa->group_tbl, of_dpa_group_fill, &fill_context);
return fill_context.list;
}
static WorldOps of_dpa_ops = {
.init = of_dpa_init,
.uninit = of_dpa_uninit,

View file

@ -714,9 +714,7 @@ int xen_be_init(void)
return -1;
}
if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0) {
goto err;
}
qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL);
if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
/* Check if xen_init() have been called */