#include "dynamic-string.h"
#include "flow.h"
#include "hash.h"
+#include "hmap.h"
#include "jsonrpc.h"
#include "list.h"
#include "mac-learning.h"
#include "ovsdb-data.h"
#include "packets.h"
#include "poll-loop.h"
-#include "port-array.h"
#include "proc-net-compat.h"
#include "process.h"
#include "sha1.h"
#include "socket-util.h"
#include "stream-ssl.h"
#include "svec.h"
+#include "system-stats.h"
#include "timeval.h"
#include "util.h"
#include "unixctl.h"
/* These members are valid only after bridge_reconfigure() causes them to
* be initialized. */
+ struct hmap_node dp_ifidx_node; /* In struct bridge's "ifaces" hmap. */
int dp_ifidx; /* Index within kernel datapath. */
struct netdev *netdev; /* Network device. */
bool enabled; /* May be chosen for flows? */
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? */
- long bond_next_fake_iface_update; /* Next update to fake bond stats. */
+ long long int bond_next_fake_iface_update; /* Time of next update. */
int bond_rebalance_interval; /* Interval between rebalances, in ms. */
long long int bond_next_rebalance; /* Next rebalancing time. */
/* Kernel datapath information. */
struct dpif *dpif; /* Datapath. */
- struct port_array ifaces; /* Indexed by kernel datapath port number. */
+ struct hmap ifaces; /* Contains "struct iface"s. */
/* Bridge ports. */
struct port **ports;
/* OVSDB IDL used to obtain configuration. */
static struct ovsdb_idl *idl;
-/* Each time this timer expires, the bridge fetches statistics for every
- * interface and pushes them into the database. */
-#define IFACE_STATS_INTERVAL (5 * 1000) /* In milliseconds. */
-static long long int iface_stats_timer = LLONG_MIN;
+/* Each time this timer expires, the bridge fetches systems and interface
+ * statistics and pushes them into the database. */
+#define STATS_INTERVAL (5 * 1000) /* In milliseconds. */
+static long long int stats_timer = LLONG_MIN;
static struct bridge *bridge_create(const struct ovsrec_bridge *br_cfg);
static void bridge_destroy(struct bridge *);
static void mirror_reconfigure_one(struct mirror *, struct ovsrec_mirror *);
static bool vlan_is_mirrored(const struct mirror *, int vlan);
-static struct iface *iface_create(struct port *port,
+static struct iface *iface_create(struct port *port,
const struct ovsrec_interface *if_cfg);
static void iface_destroy(struct iface *);
static struct iface *iface_lookup(const struct bridge *, const char *name);
/* Create connection to database. */
idl = ovsdb_idl_create(remote, &ovsrec_idl_class);
+ ovsdb_idl_set_write_only(idl, &ovsrec_open_vswitch_col_cur_cfg);
+ ovsdb_idl_set_write_only(idl, &ovsrec_open_vswitch_col_statistics);
+ ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_external_ids);
+
+ ovsdb_idl_omit(idl, &ovsrec_bridge_col_external_ids);
+
+ ovsdb_idl_omit(idl, &ovsrec_port_col_external_ids);
+ ovsdb_idl_omit(idl, &ovsrec_port_col_fake_bridge);
+
+ ovsdb_idl_set_write_only(idl, &ovsrec_interface_col_ofport);
+ ovsdb_idl_set_write_only(idl, &ovsrec_interface_col_statistics);
+ ovsdb_idl_omit(idl, &ovsrec_interface_col_external_ids);
+
/* Register unixctl commands. */
unixctl_command_register("fdb/show", bridge_unixctl_fdb_show, NULL);
unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows,
}
already_configured_once = true;
- iface_stats_timer = time_msec() + IFACE_STATS_INTERVAL;
+ stats_timer = time_msec() + STATS_INTERVAL;
/* Get all the configured bridges' names from 'cfg' into 'bridge_names'. */
svec_init(&bridge_names);
xstrdup(iface_cfg->value_options[i]));
}
+ /* Include 'other_config' keys in hash of netdev options. The
+ * namespace of 'other_config' and 'options' must be disjoint.
+ * Prefer 'options' keys over 'other_config' keys. */
+ for (i = 0; i < iface_cfg->n_other_config; i++) {
+ char *value = xstrdup(iface_cfg->value_other_config[i]);
+ if (!shash_add_once(&options, iface_cfg->key_other_config[i],
+ value)) {
+ VLOG_WARN("%s: \"other_config\" key %s conflicts with existing "
+ "\"other_config\" or \"options\" entry...ignoring",
+ iface_cfg->name, iface_cfg->key_other_config[i]);
+ free(value);
+ }
+ }
+
if (create) {
struct netdev_options netdev_options;
/* Collect old and new bridges. */
shash_init(&old_br);
shash_init(&new_br);
- LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
+ LIST_FOR_EACH (br, node, &all_bridges) {
shash_add(&old_br, br->name, br);
}
for (i = 0; i < ovs_cfg->n_bridges; i++) {
}
/* Get rid of deleted bridges and add new bridges. */
- LIST_FOR_EACH_SAFE (br, next, struct bridge, node, &all_bridges) {
+ LIST_FOR_EACH_SAFE (br, next, node, &all_bridges) {
struct ovsrec_bridge *br_cfg = shash_find_data(&new_br, br->name);
if (br_cfg) {
br->cfg = br_cfg;
shash_destroy(&new_br);
/* Reconfigure all bridges. */
- LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
+ LIST_FOR_EACH (br, node, &all_bridges) {
bridge_reconfigure_one(br);
}
* The kernel will reject any attempt to add a given port to a datapath if
* that port already belongs to a different datapath, so we must do all
* port deletions before any port additions. */
- LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
+ LIST_FOR_EACH (br, node, &all_bridges) {
struct odp_port *dpif_ports;
size_t n_dpif_ports;
struct shash want_ifaces;
shash_destroy(&want_ifaces);
free(dpif_ports);
}
- LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
+ LIST_FOR_EACH (br, node, &all_bridges) {
struct odp_port *dpif_ports;
size_t n_dpif_ports;
struct shash cur_ifaces, want_ifaces;
- struct shash_node *node;
/* Get the set of interfaces currently in this datapath. */
dpif_port_list(br->dpif, &dpif_ports, &n_dpif_ports);
shash_destroy(&want_ifaces);
}
sflow_bridge_number = 0;
- LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
+ LIST_FOR_EACH (br, node, &all_bridges) {
uint8_t ea[8];
uint64_t dpid;
struct iface *local_iface;
opts.collectors.n = nf_cfg->n_targets;
opts.collectors.names = nf_cfg->targets;
if (ofproto_set_netflow(br->ofproto, &opts)) {
- VLOG_ERR("bridge %s: problem setting netflow collectors",
+ VLOG_ERR("bridge %s: problem setting netflow collectors",
br->name);
}
} else {
struct ovsrec_controller **controllers;
struct ofproto_sflow_options oso;
size_t n_controllers;
- size_t i;
memset(&oso, 0, sizeof oso);
* the datapath ID before the controller. */
bridge_reconfigure_remotes(br, managers, n_managers);
}
- LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
+ LIST_FOR_EACH (br, node, &all_bridges) {
for (i = 0; i < br->n_ports; i++) {
struct port *port = br->ports[i];
int j;
}
}
}
- LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
+ LIST_FOR_EACH (br, node, &all_bridges) {
iterate_and_prune_ifaces(br, set_iface_properties, NULL);
}
ovsrec_interface_set_statistics(iface->cfg, keys, values, n);
}
+static void
+refresh_system_stats(const struct ovsrec_open_vswitch *cfg)
+{
+ struct ovsdb_datum datum;
+ struct shash stats;
+
+ shash_init(&stats);
+ get_system_stats(&stats);
+
+ ovsdb_datum_from_shash(&datum, &stats);
+ ovsdb_idl_txn_write(&cfg->header_, &ovsrec_open_vswitch_col_statistics,
+ &datum);
+}
+
void
bridge_run(void)
{
/* Let each bridge do the work that it needs to do. */
datapath_destroyed = false;
- LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
+ LIST_FOR_EACH (br, node, &all_bridges) {
int error = bridge_run_one(br);
if (error) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
}
#endif
- /* Refresh interface stats if necessary. */
- if (time_msec() >= iface_stats_timer) {
- struct ovsdb_idl_txn *txn;
+ /* Refresh system and interface stats if necessary. */
+ if (time_msec() >= stats_timer) {
+ if (cfg) {
+ struct ovsdb_idl_txn *txn;
- txn = ovsdb_idl_txn_create(idl);
- LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
- size_t i;
+ txn = ovsdb_idl_txn_create(idl);
+ LIST_FOR_EACH (br, node, &all_bridges) {
+ size_t i;
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
- size_t j;
+ for (i = 0; i < br->n_ports; i++) {
+ struct port *port = br->ports[i];
+ size_t j;
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
- iface_refresh_stats(iface);
+ for (j = 0; j < port->n_ifaces; j++) {
+ struct iface *iface = port->ifaces[j];
+ iface_refresh_stats(iface);
+ }
}
}
+ refresh_system_stats(cfg);
+ ovsdb_idl_txn_commit(txn);
+ ovsdb_idl_txn_destroy(txn); /* XXX */
}
- ovsdb_idl_txn_commit(txn);
- ovsdb_idl_txn_destroy(txn); /* XXX */
- iface_stats_timer = time_msec() + IFACE_STATS_INTERVAL;
+ stats_timer = time_msec() + STATS_INTERVAL;
}
}
{
struct bridge *br;
- LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
+ LIST_FOR_EACH (br, node, &all_bridges) {
ofproto_wait(br->ofproto);
if (ofproto_has_primary_controller(br->ofproto)) {
continue;
bond_wait(br);
}
ovsdb_idl_wait(idl);
- poll_timer_wait_until(iface_stats_timer);
+ poll_timer_wait_until(stats_timer);
}
/* Forces 'br' to revalidate all of its flows. This is appropriate when 'br''s
}
ds_put_cstr(&ds, " port VLAN MAC Age\n");
- LIST_FOR_EACH (e, struct mac_entry, lru_node, &br->ml->lrus) {
+ LIST_FOR_EACH (e, lru_node, &br->ml->lrus) {
if (e->port < 0 || e->port >= br->n_ports) {
continue;
}
br->ml = mac_learning_create();
eth_addr_nicira_random(br->default_ea);
- port_array_init(&br->ifaces);
+ hmap_init(&br->ifaces);
shash_init(&br->port_by_name);
shash_init(&br->iface_by_name);
dpif_close(br->dpif);
ofproto_destroy(br->ofproto);
mac_learning_destroy(br->ml);
- port_array_destroy(&br->ifaces);
+ hmap_destroy(&br->ifaces);
shash_destroy(&br->port_by_name);
shash_destroy(&br->iface_by_name);
free(br->ports);
{
struct bridge *br;
- LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
+ LIST_FOR_EACH (br, node, &all_bridges) {
if (!strcmp(br->name, name)) {
return br;
}
{
struct bridge *br;
struct ds results;
-
+
br = bridge_lookup(args);
if (!br) {
unixctl_command_reply(conn, 501, "Unknown bridge");
}
ofproto_reconnect_controllers(br->ofproto);
} else {
- LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
+ LIST_FOR_EACH (br, node, &all_bridges) {
ofproto_reconnect_controllers(br->ofproto);
}
}
iface->dp_ifidx = -1;
}
}
- port_array_clear(&br->ifaces);
+ hmap_clear(&br->ifaces);
dpif_port_list(br->dpif, &dpif_ports, &n_dpif_ports);
for (i = 0; i < n_dpif_ports; i++) {
VLOG_WARN("%s reported interface %"PRIu16" twice",
dpif_name(br->dpif), p->port);
} else {
- port_array_set(&br->ifaces, p->port, iface);
iface->dp_ifidx = p->port;
+ hmap_insert(&br->ifaces, &iface->dp_ifidx_node,
+ hash_int(iface->dp_ifidx, 0));
}
if (iface->cfg) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
VLOG_WARN_RL(&rl, "bridge %s: received packet on unknown "
- "interface %"PRIu16, br->name, flow->in_port);
+ "interface %"PRIu16, br->name, flow->in_port);
}
*in_portp = NULL;
* smallest hashes instead of the biggest ones. There is little
* reason behind this decision; we could use the opposite sort
* order to shift away big hashes ahead of small ones. */
- size_t i;
bool order_swapped;
for (i = 0; i < from->n_hashes; i++) {
ofpbuf_init(&packet, 128);
error = n_packets = n_errors = 0;
- LIST_FOR_EACH (e, struct mac_entry, lru_node, &br->ml->lrus) {
+ LIST_FOR_EACH (e, lru_node, &br->ml->lrus) {
union ofp_action actions[2], *a;
uint16_t dp_ifidx;
tag_type tags = 0;
ds_put_cstr(&ds, "bridge\tbond\tslaves\n");
- LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
+ LIST_FOR_EACH (br, node, &all_bridges) {
size_t i;
for (i = 0; i < br->n_ports; i++) {
{
const struct bridge *br;
- LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
+ LIST_FOR_EACH (br, node, &all_bridges) {
size_t i;
for (i = 0; i < br->n_ports; i++) {
hash, be->tx_bytes / 1024);
/* MACs. */
- LIST_FOR_EACH (me, struct mac_entry, lru_node,
- &port->bridge->ml->lrus) {
+ LIST_FOR_EACH (me, lru_node, &port->bridge->ml->lrus) {
uint16_t dp_ifidx;
tag_type tags = 0;
if (bond_hash(me->mac) == hash
if (port->updelay < 0) {
port->updelay = 0;
}
- port->updelay = cfg->bond_downdelay;
+ port->downdelay = cfg->bond_downdelay;
if (port->downdelay < 0) {
port->downdelay = 0;
}
trunks = NULL;
if (vlan < 0 && cfg->n_trunks) {
size_t n_errors;
- size_t i;
trunks = bitmap_allocate(4096);
n_errors = 0;
/* We need to make the same determination as the Linux bonding
* code to determine whether a slave should be consider "up".
- * The Linux function bond_miimon_inspect() supports four
+ * The Linux function bond_miimon_inspect() supports four
* BOND_LINK_* states:
- *
+ *
* - BOND_LINK_UP: carrier detected, updelay has passed.
* - BOND_LINK_FAIL: carrier lost, downdelay in progress.
* - BOND_LINK_DOWN: carrier lost, downdelay has passed.
* - BOND_LINK_BACK: carrier detected, updelay in progress.
*
- * The function bond_info_show_slave() only considers BOND_LINK_UP
+ * The function bond_info_show_slave() only considers BOND_LINK_UP
* to be "up" and anything else to be "down".
*/
slave->up = iface->enabled && iface->delay_expires == LLONG_MAX;
shash_find_and_delete_assert(&br->iface_by_name, iface->name);
if (iface->dp_ifidx >= 0) {
- port_array_set(&br->ifaces, iface->dp_ifidx, NULL);
+ hmap_remove(&br->ifaces, &iface->dp_ifidx_node);
}
del = port->ifaces[iface->port_ifidx] = port->ifaces[--port->n_ifaces];
static struct iface *
iface_from_dp_ifidx(const struct bridge *br, uint16_t dp_ifidx)
{
- return port_array_get(&br->ifaces, dp_ifidx);
+ struct iface *iface;
+
+ HMAP_FOR_EACH_IN_BUCKET (iface, dp_ifidx_node,
+ hash_int(dp_ifidx, 0), &br->ifaces) {
+ if (iface->dp_ifidx == dp_ifidx) {
+ return iface;
+ }
+ }
+ return NULL;
}
/* Returns true if 'iface' is the name of an "internal" interface on bridge