]> git.proxmox.com Git - qemu.git/blobdiff - net.c
vnc: rename vnc-encoding-* vnc-enc-*
[qemu.git] / net.c
diff --git a/net.c b/net.c
index 13bdbb2caa0d14ad25909afc18da31aec5c83df7..8ddf872a6f1b896c5db2f49a07f950c6a2c89d93 100644 (file)
--- a/net.c
+++ b/net.c
 #include "sysemu.h"
 #include "qemu-common.h"
 #include "qemu_socket.h"
+#include "hw/qdev.h"
 
 static QTAILQ_HEAD(, VLANState) vlans;
 static QTAILQ_HEAD(, VLANClientState) non_vlan_clients;
 
+int default_net = 1;
+
 /***********************************************************/
 /* network device redirectors */
 
@@ -94,7 +97,7 @@ int parse_host_src_port(struct sockaddr_in *haddr,
                         struct sockaddr_in *saddr,
                         const char *input_str)
 {
-    char *str = strdup(input_str);
+    char *str = qemu_strdup(input_str);
     char *host_str = str;
     char *src_str;
     const char *src_str2;
@@ -243,6 +246,7 @@ VLANClientState *qemu_new_net_client(NetClientInfo *info,
         QTAILQ_INSERT_TAIL(&vc->vlan->clients, vc, next);
     } else {
         if (peer) {
+            assert(!peer->peer);
             vc->peer = peer;
             peer->peer = vc;
         }
@@ -729,7 +733,7 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models,
             return i;
     }
 
-    qemu_error("qemu: Unsupported NIC model: %s\n", nd->model);
+    error_report("qemu: Unsupported NIC model: %s", nd->model);
     return -1;
 }
 
@@ -740,7 +744,7 @@ int net_handle_fd_param(Monitor *mon, const char *param)
 
         fd = monitor_get_fd(mon, param);
         if (fd == -1) {
-            qemu_error("No file descriptor named %s found", param);
+            error_report("No file descriptor named %s found", param);
             return -1;
         }
 
@@ -761,7 +765,7 @@ static int net_init_nic(QemuOpts *opts,
 
     idx = nic_get_free_idx();
     if (idx == -1 || nb_nics >= MAX_NICS) {
-        qemu_error("Too Many NICs\n");
+        error_report("Too Many NICs");
         return -1;
     }
 
@@ -772,7 +776,7 @@ static int net_init_nic(QemuOpts *opts,
     if ((netdev = qemu_opt_get(opts, "netdev"))) {
         nd->netdev = qemu_find_netdev(netdev);
         if (!nd->netdev) {
-            qemu_error("netdev '%s' not found\n", netdev);
+            error_report("netdev '%s' not found", netdev);
             return -1;
         }
     } else {
@@ -798,21 +802,19 @@ static int net_init_nic(QemuOpts *opts,
 
     if (qemu_opt_get(opts, "macaddr") &&
         net_parse_macaddr(nd->macaddr, qemu_opt_get(opts, "macaddr")) < 0) {
-        qemu_error("invalid syntax for ethernet address\n");
+        error_report("invalid syntax for ethernet address");
         return -1;
     }
 
-    nd->nvectors = qemu_opt_get_number(opts, "vectors", NIC_NVECTORS_UNSPECIFIED);
-    if (nd->nvectors != NIC_NVECTORS_UNSPECIFIED &&
+    nd->nvectors = qemu_opt_get_number(opts, "vectors",
+                                       DEV_NVECTORS_UNSPECIFIED);
+    if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
         (nd->nvectors < 0 || nd->nvectors > 0x7ffffff)) {
-        qemu_error("invalid # of vectors: %d\n", nd->nvectors);
+        error_report("invalid # of vectors: %d", nd->nvectors);
         return -1;
     }
 
     nd->used = 1;
-    if (vlan) {
-        nd->vlan->nb_guest_devs++;
-    }
     nb_nics++;
 
     return idx;
@@ -841,7 +843,7 @@ typedef int (*net_client_init_func)(QemuOpts *opts,
 /* magic number, but compiler will warn if too small */
 #define NET_MAX_DESC 20
 
-static struct {
+static const struct {
     const char *type;
     net_client_init_func init;
     QemuOptDesc desc[NET_MAX_DESC];
@@ -974,6 +976,14 @@ static struct {
                 .name = "vnet_hdr",
                 .type = QEMU_OPT_BOOL,
                 .help = "enable the IFF_VNET_HDR flag on the tap interface"
+            }, {
+                .name = "vhost",
+                .type = QEMU_OPT_BOOL,
+                .help = "enable vhost-net network accelerator",
+            }, {
+                .name = "vhostfd",
+                .type = QEMU_OPT_STRING,
+                .help = "file descriptor of an already opened vhost net device",
             },
 #endif /* _WIN32 */
             { /* end of list */ }
@@ -1055,18 +1065,12 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
     int i;
 
     type = qemu_opt_get(opts, "type");
+    if (!type) {
+        qerror_report(QERR_MISSING_PARAMETER, "type");
+        return -1;
+    }
 
-    if (!is_netdev) {
-        if (!type) {
-            qemu_error("No type specified for -net\n");
-            return -1;
-        }
-    } else {
-        if (!type) {
-            qemu_error("No type specified for -netdev\n");
-            return -1;
-        }
-
+    if (is_netdev) {
         if (strcmp(type, "tap") != 0 &&
 #ifdef CONFIG_SLIRP
             strcmp(type, "user") != 0 &&
@@ -1075,21 +1079,21 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
             strcmp(type, "vde") != 0 &&
 #endif
             strcmp(type, "socket") != 0) {
-            qemu_error("The '%s' network backend type is not valid with -netdev\n",
-                       type);
+            qerror_report(QERR_INVALID_PARAMETER_VALUE, "type",
+                          "a netdev backend type");
             return -1;
         }
 
         if (qemu_opt_get(opts, "vlan")) {
-            qemu_error("The 'vlan' parameter is not valid with -netdev\n");
+            qerror_report(QERR_INVALID_PARAMETER, "vlan");
             return -1;
         }
         if (qemu_opt_get(opts, "name")) {
-            qemu_error("The 'name' parameter is not valid with -netdev\n");
+            qerror_report(QERR_INVALID_PARAMETER, "name");
             return -1;
         }
         if (!qemu_opts_id(opts)) {
-            qemu_error("The id= parameter is required with -netdev\n");
+            qerror_report(QERR_MISSING_PARAMETER, "id");
             return -1;
         }
     }
@@ -1102,6 +1106,7 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
     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;
@@ -1114,32 +1119,24 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
                 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;
         }
     }
 
-    qemu_error("Invalid -net type '%s'\n", type);
+    qerror_report(QERR_INVALID_PARAMETER_VALUE, "type",
+                  "a network client type");
     return -1;
 }
 
-void net_client_uninit(NICInfo *nd)
-{
-    if (nd->vlan) {
-        nd->vlan->nb_guest_devs--;
-    }
-    nb_nics--;
-
-    qemu_free(nd->model);
-    qemu_free(nd->name);
-    qemu_free(nd->devaddr);
-
-    nd->used = 0;
-}
-
 static int net_host_check_device(const char *device)
 {
     int i;
@@ -1171,10 +1168,8 @@ void net_host_device_add(Monitor *mon, const QDict *qdict)
         return;
     }
 
-    opts = qemu_opts_parse(&qemu_net_opts, opts_str ? opts_str : "", NULL);
+    opts = qemu_opts_parse(&qemu_net_opts, opts_str ? opts_str : "", 0);
     if (!opts) {
-        monitor_printf(mon, "parsing network options '%s' failed\n",
-                       opts_str ? opts_str : "");
         return;
     }
 
@@ -1202,47 +1197,67 @@ void net_host_device_remove(Monitor *mon, const QDict *qdict)
     qemu_del_vlan_client(vc);
 }
 
-void net_set_boot_mask(int net_boot_mask)
+int do_netdev_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
-    int i;
+    QemuOpts *opts;
+    int res;
 
-    /* Only the first four NICs may be bootable */
-    net_boot_mask = net_boot_mask & 0xF;
+    opts = qemu_opts_from_qdict(&qemu_netdev_opts, qdict);
+    if (!opts) {
+        return -1;
+    }
 
-    for (i = 0; i < nb_nics; i++) {
-        if (net_boot_mask & (1 << i)) {
-            nd_table[i].bootable = 1;
-            net_boot_mask &= ~(1 << i);
-        }
+    res = net_client_init(mon, opts, 1);
+    if (res < 0) {
+        qemu_opts_del(opts);
     }
 
-    if (net_boot_mask) {
-        fprintf(stderr, "Cannot boot from non-existent NIC\n");
-        exit(1);
+    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_netdev_opts, id));
+    return 0;
 }
 
 void do_info_network(Monitor *mon)
 {
     VLANState *vlan;
+    VLANClientState *vc;
 
     QTAILQ_FOREACH(vlan, &vlans, next) {
-        VLANClientState *vc;
-
         monitor_printf(mon, "VLAN %d devices:\n", vlan->id);
 
         QTAILQ_FOREACH(vc, &vlan->clients, next) {
             monitor_printf(mon, "  %s: %s\n", vc->name, vc->info_str);
         }
     }
+    monitor_printf(mon, "Devices not on any VLAN:\n");
+    QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+        monitor_printf(mon, "  %s: %s", vc->name, vc->info_str);
+        if (vc->peer) {
+            monitor_printf(mon, " peer=%s", vc->peer->name);
+        }
+        monitor_printf(mon, "\n");
+    }
 }
 
-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) {
@@ -1251,24 +1266,20 @@ void do_set_link(Monitor *mon, const QDict *qdict)
             }
         }
     }
+    vc = qemu_find_netdev(name);
 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)
@@ -1287,20 +1298,41 @@ void net_cleanup(void)
     }
 }
 
-static void net_check_clients(void)
+void net_check_clients(void)
 {
     VLANState *vlan;
+    VLANClientState *vc;
+    int has_nic = 0, has_host_dev = 0;
 
     QTAILQ_FOREACH(vlan, &vlans, next) {
-        if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0)
-            continue;
-        if (vlan->nb_guest_devs == 0)
+        QTAILQ_FOREACH(vc, &vlan->clients, next) {
+            switch (vc->info->type) {
+            case NET_CLIENT_TYPE_NIC:
+                has_nic = 1;
+                break;
+            case NET_CLIENT_TYPE_SLIRP:
+            case NET_CLIENT_TYPE_TAP:
+            case NET_CLIENT_TYPE_SOCKET:
+            case NET_CLIENT_TYPE_VDE:
+                has_host_dev = 1;
+                break;
+            default: ;
+            }
+        }
+        if (has_host_dev && !has_nic)
             fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id);
-        if (vlan->nb_host_devs == 0)
+        if (has_nic && !has_host_dev)
             fprintf(stderr,
                     "Warning: vlan %d is not connected to host network\n",
                     vlan->id);
     }
+    QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+        if (!vc->peer) {
+            fprintf(stderr, "Warning: %s %s has no peer\n",
+                    vc->info->type == NET_CLIENT_TYPE_NIC ? "nic" : "netdev",
+                    vc->name);
+        }
+    }
 }
 
 static int net_init_client(QemuOpts *opts, void *dummy)
@@ -1317,7 +1349,7 @@ static int net_init_netdev(QemuOpts *opts, void *dummy)
 
 int net_init_clients(void)
 {
-    if (QTAILQ_EMPTY(&qemu_net_opts.head)) {
+    if (default_net) {
         /* if no clients, we use a default config */
         qemu_opts_set(&qemu_net_opts, NULL, "type", "nic");
 #ifdef CONFIG_SLIRP
@@ -1335,8 +1367,6 @@ int net_init_clients(void)
         return -1;
     }
 
-    net_check_clients();
-
     return 0;
 }
 
@@ -1349,9 +1379,10 @@ int net_client_parse(QemuOptsList *opts_list, const char *optarg)
     }
 #endif
 
-    if (!qemu_opts_parse(opts_list, optarg, "type")) {
+    if (!qemu_opts_parse(opts_list, optarg, 1)) {
         return -1;
     }
 
+    default_net = 0;
     return 0;
 }