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 "net/clients.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_OPTIONS_KIND_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_enabled(FpPort
*port
)
190 return port
->enabled
;
193 static void fp_port_set_link(FpPort
*port
, bool up
)
195 NetClientState
*nc
= qemu_get_queue(port
->nic
);
197 if (up
== nc
->link_down
) {
199 nc
->info
->link_status_changed(nc
);
203 void fp_port_enable(FpPort
*port
)
205 fp_port_set_link(port
, true);
206 port
->enabled
= true;
207 DPRINTF("port %d enabled\n", port
->index
);
210 void fp_port_disable(FpPort
*port
)
212 port
->enabled
= false;
213 fp_port_set_link(port
, false);
214 DPRINTF("port %d disabled\n", port
->index
);
217 FpPort
*fp_port_alloc(Rocker
*r
, char *sw_name
,
218 MACAddr
*start_mac
, unsigned int index
,
221 FpPort
*port
= g_new0(FpPort
, 1);
229 port
->pport
= index
+ 1;
231 /* front-panel switch port names are 1-based */
233 port
->name
= g_strdup_printf("%sp%d", sw_name
, port
->pport
);
235 memcpy(port
->conf
.macaddr
.a
, start_mac
, sizeof(port
->conf
.macaddr
.a
));
236 port
->conf
.macaddr
.a
[5] += index
;
237 port
->conf
.bootindex
= -1;
238 port
->conf
.peers
= *peers
;
240 port
->nic
= qemu_new_nic(&fp_port_info
, &port
->conf
,
241 sw_name
, NULL
, port
);
242 qemu_format_nic_info_str(qemu_get_queue(port
->nic
),
243 port
->conf
.macaddr
.a
);
250 void fp_port_free(FpPort
*port
)
252 qemu_del_nic(port
->nic
);
257 void fp_port_reset(FpPort
*port
)
259 fp_port_disable(port
);
260 port
->speed
= 10000; /* 10Gbps */
261 port
->duplex
= DUPLEX_FULL
;