net_hub_port_find is unused since 2018's commit
  af1a5c3eb4 ("net: Remove the deprecated "vlan" parameter")
qemu_receive_packet_iov is unused since commit
  ffbd2dbd8e ("e1000e: Perform software segmentation for loopback")
in turn it was the last user of qemu_net_queue_receive_iov.
Remove them.
Signed-off-by: Dr. David Alan Gilbert <dave@treblig.org>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
		
	
			
		
			
				
	
	
		
			323 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			323 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Hub net client
 | 
						|
 *
 | 
						|
 * Copyright IBM, Corp. 2012
 | 
						|
 *
 | 
						|
 * Authors:
 | 
						|
 *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
 | 
						|
 *  Zhi Yong Wu       <wuzhy@linux.vnet.ibm.com>
 | 
						|
 *
 | 
						|
 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
 | 
						|
 * See the COPYING.LIB file in the top-level directory.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include "qemu/osdep.h"
 | 
						|
#include "qapi/error.h"
 | 
						|
#include "monitor/monitor.h"
 | 
						|
#include "net/net.h"
 | 
						|
#include "clients.h"
 | 
						|
#include "hub.h"
 | 
						|
#include "qemu/iov.h"
 | 
						|
#include "qemu/error-report.h"
 | 
						|
#include "sysemu/qtest.h"
 | 
						|
 | 
						|
/*
 | 
						|
 * A hub broadcasts incoming packets to all its ports except the source port.
 | 
						|
 * Hubs can be used to provide independent emulated network segments.
 | 
						|
 */
 | 
						|
 | 
						|
typedef struct NetHub NetHub;
 | 
						|
 | 
						|
typedef struct NetHubPort {
 | 
						|
    NetClientState nc;
 | 
						|
    QLIST_ENTRY(NetHubPort) next;
 | 
						|
    NetHub *hub;
 | 
						|
    int id;
 | 
						|
} NetHubPort;
 | 
						|
 | 
						|
struct NetHub {
 | 
						|
    int id;
 | 
						|
    QLIST_ENTRY(NetHub) next;
 | 
						|
    int num_ports;
 | 
						|
    QLIST_HEAD(, NetHubPort) ports;
 | 
						|
};
 | 
						|
 | 
						|
static QLIST_HEAD(, NetHub) hubs = QLIST_HEAD_INITIALIZER(&hubs);
 | 
						|
 | 
						|
static ssize_t net_hub_receive(NetHub *hub, NetHubPort *source_port,
 | 
						|
                               const uint8_t *buf, size_t len)
 | 
						|
{
 | 
						|
    NetHubPort *port;
 | 
						|
 | 
						|
    QLIST_FOREACH(port, &hub->ports, next) {
 | 
						|
        if (port == source_port) {
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
 | 
						|
        qemu_send_packet(&port->nc, buf, len);
 | 
						|
    }
 | 
						|
    return len;
 | 
						|
}
 | 
						|
 | 
						|
static ssize_t net_hub_receive_iov(NetHub *hub, NetHubPort *source_port,
 | 
						|
                                   const struct iovec *iov, int iovcnt)
 | 
						|
{
 | 
						|
    NetHubPort *port;
 | 
						|
    ssize_t len = iov_size(iov, iovcnt);
 | 
						|
 | 
						|
    QLIST_FOREACH(port, &hub->ports, next) {
 | 
						|
        if (port == source_port) {
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
 | 
						|
        qemu_sendv_packet(&port->nc, iov, iovcnt);
 | 
						|
    }
 | 
						|
    return len;
 | 
						|
}
 | 
						|
 | 
						|
static NetHub *net_hub_new(int id)
 | 
						|
{
 | 
						|
    NetHub *hub;
 | 
						|
 | 
						|
    hub = g_malloc(sizeof(*hub));
 | 
						|
    hub->id = id;
 | 
						|
    hub->num_ports = 0;
 | 
						|
    QLIST_INIT(&hub->ports);
 | 
						|
 | 
						|
    QLIST_INSERT_HEAD(&hubs, hub, next);
 | 
						|
 | 
						|
    return hub;
 | 
						|
}
 | 
						|
 | 
						|
static bool net_hub_port_can_receive(NetClientState *nc)
 | 
						|
{
 | 
						|
    NetHubPort *port;
 | 
						|
    NetHubPort *src_port = DO_UPCAST(NetHubPort, nc, nc);
 | 
						|
    NetHub *hub = src_port->hub;
 | 
						|
 | 
						|
    QLIST_FOREACH(port, &hub->ports, next) {
 | 
						|
        if (port == src_port) {
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
 | 
						|
        if (qemu_can_send_packet(&port->nc)) {
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
static ssize_t net_hub_port_receive(NetClientState *nc,
 | 
						|
                                    const uint8_t *buf, size_t len)
 | 
						|
{
 | 
						|
    NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
 | 
						|
 | 
						|
    return net_hub_receive(port->hub, port, buf, len);
 | 
						|
}
 | 
						|
 | 
						|
static ssize_t net_hub_port_receive_iov(NetClientState *nc,
 | 
						|
                                        const struct iovec *iov, int iovcnt)
 | 
						|
{
 | 
						|
    NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
 | 
						|
 | 
						|
    return net_hub_receive_iov(port->hub, port, iov, iovcnt);
 | 
						|
}
 | 
						|
 | 
						|
static void net_hub_port_cleanup(NetClientState *nc)
 | 
						|
{
 | 
						|
    NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
 | 
						|
 | 
						|
    QLIST_REMOVE(port, next);
 | 
						|
}
 | 
						|
 | 
						|
static NetClientInfo net_hub_port_info = {
 | 
						|
    .type = NET_CLIENT_DRIVER_HUBPORT,
 | 
						|
    .size = sizeof(NetHubPort),
 | 
						|
    .can_receive = net_hub_port_can_receive,
 | 
						|
    .receive = net_hub_port_receive,
 | 
						|
    .receive_iov = net_hub_port_receive_iov,
 | 
						|
    .cleanup = net_hub_port_cleanup,
 | 
						|
};
 | 
						|
 | 
						|
static NetHubPort *net_hub_port_new(NetHub *hub, const char *name,
 | 
						|
                                    NetClientState *hubpeer)
 | 
						|
{
 | 
						|
    NetClientState *nc;
 | 
						|
    NetHubPort *port;
 | 
						|
    int id = hub->num_ports++;
 | 
						|
    char default_name[128];
 | 
						|
 | 
						|
    if (!name) {
 | 
						|
        snprintf(default_name, sizeof(default_name),
 | 
						|
                 "hub%dport%d", hub->id, id);
 | 
						|
        name = default_name;
 | 
						|
    }
 | 
						|
 | 
						|
    nc = qemu_new_net_client(&net_hub_port_info, hubpeer, "hub", name);
 | 
						|
    port = DO_UPCAST(NetHubPort, nc, nc);
 | 
						|
    port->id = id;
 | 
						|
    port->hub = hub;
 | 
						|
 | 
						|
    QLIST_INSERT_HEAD(&hub->ports, port, next);
 | 
						|
 | 
						|
    return port;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Create a port on a given hub
 | 
						|
 * @hub_id: Number of the hub
 | 
						|
 * @name: Net client name or NULL for default name.
 | 
						|
 * @hubpeer: Peer to use (if "netdev=id" has been specified)
 | 
						|
 *
 | 
						|
 * If there is no existing hub with the given id then a new hub is created.
 | 
						|
 */
 | 
						|
NetClientState *net_hub_add_port(int hub_id, const char *name,
 | 
						|
                                 NetClientState *hubpeer)
 | 
						|
{
 | 
						|
    NetHub *hub;
 | 
						|
    NetHubPort *port;
 | 
						|
 | 
						|
    QLIST_FOREACH(hub, &hubs, next) {
 | 
						|
        if (hub->id == hub_id) {
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!hub) {
 | 
						|
        hub = net_hub_new(hub_id);
 | 
						|
    }
 | 
						|
 | 
						|
    port = net_hub_port_new(hub, name, hubpeer);
 | 
						|
    return &port->nc;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Print hub configuration
 | 
						|
 */
 | 
						|
void net_hub_info(Monitor *mon)
 | 
						|
{
 | 
						|
    NetHub *hub;
 | 
						|
    NetHubPort *port;
 | 
						|
 | 
						|
    QLIST_FOREACH(hub, &hubs, next) {
 | 
						|
        monitor_printf(mon, "hub %d\n", hub->id);
 | 
						|
        QLIST_FOREACH(port, &hub->ports, next) {
 | 
						|
            monitor_printf(mon, " \\ %s", port->nc.name);
 | 
						|
            if (port->nc.peer) {
 | 
						|
                monitor_printf(mon, ": ");
 | 
						|
                print_net_client(mon, port->nc.peer);
 | 
						|
            } else {
 | 
						|
                monitor_printf(mon, "\n");
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Get the hub id that a client is connected to
 | 
						|
 *
 | 
						|
 * @id: Pointer for hub id output, may be NULL
 | 
						|
 */
 | 
						|
int net_hub_id_for_client(NetClientState *nc, int *id)
 | 
						|
{
 | 
						|
    NetHubPort *port;
 | 
						|
 | 
						|
    if (nc->info->type == NET_CLIENT_DRIVER_HUBPORT) {
 | 
						|
        port = DO_UPCAST(NetHubPort, nc, nc);
 | 
						|
    } else if (nc->peer != NULL && nc->peer->info->type ==
 | 
						|
            NET_CLIENT_DRIVER_HUBPORT) {
 | 
						|
        port = DO_UPCAST(NetHubPort, nc, nc->peer);
 | 
						|
    } else {
 | 
						|
        return -ENOENT;
 | 
						|
    }
 | 
						|
 | 
						|
    if (id) {
 | 
						|
        *id = port->hub->id;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int net_init_hubport(const Netdev *netdev, const char *name,
 | 
						|
                     NetClientState *peer, Error **errp)
 | 
						|
{
 | 
						|
    const NetdevHubPortOptions *hubport;
 | 
						|
    NetClientState *hubpeer = NULL;
 | 
						|
 | 
						|
    assert(netdev->type == NET_CLIENT_DRIVER_HUBPORT);
 | 
						|
    assert(!peer);
 | 
						|
    hubport = &netdev->u.hubport;
 | 
						|
 | 
						|
    if (hubport->netdev) {
 | 
						|
        hubpeer = qemu_find_netdev(hubport->netdev);
 | 
						|
        if (!hubpeer) {
 | 
						|
            error_setg(errp, "netdev '%s' not found", hubport->netdev);
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    net_hub_add_port(hubport->hubid, name, hubpeer);
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Warn if hub configurations are likely wrong
 | 
						|
 */
 | 
						|
void net_hub_check_clients(void)
 | 
						|
{
 | 
						|
    NetHub *hub;
 | 
						|
    NetHubPort *port;
 | 
						|
    NetClientState *peer;
 | 
						|
 | 
						|
    QLIST_FOREACH(hub, &hubs, next) {
 | 
						|
        int has_nic = 0, has_host_dev = 0;
 | 
						|
 | 
						|
        QLIST_FOREACH(port, &hub->ports, next) {
 | 
						|
            peer = port->nc.peer;
 | 
						|
            if (!peer) {
 | 
						|
                warn_report("hub port %s has no peer", port->nc.name);
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
 | 
						|
            switch (peer->info->type) {
 | 
						|
            case NET_CLIENT_DRIVER_NIC:
 | 
						|
                has_nic = 1;
 | 
						|
                break;
 | 
						|
            case NET_CLIENT_DRIVER_USER:
 | 
						|
            case NET_CLIENT_DRIVER_TAP:
 | 
						|
            case NET_CLIENT_DRIVER_SOCKET:
 | 
						|
            case NET_CLIENT_DRIVER_STREAM:
 | 
						|
            case NET_CLIENT_DRIVER_DGRAM:
 | 
						|
            case NET_CLIENT_DRIVER_VDE:
 | 
						|
            case NET_CLIENT_DRIVER_VHOST_USER:
 | 
						|
                has_host_dev = 1;
 | 
						|
                break;
 | 
						|
            default:
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (has_host_dev && !has_nic) {
 | 
						|
            warn_report("hub %d with no nics", hub->id);
 | 
						|
        }
 | 
						|
        if (has_nic && !has_host_dev && !qtest_enabled()) {
 | 
						|
            warn_report("hub %d is not connected to host network", hub->id);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
bool net_hub_flush(NetClientState *nc)
 | 
						|
{
 | 
						|
    NetHubPort *port;
 | 
						|
    NetHubPort *source_port = DO_UPCAST(NetHubPort, nc, nc);
 | 
						|
    int ret = 0;
 | 
						|
 | 
						|
    QLIST_FOREACH(port, &source_port->hub->ports, next) {
 | 
						|
        if (port != source_port) {
 | 
						|
            ret += qemu_net_queue_flush(port->nc.incoming_queue);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return ret ? true : false;
 | 
						|
}
 |