memset(ea, 0xff, sizeof ea);
for (i = 0; i < br->n_ports; i++) {
struct port *port = br->ports[i];
+ uint8_t iface_ea[ETH_ADDR_LEN];
+ uint64_t iface_ea_u64;
+ struct iface *iface;
+
+ /* Mirror output ports don't participate. */
if (port->is_mirror_output_port) {
continue;
}
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
- uint8_t iface_ea[ETH_ADDR_LEN];
+
+ /* Choose the MAC address to represent the port. */
+ iface_ea_u64 = cfg_get_mac(0, "port.%s.mac", port->name);
+ if (iface_ea_u64) {
+ /* User specified explicitly. */
+ eth_addr_from_uint64(iface_ea_u64, iface_ea);
+ } else {
+ /* Choose the interface whose MAC address will represent the port.
+ * The Linux kernel bonding code always chooses the MAC address of
+ * the first slave added to a bond, and the Fedora networking
+ * 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) {
+ iface = candidate;
+ }
+ }
+
+ /* The local port doesn't count (since we're trying to choose its
+ * MAC address anyway). Other internal ports don't count because
+ * we really want a physical MAC if we can get it, and internal
+ * ports typically have randomly generated MACs. */
if (iface->dp_ifidx == ODPP_LOCAL
|| cfg_get_bool(0, "iface.%s.internal", iface->name)) {
continue;
}
+
+ /* Grab MAC. */
error = netdev_nodev_get_etheraddr(iface->name, iface_ea);
- if (!error) {
- if (!eth_addr_is_multicast(iface_ea) &&
- !eth_addr_is_reserved(iface_ea) &&
- !eth_addr_is_zero(iface_ea) &&
- memcmp(iface_ea, ea, ETH_ADDR_LEN) < 0) {
- memcpy(ea, iface_ea, ETH_ADDR_LEN);
- *devname = iface->name;
- }
- } else {
+ if (error) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
VLOG_ERR_RL(&rl, "failed to obtain Ethernet address of %s: %s",
iface->name, strerror(error));
+ continue;
}
}
+
+ /* Compare against our current choice. */
+ if (!eth_addr_is_multicast(iface_ea) &&
+ !eth_addr_is_reserved(iface_ea) &&
+ !eth_addr_is_zero(iface_ea) &&
+ memcmp(iface_ea, ea, ETH_ADDR_LEN) < 0)
+ {
+ memcpy(ea, iface_ea, ETH_ADDR_LEN);
+ *devname = iface->name;
+ }
}
if (eth_addr_is_multicast(ea) || eth_addr_is_vif(ea)) {
memcpy(ea, br->default_ea, ETH_ADDR_LEN);
if (br->ml) {
const struct mac_entry *e;
LIST_FOR_EACH (e, struct mac_entry, lru_node, &br->ml->lrus) {
+ if (e->port < 0 || e->port >= br->n_ports) {
+ continue;
+ }
ds_put_format(&ds, "%5d %4d "ETH_ADDR_FMT" %3d\n",
- e->port, e->vlan, ETH_ADDR_ARGS(e->mac),
- mac_entry_age(e));
+ br->ports[e->port]->ifaces[0]->dp_ifidx,
+ e->vlan, ETH_ADDR_ARGS(e->mac), mac_entry_age(e));
}
}
unixctl_command_reply(conn, 200, ds_cstr(&ds));
if (probe < 5) {
probe = cfg_get_int(0, "mgmt.inactivity-probe");
if (probe < 5) {
- probe = 15;
+ probe = 5;
}
}
ofproto_set_probe_interval(br->ofproto, probe);
if (!max_backoff) {
max_backoff = cfg_get_int(0, "mgmt.max-backoff");
if (!max_backoff) {
- max_backoff = 15;
+ max_backoff = 8;
}
}
ofproto_set_max_backoff(br->ofproto, max_backoff);