#include "net/dump.h"
#include "net/slirp.h"
#include "net/vde.h"
+#include "net/util.h"
#include "monitor.h"
#include "sysemu.h"
#include "qemu-common.h"
static QTAILQ_HEAD(, VLANState) vlans;
static QTAILQ_HEAD(, VLANClientState) non_vlan_clients;
+int default_net = 1;
+
/***********************************************************/
/* network device redirectors */
}
#endif
-static int parse_macaddr(uint8_t *macaddr, const char *p)
-{
- int i;
- char *last_char;
- long int offset;
-
- errno = 0;
- offset = strtol(p, &last_char, 0);
- if (0 == errno && '\0' == *last_char &&
- offset >= 0 && offset <= 0xFFFFFF) {
- macaddr[3] = (offset & 0xFF0000) >> 16;
- macaddr[4] = (offset & 0xFF00) >> 8;
- macaddr[5] = offset & 0xFF;
- return 0;
- } else {
- for(i = 0; i < 6; i++) {
- macaddr[i] = strtol(p, (char **)&p, 16);
- if (i == 5) {
- if (*p != '\0')
- return -1;
- } else {
- if (*p != ':' && *p != '-')
- return -1;
- p++;
- }
- }
- return 0;
- }
-
- return -1;
-}
-
static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
{
const char *p, *p1;
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;
int iovcnt,
void *opaque);
-VLANClientState *qemu_new_vlan_client(net_client_type type,
- VLANState *vlan,
- VLANClientState *peer,
- const char *model,
- const char *name,
- NetCanReceive *can_receive,
- NetReceive *receive,
- NetReceive *receive_raw,
- NetReceiveIOV *receive_iov,
- NetCleanup *cleanup,
- void *opaque)
+VLANClientState *qemu_new_net_client(NetClientInfo *info,
+ VLANState *vlan,
+ VLANClientState *peer,
+ const char *model,
+ const char *name)
{
VLANClientState *vc;
- vc = qemu_mallocz(sizeof(VLANClientState));
+ assert(info->size >= sizeof(VLANClientState));
+
+ vc = qemu_mallocz(info->size);
- vc->type = type;
+ vc->info = info;
vc->model = qemu_strdup(model);
- if (name)
+ if (name) {
vc->name = qemu_strdup(name);
- else
+ } else {
vc->name = assign_name(vc, model);
- vc->can_receive = can_receive;
- vc->receive = receive;
- vc->receive_raw = receive_raw;
- vc->receive_iov = receive_iov;
- vc->cleanup = cleanup;
- vc->opaque = opaque;
+ }
if (vlan) {
assert(!peer);
return vc;
}
+NICState *qemu_new_nic(NetClientInfo *info,
+ NICConf *conf,
+ const char *model,
+ const char *name,
+ void *opaque)
+{
+ VLANClientState *nc;
+ NICState *nic;
+
+ assert(info->type == NET_CLIENT_TYPE_NIC);
+ assert(info->size >= sizeof(NICState));
+
+ nc = qemu_new_net_client(info, conf->vlan, conf->peer, model, name);
+
+ nic = DO_UPCAST(NICState, nc, nc);
+ nic->conf = conf;
+ nic->opaque = opaque;
+
+ return nic;
+}
+
void qemu_del_vlan_client(VLANClientState *vc)
{
if (vc->vlan) {
}
}
- if (vc->cleanup) {
- vc->cleanup(vc);
+ if (vc->info->cleanup) {
+ vc->info->cleanup(vc);
}
qemu_free(vc->name);
qemu_free(vc);
}
-VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque)
-{
- VLANClientState *vc;
-
- QTAILQ_FOREACH(vc, &vlan->clients, next) {
- if (vc->opaque == opaque) {
- return vc;
- }
- }
-
- return NULL;
-}
-
VLANClientState *
qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id,
const char *client_str)
return vc;
}
+void qemu_foreach_nic(qemu_nic_foreach func, void *opaque)
+{
+ VLANClientState *nc;
+ VLANState *vlan;
+
+ QTAILQ_FOREACH(nc, &non_vlan_clients, next) {
+ if (nc->info->type == NET_CLIENT_TYPE_NIC) {
+ func(DO_UPCAST(NICState, nc, nc), opaque);
+ }
+ }
+
+ QTAILQ_FOREACH(vlan, &vlans, next) {
+ QTAILQ_FOREACH(nc, &vlan->clients, next) {
+ if (nc->info->type == NET_CLIENT_TYPE_NIC) {
+ func(DO_UPCAST(NICState, nc, nc), opaque);
+ }
+ }
+ }
+}
+
int qemu_can_send_packet(VLANClientState *sender)
{
VLANState *vlan = sender->vlan;
if (sender->peer) {
if (sender->peer->receive_disabled) {
return 0;
- } else if (sender->peer->can_receive &&
- !sender->peer->can_receive(sender->peer)) {
+ } else if (sender->peer->info->can_receive &&
+ !sender->peer->info->can_receive(sender->peer)) {
return 0;
} else {
return 1;
}
/* no can_receive() handler, they can always receive */
- if (!vc->can_receive || vc->can_receive(vc)) {
+ if (!vc->info->can_receive || vc->info->can_receive(vc)) {
return 1;
}
}
return 0;
}
- if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->receive_raw) {
- ret = vc->receive_raw(vc, data, size);
+ if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->info->receive_raw) {
+ ret = vc->info->receive_raw(vc, data, size);
} else {
- ret = vc->receive(vc, data, size);
+ ret = vc->info->receive(vc, data, size);
}
if (ret == 0) {
continue;
}
- if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->receive_raw) {
- len = vc->receive_raw(vc, buf, size);
+ if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->info->receive_raw) {
+ len = vc->info->receive_raw(vc, buf, size);
} else {
- len = vc->receive(vc, buf, size);
+ len = vc->info->receive(vc, buf, size);
}
if (len == 0) {
offset += len;
}
- return vc->receive(vc, buffer, offset);
+ return vc->info->receive(vc, buffer, offset);
}
static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt)
return calc_iov_length(iov, iovcnt);
}
- if (vc->receive_iov) {
- return vc->receive_iov(vc, iov, iovcnt);
+ if (vc->info->receive_iov) {
+ return vc->info->receive_iov(vc, iov, iovcnt);
} else {
return vc_sendv_compat(vc, iov, iovcnt);
}
assert(!(flags & QEMU_NET_PACKET_FLAG_RAW));
- if (vc->receive_iov) {
- len = vc->receive_iov(vc, iov, iovcnt);
+ if (vc->info->receive_iov) {
+ len = vc->info->receive_iov(vc, iov, iovcnt);
} else {
len = vc_sendv_compat(vc, iov, iovcnt);
}
nd->macaddr[5] = 0x56 + idx;
if (qemu_opt_get(opts, "macaddr") &&
- parse_macaddr(nd->macaddr, qemu_opt_get(opts, "macaddr")) < 0) {
+ net_parse_macaddr(nd->macaddr, qemu_opt_get(opts, "macaddr")) < 0) {
qemu_error("invalid syntax for ethernet address\n");
return -1;
}
}
nd->used = 1;
- if (vlan) {
- nd->vlan->nb_guest_devs++;
- }
nb_nics++;
return idx;
/* 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];
int i;
type = qemu_opt_get(opts, "type");
- if (!type) {
- qemu_error("No type specified for -net\n");
- return -1;
- }
- if (is_netdev) {
+ 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 (strcmp(type, "tap") != 0 &&
#ifdef CONFIG_SLIRP
strcmp(type, "user") != 0 &&
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;
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)
}
}
}
+ vc = qemu_find_netdev(name);
done:
if (!vc) {
monitor_printf(mon, "invalid link status '%s'; only 'up' or 'down' "
"valid\n", up_or_down);
- if (vc->link_status_changed)
- vc->link_status_changed(vc);
+ if (vc->info->link_status_changed) {
+ vc->info->link_status_changed(vc);
+ }
}
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)
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
return -1;
}
- net_check_clients();
-
return 0;
}
return -1;
}
+ default_net = 0;
return 0;
}