From patchwork Thu May 16 11:07:25 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amos Kong X-Patchwork-Id: 244263 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id B98DC2C007A for ; Thu, 16 May 2013 21:08:56 +1000 (EST) Received: from localhost ([::1]:50210 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ucw3K-0005Ug-Sy for incoming@patchwork.ozlabs.org; Thu, 16 May 2013 07:08:54 -0400 Received: from eggs.gnu.org ([208.118.235.92]:35774) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ucw2B-0003wZ-Ck for qemu-devel@nongnu.org; Thu, 16 May 2013 07:07:49 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Ucw24-0007Ky-HR for qemu-devel@nongnu.org; Thu, 16 May 2013 07:07:43 -0400 Received: from mx1.redhat.com ([209.132.183.28]:46687) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ucw24-0007Km-7k for qemu-devel@nongnu.org; Thu, 16 May 2013 07:07:36 -0400 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r4GB7ZIM031913 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 16 May 2013 07:07:35 -0400 Received: from t430s.nay.redhat.com ([10.66.7.220]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id r4GB7RJD026434; Thu, 16 May 2013 07:07:33 -0400 From: Amos Kong To: qemu-devel@nongnu.org, mst@redhat.com, lcapitulino@redhat.com Date: Thu, 16 May 2013 19:07:25 +0800 Message-Id: <1368702445-30733-3-git-send-email-akong@redhat.com> In-Reply-To: <1368702445-30733-1-git-send-email-akong@redhat.com> References: <1368702445-30733-1-git-send-email-akong@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: stefanha@redhat.com Subject: [Qemu-devel] [PATCH v2 2/2] net: introduce command to query mac-table information X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org We want to implement mac programming over macvtap through Libvirt. The previous patch adds QMP event to notify management of mac-table change. This patch adds a monitor command to query rx mode information of mac-tables. (qemu) info mac-table vnet0 vnet0: \ promisc: on \ allmulti: off \ alluni: off \ nomulti: off \ nouni: off \ nobcast: off \ multi_overflow: off \ uni_overflow: off \ multicast: 01:00:5e:00:00:01 33:33:00:00:00:01 33:33:ff:12:34:56 Signed-off-by: Amos Kong --- hmp-commands.hx | 2 ++ hmp.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++ hmp.h | 1 + hw/net/virtio-net.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++ include/net/net.h | 2 ++ monitor.c | 8 ++++++ net/net.c | 38 ++++++++++++++++++++++++++++ qapi-schema.json | 57 ++++++++++++++++++++++++++++++++++++++++++ qmp-commands.hx | 53 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 295 insertions(+) diff --git a/hmp-commands.hx b/hmp-commands.hx index 9cea415..e5c1b14 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1639,6 +1639,8 @@ show qdev device model list show roms @item info tpm show the TPM device +@item info mac-table [net client name] +show the mac-table information for all nics (or for the given nic) @end table ETEXI diff --git a/hmp.c b/hmp.c index 4fb76ec..3e19df0 100644 --- a/hmp.c +++ b/hmp.c @@ -653,6 +653,77 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) qapi_free_TPMInfoList(info_list); } +void hmp_info_mac_table(Monitor *mon, const QDict *qdict) +{ + MacTableInfoList *table_list, *entry; + strList *str_entry; + bool has_name = qdict_haskey(qdict, "name"); + const char *name = NULL; + + if (has_name) { + name = qdict_get_str(qdict, "name"); + } + + table_list = qmp_query_mac_table(has_name, name, NULL); + entry = table_list; + + while (entry) { + monitor_printf(mon, "%s:\n", entry->value->name); + if (entry->value->has_promisc) { + monitor_printf(mon, " \\ promisc: %s\n", + entry->value->promisc ? "on" : "off"); + } + if (entry->value->has_allmulti) { + monitor_printf(mon, " \\ allmulti: %s\n", + entry->value->allmulti ? "on" : "off"); + } + if (entry->value->has_alluni) { + monitor_printf(mon, " \\ alluni: %s\n", + entry->value->alluni ? "on" : "off"); + } + if (entry->value->has_nomulti) { + monitor_printf(mon, " \\ nomulti: %s\n", + entry->value->nomulti ? "on" : "off"); + } + if (entry->value->has_nouni) { + monitor_printf(mon, " \\ nouni: %s\n", + entry->value->nouni ? "on" : "off"); + } + if (entry->value->has_nobcast) { + monitor_printf(mon, " \\ nobcast: %s\n", + entry->value->nobcast ? "on" : "off"); + } + if (entry->value->has_multi_overflow) { + monitor_printf(mon, " \\ multi_overflow: %s\n", + entry->value->multi_overflow ? "on" : "off"); + } + if (entry->value->has_uni_overflow) { + monitor_printf(mon, " \\ uni_overflow: %s\n", + entry->value->uni_overflow ? "on" : "off"); + } + + if (entry->value->has_unicast) { + str_entry = entry->value->unicast; + monitor_printf(mon, " \\ unicast:\n"); + while (str_entry) { + monitor_printf(mon, " %s\n", str_entry->value); + str_entry = str_entry->next; + } + } + if (entry->value->has_multicast) { + str_entry = entry->value->multicast; + monitor_printf(mon, " \\ multicast:\n"); + while (str_entry) { + monitor_printf(mon, " %s\n", str_entry->value); + str_entry = str_entry->next; + } + } + + entry = entry->next; + } + qapi_free_MacTableInfoList(table_list); +} + void hmp_quit(Monitor *mon, const QDict *qdict) { monitor_suspend(mon); diff --git a/hmp.h b/hmp.h index 95fe76e..278c722 100644 --- a/hmp.h +++ b/hmp.h @@ -37,6 +37,7 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict); void hmp_info_pci(Monitor *mon, const QDict *qdict); void hmp_info_block_jobs(Monitor *mon, const QDict *qdict); void hmp_info_tpm(Monitor *mon, const QDict *qdict); +void hmp_info_mac_table(Monitor *mon, const QDict *qdict); void hmp_quit(Monitor *mon, const QDict *qdict); void hmp_stop(Monitor *mon, const QDict *qdict); void hmp_system_reset(Monitor *mon, const QDict *qdict); diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index a9b8f53..e4b2358 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -194,6 +194,68 @@ static void virtio_net_set_link_status(NetClientState *nc) virtio_net_set_status(vdev, vdev->status); } +static MacTableInfo *virtio_net_query_mactable(NetClientState *nc) +{ + VirtIONet *n = qemu_get_nic_opaque(nc); + MacTableInfo *info; + strList *str_list = NULL; + strList *entry; + int i; + + info = g_malloc0(sizeof(*info)); + info->name = g_strdup(nc->name); + + info->promisc = n->promisc; + info->has_promisc = true; + info->allmulti = n->allmulti; + info->has_allmulti = true; + info->alluni = n->alluni; + info->has_alluni = true; + info->nomulti = n->nomulti; + info->has_nomulti = true; + info->nouni = n->nouni; + info->has_nouni = true; + info->nobcast = n->nobcast; + info->has_nobcast = true; + info->multi_overflow = n->mac_table.multi_overflow; + info->has_multi_overflow = true; + info->uni_overflow = n->mac_table.uni_overflow; + info->has_uni_overflow = true; + + for (i = 0; i < n->mac_table.first_multi; i++) { + info->has_unicast = true; + entry = g_malloc0(sizeof(*entry)); + entry->value = g_strdup_printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + n->mac_table.macs[i * ETH_ALEN], + n->mac_table.macs[i * ETH_ALEN + 1], + n->mac_table.macs[i * ETH_ALEN + 2], + n->mac_table.macs[i * ETH_ALEN + 3], + n->mac_table.macs[i * ETH_ALEN + 4], + n->mac_table.macs[i * ETH_ALEN + 5]); + entry->next = str_list; + str_list = entry; + } + info->unicast = str_list; + + str_list = NULL; + for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) { + info->has_multicast = true; + entry = g_malloc0(sizeof(*entry)); + entry->value = g_strdup_printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + n->mac_table.macs[i * ETH_ALEN], + n->mac_table.macs[i * ETH_ALEN + 1], + n->mac_table.macs[i * ETH_ALEN + 2], + n->mac_table.macs[i * ETH_ALEN + 3], + n->mac_table.macs[i * ETH_ALEN + 4], + n->mac_table.macs[i * ETH_ALEN + 5]); + entry->next = str_list; + str_list = entry; + } + info->multicast = str_list; + + return info; +} + static void virtio_net_reset(VirtIODevice *vdev) { VirtIONet *n = VIRTIO_NET(vdev); @@ -1255,6 +1317,7 @@ static NetClientInfo net_virtio_info = { .receive = virtio_net_receive, .cleanup = virtio_net_cleanup, .link_status_changed = virtio_net_set_link_status, + .query_mac_table = virtio_net_query_mactable, }; static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) diff --git a/include/net/net.h b/include/net/net.h index 43d85a1..c3ca4ea 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -49,6 +49,7 @@ typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int); typedef void (NetCleanup) (NetClientState *); typedef void (LinkStatusChanged)(NetClientState *); typedef void (NetClientDestructor)(NetClientState *); +typedef MacTableInfo *(QueryMacTable)(NetClientState *); typedef struct NetClientInfo { NetClientOptionsKind type; @@ -59,6 +60,7 @@ typedef struct NetClientInfo { NetCanReceive *can_receive; NetCleanup *cleanup; LinkStatusChanged *link_status_changed; + QueryMacTable *query_mac_table; NetPoll *poll; } NetClientInfo; diff --git a/monitor.c b/monitor.c index 9e51545..a01cdbd 100644 --- a/monitor.c +++ b/monitor.c @@ -2765,6 +2765,14 @@ static mon_cmd_t info_cmds[] = { .mhandler.cmd = hmp_info_tpm, }, { + .name = "mac-table", + .args_type = "name:s?", + .params = "[net client name]", + .help = "show the mac-table information for all nics (or" + " for the given nic)", + .mhandler.cmd = hmp_info_mac_table, + }, + { .name = NULL, }, }; diff --git a/net/net.c b/net/net.c index 43a74e4..9ff3006 100644 --- a/net/net.c +++ b/net/net.c @@ -961,6 +961,44 @@ void print_net_client(Monitor *mon, NetClientState *nc) nc->info_str); } +MacTableInfoList *qmp_query_mac_table(bool has_name, const char *name, + Error **errp) +{ + NetClientState *nc; + MacTableInfoList *table_list = NULL, *last_entry = NULL; + + QTAILQ_FOREACH(nc, &net_clients, next) { + MacTableInfoList *entry; + MacTableInfo *info; + + if (nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC) { + continue; + } + if (has_name && strcmp(nc->name, name) != 0) { + continue; + } + + if (nc->info->query_mac_table) { + info = nc->info->query_mac_table(nc); + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + + if (!table_list) { + table_list = entry; + } else { + last_entry->next = entry; + } + last_entry = entry; + } + } + + if (table_list == NULL) { + error_setg(errp, "invalid net client name: %s", name); + } + + return table_list; +} + void do_info_network(Monitor *mon, const QDict *qdict) { NetClientState *nc, *peer; diff --git a/qapi-schema.json b/qapi-schema.json index 199744a..866650c 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3619,3 +3619,60 @@ '*cpuid-input-ecx': 'int', 'cpuid-register': 'X86CPURegister32', 'features': 'int' } } + +# @MacTableInfo: +# +# Rx-mode information of mac-table for a net client. +# +# @name: the net client name +# +# @promisc: #optional promiscuous mode (default: false) +# +# @allmulti: #optional all multicast mode (default: false) +# +# @alluni: #optional all unicast mode (default: false) +# +# @nomulti: #optional no multicast mode (default: false) +# +# @nouni: #optional no unicast mode (default: false) +# +# @nobcast: #optional no broadcast mode (default: false) +# +# @multi_overflow: #optional multicast overflow mode (default: false) +# +# @uni_overflow: #optional unicast overflow mode (default: false) +# +# @unicast: #optional a list of unicast macaddr string +# +# @multicast: #optional a list of multicast macaddr string +# +# Since 1.6 +## +{ 'type': 'MacTableInfo', + 'data': { + 'name': 'str', + '*promisc': 'bool', + '*allmulti': 'bool', + '*alluni': 'bool', + '*nomulti': 'bool', + '*nouni': 'bool', + '*nobcast': 'bool', + '*multi-overflow': 'bool', + '*uni-overflow': 'bool', + '*unicast': ['str'], + '*multicast': ['str'] }} + +## +# @query-mac-table: +# +# Return mac-table information for all nics (or for the given nic). +# +# @name: #optional net client name +# +# Returns: list of @MacTableInfo for all nics (or for the given nic). +# Returns an error if the given @name doesn't exist. +# +# Since: 1.6 +## +{ 'command': 'query-mac-table', 'data': { '*name': 'str' }, + 'returns': ['MacTableInfo'] } diff --git a/qmp-commands.hx b/qmp-commands.hx index ffd130e..66826ab 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2932,3 +2932,56 @@ Example: <- { "return": {} } EQMP + { + .name = "query-mac-table", + .args_type = "name:s?", + .mhandler.cmd_new = qmp_marshal_input_query_mac_table, + }, + +SQMP +query-mac-table +--------------- + +Show mac-table information. + +Returns a json-array of mac-table information for all nics (or for the +given nic), returning an error if the given nic doesn't exist. + +Each array entry contains the following: + +- "name": net client name (jaso-string) +- "promisc": promiscuous mode (json-bool, optional) +- "allmulti": all multicast mode (json-bool, optional) +- "alluni": all unicast mode (json-bool, optional) +- "nomulti":no multicast mode (json-bool, optional) +- "nouni": no unicast mode (json-bool, optional) +- "nobcast": no broadcast mode (json-bool, optional) +- "multi-overflow": multicast overflow mode (json-bool, optional) +- "uni-overflow": unicast overflow mode (json-bool, optional) +- "unicast": a jason-array of unicast macaddr string (optional) +- "multicast": a jason-array of multicast macaddr string (optional) + +Example: + +-> { "execute": "query-mac-table", "arguments": { "name": "vnet0" }} +<- { "return": [ + { + "multi-overflow": false, + "name": "vnet0", + "uni-overflow": false, + "nobcast": false, + "promisc": true, + "multicast": [ + "01:00:5e:00:00:01", + "33:33:00:00:00:01", + "33:33:ff:12:34:56" + ], + "nouni": false, + "nomulti": false, + "allmulti": false, + "alluni": false + } + ] + } + +EQMP