[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 08/10] qmp: add rocker device support
From: |
sfeldma |
Subject: |
[Qemu-devel] [PATCH 08/10] qmp: add rocker device support |
Date: |
Mon, 29 Dec 2014 21:14:09 -0800 |
From: Scott Feldman <address@hidden>
Add QMP/HMP support for rocker devices. This is mostly for debugging purposes
to see inside the device's tables and port configurations. Some examples:
(qemu) rocker sw1
name: sw1
id: 0x0000013512005452
ports: 4
(qemu) rocker-ports sw1
ena/ speed/ auto
port link duplex neg?
sw1.1 up 10G FD No
sw1.2 up 10G FD No
sw1.3 !ena 10G FD No
sw1.4 !ena 10G FD No
(qemu) rocker-of-dpa-flows sw1
prio tbl hits key(mask) --> actions
2 60 lport 1 vlan 1 LLDP src 00:02:00:00:02:00 dst 01:80:c2:00:00:0e
2 60 lport 1 vlan 1 ARP src 00:02:00:00:02:00 dst 00:02:00:00:03:00
2 60 lport 2 vlan 2 IPv6 src 00:02:00:00:03:00 dst 33:33:ff:00:00:02
proto 58
3 50 vlan 2 dst 33:33:ff:00:00:02 --> write group 0x32000001 goto tbl
60
2 60 lport 2 vlan 2 IPv6 src 00:02:00:00:03:00 dst 33:33:ff:00:03:00
proto 58
3 50 1 vlan 2 dst 33:33:ff:00:03:00 --> write group 0x32000001 goto tbl
60
2 60 lport 2 vlan 2 ARP src 00:02:00:00:03:00 dst 00:02:00:00:02:00
3 50 2 vlan 2 dst 00:02:00:00:02:00 --> write group 0x02000001 goto tbl
60
2 60 1 lport 2 vlan 2 IP src 00:02:00:00:03:00 dst 00:02:00:00:02:00
proto 1
3 50 2 vlan 1 dst 00:02:00:00:03:00 --> write group 0x01000002 goto tbl
60
2 60 1 lport 1 vlan 1 IP src 00:02:00:00:02:00 dst 00:02:00:00:03:00
proto 1
2 60 lport 1 vlan 1 IPv6 src 00:02:00:00:02:00 dst 33:33:ff:00:00:01
proto 58
3 50 vlan 1 dst 33:33:ff:00:00:01 --> write group 0x31000000 goto tbl
60
2 60 lport 1 vlan 1 IPv6 src 00:02:00:00:02:00 dst 33:33:ff:00:02:00
proto 58
3 50 1 vlan 1 dst 33:33:ff:00:02:00 --> write group 0x31000000 goto tbl
60
1 60 173 lport 2 vlan 2 LLDP src <any> dst 01:80:c2:00:00:0e --> write
group 0x02000000
1 60 6 lport 2 vlan 2 IPv6 src <any> dst <any> --> write group 0x02000000
1 60 174 lport 1 vlan 1 LLDP src <any> dst 01:80:c2:00:00:0e --> write
group 0x01000000
1 60 174 lport 2 vlan 2 IP src <any> dst <any> --> write group 0x02000000
1 60 6 lport 1 vlan 1 IPv6 src <any> dst <any> --> write group 0x01000000
1 60 181 lport 2 vlan 2 ARP src <any> dst <any> --> write group 0x02000000
1 10 715 lport 2 --> apply new vlan 2 goto tbl 20
1 60 177 lport 1 vlan 1 ARP src <any> dst <any> --> write group 0x01000000
1 60 174 lport 1 vlan 1 IP src <any> dst <any> --> write group 0x01000000
1 10 717 lport 1 --> apply new vlan 1 goto tbl 20
1 0 1432 lport 0(0xffff) --> goto tbl 10
(qemu) rocker-of-dpa-groups sw1
id (decode) --> buckets
0x32000001 (type L2 multicast vlan 2 index 1) --> groups [0x02000001,0x02000000]
0x02000001 (type L2 interface vlan 2 lport 1) --> pop vlan out lport 1
0x01000002 (type L2 interface vlan 1 lport 2) --> pop vlan out lport 2
0x02000000 (type L2 interface vlan 2 lport 0) --> pop vlan out lport 0
0x01000000 (type L2 interface vlan 1 lport 0) --> pop vlan out lport 0
0x31000000 (type L2 multicast vlan 1 index 0) --> groups [0x01000002,0x01000000]
Signed-off-by: Scott Feldman <address@hidden>
Signed-off-by: Jiri Pirko <address@hidden>
---
hmp-commands.hx | 56 ++++++++
hmp.c | 303 ++++++++++++++++++++++++++++++++++++++++
hmp.h | 4 +
hw/net/rocker/rocker.c | 46 ++++++
hw/net/rocker/rocker_fp.c | 1 +
hw/net/rocker/rocker_of_dpa.c | 309 +++++++++++++++++++++++++++++++++++++++++
qapi-schema.json | 51 +++++++
qmp-commands.hx | 24 ++++
8 files changed, 794 insertions(+)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index e37bc8b..67ad0d9 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1786,6 +1786,62 @@ STEXI
show available trace events and their state
ETEXI
+ {
+ .name = "rocker",
+ .args_type = "name:s",
+ .params = "rocker name",
+ .help = "Show Rocker(s)",
+ .mhandler.cmd = hmp_rocker,
+ },
+
+STEXI
address@hidden rocker @var{name}
address@hidden rocker
+Show Rocker(s)
+ETEXI
+
+ {
+ .name = "rocker-ports",
+ .args_type = "name:s",
+ .params = "rocker_ports name",
+ .help = "Show Rocker ports",
+ .mhandler.cmd = hmp_rocker_ports,
+ },
+
+STEXI
address@hidden rocker_ports @var{name}
address@hidden rocker_ports
+Show Rocker ports
+ETEXI
+
+ {
+ .name = "rocker-of-dpa-flows",
+ .args_type = "name:s,tbl_id:i?",
+ .params = "rocker_of_dpa_flows name [tbl_id]",
+ .help = "Show Rocker OF-DPA flow tables",
+ .mhandler.cmd = hmp_rocker_of_dpa_flows,
+ },
+
+STEXI
address@hidden rocker_of_dpa_flows @var{name} address@hidden
address@hidden rocker_of_dpa_flows
+Show Rocker OF-DPA flow tables
+ETEXI
+
+ {
+ .name = "rocker-of-dpa-groups",
+ .args_type = "name:s,type:i?",
+ .params = "rocker_of_dpa_groups name [type]",
+ .help = "Show Rocker OF-DPA groups",
+ .mhandler.cmd = hmp_rocker_of_dpa_groups,
+ },
+
+STEXI
address@hidden rocker_of_dpa_groups @var{name} address@hidden
address@hidden rocker_of_dpa_groups
+Show Rocker OF-DPA groups
+ETEXI
+
STEXI
@end table
ETEXI
diff --git a/hmp.c b/hmp.c
index 481be80..2290d10 100644
--- a/hmp.c
+++ b/hmp.c
@@ -15,6 +15,7 @@
#include "hmp.h"
#include "net/net.h"
+#include "net/eth.h"
#include "sysemu/char.h"
#include "qemu/option.h"
#include "qemu/timer.h"
@@ -1813,3 +1814,305 @@ void hmp_info_memory_devices(Monitor *mon, const QDict
*qdict)
qapi_free_MemoryDeviceInfoList(info_list);
}
+
+void hmp_rocker(Monitor *mon, const QDict *qdict)
+{
+ const char *name = qdict_get_str(qdict, "name");
+ Rocker *rocker;
+ Error *errp = NULL;
+
+ rocker = qmp_rocker(name, &errp);
+ if (errp != NULL) {
+ hmp_handle_error(mon, &errp);
+ return;
+ }
+
+ monitor_printf(mon, "name: %s\n", rocker->name);
+ monitor_printf(mon, "id: 0x%016lx\n", rocker->id);
+ monitor_printf(mon, "ports: %d\n", rocker->ports);
+
+ qapi_free_Rocker(rocker);
+}
+
+void hmp_rocker_ports(Monitor *mon, const QDict *qdict)
+{
+ RockerPortList *list, *port;
+ const char *name = qdict_get_str(qdict, "name");
+ Error *errp = NULL;
+
+ list = qmp_rocker_ports(name, &errp);
+ if (errp != NULL) {
+ hmp_handle_error(mon, &errp);
+ return;
+ }
+
+ monitor_printf(mon, " ena/ speed/ auto\n");
+ monitor_printf(mon, " port link duplex neg?\n");
+
+ for (port = list; port; port = port->next)
+ monitor_printf(mon, "%10s %-4s %-3s %2s %-3s\n",
+ port->value->name,
+ port->value->enabled ? port->value->link_up ?
+ "up" : "down" : "!ena",
+ port->value->speed == 10000 ? "10G" : "??",
+ port->value->duplex ? "FD" : "HD",
+ port->value->autoneg ? "Yes" : "No");
+
+ qapi_free_RockerPortList(list);
+}
+
+void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict)
+{
+ RockerOfDpaFlowList *list, *info;
+ const char *name = qdict_get_str(qdict, "name");
+ uint32_t tbl_id = qdict_get_try_int(qdict, "tbl_id", -1);
+ Error *errp = NULL;
+
+ list = qmp_rocker_of_dpa_flows(name, tbl_id != -1, tbl_id, &errp);
+ if (errp != NULL) {
+ hmp_handle_error(mon, &errp);
+ return;
+ }
+
+ monitor_printf(mon, "prio tbl hits key(mask) --> actions\n");
+
+ for (info = list; info; info = info->next) {
+ RockerOfDpaFlow *flow = info->value;
+ RockerOfDpaFlowKey *key = flow->key;
+ RockerOfDpaFlowMask *mask = flow->mask;
+ RockerOfDpaFlowAction *action = flow->action;
+
+ if (flow->hits) {
+ monitor_printf(mon, "%-4d %-3d %-4ld",
+ key->priority, key->tbl_id, flow->hits);
+ } else {
+ monitor_printf(mon, "%-4d %-3d ",
+ key->priority, key->tbl_id);
+ }
+
+ if (key->has_in_pport) {
+ monitor_printf(mon, " pport %d", key->in_pport);
+ if (mask->has_in_pport) {
+ monitor_printf(mon, "(0x%x)", mask->in_pport);
+ }
+ }
+
+ if (key->has_vlan_id) {
+ monitor_printf(mon, " vlan %d",
+ key->vlan_id & VLAN_VID_MASK);
+ if (mask->has_vlan_id) {
+ monitor_printf(mon, "(0x%x)", mask->vlan_id);
+ }
+ }
+
+ if (key->has_tunnel_id) {
+ monitor_printf(mon, " tunnel %d", key->tunnel_id);
+ if (mask->has_tunnel_id) {
+ monitor_printf(mon, "(0x%x)", mask->tunnel_id);
+ }
+ }
+
+ if (key->has_eth_type) {
+ switch (key->eth_type) {
+ case 0x0806:
+ monitor_printf(mon, " ARP");
+ break;
+ case 0x0800:
+ monitor_printf(mon, " IP");
+ break;
+ case 0x86dd:
+ monitor_printf(mon, " IPv6");
+ break;
+ case 0x8809:
+ monitor_printf(mon, " LACP");
+ break;
+ case 0x88cc:
+ monitor_printf(mon, " LLDP");
+ break;
+ default:
+ monitor_printf(mon, " eth type 0x%04x", key->eth_type);
+ break;
+ }
+ }
+
+ if (key->has_eth_src) {
+ if ((strcmp(key->eth_src, "01:00:00:00:00:00") == 0) &&
+ (mask->has_eth_src) &&
+ (strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) {
+ monitor_printf(mon, " src <any mcast/bcast>");
+ } else if ((strcmp(key->eth_src, "00:00:00:00:00:00") == 0) &&
+ (mask->has_eth_src) &&
+ (strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) {
+ monitor_printf(mon, " src <any ucast>");
+ } else {
+ monitor_printf(mon, " src %s", key->eth_src);
+ if (mask->has_eth_src) {
+ monitor_printf(mon, "(%s)", mask->eth_src);
+ }
+ }
+ }
+
+ if (key->has_eth_dst) {
+ if ((strcmp(key->eth_dst, "01:00:00:00:00:00") == 0) &&
+ (mask->has_eth_dst) &&
+ (strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) {
+ monitor_printf(mon, " dst <any mcast/bcast>");
+ } else if ((strcmp(key->eth_dst, "00:00:00:00:00:00") == 0) &&
+ (mask->has_eth_dst) &&
+ (strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) {
+ monitor_printf(mon, " dst <any ucast>");
+ } else {
+ monitor_printf(mon, " dst %s", key->eth_dst);
+ if (mask->has_eth_dst) {
+ monitor_printf(mon, "(%s)", mask->eth_dst);
+ }
+ }
+ }
+
+ if (key->has_ip_proto) {
+ monitor_printf(mon, " proto %d", key->ip_proto);
+ if (mask->has_ip_proto) {
+ monitor_printf(mon, "(0x%x)", mask->ip_proto);
+ }
+ }
+
+ if (key->has_ip_tos) {
+ monitor_printf(mon, " TOS %d", key->ip_tos);
+ if (mask->has_ip_tos) {
+ monitor_printf(mon, "(0x%x)", mask->ip_tos);
+ }
+ }
+
+ if (key->has_ip_dst) {
+ monitor_printf(mon, " dst %s", key->ip_dst);
+ }
+
+ if (action->has_goto_tbl || action->has_group_id ||
+ action->has_new_vlan_id) {
+ monitor_printf(mon, " -->");
+ }
+
+ if (action->has_new_vlan_id) {
+ monitor_printf(mon, " apply new vlan %d",
+ ntohs(action->new_vlan_id));
+ }
+
+ if (action->has_group_id) {
+ monitor_printf(mon, " write group 0x%08x", action->group_id);
+ }
+
+ if (action->has_goto_tbl) {
+ monitor_printf(mon, " goto tbl %d", action->goto_tbl);
+ }
+
+ monitor_printf(mon, "\n");
+ }
+
+ qapi_free_RockerOfDpaFlowList(list);
+}
+
+void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict)
+{
+ RockerOfDpaGroupList *list, *g;
+ const char *name = qdict_get_str(qdict, "name");
+ uint8_t type = qdict_get_try_int(qdict, "type", 9);
+ Error *errp = NULL;
+ bool set = false;
+
+ list = qmp_rocker_of_dpa_groups(name, type != 9, type, &errp);
+ if (errp != NULL) {
+ hmp_handle_error(mon, &errp);
+ return;
+ }
+
+ monitor_printf(mon, "id (decode) --> buckets\n");
+
+ for (g = list; g; g = g->next) {
+ RockerOfDpaGroup *group = g->value;
+
+ monitor_printf(mon, "0x%08x", group->id);
+
+ monitor_printf(mon, " (type %s", group->type == 0 ? "L2 interface" :
+ group->type == 1 ? "L2 rewrite" :
+ group->type == 2 ? "L3 unicast" :
+ group->type == 3 ? "L2 multicast" :
+ group->type == 4 ? "L2 flood" :
+ group->type == 5 ? "L3 interface" :
+ group->type == 6 ? "L3 multicast" :
+ group->type == 7 ? "L3 ECMP" :
+ group->type == 8 ? "L2 overlay" :
+ "unknown");
+
+ if (group->has_vlan_id) {
+ monitor_printf(mon, " vlan %d", group->vlan_id);
+ }
+
+ if (group->has_pport) {
+ monitor_printf(mon, " pport %d", group->pport);
+ }
+
+ if (group->has_index) {
+ monitor_printf(mon, " index %d", group->index);
+ }
+
+ monitor_printf(mon, ") -->");
+
+ if (group->has_set_vlan_id && group->set_vlan_id) {
+ set = true;
+ monitor_printf(mon, " set vlan %d",
+ group->set_vlan_id & VLAN_VID_MASK);
+ }
+
+ if (group->has_set_eth_src) {
+ if (!set) {
+ set = true;
+ monitor_printf(mon, " set");
+ }
+ monitor_printf(mon, " src %s", group->set_eth_src);
+ }
+
+ if (group->has_set_eth_dst) {
+ if (!set) {
+ set = true;
+ monitor_printf(mon, " set");
+ }
+ monitor_printf(mon, " dst %s", group->set_eth_dst);
+ }
+
+ set = false;
+
+ if (group->has_ttl_check && group->ttl_check) {
+ monitor_printf(mon, " check TTL");
+ }
+
+ if (group->has_group_id && group->group_id) {
+ monitor_printf(mon, " group id 0x%08x", group->group_id);
+ }
+
+ if (group->has_pop_vlan && group->pop_vlan) {
+ monitor_printf(mon, " pop vlan");
+ }
+
+ if (group->has_out_pport) {
+ monitor_printf(mon, " out pport %d", group->out_pport);
+ }
+
+ if (group->has_group_ids) {
+ struct uint32List *id;
+
+ monitor_printf(mon, " groups [");
+ for (id = group->group_ids; id; id = id->next) {
+ monitor_printf(mon, "0x%08x", id->value);
+ if (id->next) {
+ monitor_printf(mon, ",");
+ }
+ }
+ monitor_printf(mon, "]");
+ }
+
+ monitor_printf(mon, "\n");
+ }
+
+ qapi_free_RockerOfDpaGroupList(list);
+}
+
diff --git a/hmp.h b/hmp.h
index 4bb5dca..dc8a15c 100644
--- a/hmp.h
+++ b/hmp.h
@@ -116,5 +116,9 @@ void host_net_remove_completion(ReadLineState *rs, int
nb_args,
const char *str);
void delvm_completion(ReadLineState *rs, int nb_args, const char *str);
void loadvm_completion(ReadLineState *rs, int nb_args, const char *str);
+void hmp_rocker(Monitor *mon, const QDict *qdict);
+void hmp_rocker_ports(Monitor *mon, const QDict *qdict);
+void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict);
+void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict);
#endif
diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c
index b410552..278894e 100644
--- a/hw/net/rocker/rocker.c
+++ b/hw/net/rocker/rocker.c
@@ -22,6 +22,7 @@
#include "net/eth.h"
#include "qemu/iov.h"
#include "qemu/bitops.h"
+#include "qmp-commands.h"
#include "rocker.h"
#include "rocker_hw.h"
@@ -92,6 +93,51 @@ struct world *rocker_get_world(struct rocker *r, enum
rocker_world_type type)
return NULL;
}
+Rocker *qmp_rocker(const char *name, Error **errp)
+{
+ Rocker *rocker = g_malloc0(sizeof(*rocker));
+ struct 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_rocker_ports(const char *name, Error **errp)
+{
+ RockerPortList *list = NULL;
+ struct 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(struct rocker *r)
{
return r->fp_ports;
diff --git a/hw/net/rocker/rocker_fp.c b/hw/net/rocker/rocker_fp.c
index 01734e5..9cb1cc5 100644
--- a/hw/net/rocker/rocker_fp.c
+++ b/hw/net/rocker/rocker_fp.c
@@ -15,6 +15,7 @@
*/
#include "net/clients.h"
+#include "qmp-commands.h"
#include "rocker.h"
#include "rocker_hw.h"
diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c
index 328f351..432665b 100644
--- a/hw/net/rocker/rocker_of_dpa.c
+++ b/hw/net/rocker/rocker_of_dpa.c
@@ -17,6 +17,7 @@
#include "net/eth.h"
#include "qemu/iov.h"
#include "qemu/timer.h"
+#include "qmp-commands.h"
#include "rocker.h"
#include "rocker_hw.h"
@@ -2321,6 +2322,314 @@ static void of_dpa_uninit(struct 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_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_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 struct world_ops of_dpa_ops = {
.init = of_dpa_init,
.uninit = of_dpa_uninit,
diff --git a/qapi-schema.json b/qapi-schema.json
index 563b4ad..6fdf58b 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3515,3 +3515,54 @@
# Since: 2.1
##
{ 'command': 'rtc-reset-reinjection' }
+
+{ 'type': 'Rocker',
+ 'data': { 'name': 'str', 'id': 'uint64', 'ports': 'uint32' } }
+
+{ 'command': 'rocker',
+ 'data': { 'name': 'str' },
+ 'returns': 'Rocker' }
+
+{ 'type': 'RockerPort',
+ 'data': { 'name': 'str', 'enabled': 'bool', 'link_up': 'bool',
+ 'speed': 'uint32', 'duplex': 'uint8', 'autoneg': 'uint8' } }
+
+{ 'command': 'rocker-ports',
+ 'data': { 'name': 'str' },
+ 'returns': ['RockerPort'] }
+
+{ 'type': 'RockerOfDpaFlowKey',
+ 'data' : { 'priority': 'uint32', 'tbl_id': 'uint32', '*in_pport': 'uint32',
+ '*tunnel_id': 'uint32', '*vlan_id': 'uint16',
+ '*eth_type': 'uint16', '*eth_src': 'str', '*eth_dst': 'str',
+ '*ip_proto': 'uint8', '*ip_tos': 'uint8', '*ip_dst': 'str' } }
+
+{ 'type': 'RockerOfDpaFlowMask',
+ 'data' : { '*in_pport': 'uint32', '*tunnel_id': 'uint32',
+ '*vlan_id': 'uint16', '*eth_src': 'str', '*eth_dst': 'str',
+ '*ip_proto': 'uint8', '*ip_tos': 'uint8' } }
+
+{ 'type': 'RockerOfDpaFlowAction',
+ 'data' : { '*goto_tbl': 'uint32', '*group_id': 'uint32',
+ '*tun_log_pport': 'uint32', '*vlan_id': 'uint16',
+ '*new_vlan_id': 'uint16', '*out_pport': 'uint32' } }
+
+{ 'type': 'RockerOfDpaFlow',
+ 'data': { 'cookie': 'uint64', 'hits': 'uint64', 'key': 'RockerOfDpaFlowKey',
+ 'mask': 'RockerOfDpaFlowMask', 'action': 'RockerOfDpaFlowAction' }
}
+
+{ 'command': 'rocker-of-dpa-flows',
+ 'data': { 'name': 'str', '*tbl_id': 'uint32' },
+ 'returns': ['RockerOfDpaFlow'] }
+
+{ 'type': 'RockerOfDpaGroup',
+ 'data': { 'id': 'uint32', 'type': 'uint8', '*vlan_id': 'uint16',
+ '*pport': 'uint32', '*index': 'uint32', '*out_pport': 'uint32',
+ '*group_id': 'uint32', '*set_vlan_id': 'uint16',
+ '*pop_vlan': 'uint8', '*group_ids': ['uint32'],
+ '*set_eth_src': 'str', '*set_eth_dst': 'str',
+ '*ttl_check': 'uint8' } }
+
+{ 'command': 'rocker-of-dpa-groups',
+ 'data': { 'name': 'str', '*type': 'uint8' },
+ 'returns': ['RockerOfDpaGroup'] }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 6945d30..fdad1c9 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3860,3 +3860,27 @@ Move mouse pointer to absolute coordinates (20000, 400).
<- { "return": {} }
EQMP
+
+ {
+ .name = "rocker",
+ .args_type = "name:s",
+ .mhandler.cmd_new = qmp_marshal_input_rocker,
+ },
+
+ {
+ .name = "rocker-ports",
+ .args_type = "name:s",
+ .mhandler.cmd_new = qmp_marshal_input_rocker_ports,
+ },
+
+ {
+ .name = "rocker-of-dpa-flows",
+ .args_type = "name:s,tbl_id:i?",
+ .mhandler.cmd_new = qmp_marshal_input_rocker_of_dpa_flows,
+ },
+
+ {
+ .name = "rocker-of-dpa-groups",
+ .args_type = "name:s,type:i?",
+ .mhandler.cmd_new = qmp_marshal_input_rocker_of_dpa_groups,
+ },
--
1.7.10.4
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemu-devel] [PATCH 08/10] qmp: add rocker device support,
sfeldma <=