#include "lacp.h"
#include "list.h"
#include "mac-learning.h"
+#include "mcast-snooping.h"
#include "meta-flow.h"
#include "netdev.h"
#include "ofp-print.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"
* 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 int stats_timer_interval;
static long long int stats_timer = LLONG_MIN;
-/* Set to true to allow experimental use of OpenFlow 1.4.
- * This is false initially because OpenFlow 1.4 is not yet safe to use: it can
- * abort due to unimplemented features. */
-static bool allow_of14;
-
/* In some datapaths, creating and destroying OpenFlow ports can be extremely
* expensive. This can cause bridge_reconfigure() to take a long time during
* which no other work can be done. To deal with this problem, we limit port
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 *);
ofp_port_t ofp_port);
static void iface_set_mac(const struct bridge *, const struct port *, struct iface *);
static void iface_set_ofport(const struct ovsrec_interface *, ofp_port_t ofport);
-static void iface_clear_db_record(const struct ovsrec_interface *if_cfg);
+static void iface_clear_db_record(const struct ovsrec_interface *if_cfg, char *errp);
static void iface_configure_qos(struct iface *, const struct ovsrec_qos *);
static void iface_configure_cfm(struct iface *);
static void iface_refresh_cfm_stats(struct iface *);
ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_remote_opstate);
ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_bfd_status);
ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_lacp_current);
+ ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_error);
ovsdb_idl_omit(idl, &ovsrec_interface_col_external_ids);
ovsdb_idl_omit_alert(idl, &ovsrec_controller_col_is_connected);
lacp_init();
bond_init();
cfm_init();
+ ovs_numa_init();
stp_init();
}
ovsdb_idl_destroy(idl);
}
-/* Enables use of OpenFlow 1.4. This is off by default because OpenFlow 1.4 is
- * not yet safe to use: it can abort due to unimplemented features. */
-void
-bridge_enable_of14(void)
-{
- allow_of14 = true;
-}
-
/* Looks at the list of managers in 'ovs_cfg' and extracts their remote IP
* addresses and ports into '*managersp' and '*n_managersp'. The caller is
* responsible for freeing '*managersp' (with free()).
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;
}
}
}
LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
iface_set_ofport(iface->cfg, iface->ofp_port);
+ /* Clear eventual previous errors */
+ ovsrec_interface_set_error(iface->cfg, NULL);
iface_configure_cfm(iface);
iface_configure_qos(iface, port->cfg->qos);
iface_set_mac(br, port, iface);
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);
}
if (strcmp(ofproto_port.type, iface->type)
- || netdev_set_config(iface->netdev, &iface->cfg->options)) {
+ || netdev_set_config(iface->netdev, &iface->cfg->options, NULL)) {
/* The interface is the wrong type or can't be configured.
* Delete it. */
goto delete;
static uint32_t
bridge_get_allowed_versions(struct bridge *br)
{
- uint32_t allowed_versions;
-
if (!br->cfg->n_protocols)
return 0;
- allowed_versions = ofputil_versions_from_strings(br->cfg->protocols,
- br->cfg->n_protocols);
- if (!allow_of14) {
- allowed_versions &= ~(1u << OFP14_VERSION);
- }
- return allowed_versions;
+ return ofputil_versions_from_strings(br->cfg->protocols,
+ br->cfg->n_protocols);
}
/* Set NetFlow configuration on '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) {
* Returns 0 if successful, otherwise a positive errno value. */
static int
iface_set_netdev_config(const struct ovsrec_interface *iface_cfg,
- struct netdev *netdev)
+ struct netdev *netdev, char **errp)
{
- return netdev_set_config(netdev, &iface_cfg->options);
+ return netdev_set_config(netdev, &iface_cfg->options, errp);
}
/* Opens a network device for 'if_cfg' and configures it. Adds the network
iface_do_create(const struct bridge *br,
const struct ovsrec_interface *iface_cfg,
const struct ovsrec_port *port_cfg,
- ofp_port_t *ofp_portp, struct netdev **netdevp)
+ ofp_port_t *ofp_portp, struct netdev **netdevp,
+ char **errp)
{
struct netdev *netdev = NULL;
int error;
error = netdev_open(iface_cfg->name,
iface_get_type(iface_cfg, br->cfg), &netdev);
if (error) {
- VLOG_WARN("could not open network device %s (%s)",
- iface_cfg->name, ovs_strerror(error));
+ VLOG_WARN_BUF(errp, "could not open network device %s (%s)",
+ iface_cfg->name, ovs_strerror(error));
goto error;
}
- error = iface_set_netdev_config(iface_cfg, netdev);
+ error = iface_set_netdev_config(iface_cfg, netdev, errp);
if (error) {
goto error;
}
struct iface *iface;
ofp_port_t ofp_port;
struct port *port;
+ char *errp = NULL;
int error;
/* Do the bits that can fail up front. */
ovs_assert(!iface_lookup(br, iface_cfg->name));
- error = iface_do_create(br, iface_cfg, port_cfg, &ofp_port, &netdev);
+ error = iface_do_create(br, iface_cfg, port_cfg, &ofp_port, &netdev, &errp);
if (error) {
- iface_clear_db_record(iface_cfg);
+ iface_clear_db_record(iface_cfg, errp);
+ free(errp);
return false;
}
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
iface_refresh_cfm_stats(struct iface *iface)
{
const struct ovsrec_interface *cfg = iface->cfg;
- struct ofproto_cfm_status status;
+ struct cfm_status status;
int error;
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);
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);
* 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 {
/* Check the need to update status. */
seq = seq_read(connectivity_seq_get());
- if (seq != connectivity_seqno) {
+ if (seq != connectivity_seqno || status_txn_try_again) {
connectivity_seqno = seq;
status_txn = ovsdb_idl_txn_create(idl);
HMAP_FOR_EACH (br, node, &all_bridges) {
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;
+ }
}
}
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 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);
oc->rate_limit = 0;
oc->burst_limit = 0;
oc->enable_async_msgs = true;
+ oc->dscp = 0;
}
/* Converts ovsrec_controller 'c' into an ofproto_controller in 'oc'. */
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;
s.n_prefix_fields = 0;
for (k = 0; k < cfg->n_prefixes; k++) {
const char *name = cfg->prefixes[k];
- const struct mf_field *mf = mf_from_name(name);
+ const struct mf_field *mf;
+
+ if (strcmp(name, "none") == 0) {
+ use_default_prefixes = false;
+ s.n_prefix_fields = 0;
+ break;
+ }
+ mf = mf_from_name(name);
if (!mf) {
VLOG_WARN("bridge %s: 'prefixes' with unknown field: %s",
br->name, name);
"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) {
- 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);
list_remove(&iface->port_elem);
hmap_remove(&br->iface_by_name, &iface->name_node);
- netdev_close(iface->netdev);
+ /* The user is changing configuration here, so netdev_remove needs to be
+ * used as opposed to netdev_close */
+ netdev_remove(iface->netdev);
free(iface->name);
free(iface);
* This is appropriate when 'if_cfg''s interface cannot be created or is
* otherwise invalid. */
static void
-iface_clear_db_record(const struct ovsrec_interface *if_cfg)
+iface_clear_db_record(const struct ovsrec_interface *if_cfg, char *errp)
{
if (!ovsdb_idl_row_is_synthetic(&if_cfg->header_)) {
iface_set_ofport(if_cfg, OFPP_NONE);
+ ovsrec_interface_set_error(if_cfg, errp);
ovsrec_interface_set_status(if_cfg, NULL);
ovsrec_interface_set_admin_state(if_cfg, NULL);
ovsrec_interface_set_duplex(if_cfg, NULL);