struct iface {
/* These members are always valid. */
+ struct list port_elem; /* Element in struct port's "ifaces" list. */
struct port *port; /* Containing port. */
char *name; /* Host network device name. */
tag_type tag; /* Tag associated with this interface. */
/* An ordinary bridge port has 1 interface.
* A bridge port for bonding has at least 2 interfaces. */
- struct iface **ifaces;
- size_t n_ifaces, allocated_ifaces;
+ struct list ifaces; /* List of "struct iface"s. */
+ size_t n_ifaces; /* list_size(ifaces). */
/* Bonding info. */
enum bond_mode bond_mode; /* Type of the bond. BM_SLB is the default. */
static void port_destroy(struct port *);
static struct port *port_lookup(const struct bridge *, const char *name);
static struct iface *port_lookup_iface(const struct port *, const char *name);
+static struct iface *port_get_an_iface(const struct port *);
static struct port *port_from_dp_ifidx(const struct bridge *,
uint16_t dp_ifidx);
static void port_update_bonding(struct port *);
void *aux),
void *aux)
{
- size_t i, j;
+ size_t i;
for (i = 0; i < br->n_ports; ) {
struct port *port = br->ports[i];
- for (j = 0; j < port->n_ifaces; ) {
- struct iface *iface = port->ifaces[j];
- if (cb(br, iface, aux)) {
- j++;
- } else {
+ struct iface *iface, *next;
+
+ LIST_FOR_EACH_SAFE (iface, next, port_elem, &port->ifaces) {
+ if (!cb(br, iface, aux)) {
iface_set_ofport(iface->cfg, -1);
iface_destroy(iface);
}
LIST_FOR_EACH (br, node, &all_bridges) {
for (i = 0; i < br->n_ports; i++) {
struct port *port = br->ports[i];
- int j;
+ struct iface *iface;
if (port->monitor) {
- for (j = 0; j < port->n_ifaces; j++) {
- netdev_monitor_add(port->monitor, port->ifaces[j]->netdev);
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+ netdev_monitor_add(port->monitor, iface->netdev);
}
} else {
port->miimon_next_update = 0;
port_update_lacp(port);
port_update_bonding(port);
- for (j = 0; j < port->n_ifaces; j++) {
- iface_update_qos(port->ifaces[j], port->cfg->qos);
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+ iface_update_qos(iface, port->cfg->qos);
}
}
}
struct iface **hw_addr_iface)
{
const char *hwaddr;
- size_t i, j;
+ size_t i;
int error;
*hw_addr_iface = NULL;
for (i = 0; i < br->n_ports; i++) {
struct port *port = br->ports[i];
uint8_t iface_ea[ETH_ADDR_LEN];
+ struct iface *candidate;
struct iface *iface;
/* Mirror output ports don't participate. */
}
/* Choose the MAC address to represent the port. */
+ iface = NULL;
if (port->cfg->mac && eth_addr_from_string(port->cfg->mac, iface_ea)) {
/* Find the interface with this Ethernet address (if any) so that
* we can provide the correct devname to the caller. */
- iface = NULL;
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *candidate = port->ifaces[j];
+ LIST_FOR_EACH (candidate, port_elem, &port->ifaces) {
uint8_t candidate_ea[ETH_ADDR_LEN];
if (!netdev_get_etheraddr(candidate->netdev, candidate_ea)
&& eth_addr_equals(iface_ea, candidate_ea)) {
* scripts always add slaves to a bond in alphabetical order, so
* for compatibility we choose the interface with the name that is
* first in alphabetical order. */
- iface = port->ifaces[0];
- for (j = 1; j < port->n_ifaces; j++) {
- struct iface *candidate = port->ifaces[j];
- if (strcmp(candidate->name, iface->name) < 0) {
+ LIST_FOR_EACH (candidate, port_elem, &port->ifaces) {
+ if (!iface || strcmp(candidate->name, iface->name) < 0) {
iface = candidate;
}
}
for (i = 0; i < br->n_ports; i++) {
struct port *port = br->ports[i];
- size_t j;
+ struct iface *iface;
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
iface_refresh_stats(iface);
iface_refresh_cfm_stats(iface);
iface_refresh_status(iface);
continue;
}
ds_put_format(&ds, "%5d %4d "ETH_ADDR_FMT" %3d\n",
- br->ports[e->port]->ifaces[0]->dp_ifidx,
+ port_get_an_iface(br->ports[e->port])->dp_ifidx,
e->vlan, ETH_ADDR_ARGS(e->mac), mac_entry_age(e));
}
unixctl_command_reply(conn, 200, ds_cstr(&ds));
static void
bridge_get_all_ifaces(const struct bridge *br, struct shash *ifaces)
{
- size_t i, j;
+ size_t i;
shash_init(ifaces);
for (i = 0; i < br->n_ports; i++) {
struct port *port = br->ports[i];
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
+ struct iface *iface;
+
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
shash_add_once(ifaces, iface->name, iface);
}
if (port->n_ifaces > 1 && port->cfg->bond_fake_iface) {
{
struct dpif_port_dump dump;
struct dpif_port dpif_port;
- size_t i, j;
+ size_t i;
/* Reset all interface numbers. */
for (i = 0; i < br->n_ports; i++) {
struct port *port = br->ports[i];
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
+ struct iface *iface;
+
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
iface->dp_ifidx = -1;
}
}
{
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
struct iface *best_down_slave;
- size_t i;
+ struct iface *iface;
best_down_slave = NULL;
- for (i = 0; i < port->n_ifaces; i++) {
- struct iface *iface = port->ifaces[i];
-
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
if (iface->enabled) {
return iface;
} else if ((!best_down_slave
assert(port->n_ifaces);
if (port->n_ifaces == 1) {
- iface = port->ifaces[0];
+ iface = port_get_an_iface(port);
} else if (port->bond_mode == BM_AB) {
iface = port->active_iface;
if (!iface) {
{
struct netdev_stats bond_stats;
struct netdev *bond_dev;
- size_t i;
+ struct iface *iface;
memset(&bond_stats, 0, sizeof bond_stats);
- for (i = 0; i < port->n_ifaces; i++) {
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
struct netdev_stats slave_stats;
- if (!netdev_get_stats(port->ifaces[i]->netdev, &slave_stats)) {
+ if (!netdev_get_stats(iface->netdev, &slave_stats)) {
/* XXX: We swap the stats here because they are swapped back when
* reported by the internal device. The reason for this is
* internal devices normally represent packets going into the system
static void
bond_run(struct port *port)
{
- size_t i;
+ struct iface *iface;
if (port->n_ifaces < 2) {
return;
}
- for (i = 0; i < port->n_ifaces; i++) {
- bond_link_status_update(port->ifaces[i]);
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+ bond_link_status_update(iface);
}
- for (i = 0; i < port->n_ifaces; i++) {
- struct iface *iface = port->ifaces[i];
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
if (time_msec() >= iface->delay_expires) {
bond_enable_slave(iface, !iface->enabled);
}
static void
bond_wait(struct port *port)
{
- size_t i;
+ struct iface *iface;
if (port->n_ifaces < 2) {
return;
}
- for (i = 0; i < port->n_ifaces; i++) {
- struct iface *iface = port->ifaces[i];
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
if (iface->delay_expires != LLONG_MAX) {
poll_timer_wait_until(iface->delay_expires);
}
static bool
port_is_floodable(const struct port *port)
{
- int i;
+ struct iface *iface;
- for (i = 0; i < port->n_ifaces; i++) {
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
if (!ofproto_port_is_floodable(port->bridge->ofproto,
- port->ifaces[i]->dp_ifidx)) {
+ iface->dp_ifidx)) {
return false;
}
}
: port->no_ifaces_tag);
}
+/* Returns an arbitrary interface within 'port'.
+ *
+ * 'port' must have at least one interface. */
+static struct iface *
+port_get_an_iface(const struct port *port)
+{
+ return CONTAINER_OF(list_front(&port->ifaces), struct iface, port_elem);
+}
+
static void
compose_dsts(const struct bridge *br, const struct flow *flow, uint16_t vlan,
const struct port *in_port, const struct port *out_port,
struct bond_entry *hashes[BOND_MASK + 1];
struct slave_balance *b, *from, *to;
struct bond_entry *e;
+ struct iface *iface;
size_t i;
assert(port->bond_mode != BM_AB);
* become contiguous in memory, and then we point each 'hashes' members of
* a slave_balance structure to the start of a contiguous group. */
n_bals = port->n_ifaces;
- bals = xmalloc(n_bals * sizeof *bals);
- for (b = bals; b < &bals[n_bals]; b++) {
- b->iface = port->ifaces[b - bals];
+ b = bals = xmalloc(n_bals * sizeof *bals);
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+ b->iface = iface;
b->tx_bytes = 0;
b->hashes = NULL;
b->n_hashes = 0;
+ b++;
}
+ assert(b == &bals[n_bals]);
for (i = 0; i <= BOND_MASK; i++) {
hashes[i] = &port->bond_hash[i];
}
for (i = 0; i < br->n_ports; i++) {
const struct port *port = br->ports[i];
if (port->n_ifaces > 1) {
- size_t j;
+ struct iface *iface;
ds_put_format(&ds, "%s\t%s\t%s\t", br->name, port->name,
bond_mode_to_string(port->bond_mode));
- for (j = 0; j < port->n_ifaces; j++) {
- const struct iface *iface = port->ifaces[j];
- if (j) {
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+ if (&iface->port_elem != list_front(&port->ifaces)) {
ds_put_cstr(&ds, ", ");
}
ds_put_cstr(&ds, iface->name);
{
struct ds ds = DS_EMPTY_INITIALIZER;
const struct port *port;
- size_t j;
+ struct iface *iface;
port = bond_find(args);
if (!port) {
port->bond_next_rebalance - time_msec());
}
- for (j = 0; j < port->n_ifaces; j++) {
- const struct iface *iface = port->ifaces[j];
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
struct bond_entry *be;
struct flow flow;
free(devname);
}
} else if (time_msec() >= port->miimon_next_update) {
- size_t i;
+ struct iface *iface;
- for (i = 0; i < port->n_ifaces; i++) {
- struct iface *iface = port->ifaces[i];
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
iface_update_carrier(iface);
}
port->miimon_next_update = time_msec() + port->miimon_interval;
}
if (port->lacp) {
- size_t i;
+ struct iface *iface;
- for (i = 0; i < port->n_ifaces; i++) {
- struct iface *iface = port->ifaces[i];
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
lacp_slave_enable(port->lacp, iface, iface->enabled);
}
port->trunks = NULL;
port->name = xstrdup(name);
port->active_iface = NULL;
+ list_init(&port->ifaces);
if (br->n_ports >= br->allocated_ports) {
br->ports = x2nrealloc(br->ports, &br->allocated_ports,
static void
port_del_ifaces(struct port *port, const struct ovsrec_port *cfg)
{
+ struct iface *iface, *next;
struct shash new_ifaces;
size_t i;
}
/* Get rid of deleted interfaces. */
- for (i = 0; i < port->n_ifaces; ) {
- struct iface *iface = port->ifaces[i];
+ LIST_FOR_EACH_SAFE (iface, next, port_elem, &port->ifaces) {
if (!shash_find(&new_ifaces, iface->name)) {
iface_destroy(iface);
- } else {
- i++;
}
}
{
if (port) {
struct bridge *br = port->bridge;
+ struct iface *iface, *next;
struct port *del;
int i;
}
}
- while (port->n_ifaces > 0) {
- iface_destroy(port->ifaces[port->n_ifaces - 1]);
+ LIST_FOR_EACH_SAFE (iface, next, port_elem, &port->ifaces) {
+ iface_destroy(iface);
}
shash_find_and_delete_assert(&br->port_by_name, port->name);
VLOG_INFO("destroyed port %s on bridge %s", port->name, br->name);
netdev_monitor_destroy(port->monitor);
- free(port->ifaces);
bitmap_free(port->trunks);
free(port->name);
free(port);
port_update_lacp(struct port *port)
{
if (port->lacp) {
- size_t i;
+ struct iface *iface;
lacp_configure(port->lacp, port->name,
port->bridge->ea, port->lacp_priority,
port->lacp_active, port->lacp_fast);
- for (i = 0; i < port->n_ifaces; i++) {
- struct iface *iface = port->ifaces[i];
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
lacp_slave_register(port->lacp, iface, iface->name,
iface->dp_ifidx, iface->lacp_priority);
}
shash_add_assert(&br->iface_by_name, iface->name, iface);
- if (port->n_ifaces >= port->allocated_ifaces) {
- port->ifaces = x2nrealloc(port->ifaces, &port->allocated_ifaces,
- sizeof *port->ifaces);
- }
- port->ifaces[port->n_ifaces++] = iface;
+ list_push_back(&port->ifaces, &iface->port_elem);
+ port->n_ifaces++;
+
if (port->n_ifaces > 1) {
br->has_bonded_ports = true;
}
struct port *port = iface->port;
struct bridge *br = port->bridge;
bool del_active = port->active_iface == iface;
- size_t i;
if (port->bond_hash) {
struct bond_entry *e;
hmap_remove(&br->ifaces, &iface->dp_ifidx_node);
}
- for (i = 0; i < port->n_ifaces; i++) {
- if (iface == port->ifaces[i]) {
- port->ifaces[i] = port->ifaces[--port->n_ifaces];
- break;
- }
- }
+ list_remove(&iface->port_elem);
+ port->n_ifaces--;
netdev_close(iface->netdev);