tag_type iface_tag; /* Tag associated with iface_idx. */
};
-enum bond_type {
- BT_SLB, /* Source Load Balance (Default). */
- BT_AB /* Active Backup. */
+enum bond_mode {
+ BM_SLB, /* Source Load Balance (Default). */
+ BM_AB /* Active Backup. */
};
#define MAX_MIRRORS 32
size_t n_ifaces, allocated_ifaces;
/* Bonding info. */
- enum bond_type bond_type; /* Type of the bond. BT_SLB is the default. */
+ enum bond_mode bond_mode; /* Type of the bond. BM_SLB is the default. */
int active_iface; /* Ifidx on which bcasts accepted, or -1. */
tag_type active_iface_tag; /* Tag for bcast flows. */
tag_type no_ifaces_tag; /* Tag for flows when all ifaces disabled. */
int updelay, downdelay; /* Delay before iface goes up/down, in ms. */
bool bond_compat_is_stale; /* Need to call port_update_bond_compat()? */
bool bond_fake_iface; /* Fake a bond interface for legacy compat? */
+ bool miimon; /* Use miimon instead of carrier? */
+ long long int bond_miimon_interval; /* Miimon status refresh interval. */
+ long long int bond_miimon_next_update; /* Time of next miimon update. */
long long int bond_next_fake_iface_update; /* Time of next update. */
struct netdev_monitor *monitor; /* Tracks carrier up/down status. */
{
struct shash sh;
+ enum netdev_flags flags;
+ uint32_t current;
+ int64_t bps;
+ int mtu;
+ int64_t mtu_64;
+ int error;
+
shash_init(&sh);
if (!netdev_get_status(iface->netdev, &sh)) {
}
shash_destroy_free_data(&sh);
+
+ error = netdev_get_flags(iface->netdev, &flags);
+ if (!error) {
+ ovsrec_interface_set_admin_state(iface->cfg, flags & NETDEV_UP ? "up" : "down");
+ }
+ else {
+ ovsrec_interface_set_admin_state(iface->cfg, NULL);
+ }
+
+ error = netdev_get_features(iface->netdev, ¤t, NULL, NULL, NULL);
+ if (!error) {
+ ovsrec_interface_set_duplex(iface->cfg,
+ netdev_features_is_full_duplex(current)
+ ? "full" : "half");
+ /* warning: uint64_t -> int64_t conversion */
+ bps = netdev_features_to_bps(current);
+ ovsrec_interface_set_link_speed(iface->cfg, &bps, 1);
+ }
+ else {
+ ovsrec_interface_set_duplex(iface->cfg, NULL);
+ ovsrec_interface_set_link_speed(iface->cfg, NULL, 0);
+ }
+
+
+ ovsrec_interface_set_link_state(iface->cfg,
+ netdev_get_carrier(iface->netdev)
+ ? "up" : "down");
+
+ error = netdev_get_mtu(iface->netdev, &mtu);
+ if (!error) {
+ mtu_64 = mtu;
+ ovsrec_interface_set_mtu(iface->cfg, &mtu_64, 1);
+ }
+ else {
+ ovsrec_interface_set_mtu(iface->cfg, NULL, 0);
+ }
}
static void
&datum);
}
+static inline const char *
+nx_role_to_str(enum nx_role role)
+{
+ switch (role) {
+ case NX_ROLE_OTHER:
+ return "other";
+ case NX_ROLE_MASTER:
+ return "master";
+ case NX_ROLE_SLAVE:
+ return "slave";
+ default:
+ return "*** INVALID ROLE ***";
+ }
+}
+
+static void
+bridge_refresh_controller_status(const struct bridge *br)
+{
+ struct shash info;
+ const struct ovsrec_controller *cfg;
+
+ ofproto_get_ofproto_controller_info(br->ofproto, &info);
+
+ OVSREC_CONTROLLER_FOR_EACH(cfg, idl) {
+ struct ofproto_controller_info *cinfo =
+ shash_find_data(&info, cfg->target);
+
+ if (cinfo) {
+ ovsrec_controller_set_is_connected(cfg, cinfo->is_connected);
+ ovsrec_controller_set_role(cfg, nx_role_to_str(cinfo->role));
+ ovsrec_controller_set_status(cfg, (char **) cinfo->pairs.keys,
+ (char **) cinfo->pairs.values,
+ cinfo->pairs.n);
+ } else {
+ ovsrec_controller_set_is_connected(cfg, false);
+ ovsrec_controller_set_role(cfg, NULL);
+ ovsrec_controller_set_status(cfg, NULL, NULL, 0);
+ }
+ }
+
+ ofproto_free_ofproto_controller_info(&info);
+}
+
void
bridge_run(void)
{
iface_refresh_status(iface);
}
}
+ bridge_refresh_controller_status(br);
}
refresh_system_stats(cfg);
ovsdb_idl_txn_commit(txn);
lookup_bond_entry(const struct port *port, const uint8_t mac[ETH_ADDR_LEN],
uint16_t vlan)
{
- assert(port->bond_type == BT_SLB);
+ assert(port->bond_mode == BM_SLB);
return &port->bond_hash[bond_hash(mac, vlan)];
}
assert(port->n_ifaces);
if (port->n_ifaces == 1) {
iface = port->ifaces[0];
- } else if (port->bond_type == BT_AB) {
+ } else if (port->bond_mode == BM_AB) {
if (port->active_iface < 0) {
*tags |= port->no_ifaces_tag;
return false;
}
iface = port->ifaces[port->active_iface];
- } else if (port->bond_type == BT_SLB){
+ } else if (port->bond_mode == BM_SLB){
struct bond_entry *e = lookup_bond_entry(port, dl_src, vlan);
if (e->iface_idx < 0 || e->iface_idx >= port->n_ifaces
|| !port->ifaces[e->iface_idx]->enabled) {
/* Nothing to do. */
return;
}
- VLOG_INFO_RL(&rl, "interface %s: carrier %s",
- iface->name, carrier ? "detected" : "dropped");
+ VLOG_INFO_RL(&rl, "interface %s: link state %s",
+ iface->name, carrier ? "up" : "down");
if (carrier == iface->enabled) {
iface->delay_expires = LLONG_MAX;
VLOG_INFO_RL(&rl, "interface %s: will not be %s",
if (port->n_ifaces >= 2) {
char *devname;
- /* Track carrier going up and down on interfaces. */
- while (!netdev_monitor_poll(port->monitor, &devname)) {
- struct iface *iface;
+ if (port->monitor) {
+ assert(!port->miimon);
- iface = port_lookup_iface(port, devname);
- if (iface) {
- bool carrier = netdev_get_carrier(iface->netdev);
+ /* Track carrier going up and down on interfaces. */
+ while (!netdev_monitor_poll(port->monitor, &devname)) {
+ struct iface *iface;
+
+ iface = port_lookup_iface(port, devname);
+ if (iface) {
+ bool up = netdev_get_carrier(iface->netdev);
+
+ bond_link_status_update(iface, up);
+ port_update_bond_compat(port);
+ }
+ free(devname);
+ }
+ } else {
+ assert(port->miimon);
+
+ if (time_msec() >= port->bond_miimon_next_update) {
+ for (j = 0; j < port->n_ifaces; j++) {
+ struct iface *iface = port->ifaces[j];
+ bool up = netdev_get_miimon(iface->netdev);
- bond_link_status_update(iface, carrier);
- port_update_bond_compat(port);
+ bond_link_status_update(iface, up);
+ port_update_bond_compat(port);
+ }
+ port->bond_miimon_next_update = time_msec() +
+ port->bond_miimon_interval;
}
- free(devname);
}
for (j = 0; j < port->n_ifaces; j++) {
if (port->n_ifaces < 2) {
continue;
}
- netdev_monitor_poll_wait(port->monitor);
+
+ if (port->monitor) {
+ netdev_monitor_poll_wait(port->monitor);
+ }
+
+ if (port->miimon) {
+ poll_timer_wait_until(port->bond_miimon_next_update);
+ }
+
for (j = 0; j < port->n_ifaces; j++) {
struct iface *iface = port->ifaces[j];
if (iface->delay_expires != LLONG_MAX) {
if (nl_attr_type(a) == ODPAT_OUTPUT) {
struct port *out_port = port_from_dp_ifidx(br, nl_attr_get_u32(a));
if (out_port && out_port->n_ifaces >= 2 &&
- out_port->bond_type == BT_SLB) {
+ out_port->bond_mode == BM_SLB) {
uint16_t vlan = (flow->vlan_tci
? vlan_tci_to_vid(flow->vlan_tci)
: OFP_VLAN_NONE);
now = time_msec();
for (i = 0; i < br->n_ports; i++) {
struct port *port = br->ports[i];
- if (port->n_ifaces > 1 && port->bond_type == BT_SLB
+ if (port->n_ifaces > 1 && port->bond_mode == BM_SLB
&& now >= port->bond_next_rebalance) {
port->bond_next_rebalance = now + port->bond_rebalance_interval;
bond_rebalance_port(port);
};
static const char *
-bond_type_to_string(enum bond_type bt) {
- static char *bt_slb = "slb";
- static char *bt_ab = "active-backup";
+bond_mode_to_string(enum bond_mode bm) {
+ static char *bm_slb = "balance-slb";
+ static char *bm_ab = "active-backup";
- switch (bt) {
- case BT_SLB: return bt_slb;
- case BT_AB: return bt_ab;
+ switch (bm) {
+ case BM_SLB: return bm_slb;
+ case BM_AB: return bm_ab;
}
NOT_REACHED();
struct port *port = from->iface->port;
uint64_t delta = hash->tx_bytes;
- assert(port->bond_type == BT_SLB);
+ assert(port->bond_mode == BM_SLB);
VLOG_INFO("bond %s: shift %"PRIu64"kB of load (with hash %td) "
"from %s to %s (now carrying %"PRIu64"kB and "
struct bond_entry *e;
size_t i;
- assert(port->bond_type == BT_SLB);
+ assert(port->bond_mode == BM_SLB);
/* Sets up 'bals' to describe each of the port's interfaces, sorted in
* descending order of tx_bytes, so that bals[0] represents the most
size_t j;
ds_put_format(&ds, "%s\t%s\t%s\t", br->name, port->name,
- bond_type_to_string(port->bond_type));
+ bond_mode_to_string(port->bond_mode));
for (j = 0; j < port->n_ifaces; j++) {
const struct iface *iface = port->ifaces[j];
if (j) {
return;
}
- ds_put_format(&ds, "bond_type: %s\n",
- bond_type_to_string(port->bond_type));
+ ds_put_format(&ds, "bond_mode: %s\n",
+ bond_mode_to_string(port->bond_mode));
+ ds_put_format(&ds, "bond-detect-mode: %s\n",
+ port->miimon ? "miimon" : "carrier");
+
+ if (port->miimon) {
+ ds_put_format(&ds, "bond-miimon-interval: %lld\n",
+ port->bond_miimon_interval);
+ }
+
ds_put_format(&ds, "updelay: %d ms\n", port->updelay);
ds_put_format(&ds, "downdelay: %d ms\n", port->downdelay);
- if (port->bond_type == BT_SLB) {
+ if (port->bond_mode == BM_SLB) {
ds_put_format(&ds, "next rebalance: %lld ms\n",
port->bond_next_rebalance - time_msec());
}
iface->delay_expires - time_msec());
}
- if (port->bond_type != BT_SLB) {
+ if (port->bond_mode != BM_SLB) {
continue;
}
return;
}
- if (port->bond_type != BT_SLB) {
+ if (port->bond_mode != BM_SLB) {
unixctl_command_reply(conn, 501, "not an SLB bond");
return;
}
static void
port_reconfigure(struct port *port, const struct ovsrec_port *cfg)
{
+ const char *detect_mode;
struct shash new_ifaces;
- long long int next_rebalance;
+ long long int next_rebalance, miimon_next_update;
unsigned long *trunks;
int vlan;
size_t i;
port->bond_next_rebalance = next_rebalance;
}
- if (!port->cfg->bond_type ||
- !strcmp(port->cfg->bond_type, bond_type_to_string(BT_SLB))) {
- port->bond_type = BT_SLB;
- } else if (!strcmp(port->cfg->bond_type, bond_type_to_string(BT_AB))) {
- port->bond_type = BT_AB;
+ detect_mode = get_port_other_config(cfg, "bond-detect-mode",
+ "carrier");
+
+ if (!strcmp(detect_mode, "carrier")) {
+ port->miimon = false;
+ } else if (!strcmp(detect_mode, "miimon")) {
+ port->miimon = true;
} else {
- port->bond_type = BT_SLB;
- VLOG_WARN("port %s: unknown bond_type %s, defaulting to %s",
- port->name, port->cfg->bond_type,
- bond_type_to_string(port->bond_type));
+ port->miimon = false;
+ VLOG_WARN("port %s: unsupported bond-detect-mode %s, defaulting to "
+ "carrier", port->name, detect_mode);
+ }
+
+ port->bond_miimon_interval = atoi(
+ get_port_other_config(cfg, "bond-miimon-interval", "200"));
+ if (port->bond_miimon_interval < 100) {
+ port->bond_miimon_interval = 100;
+ }
+ miimon_next_update = time_msec() + port->bond_miimon_interval;
+ if (port->bond_miimon_next_update > miimon_next_update) {
+ port->bond_miimon_next_update = miimon_next_update;
+ }
+
+ if (!port->cfg->bond_mode ||
+ !strcmp(port->cfg->bond_mode, bond_mode_to_string(BM_SLB))) {
+ port->bond_mode = BM_SLB;
+ } else if (!strcmp(port->cfg->bond_mode, bond_mode_to_string(BM_AB))) {
+ port->bond_mode = BM_AB;
+ } else {
+ port->bond_mode = BM_SLB;
+ VLOG_WARN("port %s: unknown bond_mode %s, defaulting to %s",
+ port->name, port->cfg->bond_mode,
+ bond_mode_to_string(port->bond_mode));
}
/* Add new interfaces and update 'cfg' member of existing ones. */
} else {
size_t i;
- if (port->bond_type == BT_SLB && !port->bond_hash) {
+ if (port->bond_mode == BM_SLB && !port->bond_hash) {
port->bond_hash = xcalloc(BOND_MASK + 1, sizeof *port->bond_hash);
for (i = 0; i <= BOND_MASK; i++) {
struct bond_entry *e = &port->bond_hash[i];
if (port->cfg->bond_fake_iface) {
port->bond_next_fake_iface_update = time_msec();
}
- } else if (port->bond_type != BT_SLB) {
+ } else if (port->bond_mode != BM_SLB) {
free(port->bond_hash);
port->bond_hash = NULL;
}
port->bond_compat_is_stale = true;
port->bond_fake_iface = port->cfg->bond_fake_iface;
- port->monitor = netdev_monitor_create();
- for (i = 0; i < port->n_ifaces; i++) {
- netdev_monitor_add(port->monitor, port->ifaces[i]->netdev);
+ if (!port->miimon) {
+ port->monitor = netdev_monitor_create();
+ for (i = 0; i < port->n_ifaces; i++) {
+ netdev_monitor_add(port->monitor, port->ifaces[i]->netdev);
+ }
}
}
}
struct compat_bond bond;
size_t i;
- if (port->n_ifaces < 2 || port->bond_type != BT_SLB) {
+ if (port->n_ifaces < 2 || port->bond_mode != BM_SLB) {
proc_net_compat_update_bond(port->name, NULL);
return;
}