On 05/16/2013 07:07 PM, Amos Kong wrote: > 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 <ak...@redhat.com>
Maybe you also need a command to query the vlan table, or rename the command as "info filter" and do it here. > --- > 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