2 * QEMU rocker switch emulation - front-panel ports
4 * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
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.
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.
17 #include "qemu/osdep.h"
18 #include "qapi/qapi-types-rocker.h"
20 #include "rocker_hw.h"
21 #include "rocker_fp.h"
22 #include "rocker_world.h"
44 char *fp_port_get_name(FpPort
*port
)
49 bool fp_port_get_link_up(FpPort
*port
)
51 return !qemu_get_queue(port
->nic
)->link_down
;
54 void fp_port_get_info(FpPort
*port
, RockerPortList
*info
)
56 info
->value
->name
= g_strdup(port
->name
);
57 info
->value
->enabled
= port
->enabled
;
58 info
->value
->link_up
= fp_port_get_link_up(port
);
59 info
->value
->speed
= port
->speed
;
60 info
->value
->duplex
= port
->duplex
;
61 info
->value
->autoneg
= port
->autoneg
;
64 void fp_port_get_macaddr(FpPort
*port
, MACAddr
*macaddr
)
66 memcpy(macaddr
->a
, port
->conf
.macaddr
.a
, sizeof(macaddr
->a
));
69 void fp_port_set_macaddr(FpPort
*port
, MACAddr
*macaddr
)
71 /* XXX TODO implement and test setting mac addr
72 * XXX memcpy(port->conf.macaddr.a, macaddr.a, sizeof(port->conf.macaddr.a));
76 uint8_t fp_port_get_learning(FpPort
*port
)
78 return port
->learning
;
81 void fp_port_set_learning(FpPort
*port
, uint8_t learning
)
83 port
->learning
= learning
;
86 int fp_port_get_settings(FpPort
*port
, uint32_t *speed
,
87 uint8_t *duplex
, uint8_t *autoneg
)
90 *duplex
= port
->duplex
;
91 *autoneg
= port
->autoneg
;
96 int fp_port_set_settings(FpPort
*port
, uint32_t speed
,
97 uint8_t duplex
, uint8_t autoneg
)
99 /* XXX validate inputs */
102 port
->duplex
= duplex
;
103 port
->autoneg
= autoneg
;
108 bool fp_port_from_pport(uint32_t pport
, uint32_t *port
)
110 if (pport
< 1 || pport
> ROCKER_FP_PORTS_MAX
) {
117 int fp_port_eg(FpPort
*port
, const struct iovec
*iov
, int iovcnt
)
119 NetClientState
*nc
= qemu_get_queue(port
->nic
);
122 qemu_sendv_packet(nc
, iov
, iovcnt
);
128 static ssize_t
fp_port_receive_iov(NetClientState
*nc
, const struct iovec
*iov
,
131 FpPort
*port
= qemu_get_nic_opaque(nc
);
133 /* If the port is disabled, we want to drop this pkt
134 * now rather than queing it for later. We don't want
135 * any stale pkts getting into the device when the port
136 * transitions to enabled.
139 if (!port
->enabled
) {
143 return world_ingress(port
->world
, port
->pport
, iov
, iovcnt
);
146 static ssize_t
fp_port_receive(NetClientState
*nc
, const uint8_t *buf
,
149 const struct iovec iov
= {
150 .iov_base
= (uint8_t *)buf
,
154 return fp_port_receive_iov(nc
, &iov
, 1);
157 static void fp_port_cleanup(NetClientState
*nc
)
161 static void fp_port_set_link_status(NetClientState
*nc
)
163 FpPort
*port
= qemu_get_nic_opaque(nc
);
165 rocker_event_link_changed(port
->r
, port
->pport
, !nc
->link_down
);
168 static NetClientInfo fp_port_info
= {
169 .type
= NET_CLIENT_DRIVER_NIC
,
170 .size
= sizeof(NICState
),
171 .receive
= fp_port_receive
,
172 .receive_iov
= fp_port_receive_iov
,
173 .cleanup
= fp_port_cleanup
,
174 .link_status_changed
= fp_port_set_link_status
,
177 World
*fp_port_get_world(FpPort
*port
)
182 void fp_port_set_world(FpPort
*port
, World
*world
)
184 DPRINTF("port %d setting world \"%s\"\n", port
->index
, world_name(world
));
188 bool fp_port_check_world(FpPort
*port
, World
*world
)
190 return port
->world
== world
;
193 bool fp_port_enabled(FpPort
*port
)
195 return port
->enabled
;
198 static void fp_port_set_link(FpPort
*port
, bool up
)
200 NetClientState
*nc
= qemu_get_queue(port
->nic
);
202 if (up
== nc
->link_down
) {
204 nc
->info
->link_status_changed(nc
);
208 void fp_port_enable(FpPort
*port
)
210 fp_port_set_link(port
, true);
211 port
->enabled
= true;
212 DPRINTF("port %d enabled\n", port
->index
);
215 void fp_port_disable(FpPort
*port
)
217 port
->enabled
= false;
218 fp_port_set_link(port
, false);
219 DPRINTF("port %d disabled\n", port
->index
);
222 FpPort
*fp_port_alloc(Rocker
*r
, char *sw_name
,
223 MACAddr
*start_mac
, unsigned int index
,
226 FpPort
*port
= g_new0(FpPort
, 1);
230 port
->pport
= index
+ 1;
232 /* front-panel switch port names are 1-based */
234 port
->name
= g_strdup_printf("%sp%d", sw_name
, port
->pport
);
236 memcpy(port
->conf
.macaddr
.a
, start_mac
, sizeof(port
->conf
.macaddr
.a
));
237 port
->conf
.macaddr
.a
[5] += index
;
238 port
->conf
.bootindex
= -1;
239 port
->conf
.peers
= *peers
;
241 port
->nic
= qemu_new_nic(&fp_port_info
, &port
->conf
,
242 sw_name
, NULL
, port
);
243 qemu_format_nic_info_str(qemu_get_queue(port
->nic
),
244 port
->conf
.macaddr
.a
);
251 void fp_port_free(FpPort
*port
)
253 qemu_del_nic(port
->nic
);
258 void fp_port_reset(FpPort
*port
)
260 fp_port_disable(port
);
261 port
->speed
= 10000; /* 10Gbps */
262 port
->duplex
= DUPLEX_FULL
;