X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/641f6eae757e5b2cf854fec14038ffd229e9adea..d1b719e98ce8b506d122a845d405f941a7a497c1:/net.c diff --git a/net.c b/net.c index 68c2840621..1922d8abd1 100644 --- a/net.c +++ b/net.c @@ -34,9 +34,15 @@ #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; @@ -150,12 +156,11 @@ void qemu_macaddr_default_if_unset(MACAddr *macaddr) static char *assign_name(VLANClientState *vc1, const char *model) { VLANState *vlan; + VLANClientState *vc; char buf[256]; int id = 0; QTAILQ_FOREACH(vlan, &vlans, next) { - VLANClientState *vc; - QTAILQ_FOREACH(vc, &vlan->clients, next) { if (vc != vc1 && strcmp(vc->model, model) == 0) { id++; @@ -163,9 +168,15 @@ static char *assign_name(VLANClientState *vc1, const char *model) } } + QTAILQ_FOREACH(vc, &non_vlan_clients, next) { + if (vc != vc1 && strcmp(vc->model, model) == 0) { + id++; + } + } + snprintf(buf, sizeof(buf), "%s.%d", model, id); - return qemu_strdup(buf); + return g_strdup(buf); } static ssize_t qemu_deliver_packet(VLANClientState *sender, @@ -189,12 +200,12 @@ VLANClientState *qemu_new_net_client(NetClientInfo *info, assert(info->size >= sizeof(VLANClientState)); - vc = qemu_mallocz(info->size); + vc = g_malloc0(info->size); vc->info = info; - vc->model = qemu_strdup(model); + vc->model = g_strdup(model); if (name) { - vc->name = qemu_strdup(name); + vc->name = g_strdup(name); } else { vc->name = assign_name(vc, model); } @@ -263,9 +274,9 @@ static void qemu_free_vlan_client(VLANClientState *vc) vc->peer->peer = NULL; } } - qemu_free(vc->name); - qemu_free(vc->model); - qemu_free(vc); + g_free(vc->name); + g_free(vc->model); + g_free(vc); } void qemu_del_vlan_client(VLANClientState *vc) @@ -635,7 +646,7 @@ VLANState *qemu_find_vlan(int id, int allocate) return NULL; } - vlan = qemu_mallocz(sizeof(VLANState)); + vlan = g_malloc0(sizeof(VLANState)); vlan->id = id; QTAILQ_INIT(&vlan->clients); @@ -653,6 +664,8 @@ VLANClientState *qemu_find_netdev(const char *id) VLANClientState *vc; QTAILQ_FOREACH(vc, &non_vlan_clients, next) { + if (vc->info->type == NET_CLIENT_TYPE_NIC) + continue; if (!strcmp(vc->name, id)) { return vc; } @@ -703,14 +716,14 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models, int i; if (!nd->model) - nd->model = qemu_strdup(default_model); + nd->model = g_strdup(default_model); for (i = 0 ; models[i]; i++) { if (strcmp(nd->model, models[i]) == 0) return i; } - error_report("qemu: Unsupported NIC model: %s", nd->model); + error_report("Unsupported NIC model: %s", nd->model); return -1; } @@ -726,12 +739,7 @@ int net_handle_fd_param(Monitor *mon, const char *param) return -1; } } else { - char *endptr = NULL; - - fd = strtol(param, &endptr, 10); - if (*endptr || (fd == 0 && param == endptr)) { - return -1; - } + fd = qemu_parse_fd(param); } return fd; @@ -767,27 +775,21 @@ static int net_init_nic(QemuOpts *opts, nd->vlan = vlan; } if (name) { - nd->name = qemu_strdup(name); + nd->name = g_strdup(name); } if (qemu_opt_get(opts, "model")) { - nd->model = qemu_strdup(qemu_opt_get(opts, "model")); + nd->model = g_strdup(qemu_opt_get(opts, "model")); } if (qemu_opt_get(opts, "addr")) { - nd->devaddr = qemu_strdup(qemu_opt_get(opts, "addr")); + nd->devaddr = g_strdup(qemu_opt_get(opts, "addr")); } - nd->macaddr[0] = 0x52; - nd->macaddr[1] = 0x54; - nd->macaddr[2] = 0x00; - nd->macaddr[3] = 0x12; - nd->macaddr[4] = 0x34; - nd->macaddr[5] = 0x56 + idx; - if (qemu_opt_get(opts, "macaddr") && - net_parse_macaddr(nd->macaddr, qemu_opt_get(opts, "macaddr")) < 0) { + net_parse_macaddr(nd->macaddr.a, qemu_opt_get(opts, "macaddr")) < 0) { error_report("invalid syntax for ethernet address"); return -1; } + qemu_macaddr_default_if_unset(&nd->macaddr); nd->nvectors = qemu_opt_get_number(opts, "vectors", DEV_NVECTORS_UNSPECIFIED); @@ -830,14 +832,15 @@ static const struct { const char *type; net_client_init_func init; QemuOptDesc desc[NET_MAX_DESC]; -} net_client_types[] = { - { +} net_client_types[NET_CLIENT_TYPE_MAX] = { + [NET_CLIENT_TYPE_NONE] = { .type = "none", .desc = { NET_COMMON_PARAMS_DESC, { /* end of list */ } }, - }, { + }, + [NET_CLIENT_TYPE_NIC] = { .type = "nic", .init = net_init_nic, .desc = { @@ -866,8 +869,9 @@ static const struct { }, { /* end of list */ } }, + }, #ifdef CONFIG_SLIRP - }, { + [NET_CLIENT_TYPE_USER] = { .type = "user", .init = net_init_slirp, .desc = { @@ -927,8 +931,9 @@ static const struct { }, { /* end of list */ } }, + }, #endif - }, { + [NET_CLIENT_TYPE_TAP] = { .type = "tap", .init = net_init_tap, .desc = { @@ -952,6 +957,12 @@ static const struct { .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" @@ -975,7 +986,8 @@ static const struct { #endif /* _WIN32 */ { /* end of list */ } }, - }, { + }, + [NET_CLIENT_TYPE_SOCKET] = { .type = "socket", .init = net_init_socket, .desc = { @@ -999,12 +1011,17 @@ static const struct { }, { .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 */ } }, + }, #ifdef CONFIG_VDE - }, { + [NET_CLIENT_TYPE_VDE] = { .type = "vde", .init = net_init_vde, .desc = { @@ -1028,8 +1045,9 @@ static const struct { }, { /* end of list */ } }, + }, #endif - }, { + [NET_CLIENT_TYPE_DUMP] = { .type = "dump", .init = net_init_dump, .desc = { @@ -1046,7 +1064,25 @@ static const struct { { /* 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) @@ -1063,6 +1099,9 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev) 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 @@ -1094,8 +1133,9 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev) name = qemu_opt_get(opts, "name"); } - for (i = 0; net_client_types[i].type != NULL; i++) { - if (!strcmp(net_client_types[i].type, type)) { + for (i = 0; i < NET_CLIENT_TYPE_MAX; i++) { + if (net_client_types[i].type != NULL && + !strcmp(net_client_types[i].type, type)) { VLANState *vlan = NULL; int ret; @@ -1132,6 +1172,9 @@ static int net_host_check_device(const char *device) { int i; const char *valid_param_list[] = { "tap", "socket", "dump" +#ifdef CONFIG_NET_BRIDGE + , "bridge" +#endif #ifdef CONFIG_SLIRP ,"user" #endif @@ -1212,7 +1255,7 @@ int do_netdev_del(Monitor *mon, const QDict *qdict, QObject **ret_data) VLANClientState *vc; vc = qemu_find_netdev(id); - if (!vc || vc->info->type == NET_CLIENT_TYPE_NIC) { + if (!vc) { qerror_report(QERR_DEVICE_NOT_FOUND, id); return -1; } @@ -1221,34 +1264,45 @@ int do_netdev_del(Monitor *mon, const QDict *qdict, QObject **ret_data) return 0; } +static void print_net_client(Monitor *mon, VLANClientState *vc) +{ + monitor_printf(mon, "%s: type=%s,%s\n", vc->name, + net_client_types[vc->info->type].type, vc->info_str); +} + void do_info_network(Monitor *mon) { VLANState *vlan; - VLANClientState *vc; + VLANClientState *vc, *peer; + net_client_type type; QTAILQ_FOREACH(vlan, &vlans, next) { 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, " "); + print_net_client(mon, vc); } } 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); + peer = vc->peer; + type = vc->info->type; + if (!peer || type == NET_CLIENT_TYPE_NIC) { + monitor_printf(mon, " "); + print_net_client(mon, vc); + } /* else it's a netdev connected to a NIC, printed with the NIC */ + if (peer && type == NET_CLIENT_TYPE_NIC) { + monitor_printf(mon, " \\ "); + print_net_client(mon, peer); } - monitor_printf(mon, "\n"); } } -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) { @@ -1257,12 +1311,16 @@ int do_set_link(Monitor *mon, const QDict *qdict, QObject **ret_data) } } } - vc = qemu_find_netdev(name); + QTAILQ_FOREACH(vc, &non_vlan_clients, next) { + if (!strcmp(vc->name, name)) { + goto done; + } + } 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; @@ -1281,7 +1339,6 @@ done: if (vc->peer && vc->peer->info->link_status_changed) { vc->peer->info->link_status_changed(vc->peer); } - return 0; } void net_cleanup(void) @@ -1304,6 +1361,7 @@ void net_check_clients(void) { VLANState *vlan; VLANClientState *vc; + int i; /* Don't warn about the default network setup that you get if * no command line -net or -netdev options are specified. There @@ -1325,7 +1383,7 @@ void net_check_clients(void) case NET_CLIENT_TYPE_NIC: has_nic = 1; break; - case NET_CLIENT_TYPE_SLIRP: + case NET_CLIENT_TYPE_USER: case NET_CLIENT_TYPE_TAP: case NET_CLIENT_TYPE_SOCKET: case NET_CLIENT_TYPE_VDE: @@ -1348,6 +1406,20 @@ void net_check_clients(void) vc->name); } } + + /* Check that all NICs requested via -net nic actually got created. + * NICs created via -device don't need to be checked here because + * they are always instantiated. + */ + for (i = 0; i < MAX_NICS; i++) { + NICInfo *nd = &nd_table[i]; + if (nd->used && !nd->instantiated) { + fprintf(stderr, "Warning: requested NIC (%s, model %s) " + "was not created (not supported by this machine?)\n", + nd->name ? nd->name : "anonymous", + nd->model ? nd->model : "unspecified"); + } + } } static int net_init_client(QemuOpts *opts, void *dummy) @@ -1403,3 +1475,26 @@ int net_client_parse(QemuOptsList *opts_list, const char *optarg) 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; +}