cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

hub.c (8348B)


      1/*
      2 * Hub net client
      3 *
      4 * Copyright IBM, Corp. 2012
      5 *
      6 * Authors:
      7 *  Stefan Hajnoczi   <stefanha@linux.vnet.ibm.com>
      8 *  Zhi Yong Wu       <wuzhy@linux.vnet.ibm.com>
      9 *
     10 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
     11 * See the COPYING.LIB file in the top-level directory.
     12 *
     13 */
     14
     15#include "qemu/osdep.h"
     16#include "qapi/error.h"
     17#include "monitor/monitor.h"
     18#include "net/net.h"
     19#include "clients.h"
     20#include "hub.h"
     21#include "qemu/iov.h"
     22#include "qemu/error-report.h"
     23#include "sysemu/qtest.h"
     24
     25/*
     26 * A hub broadcasts incoming packets to all its ports except the source port.
     27 * Hubs can be used to provide independent emulated network segments.
     28 */
     29
     30typedef struct NetHub NetHub;
     31
     32typedef struct NetHubPort {
     33    NetClientState nc;
     34    QLIST_ENTRY(NetHubPort) next;
     35    NetHub *hub;
     36    int id;
     37} NetHubPort;
     38
     39struct NetHub {
     40    int id;
     41    QLIST_ENTRY(NetHub) next;
     42    int num_ports;
     43    QLIST_HEAD(, NetHubPort) ports;
     44};
     45
     46static QLIST_HEAD(, NetHub) hubs = QLIST_HEAD_INITIALIZER(&hubs);
     47
     48static ssize_t net_hub_receive(NetHub *hub, NetHubPort *source_port,
     49                               const uint8_t *buf, size_t len)
     50{
     51    NetHubPort *port;
     52
     53    QLIST_FOREACH(port, &hub->ports, next) {
     54        if (port == source_port) {
     55            continue;
     56        }
     57
     58        qemu_send_packet(&port->nc, buf, len);
     59    }
     60    return len;
     61}
     62
     63static ssize_t net_hub_receive_iov(NetHub *hub, NetHubPort *source_port,
     64                                   const struct iovec *iov, int iovcnt)
     65{
     66    NetHubPort *port;
     67    ssize_t len = iov_size(iov, iovcnt);
     68
     69    QLIST_FOREACH(port, &hub->ports, next) {
     70        if (port == source_port) {
     71            continue;
     72        }
     73
     74        qemu_sendv_packet(&port->nc, iov, iovcnt);
     75    }
     76    return len;
     77}
     78
     79static NetHub *net_hub_new(int id)
     80{
     81    NetHub *hub;
     82
     83    hub = g_malloc(sizeof(*hub));
     84    hub->id = id;
     85    hub->num_ports = 0;
     86    QLIST_INIT(&hub->ports);
     87
     88    QLIST_INSERT_HEAD(&hubs, hub, next);
     89
     90    return hub;
     91}
     92
     93static bool net_hub_port_can_receive(NetClientState *nc)
     94{
     95    NetHubPort *port;
     96    NetHubPort *src_port = DO_UPCAST(NetHubPort, nc, nc);
     97    NetHub *hub = src_port->hub;
     98
     99    QLIST_FOREACH(port, &hub->ports, next) {
    100        if (port == src_port) {
    101            continue;
    102        }
    103
    104        if (qemu_can_send_packet(&port->nc)) {
    105            return true;
    106        }
    107    }
    108
    109    return false;
    110}
    111
    112static ssize_t net_hub_port_receive(NetClientState *nc,
    113                                    const uint8_t *buf, size_t len)
    114{
    115    NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
    116
    117    return net_hub_receive(port->hub, port, buf, len);
    118}
    119
    120static ssize_t net_hub_port_receive_iov(NetClientState *nc,
    121                                        const struct iovec *iov, int iovcnt)
    122{
    123    NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
    124
    125    return net_hub_receive_iov(port->hub, port, iov, iovcnt);
    126}
    127
    128static void net_hub_port_cleanup(NetClientState *nc)
    129{
    130    NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc);
    131
    132    QLIST_REMOVE(port, next);
    133}
    134
    135static NetClientInfo net_hub_port_info = {
    136    .type = NET_CLIENT_DRIVER_HUBPORT,
    137    .size = sizeof(NetHubPort),
    138    .can_receive = net_hub_port_can_receive,
    139    .receive = net_hub_port_receive,
    140    .receive_iov = net_hub_port_receive_iov,
    141    .cleanup = net_hub_port_cleanup,
    142};
    143
    144static NetHubPort *net_hub_port_new(NetHub *hub, const char *name,
    145                                    NetClientState *hubpeer)
    146{
    147    NetClientState *nc;
    148    NetHubPort *port;
    149    int id = hub->num_ports++;
    150    char default_name[128];
    151
    152    if (!name) {
    153        snprintf(default_name, sizeof(default_name),
    154                 "hub%dport%d", hub->id, id);
    155        name = default_name;
    156    }
    157
    158    nc = qemu_new_net_client(&net_hub_port_info, hubpeer, "hub", name);
    159    port = DO_UPCAST(NetHubPort, nc, nc);
    160    port->id = id;
    161    port->hub = hub;
    162
    163    QLIST_INSERT_HEAD(&hub->ports, port, next);
    164
    165    return port;
    166}
    167
    168/**
    169 * Create a port on a given hub
    170 * @hub_id: Number of the hub
    171 * @name: Net client name or NULL for default name.
    172 * @hubpeer: Peer to use (if "netdev=id" has been specified)
    173 *
    174 * If there is no existing hub with the given id then a new hub is created.
    175 */
    176NetClientState *net_hub_add_port(int hub_id, const char *name,
    177                                 NetClientState *hubpeer)
    178{
    179    NetHub *hub;
    180    NetHubPort *port;
    181
    182    QLIST_FOREACH(hub, &hubs, next) {
    183        if (hub->id == hub_id) {
    184            break;
    185        }
    186    }
    187
    188    if (!hub) {
    189        hub = net_hub_new(hub_id);
    190    }
    191
    192    port = net_hub_port_new(hub, name, hubpeer);
    193    return &port->nc;
    194}
    195
    196/**
    197 * Find a available port on a hub; otherwise create one new port
    198 */
    199NetClientState *net_hub_port_find(int hub_id)
    200{
    201    NetHub *hub;
    202    NetHubPort *port;
    203    NetClientState *nc;
    204
    205    QLIST_FOREACH(hub, &hubs, next) {
    206        if (hub->id == hub_id) {
    207            QLIST_FOREACH(port, &hub->ports, next) {
    208                nc = port->nc.peer;
    209                if (!nc) {
    210                    return &(port->nc);
    211                }
    212            }
    213            break;
    214        }
    215    }
    216
    217    nc = net_hub_add_port(hub_id, NULL, NULL);
    218    return nc;
    219}
    220
    221/**
    222 * Print hub configuration
    223 */
    224void net_hub_info(Monitor *mon)
    225{
    226    NetHub *hub;
    227    NetHubPort *port;
    228
    229    QLIST_FOREACH(hub, &hubs, next) {
    230        monitor_printf(mon, "hub %d\n", hub->id);
    231        QLIST_FOREACH(port, &hub->ports, next) {
    232            monitor_printf(mon, " \\ %s", port->nc.name);
    233            if (port->nc.peer) {
    234                monitor_printf(mon, ": ");
    235                print_net_client(mon, port->nc.peer);
    236            } else {
    237                monitor_printf(mon, "\n");
    238            }
    239        }
    240    }
    241}
    242
    243/**
    244 * Get the hub id that a client is connected to
    245 *
    246 * @id: Pointer for hub id output, may be NULL
    247 */
    248int net_hub_id_for_client(NetClientState *nc, int *id)
    249{
    250    NetHubPort *port;
    251
    252    if (nc->info->type == NET_CLIENT_DRIVER_HUBPORT) {
    253        port = DO_UPCAST(NetHubPort, nc, nc);
    254    } else if (nc->peer != NULL && nc->peer->info->type ==
    255            NET_CLIENT_DRIVER_HUBPORT) {
    256        port = DO_UPCAST(NetHubPort, nc, nc->peer);
    257    } else {
    258        return -ENOENT;
    259    }
    260
    261    if (id) {
    262        *id = port->hub->id;
    263    }
    264    return 0;
    265}
    266
    267int net_init_hubport(const Netdev *netdev, const char *name,
    268                     NetClientState *peer, Error **errp)
    269{
    270    const NetdevHubPortOptions *hubport;
    271    NetClientState *hubpeer = NULL;
    272
    273    assert(netdev->type == NET_CLIENT_DRIVER_HUBPORT);
    274    assert(!peer);
    275    hubport = &netdev->u.hubport;
    276
    277    if (hubport->has_netdev) {
    278        hubpeer = qemu_find_netdev(hubport->netdev);
    279        if (!hubpeer) {
    280            error_setg(errp, "netdev '%s' not found", hubport->netdev);
    281            return -1;
    282        }
    283    }
    284
    285    net_hub_add_port(hubport->hubid, name, hubpeer);
    286
    287    return 0;
    288}
    289
    290/**
    291 * Warn if hub configurations are likely wrong
    292 */
    293void net_hub_check_clients(void)
    294{
    295    NetHub *hub;
    296    NetHubPort *port;
    297    NetClientState *peer;
    298
    299    QLIST_FOREACH(hub, &hubs, next) {
    300        int has_nic = 0, has_host_dev = 0;
    301
    302        QLIST_FOREACH(port, &hub->ports, next) {
    303            peer = port->nc.peer;
    304            if (!peer) {
    305                warn_report("hub port %s has no peer", port->nc.name);
    306                continue;
    307            }
    308
    309            switch (peer->info->type) {
    310            case NET_CLIENT_DRIVER_NIC:
    311                has_nic = 1;
    312                break;
    313            case NET_CLIENT_DRIVER_USER:
    314            case NET_CLIENT_DRIVER_TAP:
    315            case NET_CLIENT_DRIVER_SOCKET:
    316            case NET_CLIENT_DRIVER_VDE:
    317            case NET_CLIENT_DRIVER_VHOST_USER:
    318                has_host_dev = 1;
    319                break;
    320            default:
    321                break;
    322            }
    323        }
    324        if (has_host_dev && !has_nic) {
    325            warn_report("hub %d with no nics", hub->id);
    326        }
    327        if (has_nic && !has_host_dev && !qtest_enabled()) {
    328            warn_report("hub %d is not connected to host network", hub->id);
    329        }
    330    }
    331}
    332
    333bool net_hub_flush(NetClientState *nc)
    334{
    335    NetHubPort *port;
    336    NetHubPort *source_port = DO_UPCAST(NetHubPort, nc, nc);
    337    int ret = 0;
    338
    339    QLIST_FOREACH(port, &source_port->hub->ports, next) {
    340        if (port != source_port) {
    341            ret += qemu_net_queue_flush(port->nc.incoming_queue);
    342        }
    343    }
    344    return ret ? true : false;
    345}