qmp/hmp: add rocker device support
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) info rocker sw1
name: sw1
id: 0x0000013512005452
ports: 4
(qemu) info 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) info rocker-of-dpa-flows sw1
prio tbl hits key(mask) --> actions
2 60 pport 1 vlan 1 LLDP src 00:02:00:00:02:00 dst 01:80:c2:00:00:0e
2 60 pport 1 vlan 1 ARP src 00:02:00:00:02:00 dst 00:02:00:00:03:00
2 60 pport 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 pport 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 pport 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 pport 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 pport 1 vlan 1 IP src 00:02:00:00:02:00 dst 00:02:00:00:03:00 proto 1
2 60 pport 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 pport 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 pport 2 vlan 2 LLDP src <any> dst 01:80:c2:00:00:0e --> write group 0x02000000
1 60 6 pport 2 vlan 2 IPv6 src <any> dst <any> --> write group 0x02000000
1 60 174 pport 1 vlan 1 LLDP src <any> dst 01:80:c2:00:00:0e --> write group 0x01000000
1 60 174 pport 2 vlan 2 IP src <any> dst <any> --> write group 0x02000000
1 60 6 pport 1 vlan 1 IPv6 src <any> dst <any> --> write group 0x01000000
1 60 181 pport 2 vlan 2 ARP src <any> dst <any> --> write group 0x02000000
1 10 715 pport 2 --> apply new vlan 2 goto tbl 20
1 60 177 pport 1 vlan 1 ARP src <any> dst <any> --> write group 0x01000000
1 60 174 pport 1 vlan 1 IP src <any> dst <any> --> write group 0x01000000
1 10 717 pport 1 --> apply new vlan 1 goto tbl 20
1 0 1432 pport 0(0xffff) --> goto tbl 10
(qemu) info 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 pport 1) --> pop vlan out pport 1
0x01000002 (type L2 interface vlan 1 pport 2) --> pop vlan out pport 2
0x02000000 (type L2 interface vlan 2 pport 0) --> pop vlan out pport 0
0x01000000 (type L2 interface vlan 1 pport 0) --> pop vlan out pport 0
0x31000000 (type L2 multicast vlan 1 index 0) --> groups [0x01000002,0x01000000]
[Added "query-" prefixes to rocker.json commands as suggested by Eric
Blake <eblake@redhat.com>.
--Stefan]
Signed-off-by: Scott Feldman <sfeldma@gmail.com>
Signed-off-by: Jiri Pirko <jiri@resnulli.us>
Message-id: 1433985681-56138-5-git-send-email-sfeldma@gmail.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
diff --git a/hmp.c b/hmp.c
index 514f22f..1e7cac0 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 "sysemu/block-backend.h"
#include "qemu/option.h"
@@ -1999,3 +2000,305 @@
}
hmp_handle_error(mon, &err);
}
+
+void hmp_rocker(Monitor *mon, const QDict *qdict)
+{
+ const char *name = qdict_get_str(qdict, "name");
+ RockerSwitch *rocker;
+ Error *errp = NULL;
+
+ rocker = qmp_query_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%" PRIx64 "\n", rocker->id);
+ monitor_printf(mon, "ports: %d\n", rocker->ports);
+
+ qapi_free_RockerSwitch(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_query_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_query_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 %-4" PRIu64,
+ 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_query_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);
+}