return nic;
}
-void qemu_del_vlan_client(VLANClientState *vc)
+static void qemu_cleanup_vlan_client(VLANClientState *vc)
{
if (vc->vlan) {
QTAILQ_REMOVE(&vc->vlan->clients, vc, next);
} else {
- if (vc->send_queue) {
- qemu_del_net_queue(vc->send_queue);
- }
QTAILQ_REMOVE(&non_vlan_clients, vc, next);
- if (vc->peer) {
- vc->peer->peer = NULL;
- }
}
if (vc->info->cleanup) {
vc->info->cleanup(vc);
}
+}
+static void qemu_free_vlan_client(VLANClientState *vc)
+{
+ if (!vc->vlan) {
+ if (vc->send_queue) {
+ qemu_del_net_queue(vc->send_queue);
+ }
+ if (vc->peer) {
+ vc->peer->peer = NULL;
+ }
+ }
qemu_free(vc->name);
qemu_free(vc->model);
qemu_free(vc);
}
+void qemu_del_vlan_client(VLANClientState *vc)
+{
+ /* If there is a peer NIC, delete and cleanup client, but do not free. */
+ if (!vc->vlan && vc->peer && vc->peer->info->type == NET_CLIENT_TYPE_NIC) {
+ NICState *nic = DO_UPCAST(NICState, nc, vc->peer);
+ if (nic->peer_deleted) {
+ return;
+ }
+ nic->peer_deleted = true;
+ /* Let NIC know peer is gone. */
+ vc->peer->link_down = true;
+ if (vc->peer->info->link_status_changed) {
+ vc->peer->info->link_status_changed(vc->peer);
+ }
+ qemu_cleanup_vlan_client(vc);
+ return;
+ }
+
+ /* If this is a peer NIC and peer has already been deleted, free it now. */
+ if (!vc->vlan && vc->peer && vc->info->type == NET_CLIENT_TYPE_NIC) {
+ NICState *nic = DO_UPCAST(NICState, nc, vc);
+ if (nic->peer_deleted) {
+ qemu_free_vlan_client(vc->peer);
+ }
+ }
+
+ qemu_cleanup_vlan_client(vc);
+ qemu_free_vlan_client(vc);
+}
+
VLANClientState *
qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id,
const char *client_str)
int net_handle_fd_param(Monitor *mon, const char *param)
{
- if (!qemu_isdigit(param[0])) {
- int fd;
+ int fd;
+
+ if (!qemu_isdigit(param[0]) && mon) {
fd = monitor_get_fd(mon, param);
if (fd == -1) {
error_report("No file descriptor named %s found", param);
return -1;
}
-
- return fd;
} else {
- return strtol(param, NULL, 0);
+ char *endptr = NULL;
+
+ fd = strtol(param, &endptr, 10);
+ if (*endptr || (fd == 0 && param == endptr)) {
+ return -1;
+ }
}
+
+ return fd;
}
static int net_init_nic(QemuOpts *opts,
int i;
type = qemu_opt_get(opts, "type");
+ if (!type) {
+ qerror_report(QERR_MISSING_PARAMETER, "type");
+ return -1;
+ }
- if (!is_netdev) {
- if (!type) {
- error_report("No type specified for -net");
- return -1;
- }
- } else {
- if (!type) {
- error_report("No type specified for -netdev");
- return -1;
- }
-
+ if (is_netdev) {
if (strcmp(type, "tap") != 0 &&
#ifdef CONFIG_SLIRP
strcmp(type, "user") != 0 &&
strcmp(type, "vde") != 0 &&
#endif
strcmp(type, "socket") != 0) {
- error_report("The '%s' network backend type is not valid with -netdev",
- type);
+ qerror_report(QERR_INVALID_PARAMETER_VALUE, "type",
+ "a netdev backend type");
return -1;
}
if (qemu_opt_get(opts, "vlan")) {
- error_report("The 'vlan' parameter is not valid with -netdev");
+ qerror_report(QERR_INVALID_PARAMETER, "vlan");
return -1;
}
if (qemu_opt_get(opts, "name")) {
- error_report("The 'name' parameter is not valid with -netdev");
+ qerror_report(QERR_INVALID_PARAMETER, "name");
return -1;
}
if (!qemu_opts_id(opts)) {
- error_report("The id= parameter is required with -netdev");
+ qerror_report(QERR_MISSING_PARAMETER, "id");
return -1;
}
}
for (i = 0; net_client_types[i].type != NULL; i++) {
if (!strcmp(net_client_types[i].type, type)) {
VLANState *vlan = NULL;
+ int ret;
if (qemu_opts_validate(opts, &net_client_types[i].desc[0]) == -1) {
return -1;
vlan = qemu_find_vlan(qemu_opt_get_number(opts, "vlan", 0), 1);
}
+ ret = 0;
if (net_client_types[i].init) {
- return net_client_types[i].init(opts, mon, name, vlan);
- } else {
- return 0;
+ ret = net_client_types[i].init(opts, mon, name, vlan);
+ if (ret < 0) {
+ /* TODO push error reporting into init() methods */
+ qerror_report(QERR_DEVICE_INIT_FAILED, type);
+ return -1;
+ }
}
+ return ret;
}
}
- error_report("Invalid -net type '%s'", type);
+ qerror_report(QERR_INVALID_PARAMETER_VALUE, "type",
+ "a network client type");
return -1;
}
return;
}
- opts = qemu_opts_parse(&qemu_net_opts, opts_str ? opts_str : "", 0);
+ opts = qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_str : "", 0);
if (!opts) {
- monitor_printf(mon, "parsing network options '%s' failed\n",
- opts_str ? opts_str : "");
return;
}
qemu_del_vlan_client(vc);
}
+int do_netdev_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ QemuOpts *opts;
+ int res;
+
+ opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict);
+ if (!opts) {
+ return -1;
+ }
+
+ res = net_client_init(mon, opts, 1);
+ if (res < 0) {
+ qemu_opts_del(opts);
+ }
+
+ return res;
+}
+
+int do_netdev_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ const char *id = qdict_get_str(qdict, "id");
+ VLANClientState *vc;
+
+ vc = qemu_find_netdev(id);
+ if (!vc || vc->info->type == NET_CLIENT_TYPE_NIC) {
+ qerror_report(QERR_DEVICE_NOT_FOUND, id);
+ return -1;
+ }
+ qemu_del_vlan_client(vc);
+ qemu_opts_del(qemu_opts_find(qemu_find_opts("netdev"), id));
+ return 0;
+}
+
void do_info_network(Monitor *mon)
{
VLANState *vlan;
}
}
-void do_set_link(Monitor *mon, const QDict *qdict)
+int do_set_link(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
VLANState *vlan;
VLANClientState *vc = NULL;
const char *name = qdict_get_str(qdict, "name");
- const char *up_or_down = qdict_get_str(qdict, "up_or_down");
+ int up = qdict_get_bool(qdict, "up");
QTAILQ_FOREACH(vlan, &vlans, next) {
QTAILQ_FOREACH(vc, &vlan->clients, next) {
done:
if (!vc) {
- monitor_printf(mon, "could not find network device '%s'\n", name);
- return;
+ qerror_report(QERR_DEVICE_NOT_FOUND, name);
+ return -1;
}
- if (strcmp(up_or_down, "up") == 0)
- vc->link_down = 0;
- else if (strcmp(up_or_down, "down") == 0)
- vc->link_down = 1;
- else
- monitor_printf(mon, "invalid link status '%s'; only 'up' or 'down' "
- "valid\n", up_or_down);
+ vc->link_down = !up;
if (vc->info->link_status_changed) {
vc->info->link_status_changed(vc);
}
+ return 0;
}
void net_cleanup(void)
int net_init_clients(void)
{
+ QemuOptsList *net = qemu_find_opts("net");
+
if (default_net) {
/* if no clients, we use a default config */
- qemu_opts_set(&qemu_net_opts, NULL, "type", "nic");
+ qemu_opts_set(net, NULL, "type", "nic");
#ifdef CONFIG_SLIRP
- qemu_opts_set(&qemu_net_opts, NULL, "type", "user");
+ qemu_opts_set(net, NULL, "type", "user");
#endif
}
QTAILQ_INIT(&vlans);
QTAILQ_INIT(&non_vlan_clients);
- if (qemu_opts_foreach(&qemu_netdev_opts, net_init_netdev, NULL, 1) == -1)
+ if (qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL, 1) == -1)
return -1;
- if (qemu_opts_foreach(&qemu_net_opts, net_init_client, NULL, 1) == -1) {
+ if (qemu_opts_foreach(net, net_init_client, NULL, 1) == -1) {
return -1;
}