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 "net/clients.h"
21 #include "rocker_hw.h"
22 #include "rocker_fp.h"
23 #include "rocker_world.h"
45 char *fp_port_get_name(FpPort
*port
)
50 bool fp_port_get_link_up(FpPort
*port
)
52 return !qemu_get_queue(port
->nic
)->link_down
;
55 void fp_port_get_info(FpPort
*port
, RockerPortList
*info
)
57 info
->value
->name
= g_strdup(port
->name
);
58 info
->value
->enabled
= port
->enabled
;
59 info
->value
->link_up
= fp_port_get_link_up(port
);
60 info
->value
->speed
= port
->speed
;
61 info
->value
->duplex
= port
->duplex
;
62 info
->value
->autoneg
= port
->autoneg
;
65 void fp_port_get_macaddr(FpPort
*port
, MACAddr
*macaddr
)
67 memcpy(macaddr
->a
, port
->conf
.macaddr
.a
, sizeof(macaddr
->a
));
70 void fp_port_set_macaddr(FpPort
*port
, MACAddr
*macaddr
)
72 /* XXX TODO implement and test setting mac addr
73 * XXX memcpy(port->conf.macaddr.a, macaddr.a, sizeof(port->conf.macaddr.a));
77 uint8_t fp_port_get_learning(FpPort
*port
)
79 return port
->learning
;
82 void fp_port_set_learning(FpPort
*port
, uint8_t learning
)
84 port
->learning
= learning
;
87 int fp_port_get_settings(FpPort
*port
, uint32_t *speed
,
88 uint8_t *duplex
, uint8_t *autoneg
)
91 *duplex
= port
->duplex
;
92 *autoneg
= port
->autoneg
;
97 int fp_port_set_settings(FpPort
*port
, uint32_t speed
,
98 uint8_t duplex
, uint8_t autoneg
)
100 /* XXX validate inputs */
103 port
->duplex
= duplex
;
104 port
->autoneg
= autoneg
;
109 bool fp_port_from_pport(uint32_t pport
, uint32_t *port
)
111 if (pport
< 1 || pport
> ROCKER_FP_PORTS_MAX
) {
118 int fp_port_eg(FpPort
*port
, const struct iovec
*iov
, int iovcnt
)
120 NetClientState
*nc
= qemu_get_queue(port
->nic
);
123 qemu_sendv_packet(nc
, iov
, iovcnt
);
129 static ssize_t
fp_port_receive_iov(NetClientState
*nc
, const struct iovec
*iov
,
132 FpPort
*port
= qemu_get_nic_opaque(nc
);
134 /* If the port is disabled, we want to drop this pkt
135 * now rather than queing it for later. We don't want
136 * any stale pkts getting into the device when the port
137 * transitions to enabled.
140 if (!port
->enabled
) {
144 return world_ingress(port
->world
, port
->pport
, iov
, iovcnt
);
147 static ssize_t
fp_port_receive(NetClientState
*nc
, const uint8_t *buf
,
150 const struct iovec iov
= {
151 .iov_base
= (uint8_t *)buf
,
155 return fp_port_receive_iov(nc
, &iov
, 1);
158 static void fp_port_cleanup(NetClientState
*nc
)
162 static void fp_port_set_link_status(NetClientState
*nc
)
164 FpPort
*port
= qemu_get_nic_opaque(nc
);
166 rocker_event_link_changed(port
->r
, port
->pport
, !nc
->link_down
);
169 static NetClientInfo fp_port_info
= {
170 .type
= NET_CLIENT_OPTIONS_KIND_NIC
,
171 .size
= sizeof(NICState
),
172 .receive
= fp_port_receive
,
173 .receive_iov
= fp_port_receive_iov
,
174 .cleanup
= fp_port_cleanup
,
175 .link_status_changed
= fp_port_set_link_status
,
178 World
*fp_port_get_world(FpPort
*port
)
183 void fp_port_set_world(FpPort
*port
, World
*world
)
185 DPRINTF("port %d setting world \"%s\"\n", port
->index
, world_name(world
));
189 bool fp_port_check_world(FpPort
*port
, World
*world
)
191 return port
->world
== world
;
194 bool fp_port_enabled(FpPort
*port
)
196 return port
->enabled
;
199 static void fp_port_set_link(FpPort
*port
, bool up
)
201 NetClientState
*nc
= qemu_get_queue(port
->nic
);
203 if (up
== nc
->link_down
) {
205 nc
->info
->link_status_changed(nc
);
209 void fp_port_enable(FpPort
*port
)
211 fp_port_set_link(port
, true);
212 port
->enabled
= true;
213 DPRINTF("port %d enabled\n", port
->index
);
216 void fp_port_disable(FpPort
*port
)
218 port
->enabled
= false;
219 fp_port_set_link(port
, false);
220 DPRINTF("port %d disabled\n", port
->index
);
223 FpPort
*fp_port_alloc(Rocker
*r
, char *sw_name
,
224 MACAddr
*start_mac
, unsigned int index
,
227 FpPort
*port
= g_new0(FpPort
, 1);
235 port
->pport
= index
+ 1;
237 /* front-panel switch port names are 1-based */
239 port
->name
= g_strdup_printf("%sp%d", sw_name
, port
->pport
);
241 memcpy(port
->conf
.macaddr
.a
, start_mac
, sizeof(port
->conf
.macaddr
.a
));
242 port
->conf
.macaddr
.a
[5] += index
;
243 port
->conf
.bootindex
= -1;
244 port
->conf
.peers
= *peers
;
246 port
->nic
= qemu_new_nic(&fp_port_info
, &port
->conf
,
247 sw_name
, NULL
, port
);
248 qemu_format_nic_info_str(qemu_get_queue(port
->nic
),
249 port
->conf
.macaddr
.a
);
256 void fp_port_free(FpPort
*port
)
258 qemu_del_nic(port
->nic
);
263 void fp_port_reset(FpPort
*port
)
265 fp_port_disable(port
);
266 port
->speed
= 10000; /* 10Gbps */
267 port
->duplex
= DUPLEX_FULL
;