static uint64_t dpid_from_hash(const void *, size_t nbytes);
static unixctl_cb_func bridge_unixctl_fdb_show;
+static unixctl_cb_func qos_unixctl_show;
-static void lacp_run(struct bridge *);
-static void lacp_wait(struct bridge *);
+static void lacp_run(struct port *);
+static void lacp_wait(struct port *);
static void lacp_process_packet(const struct ofpbuf *, struct iface *);
static void bond_init(void);
-static void bond_run(struct bridge *);
-static void bond_wait(struct bridge *);
+static void bond_run(struct port *);
+static void bond_wait(struct port *);
static void bond_rebalance_port(struct port *);
static void bond_send_learning_packets(struct port *);
static void bond_enable_slave(struct iface *iface, bool enable);
+static void port_run(struct port *);
+static void port_wait(struct port *);
static struct port *port_create(struct bridge *, const char *name);
static void port_reconfigure(struct port *, const struct ovsrec_port *);
static void port_del_ifaces(struct port *, const struct ovsrec_port *);
const struct ovsrec_interface *if_cfg);
static void iface_destroy(struct iface *);
static struct iface *iface_lookup(const struct bridge *, const char *name);
+static struct iface *iface_find(const char *name);
static struct iface *iface_from_dp_ifidx(const struct bridge *,
uint16_t dp_ifidx);
static void iface_set_mac(struct iface *);
/* Register unixctl commands. */
unixctl_command_register("fdb/show", bridge_unixctl_fdb_show, NULL);
+ unixctl_command_register("qos/show", qos_unixctl_show, NULL);
unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows,
NULL);
unixctl_command_register("bridge/reconnect", bridge_unixctl_reconnect,
if (port->n_ifaces) {
i++;
} else {
- VLOG_ERR("%s port has no interfaces, dropping", port->name);
+ VLOG_WARN("%s port has no interfaces, dropping", port->name);
port_destroy(port);
}
}
&& strcmp(dpif_port.name, br->name)) {
int retval = dpif_port_del(br->dpif, dpif_port.port_no);
if (retval) {
- VLOG_ERR("failed to remove %s interface from %s: %s",
- dpif_port.name, dpif_name(br->dpif),
- strerror(retval));
+ VLOG_WARN("failed to remove %s interface from %s: %s",
+ dpif_port.name, dpif_name(br->dpif),
+ strerror(retval));
}
}
}
dpif_name(br->dpif));
break;
} else {
- VLOG_ERR("failed to add %s interface to %s: %s",
- if_name, dpif_name(br->dpif),
- strerror(error));
+ VLOG_WARN("failed to add %s interface to %s: %s",
+ if_name, dpif_name(br->dpif),
+ strerror(error));
continue;
}
}
bridge_wait(void)
{
struct bridge *br;
- struct iface *iface;
LIST_FOR_EACH (br, node, &all_bridges) {
+ size_t i;
+
ofproto_wait(br->ofproto);
if (ofproto_has_primary_controller(br->ofproto)) {
continue;
}
mac_learning_wait(br->ml);
- lacp_wait(br);
- bond_wait(br);
- HMAP_FOR_EACH (iface, dp_ifidx_node, &br->ifaces) {
- if (iface->cfm) {
- cfm_wait(iface->cfm);
- }
+ for (i = 0; i < br->n_ports; i++) {
+ port_wait(br->ports[i]);
}
}
ovsdb_idl_wait(idl);
ds_destroy(&ds);
}
\f
+/* QoS unixctl user interface functions. */
+
+struct qos_unixctl_show_cbdata {
+ struct ds *ds;
+ struct iface *iface;
+};
+
+static void
+qos_unixctl_show_cb(unsigned int queue_id,
+ const struct shash *details,
+ void *aux)
+{
+ struct qos_unixctl_show_cbdata *data = aux;
+ struct ds *ds = data->ds;
+ struct iface *iface = data->iface;
+ struct netdev_queue_stats stats;
+ struct shash_node *node;
+ int error;
+
+ ds_put_cstr(ds, "\n");
+ if (queue_id) {
+ ds_put_format(ds, "Queue %u:\n", queue_id);
+ } else {
+ ds_put_cstr(ds, "Default:\n");
+ }
+
+ SHASH_FOR_EACH (node, details) {
+ ds_put_format(ds, "\t%s: %s\n", node->name, (char *)node->data);
+ }
+
+ error = netdev_get_queue_stats(iface->netdev, queue_id, &stats);
+ if (!error) {
+ if (stats.tx_packets != UINT64_MAX) {
+ ds_put_format(ds, "\ttx_packets: %"PRIu64"\n", stats.tx_packets);
+ }
+
+ if (stats.tx_bytes != UINT64_MAX) {
+ ds_put_format(ds, "\ttx_bytes: %"PRIu64"\n", stats.tx_bytes);
+ }
+
+ if (stats.tx_errors != UINT64_MAX) {
+ ds_put_format(ds, "\ttx_errors: %"PRIu64"\n", stats.tx_errors);
+ }
+ } else {
+ ds_put_format(ds, "\tFailed to get statistics for queue %u: %s",
+ queue_id, strerror(error));
+ }
+}
+
+static void
+qos_unixctl_show(struct unixctl_conn *conn,
+ const char *args, void *aux OVS_UNUSED)
+{
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ struct shash sh = SHASH_INITIALIZER(&sh);
+ struct iface *iface;
+ const char *type;
+ struct shash_node *node;
+ struct qos_unixctl_show_cbdata data;
+ int error;
+
+ iface = iface_find(args);
+ if (!iface) {
+ unixctl_command_reply(conn, 501, "no such interface");
+ return;
+ }
+
+ netdev_get_qos(iface->netdev, &type, &sh);
+
+ if (*type != '\0') {
+ ds_put_format(&ds, "QoS: %s %s\n", iface->name, type);
+
+ SHASH_FOR_EACH (node, &sh) {
+ ds_put_format(&ds, "%s: %s\n", node->name, (char *)node->data);
+ }
+
+ data.ds = &ds;
+ data.iface = iface;
+ error = netdev_dump_queues(iface->netdev, qos_unixctl_show_cb, &data);
+
+ if (error) {
+ ds_put_format(&ds, "failed to dump queues: %s", strerror(error));
+ }
+ unixctl_command_reply(conn, 200, ds_cstr(&ds));
+ } else {
+ ds_put_format(&ds, "QoS not configured on %s\n", iface->name);
+ unixctl_command_reply(conn, 501, ds_cstr(&ds));
+ }
+
+ shash_destroy_free_data(&sh);
+ ds_destroy(&ds);
+}
+\f
/* Bridge reconfiguration functions. */
static struct bridge *
bridge_create(const struct ovsrec_bridge *br_cfg)
static int
bridge_run_one(struct bridge *br)
{
+ size_t i;
int error;
- struct iface *iface;
error = ofproto_run1(br->ofproto);
if (error) {
}
mac_learning_run(br->ml, ofproto_get_revalidate_set(br->ofproto));
- lacp_run(br);
- bond_run(br);
+
+ for (i = 0; i < br->n_ports; i++) {
+ port_run(br->ports[i]);
+ }
error = ofproto_run2(br->ofproto, br->flush);
br->flush = false;
- HMAP_FOR_EACH (iface, dp_ifidx_node, &br->ifaces) {
- struct ofpbuf *packet;
-
- if (!iface->cfm) {
- continue;
- }
-
- packet = cfm_run(iface->cfm);
- if (packet) {
- iface_send_packet(iface, packet);
- ofpbuf_uninit(packet);
- free(packet);
- }
- }
-
return error;
}
}
static void
-bond_run(struct bridge *br)
+bond_run(struct port *port)
{
- size_t i, j;
-
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
-
- if (port->n_ifaces >= 2) {
- char *devname;
+ size_t i;
+ char *devname;
- if (port->monitor) {
- assert(!port->miimon);
+ if (port->n_ifaces < 2) {
+ return;
+ }
- /* 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 up = netdev_get_carrier(iface->netdev);
- bond_link_carrier_update(iface, up);
- }
- free(devname);
- }
- } else {
- assert(port->miimon);
+ /* Track carrier going up and down on interfaces. */
+ while (!netdev_monitor_poll(port->monitor, &devname)) {
+ struct iface *iface;
- 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_carrier_update(iface, up);
- }
- port->bond_miimon_next_update = time_msec() +
- port->bond_miimon_interval;
- }
+ iface = port_lookup_iface(port, devname);
+ if (iface) {
+ bool up = netdev_get_carrier(iface->netdev);
+ bond_link_carrier_update(iface, up);
}
+ free(devname);
+ }
+ } else {
+ assert(port->miimon);
- for (j = 0; j < port->n_ifaces; j++) {
- bond_link_status_update(port->ifaces[j]);
+ if (time_msec() >= port->bond_miimon_next_update) {
+ for (i = 0; i < port->n_ifaces; i++) {
+ struct iface *iface = port->ifaces[i];
+ bool up = netdev_get_miimon(iface->netdev);
+ bond_link_carrier_update(iface, up);
}
+ port->bond_miimon_next_update = time_msec() +
+ port->bond_miimon_interval;
+ }
+ }
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
- if (time_msec() >= iface->delay_expires) {
- bond_enable_slave(iface, !iface->enabled);
- }
- }
+ for (i = 0; i < port->n_ifaces; i++) {
+ bond_link_status_update(port->ifaces[i]);
+ }
- if (port->bond_fake_iface
- && time_msec() >= port->bond_next_fake_iface_update) {
- bond_update_fake_iface_stats(port);
- port->bond_next_fake_iface_update = time_msec() + 1000;
- }
+ for (i = 0; i < port->n_ifaces; i++) {
+ struct iface *iface = port->ifaces[i];
+ if (time_msec() >= iface->delay_expires) {
+ bond_enable_slave(iface, !iface->enabled);
}
}
+
+ if (port->bond_fake_iface
+ && time_msec() >= port->bond_next_fake_iface_update) {
+ bond_update_fake_iface_stats(port);
+ port->bond_next_fake_iface_update = time_msec() + 1000;
+ }
}
static void
-bond_wait(struct bridge *br)
+bond_wait(struct port *port)
{
- size_t i, j;
+ size_t i;
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
- if (port->n_ifaces < 2) {
- continue;
- }
+ if (port->n_ifaces < 2) {
+ return;
+ }
- if (port->monitor) {
- 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);
- }
+ 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) {
- poll_timer_wait_until(iface->delay_expires);
- }
- }
- if (port->bond_fake_iface) {
- poll_timer_wait_until(port->bond_next_fake_iface_update);
+ for (i = 0; i < port->n_ifaces; i++) {
+ struct iface *iface = port->ifaces[i];
+ if (iface->delay_expires != LLONG_MAX) {
+ poll_timer_wait_until(iface->delay_expires);
}
}
+
+ if (port->bond_fake_iface) {
+ poll_timer_wait_until(port->bond_next_fake_iface_update);
+ }
}
static bool
}
static void
-lacp_run(struct bridge *br)
+lacp_run(struct port *port)
{
- size_t i, j;
+ size_t i;
struct ofpbuf packet;
- ofpbuf_init(&packet, ETH_HEADER_LEN + LACP_PDU_LEN);
-
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
+ if (!port->lacp) {
+ return;
+ }
- if (!port->lacp) {
- continue;
- }
+ ofpbuf_init(&packet, ETH_HEADER_LEN + LACP_PDU_LEN);
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
+ for (i = 0; i < port->n_ifaces; i++) {
+ struct iface *iface = port->ifaces[i];
- if (time_msec() > iface->lacp_rx) {
- if (iface->lacp_status & LACP_CURRENT) {
- iface_set_lacp_expired(iface);
- } else if (iface->lacp_status & LACP_EXPIRED) {
- iface_set_lacp_defaulted(iface);
- }
+ if (time_msec() > iface->lacp_rx) {
+ if (iface->lacp_status & LACP_CURRENT) {
+ iface_set_lacp_expired(iface);
+ } else if (iface->lacp_status & LACP_EXPIRED) {
+ iface_set_lacp_defaulted(iface);
}
}
+ }
- if (port->lacp_need_update) {
- lacp_update_ifaces(port);
- }
-
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
- uint8_t ea[ETH_ADDR_LEN];
- int error;
+ if (port->lacp_need_update) {
+ lacp_update_ifaces(port);
+ }
- if (time_msec() < iface->lacp_tx || !lacp_iface_may_tx(iface)) {
- continue;
- }
+ for (i = 0; i < port->n_ifaces; i++) {
+ struct iface *iface = port->ifaces[i];
+ uint8_t ea[ETH_ADDR_LEN];
+ int error;
- error = netdev_get_etheraddr(iface->netdev, ea);
- if (!error) {
- iface->lacp_actor.state = iface_get_lacp_state(iface);
- compose_lacp_packet(&packet, &iface->lacp_actor,
- &iface->lacp_partner, ea);
- iface_send_packet(iface, &packet);
- } else {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10);
- VLOG_ERR_RL(&rl, "iface %s: failed to obtain Ethernet address "
- "(%s)", iface->name, strerror(error));
- }
+ if (time_msec() < iface->lacp_tx || !lacp_iface_may_tx(iface)) {
+ continue;
+ }
- iface->lacp_tx = time_msec() +
- (iface->lacp_partner.state & LACP_STATE_TIME
- ? LACP_FAST_TIME_TX
- : LACP_SLOW_TIME_TX);
+ error = netdev_get_etheraddr(iface->netdev, ea);
+ if (!error) {
+ iface->lacp_actor.state = iface_get_lacp_state(iface);
+ compose_lacp_packet(&packet, &iface->lacp_actor,
+ &iface->lacp_partner, ea);
+ iface_send_packet(iface, &packet);
+ } else {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10);
+ VLOG_ERR_RL(&rl, "iface %s: failed to obtain Ethernet address "
+ "(%s)", iface->name, strerror(error));
}
+
+ iface->lacp_tx = time_msec() +
+ (iface->lacp_partner.state & LACP_STATE_TIME
+ ? LACP_FAST_TIME_TX
+ : LACP_SLOW_TIME_TX);
}
ofpbuf_uninit(&packet);
}
static void
-lacp_wait(struct bridge *br)
+lacp_wait(struct port *port)
{
- size_t i, j;
-
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
+ size_t i;
- if (!port->lacp) {
- continue;
- }
+ if (!port->lacp) {
+ return;
+ }
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
+ for (i = 0; i < port->n_ifaces; i++) {
+ struct iface *iface = port->ifaces[i];
- if (lacp_iface_may_tx(iface)) {
- poll_timer_wait_until(iface->lacp_tx);
- }
+ if (lacp_iface_may_tx(iface)) {
+ poll_timer_wait_until(iface->lacp_tx);
+ }
- if (iface->lacp_status & (LACP_CURRENT | LACP_EXPIRED)) {
- poll_timer_wait_until(iface->lacp_rx);
- }
+ if (iface->lacp_status & (LACP_CURRENT | LACP_EXPIRED)) {
+ poll_timer_wait_until(iface->lacp_rx);
}
}
}
\f
/* Port functions. */
+static void
+port_run(struct port *port)
+{
+ size_t i;
+
+ lacp_run(port);
+ bond_run(port);
+
+ for (i = 0; i < port->n_ifaces; i++) {
+ struct iface *iface = port->ifaces[i];
+
+ if (iface->cfm) {
+ struct ofpbuf *packet = cfm_run(iface->cfm);
+ if (packet) {
+ iface_send_packet(iface, packet);
+ ofpbuf_uninit(packet);
+ free(packet);
+ }
+ }
+ }
+}
+
+static void
+port_wait(struct port *port)
+{
+ size_t i;
+
+ lacp_wait(port);
+ bond_wait(port);
+
+ for (i = 0; i < port->n_ifaces; i++) {
+ struct iface *iface = port->ifaces[i];
+ if (iface->cfm) {
+ cfm_wait(iface->cfm);
+ }
+ }
+}
+
static struct port *
port_create(struct bridge *br, const char *name)
{
free(port->bond_hash);
port->bond_hash = NULL;
port->bond_fake_iface = false;
+ port->active_iface = -1;
+ port->no_ifaces_tag = 0;
} else {
size_t i;
e->iface_idx = -1;
e->tx_bytes = 0;
}
- port->no_ifaces_tag = tag_create_random();
- bond_choose_active_iface(port);
port->bond_next_rebalance
= time_msec() + port->bond_rebalance_interval;
-
- if (port->cfg->bond_fake_iface) {
- port->bond_next_fake_iface_update = time_msec();
- }
} else if (port->bond_mode == BM_AB) {
free(port->bond_hash);
port->bond_hash = NULL;
}
+
+ if (!port->no_ifaces_tag) {
+ port->no_ifaces_tag = tag_create_random();
+ }
+
+ if (port->active_iface < 0) {
+ bond_choose_active_iface(port);
+ }
+
port->bond_fake_iface = port->cfg->bond_fake_iface;
+ if (port->bond_fake_iface) {
+ port->bond_next_fake_iface_update = time_msec();
+ }
if (!port->miimon) {
port->monitor = netdev_monitor_create();
return shash_find_data(&br->iface_by_name, name);
}
+static struct iface *
+iface_find(const char *name)
+{
+ const struct bridge *br;
+
+ LIST_FOR_EACH (br, node, &all_bridges) {
+ struct iface *iface = iface_lookup(br, name);
+
+ if (iface) {
+ return iface;
+ }
+ }
+ return NULL;
+}
+
static struct iface *
iface_from_dp_ifidx(const struct bridge *br, uint16_t dp_ifidx)
{