qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

rocker_fp.c (6210B)


      1 /*
      2  * QEMU rocker switch emulation - front-panel ports
      3  *
      4  * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
      5  *
      6  * This program is free software; you can redistribute it and/or modify
      7  * it under the terms of the GNU General Public License as published by
      8  * the Free Software Foundation; either version 2 of the License, or
      9  * (at your option) any later version.
     10  *
     11  * This program is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     14  * GNU General Public License for more details.
     15  */
     16 
     17 #include "qemu/osdep.h"
     18 #include "qapi/qapi-types-rocker.h"
     19 #include "rocker.h"
     20 #include "rocker_hw.h"
     21 #include "rocker_fp.h"
     22 #include "rocker_world.h"
     23 
     24 enum duplex {
     25     DUPLEX_HALF = 0,
     26     DUPLEX_FULL
     27 };
     28 
     29 struct fp_port {
     30     Rocker *r;
     31     World *world;
     32     unsigned int index;
     33     char *name;
     34     uint32_t pport;
     35     bool enabled;
     36     uint32_t speed;
     37     uint8_t duplex;
     38     uint8_t autoneg;
     39     uint8_t learning;
     40     NICState *nic;
     41     NICConf conf;
     42 };
     43 
     44 char *fp_port_get_name(FpPort *port)
     45 {
     46     return port->name;
     47 }
     48 
     49 bool fp_port_get_link_up(FpPort *port)
     50 {
     51     return !qemu_get_queue(port->nic)->link_down;
     52 }
     53 
     54 RockerPort *fp_port_get_info(FpPort *port)
     55 {
     56     RockerPort *value = g_malloc0(sizeof(*value));
     57 
     58     value->name = g_strdup(port->name);
     59     value->enabled = port->enabled;
     60     value->link_up = fp_port_get_link_up(port);
     61     value->speed = port->speed;
     62     value->duplex = port->duplex;
     63     value->autoneg = port->autoneg;
     64     return value;
     65 }
     66 
     67 void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr)
     68 {
     69     memcpy(macaddr->a, port->conf.macaddr.a, sizeof(macaddr->a));
     70 }
     71 
     72 void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr)
     73 {
     74 /* XXX TODO implement and test setting mac addr
     75  * XXX memcpy(port->conf.macaddr.a, macaddr.a, sizeof(port->conf.macaddr.a));
     76  */
     77 }
     78 
     79 uint8_t fp_port_get_learning(FpPort *port)
     80 {
     81     return port->learning;
     82 }
     83 
     84 void fp_port_set_learning(FpPort *port, uint8_t learning)
     85 {
     86     port->learning = learning;
     87 }
     88 
     89 int fp_port_get_settings(FpPort *port, uint32_t *speed,
     90                          uint8_t *duplex, uint8_t *autoneg)
     91 {
     92     *speed = port->speed;
     93     *duplex = port->duplex;
     94     *autoneg = port->autoneg;
     95 
     96     return ROCKER_OK;
     97 }
     98 
     99 int fp_port_set_settings(FpPort *port, uint32_t speed,
    100                          uint8_t duplex, uint8_t autoneg)
    101 {
    102     /* XXX validate inputs */
    103 
    104     port->speed = speed;
    105     port->duplex = duplex;
    106     port->autoneg = autoneg;
    107 
    108     return ROCKER_OK;
    109 }
    110 
    111 bool fp_port_from_pport(uint32_t pport, uint32_t *port)
    112 {
    113     if (pport < 1 || pport > ROCKER_FP_PORTS_MAX) {
    114         return false;
    115     }
    116     *port = pport - 1;
    117     return true;
    118 }
    119 
    120 int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt)
    121 {
    122     NetClientState *nc = qemu_get_queue(port->nic);
    123 
    124     if (port->enabled) {
    125         qemu_sendv_packet(nc, iov, iovcnt);
    126     }
    127 
    128     return ROCKER_OK;
    129 }
    130 
    131 static ssize_t fp_port_receive_iov(NetClientState *nc, const struct iovec *iov,
    132                                    int iovcnt)
    133 {
    134     FpPort *port = qemu_get_nic_opaque(nc);
    135 
    136     /* If the port is disabled, we want to drop this pkt
    137      * now rather than queing it for later.  We don't want
    138      * any stale pkts getting into the device when the port
    139      * transitions to enabled.
    140      */
    141 
    142     if (!port->enabled) {
    143         return -1;
    144     }
    145 
    146     return world_ingress(port->world, port->pport, iov, iovcnt);
    147 }
    148 
    149 static ssize_t fp_port_receive(NetClientState *nc, const uint8_t *buf,
    150                                size_t size)
    151 {
    152     const struct iovec iov = {
    153         .iov_base = (uint8_t *)buf,
    154         .iov_len = size
    155     };
    156 
    157     return fp_port_receive_iov(nc, &iov, 1);
    158 }
    159 
    160 static void fp_port_cleanup(NetClientState *nc)
    161 {
    162 }
    163 
    164 static void fp_port_set_link_status(NetClientState *nc)
    165 {
    166     FpPort *port = qemu_get_nic_opaque(nc);
    167 
    168     rocker_event_link_changed(port->r, port->pport, !nc->link_down);
    169 }
    170 
    171 static NetClientInfo fp_port_info = {
    172     .type = NET_CLIENT_DRIVER_NIC,
    173     .size = sizeof(NICState),
    174     .receive = fp_port_receive,
    175     .receive_iov = fp_port_receive_iov,
    176     .cleanup = fp_port_cleanup,
    177     .link_status_changed = fp_port_set_link_status,
    178 };
    179 
    180 World *fp_port_get_world(FpPort *port)
    181 {
    182     return port->world;
    183 }
    184 
    185 void fp_port_set_world(FpPort *port, World *world)
    186 {
    187     DPRINTF("port %d setting world \"%s\"\n", port->index, world_name(world));
    188     port->world = world;
    189 }
    190 
    191 bool fp_port_check_world(FpPort *port, World *world)
    192 {
    193     return port->world == world;
    194 }
    195 
    196 bool fp_port_enabled(FpPort *port)
    197 {
    198     return port->enabled;
    199 }
    200 
    201 static void fp_port_set_link(FpPort *port, bool up)
    202 {
    203     NetClientState *nc = qemu_get_queue(port->nic);
    204 
    205     if (up == nc->link_down) {
    206         nc->link_down = !up;
    207         nc->info->link_status_changed(nc);
    208     }
    209 }
    210 
    211 void fp_port_enable(FpPort *port)
    212 {
    213     fp_port_set_link(port, true);
    214     port->enabled = true;
    215     DPRINTF("port %d enabled\n", port->index);
    216 }
    217 
    218 void fp_port_disable(FpPort *port)
    219 {
    220     port->enabled = false;
    221     fp_port_set_link(port, false);
    222     DPRINTF("port %d disabled\n", port->index);
    223 }
    224 
    225 FpPort *fp_port_alloc(Rocker *r, char *sw_name,
    226                       MACAddr *start_mac, unsigned int index,
    227                       NICPeers *peers)
    228 {
    229     FpPort *port = g_new0(FpPort, 1);
    230 
    231     port->r = r;
    232     port->index = index;
    233     port->pport = index + 1;
    234 
    235     /* front-panel switch port names are 1-based */
    236 
    237     port->name = g_strdup_printf("%sp%d", sw_name, port->pport);
    238 
    239     memcpy(port->conf.macaddr.a, start_mac, sizeof(port->conf.macaddr.a));
    240     port->conf.macaddr.a[5] += index;
    241     port->conf.bootindex = -1;
    242     port->conf.peers = *peers;
    243 
    244     port->nic = qemu_new_nic(&fp_port_info, &port->conf,
    245                              sw_name, NULL, port);
    246     qemu_format_nic_info_str(qemu_get_queue(port->nic),
    247                              port->conf.macaddr.a);
    248 
    249     fp_port_reset(port);
    250 
    251     return port;
    252 }
    253 
    254 void fp_port_free(FpPort *port)
    255 {
    256     qemu_del_nic(port->nic);
    257     g_free(port->name);
    258     g_free(port);
    259 }
    260 
    261 void fp_port_reset(FpPort *port)
    262 {
    263     fp_port_disable(port);
    264     port->speed = 10000;   /* 10Gbps */
    265     port->duplex = DUPLEX_FULL;
    266     port->autoneg = 0;
    267 }