#include "lacp.h"
#include "list.h"
#include "mac-learning.h"
+#include "mcast-snooping.h"
#include "meta-flow.h"
#include "netdev.h"
+#include "nx-match.h"
#include "ofp-print.h"
#include "ofp-util.h"
#include "ofpbuf.h"
#include "ofproto/bond.h"
#include "ofproto/ofproto.h"
+#include "ovs-numa.h"
#include "poll-loop.h"
#include "seq.h"
#include "sha1.h"
#include "vlog.h"
#include "sflow_api.h"
#include "vlan-bitmap.h"
+#include "packets.h"
VLOG_DEFINE_THIS_MODULE(bridge);
* update if the previous transaction status is 'TXN_INCOMPLETE'.
*
* 'statux_txn' is NULL if there is no ongoing status update.
+ *
+ * If the previous database transaction was failed (is not 'TXN_SUCCESS',
+ * 'TXN_UNCHANGED' or 'TXN_INCOMPLETE'), 'status_txn_try_again' is set to true,
+ * which will cause the main thread wake up soon and retry the status update.
*/
static struct ovsdb_idl_txn *status_txn;
+static bool status_txn_try_again;
/* When the status update transaction returns 'TXN_INCOMPLETE', should register a
* timeout in 'STATUS_CHECK_AGAIN_MSEC' to check again. */
static void bridge_configure_netflow(struct bridge *);
static void bridge_configure_forward_bpdu(struct bridge *);
static void bridge_configure_mac_table(struct bridge *);
+static void bridge_configure_mcast_snooping(struct bridge *);
static void bridge_configure_sflow(struct bridge *, int *sflow_bridge_number);
static void bridge_configure_ipfix(struct bridge *);
static void bridge_configure_stp(struct bridge *);
+static void bridge_configure_rstp(struct bridge *);
static void bridge_configure_tables(struct bridge *);
static void bridge_configure_dp_desc(struct bridge *);
static void bridge_configure_remotes(struct bridge *,
ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_datapath_id);
ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_status);
+ ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_rstp_status);
+ ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_stp_enable);
+ ovsdb_idl_omit_alert(idl, &ovsrec_bridge_col_rstp_enable);
ovsdb_idl_omit(idl, &ovsrec_bridge_col_external_ids);
ovsdb_idl_omit_alert(idl, &ovsrec_port_col_status);
+ ovsdb_idl_omit_alert(idl, &ovsrec_port_col_rstp_status);
+ ovsdb_idl_omit_alert(idl, &ovsrec_port_col_rstp_statistics);
ovsdb_idl_omit_alert(idl, &ovsrec_port_col_statistics);
+ ovsdb_idl_omit_alert(idl, &ovsrec_port_col_bond_active_slave);
ovsdb_idl_omit(idl, &ovsrec_port_col_external_ids);
ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_admin_state);
lacp_init();
bond_init();
cfm_init();
+ ovs_numa_init();
stp_init();
+ rstp_init();
}
void
managers = xmalloc(sset_count(&targets) * sizeof *managers);
SSET_FOR_EACH (target, &targets) {
- struct sockaddr_storage ss;
+ union {
+ struct sockaddr_storage ss;
+ struct sockaddr_in in;
+ } sa;
if (stream_parse_target_with_default_port(target, OVSDB_OLD_PORT,
- &ss)
- && ss.ss_family == AF_INET) {
- managers[n_managers++] = *(struct sockaddr_in *) &ss;
+ &sa.ss)
+ && sa.ss.ss_family == AF_INET) {
+ managers[n_managers++] = sa.in;
}
}
}
OFPROTO_FLOW_LIMIT_DEFAULT));
ofproto_set_max_idle(smap_get_int(&ovs_cfg->other_config, "max-idle",
OFPROTO_MAX_IDLE_DEFAULT));
+ ofproto_set_n_dpdk_rxqs(smap_get_int(&ovs_cfg->other_config,
+ "n-dpdk-rxqs", 0));
+ ofproto_set_cpu_mask(smap_get(&ovs_cfg->other_config, "pmd-cpu-mask"));
ofproto_set_threads(
smap_get_int(&ovs_cfg->other_config, "n-handler-threads", 0),
bridge_configure_mirrors(br);
bridge_configure_forward_bpdu(br);
bridge_configure_mac_table(br);
+ bridge_configure_mcast_snooping(br);
bridge_configure_remotes(br, managers, n_managers);
bridge_configure_netflow(br);
bridge_configure_sflow(br, &sflow_bridge_number);
bridge_configure_ipfix(br);
bridge_configure_stp(br);
+ bridge_configure_rstp(br);
bridge_configure_tables(br);
bridge_configure_dp_desc(br);
}
if (be_cfg->cache_max_flows) {
be_opts.cache_max_flows = *be_cfg->cache_max_flows;
}
+
+ be_opts.enable_tunnel_sampling = smap_get_bool(&be_cfg->other_config,
+ "enable-tunnel-sampling", true);
+
+ be_opts.enable_input_sampling = !smap_get_bool(&be_cfg->other_config,
+ "enable-input-sampling", false);
+
+ be_opts.enable_output_sampling = !smap_get_bool(&be_cfg->other_config,
+ "enable-output-sampling", false);
}
if (n_fe_opts > 0) {
}
}
+static void
+port_configure_rstp(const struct ofproto *ofproto, struct port *port,
+ struct ofproto_port_rstp_settings *port_s, int *port_num_counter)
+{
+ const char *config_str;
+ struct iface *iface;
+
+ if (!smap_get_bool(&port->cfg->other_config, "rstp-enable", true)) {
+ port_s->enable = false;
+ return;
+ } else {
+ port_s->enable = true;
+ }
+
+ /* RSTP over bonds is not supported. */
+ if (!list_is_singleton(&port->ifaces)) {
+ VLOG_ERR("port %s: cannot enable RSTP on bonds, disabling",
+ port->name);
+ port_s->enable = false;
+ return;
+ }
+
+ iface = CONTAINER_OF(list_front(&port->ifaces), struct iface, port_elem);
+
+ /* Internal ports shouldn't participate in spanning tree, so
+ * skip them. */
+ if (!strcmp(iface->type, "internal")) {
+ VLOG_DBG("port %s: disable RSTP on internal ports", port->name);
+ port_s->enable = false;
+ return;
+ }
+
+ /* RSTP on mirror output ports is not supported. */
+ if (ofproto_is_mirror_output_bundle(ofproto, port)) {
+ VLOG_DBG("port %s: disable RSTP on mirror ports", port->name);
+ port_s->enable = false;
+ return;
+ }
+
+ config_str = smap_get(&port->cfg->other_config, "rstp-port-num");
+ if (config_str) {
+ unsigned long int port_num = strtoul(config_str, NULL, 0);
+ if (port_num < 1 || port_num > RSTP_MAX_PORTS) {
+ VLOG_ERR("port %s: invalid rstp-port-num", port->name);
+ port_s->enable = false;
+ return;
+ }
+ port_s->port_num = port_num;
+ } else {
+ if (*port_num_counter >= RSTP_MAX_PORTS) {
+ VLOG_ERR("port %s: too many RSTP ports, disabling", port->name);
+ port_s->enable = false;
+ return;
+ }
+ /* If rstp-port-num is not specified, use 0.
+ * rstp_port_set_port_number() will look for the first free one. */
+ port_s->port_num = 0;
+ }
+
+ config_str = smap_get(&port->cfg->other_config, "rstp-path-cost");
+ if (config_str) {
+ port_s->path_cost = strtoul(config_str, NULL, 10);
+ } else {
+ enum netdev_features current;
+ unsigned int mbps;
+
+ netdev_get_features(iface->netdev, ¤t, NULL, NULL, NULL);
+ mbps = netdev_features_to_bps(current, 100 * 1000 * 1000) / 1000000;
+ port_s->path_cost = rstp_convert_speed_to_cost(mbps);
+ }
+
+ config_str = smap_get(&port->cfg->other_config, "rstp-port-priority");
+ if (config_str) {
+ port_s->priority = strtoul(config_str, NULL, 0);
+ } else {
+ port_s->priority = RSTP_DEFAULT_PORT_PRIORITY;
+ }
+
+ port_s->admin_edge_port = smap_get_bool(&port->cfg->other_config,
+ "rstp-port-admin-edge", false);
+ port_s->auto_edge = smap_get_bool(&port->cfg->other_config,
+ "rstp-port-auto-edge", true);
+ port_s->mcheck = smap_get_bool(&port->cfg->other_config,
+ "rstp-port-mcheck", false);
+}
+
/* Set spanning tree configuration on 'br'. */
static void
bridge_configure_stp(struct bridge *br)
{
+ struct ofproto_rstp_status rstp_status;
+
+ ofproto_get_rstp_status(br->ofproto, &rstp_status);
if (!br->cfg->stp_enable) {
ofproto_set_stp(br->ofproto, NULL);
+ } else if (rstp_status.enabled) {
+ /* Do not activate STP if RSTP is enabled. */
+ VLOG_ERR("STP cannot be enabled if RSTP is running.");
+ ofproto_set_stp(br->ofproto, NULL);
+ ovsrec_bridge_set_stp_enable(br->cfg, false);
} else {
struct ofproto_stp_settings br_s;
const char *config_str;
}
}
+static void
+bridge_configure_rstp(struct bridge *br)
+{
+ struct ofproto_stp_status stp_status;
+
+ ofproto_get_stp_status(br->ofproto, &stp_status);
+ if (!br->cfg->rstp_enable) {
+ ofproto_set_rstp(br->ofproto, NULL);
+ } else if (stp_status.enabled) {
+ /* Do not activate RSTP if STP is enabled. */
+ VLOG_ERR("RSTP cannot be enabled if STP is running.");
+ ofproto_set_rstp(br->ofproto, NULL);
+ ovsrec_bridge_set_rstp_enable(br->cfg, false);
+ } else {
+ struct ofproto_rstp_settings br_s;
+ const char *config_str;
+ struct port *port;
+ int port_num_counter;
+
+ config_str = smap_get(&br->cfg->other_config, "rstp-address");
+ if (config_str) {
+ uint8_t ea[ETH_ADDR_LEN];
+
+ if (eth_addr_from_string(config_str, ea)) {
+ br_s.address = eth_addr_to_uint64(ea);
+ }
+ else {
+ br_s.address = eth_addr_to_uint64(br->ea);
+ VLOG_ERR("bridge %s: invalid rstp-address, defaulting "
+ "to "ETH_ADDR_FMT, br->name, ETH_ADDR_ARGS(br->ea));
+ }
+ }
+ else {
+ br_s.address = eth_addr_to_uint64(br->ea);
+ }
+
+ config_str = smap_get(&br->cfg->other_config, "rstp-priority");
+ if (config_str) {
+ br_s.priority = strtoul(config_str, NULL, 0);
+ } else {
+ br_s.priority = RSTP_DEFAULT_PRIORITY;
+ }
+
+ config_str = smap_get(&br->cfg->other_config, "rstp-ageing-time");
+ if (config_str) {
+ br_s.ageing_time = strtoul(config_str, NULL, 0);
+ } else {
+ br_s.ageing_time = RSTP_DEFAULT_AGEING_TIME;
+ }
+
+ config_str = smap_get(&br->cfg->other_config,
+ "rstp-force-protocol-version");
+ if (config_str) {
+ br_s.force_protocol_version = strtoul(config_str, NULL, 0);
+ } else {
+ br_s.force_protocol_version = FPV_DEFAULT;
+ }
+
+ config_str = smap_get(&br->cfg->other_config, "rstp-max-age");
+ if (config_str) {
+ br_s.bridge_max_age = strtoul(config_str, NULL, 10);
+ } else {
+ br_s.bridge_max_age = RSTP_DEFAULT_BRIDGE_MAX_AGE;
+ }
+
+ config_str = smap_get(&br->cfg->other_config, "rstp-forward-delay");
+ if (config_str) {
+ br_s.bridge_forward_delay = strtoul(config_str, NULL, 10);
+ } else {
+ br_s.bridge_forward_delay = RSTP_DEFAULT_BRIDGE_FORWARD_DELAY;
+ }
+
+ config_str = smap_get(&br->cfg->other_config,
+ "rstp-transmit-hold-count");
+ if (config_str) {
+ br_s.transmit_hold_count = strtoul(config_str, NULL, 10);
+ } else {
+ br_s.transmit_hold_count = RSTP_DEFAULT_TRANSMIT_HOLD_COUNT;
+ }
+
+ /* Configure RSTP on the bridge. */
+ if (ofproto_set_rstp(br->ofproto, &br_s)) {
+ VLOG_ERR("bridge %s: could not enable RSTP", br->name);
+ return;
+ }
+
+ port_num_counter = 0;
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+ struct ofproto_port_rstp_settings port_s;
+ struct iface *iface;
+
+ port_configure_rstp(br->ofproto, port, &port_s,
+ &port_num_counter);
+
+ /* As bonds are not supported, just apply configuration to
+ * all interfaces. */
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+ if (ofproto_port_set_rstp(br->ofproto, iface->ofp_port,
+ &port_s)) {
+ VLOG_ERR("port %s: could not enable RSTP", port->name);
+ continue;
+ }
+ }
+ }
+ }
+}
+
static bool
bridge_has_bond_fake_iface(const struct bridge *br, const char *name)
{
ofproto_set_mac_table_config(br->ofproto, idle_time, mac_table_size);
}
+/* Set multicast snooping table configuration for 'br'. */
+static void
+bridge_configure_mcast_snooping(struct bridge *br)
+{
+ if (!br->cfg->mcast_snooping_enable) {
+ ofproto_set_mcast_snooping(br->ofproto, NULL);
+ } else {
+ struct port *port;
+ struct ofproto_mcast_snooping_settings br_s;
+ const char *idle_time_str;
+ const char *max_entries_str;
+
+ idle_time_str = smap_get(&br->cfg->other_config,
+ "mcast-snooping-aging-time");
+ br_s.idle_time = (idle_time_str && atoi(idle_time_str)
+ ? atoi(idle_time_str)
+ : MCAST_ENTRY_DEFAULT_IDLE_TIME);
+
+ max_entries_str = smap_get(&br->cfg->other_config,
+ "mcast-snooping-table-size");
+ br_s.max_entries = (max_entries_str && atoi(max_entries_str)
+ ? atoi(max_entries_str)
+ : MCAST_DEFAULT_MAX_ENTRIES);
+
+ br_s.flood_unreg = !smap_get_bool(&br->cfg->other_config,
+ "mcast-snooping-disable-flood-unregistered",
+ false);
+
+ /* Configure multicast snooping on the bridge */
+ if (ofproto_set_mcast_snooping(br->ofproto, &br_s)) {
+ VLOG_ERR("bridge %s: could not enable multicast snooping",
+ br->name);
+ return;
+ }
+
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+ bool flood = smap_get_bool(&port->cfg->other_config,
+ "mcast-snooping-flood", false);
+ if (ofproto_port_set_mcast_snooping(br->ofproto, port, flood)) {
+ VLOG_ERR("port %s: could not configure mcast snooping",
+ port->name);
+ }
+ }
+ }
+}
+
static void
find_local_hw_addr(const struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
const struct port *fake_br, struct iface **hw_addr_iface)
return;
}
- if (iface->change_seq == netdev_get_change_seq(iface->netdev)) {
+ if (iface->change_seq == netdev_get_change_seq(iface->netdev)
+ && !status_txn_try_again) {
return;
}
static void
iface_refresh_ofproto_status(struct iface *iface)
{
- struct smap smap;
- int current, error;
+ int current;
if (iface_is_synthetic(iface)) {
return;
ovsrec_interface_set_lacp_current(iface->cfg, NULL, 0);
}
- iface_refresh_cfm_stats(iface);
+ if (ofproto_port_cfm_status_changed(iface->port->bridge->ofproto,
+ iface->ofp_port)
+ || status_txn_try_again) {
+ iface_refresh_cfm_stats(iface);
+ }
- smap_init(&smap);
- error = ofproto_port_get_bfd_status(iface->port->bridge->ofproto,
- iface->ofp_port, &smap);
- if (error >= 0) {
+ if (ofproto_port_bfd_status_changed(iface->port->bridge->ofproto,
+ iface->ofp_port)
+ || status_txn_try_again) {
+ struct smap smap;
+
+ smap_init(&smap);
+ ofproto_port_get_bfd_status(iface->port->bridge->ofproto,
+ iface->ofp_port, &smap);
ovsrec_interface_set_bfd_status(iface->cfg, &smap);
+ smap_destroy(&smap);
}
- smap_destroy(&smap);
}
/* Writes 'iface''s CFM statistics to the database. 'iface' must not be
error = ofproto_port_get_cfm_status(iface->port->bridge->ofproto,
iface->ofp_port, &status);
- if (error < 0) {
- /* Do nothing if there is no status change since last update. */
- } else if (error > 0) {
+ if (error > 0) {
ovsrec_interface_set_cfm_fault(cfg, NULL, 0);
ovsrec_interface_set_cfm_fault_status(cfg, NULL, 0);
ovsrec_interface_set_cfm_remote_opstate(cfg, NULL);
ARRAY_SIZE(int_values));
}
+static void
+br_refresh_rstp_status(struct bridge *br)
+{
+ struct smap smap = SMAP_INITIALIZER(&smap);
+ struct ofproto *ofproto = br->ofproto;
+ struct ofproto_rstp_status status;
+
+ if (ofproto_get_rstp_status(ofproto, &status)) {
+ return;
+ }
+ if (!status.enabled) {
+ ovsrec_bridge_set_rstp_status(br->cfg, NULL);
+ return;
+ }
+ smap_add_format(&smap, "rstp_bridge_id", RSTP_ID_FMT,
+ RSTP_ID_ARGS(status.bridge_id));
+ smap_add_format(&smap, "rstp_root_path_cost", "%d",
+ status.root_path_cost);
+ smap_add_format(&smap, "rstp_root_id", RSTP_ID_FMT,
+ RSTP_ID_ARGS(status.root_id));
+ smap_add_format(&smap, "rstp_designated_id", RSTP_ID_FMT,
+ RSTP_ID_ARGS(status.designated_id));
+ smap_add_format(&smap, "rstp_designated_port_id", RSTP_PORT_ID_FMT,
+ status.designated_port_id);
+ smap_add_format(&smap, "rstp_bridge_port_id", RSTP_PORT_ID_FMT,
+ status.bridge_port_id);
+ ovsrec_bridge_set_rstp_status(br->cfg, &smap);
+ smap_destroy(&smap);
+}
+
+static void
+port_refresh_rstp_status(struct port *port)
+{
+ struct ofproto *ofproto = port->bridge->ofproto;
+ struct iface *iface;
+ struct ofproto_port_rstp_status status;
+ char *keys[3];
+ int64_t int_values[3];
+ struct smap smap;
+
+ if (port_is_synthetic(port)) {
+ return;
+ }
+
+ /* RSTP doesn't currently support bonds. */
+ if (!list_is_singleton(&port->ifaces)) {
+ ovsrec_port_set_rstp_status(port->cfg, NULL);
+ return;
+ }
+
+ iface = CONTAINER_OF(list_front(&port->ifaces), struct iface, port_elem);
+ if (ofproto_port_get_rstp_status(ofproto, iface->ofp_port, &status)) {
+ return;
+ }
+
+ if (!status.enabled) {
+ ovsrec_port_set_rstp_status(port->cfg, NULL);
+ ovsrec_port_set_rstp_statistics(port->cfg, NULL, NULL, 0);
+ return;
+ }
+ /* Set Status column. */
+ smap_init(&smap);
+
+ smap_add_format(&smap, "rstp_port_id", RSTP_PORT_ID_FMT,
+ status.port_id);
+ smap_add_format(&smap, "rstp_port_role", "%s",
+ rstp_port_role_name(status.role));
+ smap_add_format(&smap, "rstp_port_state", "%s",
+ rstp_state_name(status.state));
+
+ ovsrec_port_set_rstp_status(port->cfg, &smap);
+ smap_destroy(&smap);
+
+ /* Set Statistics column. */
+ keys[0] = "rstp_tx_count";
+ int_values[0] = status.tx_count;
+ keys[1] = "rstp_rx_count";
+ int_values[1] = status.rx_count;
+ keys[2] = "rstp_uptime";
+ int_values[2] = status.uptime;
+ ovsrec_port_set_rstp_statistics(port->cfg, keys, int_values,
+ ARRAY_SIZE(int_values));
+}
+
+static void
+port_refresh_bond_status(struct port *port, bool force_update)
+{
+ uint8_t mac[6];
+
+ /* Return if port is not a bond */
+ if (list_is_singleton(&port->ifaces)) {
+ return;
+ }
+
+ if (bond_get_changed_active_slave(port->name, mac, force_update)) {
+ struct ds mac_s;
+
+ ds_init(&mac_s);
+ ds_put_format(&mac_s, ETH_ADDR_FMT, ETH_ADDR_ARGS(mac));
+ ovsrec_port_set_bond_active_slave(port->cfg, ds_cstr(&mac_s));
+ ds_destroy(&mac_s);
+ }
+}
+
static bool
enable_system_stats(const struct ovsrec_open_vswitch *cfg)
{
shash_find_data(&info, cfg->target);
if (cinfo) {
- struct smap smap = SMAP_INITIALIZER(&smap);
- const char **values = cinfo->pairs.values;
- const char **keys = cinfo->pairs.keys;
- size_t i;
-
- for (i = 0; i < cinfo->pairs.n; i++) {
- smap_add(&smap, keys[i], values[i]);
- }
-
ovsrec_controller_set_is_connected(cfg, cinfo->is_connected);
ovsrec_controller_set_role(cfg, ofp12_controller_role_to_str(
cinfo->role));
- ovsrec_controller_set_status(cfg, &smap);
- smap_destroy(&smap);
+ ovsrec_controller_set_status(cfg, &cinfo->pairs);
} else {
ovsrec_controller_set_is_connected(cfg, false);
ovsrec_controller_set_role(cfg, NULL);
ofproto_free_ofproto_controller_info(&info);
}
\f
+/* Update interface and mirror statistics if necessary. */
+static void
+run_stats_update(void)
+{
+ static struct ovsdb_idl_txn *stats_txn;
+ const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_first(idl);
+ int stats_interval;
+
+ if (!cfg) {
+ return;
+ }
+
+ /* Statistics update interval should always be greater than or equal to
+ * 5000 ms. */
+ stats_interval = MAX(smap_get_int(&cfg->other_config,
+ "stats-update-interval",
+ 5000), 5000);
+ if (stats_timer_interval != stats_interval) {
+ stats_timer_interval = stats_interval;
+ stats_timer = LLONG_MIN;
+ }
+
+ if (time_msec() >= stats_timer) {
+ enum ovsdb_idl_txn_status status;
+
+ /* Rate limit the update. Do not start a new update if the
+ * previous one is not done. */
+ if (!stats_txn) {
+ struct bridge *br;
+
+ stats_txn = ovsdb_idl_txn_create(idl);
+ HMAP_FOR_EACH (br, node, &all_bridges) {
+ struct port *port;
+ struct mirror *m;
+
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+ struct iface *iface;
+
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+ iface_refresh_stats(iface);
+ }
+ port_refresh_stp_stats(port);
+ }
+ HMAP_FOR_EACH (m, hmap_node, &br->mirrors) {
+ mirror_refresh_stats(m);
+ }
+ }
+ refresh_controller_status();
+ }
+
+ status = ovsdb_idl_txn_commit(stats_txn);
+ if (status != TXN_INCOMPLETE) {
+ stats_timer = time_msec() + stats_timer_interval;
+ ovsdb_idl_txn_destroy(stats_txn);
+ stats_txn = NULL;
+ }
+ }
+}
+
+/* Update bridge/port/interface status if necessary. */
+static void
+run_status_update(void)
+{
+ if (!status_txn) {
+ uint64_t seq;
+
+ /* Rate limit the update. Do not start a new update if the
+ * previous one is not done. */
+ seq = seq_read(connectivity_seq_get());
+ if (seq != connectivity_seqno || status_txn_try_again) {
+ struct bridge *br;
+
+ connectivity_seqno = seq;
+ status_txn = ovsdb_idl_txn_create(idl);
+ HMAP_FOR_EACH (br, node, &all_bridges) {
+ struct port *port;
+
+ br_refresh_stp_status(br);
+ br_refresh_rstp_status(br);
+ HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+ struct iface *iface;
+
+ port_refresh_stp_status(port);
+ port_refresh_rstp_status(port);
+ port_refresh_bond_status(port, status_txn_try_again);
+ LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
+ iface_refresh_netdev_status(iface);
+ iface_refresh_ofproto_status(iface);
+ }
+ }
+ }
+ }
+ }
+
+ /* Commit the transaction and get the status. If the transaction finishes,
+ * then destroy the transaction. Otherwise, keep it so that we can check
+ * progress the next time that this function is called. */
+ if (status_txn) {
+ enum ovsdb_idl_txn_status status;
+
+ status = ovsdb_idl_txn_commit(status_txn);
+ if (status != TXN_INCOMPLETE) {
+ ovsdb_idl_txn_destroy(status_txn);
+ status_txn = NULL;
+
+ /* Sets the 'status_txn_try_again' if the transaction fails. */
+ if (status == TXN_SUCCESS || status == TXN_UNCHANGED) {
+ status_txn_try_again = false;
+ } else {
+ status_txn_try_again = true;
+ }
+ }
+ }
+}
+
+static void
+status_update_wait(void)
+{
+ /* This prevents the process from constantly waking up on
+ * connectivity seq, when there is no connection to ovsdb. */
+ if (!ovsdb_idl_has_lock(idl)) {
+ return;
+ }
+
+ /* If the 'status_txn' is non-null (transaction incomplete), waits for the
+ * transaction to complete. If the status update to database needs to be
+ * run again (transaction fails), registers a timeout in
+ * 'STATUS_CHECK_AGAIN_MSEC'. Otherwise, waits on the global connectivity
+ * sequence number. */
+ if (status_txn) {
+ ovsdb_idl_txn_wait(status_txn);
+ } else if (status_txn_try_again) {
+ poll_timer_wait_until(time_msec() + STATUS_CHECK_AGAIN_MSEC);
+ } else {
+ seq_wait(connectivity_seq_get(), connectivity_seqno);
+ }
+}
+
static void
bridge_run__(void)
{
const struct ovsrec_open_vswitch *cfg;
bool vlan_splinters_changed;
- struct bridge *br;
- int stats_interval;
ovsrec_open_vswitch_init(&null_cfg);
* usage has changed. */
vlan_splinters_changed = false;
if (vlan_splinters_enabled_anywhere) {
+ struct bridge *br;
+
HMAP_FOR_EACH (br, node, &all_bridges) {
if (ofproto_has_vlan_usage_changed(br->ofproto)) {
vlan_splinters_changed = true;
* of ovs-vswitchd, then keep the transaction around to monitor
* it for completion. */
if (initial_config_done) {
+ /* Always sets the 'status_txn_try_again' to check again,
+ * in case that this transaction fails. */
+ status_txn_try_again = true;
ovsdb_idl_txn_commit(txn);
ovsdb_idl_txn_destroy(txn);
} else {
}
}
- /* Statistics update interval should always be greater than or equal to
- * 5000 ms. */
- if (cfg) {
- stats_interval = MAX(smap_get_int(&cfg->other_config,
- "stats-update-interval",
- 5000), 5000);
- } else {
- stats_interval = 5000;
- }
- if (stats_timer_interval != stats_interval) {
- stats_timer_interval = stats_interval;
- stats_timer = LLONG_MIN;
- }
-
- /* Refresh interface and mirror stats if necessary. */
- if (time_msec() >= stats_timer) {
- if (cfg) {
- struct ovsdb_idl_txn *txn;
-
- txn = ovsdb_idl_txn_create(idl);
- HMAP_FOR_EACH (br, node, &all_bridges) {
- struct port *port;
- struct mirror *m;
-
- HMAP_FOR_EACH (port, hmap_node, &br->ports) {
- struct iface *iface;
-
- LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
- iface_refresh_stats(iface);
- }
-
- port_refresh_stp_stats(port);
- }
-
- HMAP_FOR_EACH (m, hmap_node, &br->mirrors) {
- mirror_refresh_stats(m);
- }
-
- }
- refresh_controller_status();
- ovsdb_idl_txn_commit(txn);
- ovsdb_idl_txn_destroy(txn); /* XXX */
- }
-
- stats_timer = time_msec() + stats_timer_interval;
- }
-
- if (!status_txn) {
- uint64_t seq;
-
- /* Check the need to update status. */
- seq = seq_read(connectivity_seq_get());
- if (seq != connectivity_seqno) {
- connectivity_seqno = seq;
- status_txn = ovsdb_idl_txn_create(idl);
- HMAP_FOR_EACH (br, node, &all_bridges) {
- struct port *port;
-
- br_refresh_stp_status(br);
- HMAP_FOR_EACH (port, hmap_node, &br->ports) {
- struct iface *iface;
-
- port_refresh_stp_status(port);
- LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
- iface_refresh_netdev_status(iface);
- iface_refresh_ofproto_status(iface);
- }
- }
- }
- }
- }
-
- if (status_txn) {
- enum ovsdb_idl_txn_status status;
-
- status = ovsdb_idl_txn_commit(status_txn);
- /* Do not destroy "status_txn" if the transaction is
- * "TXN_INCOMPLETE". */
- if (status != TXN_INCOMPLETE) {
- ovsdb_idl_txn_destroy(status_txn);
- status_txn = NULL;
- }
- }
-
+ run_stats_update();
+ run_status_update();
run_system_stats();
}
poll_timer_wait_until(stats_timer);
}
- /* If the status database transaction is 'TXN_INCOMPLETE' in this run,
- * register a timeout in 'STATUS_CHECK_AGAIN_MSEC'. Else, wait on the
- * global connectivity sequence number. Note, this also helps batch
- * multiple status changes into one transaction. */
- if (status_txn) {
- poll_timer_wait_until(time_msec() + STATUS_CHECK_AGAIN_MSEC);
- } else {
- seq_wait(connectivity_seq_get(), connectivity_seqno);
- }
-
+ status_update_wait();
system_stats_wait();
}
j = 0;
for (i = 0; i < n_tables; i++) {
struct ofproto_table_settings s;
+ bool use_default_prefixes = true;
s.name = NULL;
s.max_flows = UINT_MAX;
if (j < br->cfg->n_flow_tables && i == br->cfg->key_flow_tables[j]) {
struct ovsrec_flow_table *cfg = br->cfg->value_flow_tables[j++];
- bool no_prefixes;
s.name = cfg->name;
if (cfg->n_flow_limit && *cfg->flow_limit < UINT_MAX) {
}
}
/* Prefix lookup fields. */
- no_prefixes = false;
s.n_prefix_fields = 0;
for (k = 0; k < cfg->n_prefixes; k++) {
const char *name = cfg->prefixes[k];
const struct mf_field *mf;
if (strcmp(name, "none") == 0) {
- no_prefixes = true;
- continue;
+ use_default_prefixes = false;
+ s.n_prefix_fields = 0;
+ break;
}
mf = mf_from_name(name);
if (!mf) {
"field not used: %s", br->name, name);
continue;
}
+ use_default_prefixes = false;
s.prefix_fields[s.n_prefix_fields++] = mf->id;
}
- if (s.n_prefix_fields == 0 && !no_prefixes) {
- /* Use default values. */
- s.n_prefix_fields = ARRAY_SIZE(default_prefix_fields);
- memcpy(s.prefix_fields, default_prefix_fields,
- sizeof default_prefix_fields);
- }
- if (s.n_prefix_fields > 0) {
- int k;
- struct ds ds = DS_EMPTY_INITIALIZER;
- for (k = 0; k < s.n_prefix_fields; k++) {
- if (k) {
- ds_put_char(&ds, ',');
- }
- ds_put_cstr(&ds, mf_from_id(s.prefix_fields[k])->name);
+ }
+ if (use_default_prefixes) {
+ /* Use default values. */
+ s.n_prefix_fields = ARRAY_SIZE(default_prefix_fields);
+ memcpy(s.prefix_fields, default_prefix_fields,
+ sizeof default_prefix_fields);
+ } else {
+ int k;
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ for (k = 0; k < s.n_prefix_fields; k++) {
+ if (k) {
+ ds_put_char(&ds, ',');
}
- VLOG_INFO("bridge %s table %d: Prefix lookup with: %s.",
- br->name, i, ds_cstr(&ds));
- ds_destroy(&ds);
+ ds_put_cstr(&ds, mf_from_id(s.prefix_fields[k])->name);
+ }
+ if (s.n_prefix_fields == 0) {
+ ds_put_cstr(&ds, "none");
}
+ VLOG_INFO("bridge %s table %d: Prefix lookup with: %s.",
+ br->name, i, ds_cstr(&ds));
+ ds_destroy(&ds);
}
ofproto_configure_table(br->ofproto, i, &s);
{
const char *detect_s;
struct iface *iface;
+ const char *mac_s;
int miimon_interval;
s->name = port->name;
s->rebalance_interval = 1000;
}
- s->fake_iface = port->cfg->bond_fake_iface;
-
s->lacp_fallback_ab_cfg = smap_get_bool(&port->cfg->other_config,
"lacp-fallback-ab", false);
LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
netdev_set_miimon_interval(iface->netdev, miimon_interval);
}
+
+ mac_s = port->cfg->bond_active_slave;
+ if (!mac_s || !ovs_scan(mac_s, ETH_ADDR_SCAN_FMT,
+ ETH_ADDR_SCAN_ARGS(s->active_slave_mac))) {
+ /* OVSDB did not store the last active interface */
+ memset(s->active_slave_mac, 0, sizeof(s->active_slave_mac));
+ }
}
/* Returns true if 'port' is synthetic, that is, if we constructed it locally