#include "monitor.h"
#include "qemu-common.h"
#include "qemu_socket.h"
+#include "qmp-commands.h"
#include "hw/qdev.h"
#include "iov.h"
+/* Net bridge is currently not supported for W32. */
+#if !defined(_WIN32)
+# define CONFIG_NET_BRIDGE
+#endif
+
static QTAILQ_HEAD(, VLANState) vlans;
static QTAILQ_HEAD(, VLANClientState) non_vlan_clients;
return fd;
}
-static int net_init_nic(QemuOpts *opts,
- Monitor *mon,
- const char *name,
- VLANState *vlan)
+static int net_init_nic(QemuOpts *opts, const char *name, VLANState *vlan)
{
int idx;
NICInfo *nd;
}
typedef int (*net_client_init_func)(QemuOpts *opts,
- Monitor *mon,
const char *name,
VLANState *vlan);
.type = QEMU_OPT_STRING,
.help = "script to shut down the interface",
}, {
+#ifdef CONFIG_NET_BRIDGE
+ .name = "helper",
+ .type = QEMU_OPT_STRING,
+ .help = "command to execute to configure bridge",
+ }, {
+#endif
.name = "sndbuf",
.type = QEMU_OPT_SIZE,
.help = "send buffer limit"
}, {
.name = "localaddr",
.type = QEMU_OPT_STRING,
- .help = "source address for multicast packets",
+ .help = "source address and port for multicast and udp packets",
+ }, {
+ .name = "udp",
+ .type = QEMU_OPT_STRING,
+ .help = "UDP unicast address and port number",
},
{ /* end of list */ }
},
{ /* end of list */ }
},
},
+#ifdef CONFIG_NET_BRIDGE
+ [NET_CLIENT_TYPE_BRIDGE] = {
+ .type = "bridge",
+ .init = net_init_bridge,
+ .desc = {
+ NET_COMMON_PARAMS_DESC,
+ {
+ .name = "br",
+ .type = QEMU_OPT_STRING,
+ .help = "bridge name",
+ }, {
+ .name = "helper",
+ .type = QEMU_OPT_STRING,
+ .help = "command to execute to configure bridge",
+ },
+ { /* end of list */ }
+ },
+ },
+#endif /* CONFIG_NET_BRIDGE */
};
-int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
+int net_client_init(QemuOpts *opts, int is_netdev, Error **errp)
{
const char *name;
const char *type;
type = qemu_opt_get(opts, "type");
if (!type) {
- qerror_report(QERR_MISSING_PARAMETER, "type");
+ error_set(errp, QERR_MISSING_PARAMETER, "type");
return -1;
}
if (is_netdev) {
if (strcmp(type, "tap") != 0 &&
+#ifdef CONFIG_NET_BRIDGE
+ strcmp(type, "bridge") != 0 &&
+#endif
#ifdef CONFIG_SLIRP
strcmp(type, "user") != 0 &&
#endif
strcmp(type, "vde") != 0 &&
#endif
strcmp(type, "socket") != 0) {
- qerror_report(QERR_INVALID_PARAMETER_VALUE, "type",
- "a netdev backend type");
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "type",
+ "a netdev backend type");
return -1;
}
if (qemu_opt_get(opts, "vlan")) {
- qerror_report(QERR_INVALID_PARAMETER, "vlan");
+ error_set(errp, QERR_INVALID_PARAMETER, "vlan");
return -1;
}
if (qemu_opt_get(opts, "name")) {
- qerror_report(QERR_INVALID_PARAMETER, "name");
+ error_set(errp, QERR_INVALID_PARAMETER, "name");
return -1;
}
if (!qemu_opts_id(opts)) {
- qerror_report(QERR_MISSING_PARAMETER, "id");
+ error_set(errp, QERR_MISSING_PARAMETER, "id");
return -1;
}
}
for (i = 0; i < NET_CLIENT_TYPE_MAX; i++) {
if (net_client_types[i].type != NULL &&
!strcmp(net_client_types[i].type, type)) {
+ Error *local_err = NULL;
VLANState *vlan = NULL;
int ret;
- if (qemu_opts_validate(opts, &net_client_types[i].desc[0]) == -1) {
+ qemu_opts_validate(opts, &net_client_types[i].desc[0], &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
return -1;
}
ret = 0;
if (net_client_types[i].init) {
- ret = net_client_types[i].init(opts, mon, name, vlan);
+ ret = net_client_types[i].init(opts, name, vlan);
if (ret < 0) {
/* TODO push error reporting into init() methods */
- qerror_report(QERR_DEVICE_INIT_FAILED, type);
+ error_set(errp, QERR_DEVICE_INIT_FAILED, type);
return -1;
}
}
}
}
- qerror_report(QERR_INVALID_PARAMETER_VALUE, "type",
- "a network client type");
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "type",
+ "a network client type");
return -1;
}
{
int i;
const char *valid_param_list[] = { "tap", "socket", "dump"
+#ifdef CONFIG_NET_BRIDGE
+ , "bridge"
+#endif
#ifdef CONFIG_SLIRP
,"user"
#endif
{
const char *device = qdict_get_str(qdict, "device");
const char *opts_str = qdict_get_try_str(qdict, "opts");
+ Error *local_err = NULL;
QemuOpts *opts;
if (!net_host_check_device(device)) {
qemu_opt_set(opts, "type", device);
- if (net_client_init(mon, opts, 0) < 0) {
+ net_client_init(opts, 0, &local_err);
+ if (error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
monitor_printf(mon, "adding host network device %s failed\n", device);
}
}
qemu_del_vlan_client(vc);
}
-int do_netdev_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
+void netdev_add(QemuOpts *opts, Error **errp)
{
+ net_client_init(opts, 1, errp);
+}
+
+int qmp_netdev_add(Monitor *mon, const QDict *qdict, QObject **ret)
+{
+ Error *local_err = NULL;
+ QemuOptsList *opts_list;
QemuOpts *opts;
- int res;
- opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict);
- if (!opts) {
- return -1;
+ opts_list = qemu_find_opts_err("netdev", &local_err);
+ if (error_is_set(&local_err)) {
+ goto exit_err;
+ }
+
+ opts = qemu_opts_from_qdict(opts_list, qdict, &local_err);
+ if (error_is_set(&local_err)) {
+ goto exit_err;
}
- res = net_client_init(mon, opts, 1);
- if (res < 0) {
+ netdev_add(opts, &local_err);
+ if (error_is_set(&local_err)) {
qemu_opts_del(opts);
+ goto exit_err;
}
- return res;
+ return 0;
+
+exit_err:
+ qerror_report_err(local_err);
+ error_free(local_err);
+ return -1;
}
-int do_netdev_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
+void qmp_netdev_del(const char *id, Error **errp)
{
- const char *id = qdict_get_str(qdict, "id");
VLANClientState *vc;
vc = qemu_find_netdev(id);
if (!vc) {
- qerror_report(QERR_DEVICE_NOT_FOUND, id);
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, id);
+ return;
}
+
qemu_del_vlan_client(vc);
- qemu_opts_del(qemu_opts_find(qemu_find_opts("netdev"), id));
- return 0;
+ qemu_opts_del(qemu_opts_find(qemu_find_opts_err("netdev", errp), id));
}
static void print_net_client(Monitor *mon, VLANClientState *vc)
}
}
-int do_set_link(Monitor *mon, const QDict *qdict, QObject **ret_data)
+void qmp_set_link(const char *name, bool up, Error **errp)
{
VLANState *vlan;
VLANClientState *vc = NULL;
- const char *name = qdict_get_str(qdict, "name");
- int up = qdict_get_bool(qdict, "up");
QTAILQ_FOREACH(vlan, &vlans, next) {
QTAILQ_FOREACH(vc, &vlan->clients, next) {
done:
if (!vc) {
- qerror_report(QERR_DEVICE_NOT_FOUND, name);
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, name);
+ return;
}
vc->link_down = !up;
if (vc->peer && vc->peer->info->link_status_changed) {
vc->peer->info->link_status_changed(vc->peer);
}
- return 0;
}
void net_cleanup(void)
static int net_init_client(QemuOpts *opts, void *dummy)
{
- if (net_client_init(NULL, opts, 0) < 0)
+ Error *local_err = NULL;
+
+ net_client_init(opts, 0, &local_err);
+ if (error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
return -1;
+ }
+
return 0;
}
static int net_init_netdev(QemuOpts *opts, void *dummy)
{
- return net_client_init(NULL, opts, 1);
+ Error *local_err = NULL;
+ int ret;
+
+ ret = net_client_init(opts, 1, &local_err);
+ if (error_is_set(&local_err)) {
+ qerror_report_err(local_err);
+ error_free(local_err);
+ return -1;
+ }
+
+ return ret;
}
int net_init_clients(void)
default_net = 0;
return 0;
}
+
+/* From FreeBSD */
+/* XXX: optimize */
+unsigned compute_mcast_idx(const uint8_t *ep)
+{
+ uint32_t crc;
+ int carry, i, j;
+ uint8_t b;
+
+ crc = 0xffffffff;
+ for (i = 0; i < 6; i++) {
+ b = *ep++;
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+ crc <<= 1;
+ b >>= 1;
+ if (carry) {
+ crc = ((crc ^ POLYNOMIAL) | carry);
+ }
+ }
+ }
+ return crc >> 26;
+}