#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
+
#include "async-append.h"
#include "bfd.h"
#include "bitmap.h"
#include "coverage.h"
#include "daemon.h"
#include "dirs.h"
+#include "dpif.h"
#include "dynamic-string.h"
#include "hash.h"
#include "hmap.h"
* timeout in 'STATUS_CHECK_AGAIN_MSEC' to check again. */
#define STATUS_CHECK_AGAIN_MSEC 100
+/* Statistics update to database. */
+static struct ovsdb_idl_txn *stats_txn;
+
/* Each time this timer expires, the bridge fetches interface and mirror
* statistics and pushes them into the database. */
static int stats_timer_interval;
#define AA_REFRESH_INTERVAL (1000) /* In milliseconds. */
static long long int aa_refresh_timer = LLONG_MIN;
-/* 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
- * adds and deletions to a window of OFP_PORT_ACTION_WINDOW milliseconds per
- * call to bridge_reconfigure(). If there is more work to do after the limit
- * is reached, 'need_reconfigure', is flagged and it's done on the next loop.
- * This allows the rest of the code to catch up on important things like
- * forwarding packets. */
-#define OFP_PORT_ACTION_WINDOW 10
-
static void add_del_bridges(const struct ovsrec_open_vswitch *);
static void bridge_run__(void);
static void bridge_create(const struct ovsrec_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_spanning_tree(struct bridge *);
static void bridge_configure_tables(struct bridge *);
static void bridge_configure_dp_desc(struct bridge *);
static void bridge_configure_aa(struct bridge *);
const struct ovsrec_interface *);
static ofp_port_t iface_pick_ofport(const struct ovsrec_interface *);
+
/* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.)
*
* This is deprecated. It is only for compatibility with broken device drivers
const unsigned long int *splinter_vlans,
struct shash *ports);
+static void discover_types(const struct ovsrec_open_vswitch *cfg);
+
static void
bridge_init_ofproto(const struct ovsrec_open_vswitch *cfg)
{
ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_cur_cfg);
ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_statistics);
+ ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_datapath_types);
+ ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_iface_types);
ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_external_ids);
ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_ovs_version);
ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_db_version);
* should not be and in fact is not directly involved in that. But
* ovs-vswitchd needs to make sure that ovsdb-server can reach the managers, so
* it has to tell in-band control where the managers are to enable that.
- * (Thus, only managers connected in-band are collected.)
+ * (Thus, only managers connected in-band and with non-loopback addresses
+ * are collected.)
*/
static void
collect_in_band_managers(const struct ovsrec_open_vswitch *ovs_cfg,
struct sockaddr_in in;
} sa;
- if (stream_parse_target_with_default_port(target, OVSDB_OLD_PORT,
+ /* Ignore loopback. */
+ if (stream_parse_target_with_default_port(target, OVSDB_PORT,
&sa.ss)
- && sa.ss.ss_family == AF_INET) {
+ && sa.ss.ss_family == AF_INET
+ && sa.in.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
managers[n_managers++] = sa.in;
}
}
smap_get_int(&ovs_cfg->other_config, "n-handler-threads", 0),
smap_get_int(&ovs_cfg->other_config, "n-revalidator-threads", 0));
+ if (ovs_cfg) {
+ discover_types(ovs_cfg);
+ }
+
/* Destroy "struct bridge"s, "struct port"s, and "struct iface"s according
* to 'ovs_cfg', with only very minimal configuration otherwise.
*
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_spanning_tree(br);
bridge_configure_tables(br);
bridge_configure_dp_desc(br);
bridge_configure_aa(br);
/* Set spanning tree configuration on 'br'. */
static void
-bridge_configure_stp(struct bridge *br)
+bridge_configure_stp(struct bridge *br, bool enable_stp)
{
- 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.");
+ if (!enable_stp) {
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)
+bridge_configure_rstp(struct bridge *br, bool enable_rstp)
{
- 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.");
+ if (!enable_rstp) {
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;
}
}
+static void
+bridge_configure_spanning_tree(struct bridge *br)
+{
+ bool enable_rstp = br->cfg->rstp_enable;
+ bool enable_stp = br->cfg->stp_enable;
+
+ if (enable_rstp && enable_stp) {
+ VLOG_WARN("%s: RSTP and STP are mutually exclusive but both are "
+ "configured; enabling RSTP", br->name);
+ enable_stp = false;
+ }
+
+ bridge_configure_stp(br, enable_stp);
+ bridge_configure_rstp(br, enable_rstp);
+}
+
static bool
bridge_has_bond_fake_iface(const struct bridge *br, const char *name)
{
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;
}
}
+static void
+stats_update_wait(void)
+{
+ /* If the 'stats_txn' is non-null (transaction incomplete), waits for the
+ * transaction to complete. Otherwise, waits for the 'stats_timer'. */
+ if (stats_txn) {
+ ovsdb_idl_txn_wait(stats_txn);
+ } else {
+ poll_timer_wait_until(stats_timer);
+ }
+}
+
/* Update bridge/port/interface status if necessary. */
static void
run_status_update(void)
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
* disable system stats collection. */
system_stats_enable(false);
return;
- } else if (!ovsdb_idl_has_lock(idl)) {
+ } else if (!ovsdb_idl_has_lock(idl)
+ || !ovsdb_idl_has_ever_connected(idl)) {
+ /* Returns if not holding the lock or not done retrieving db
+ * contents. */
return;
}
cfg = ovsrec_open_vswitch_first(idl);
if (cfg) {
ovsrec_open_vswitch_set_cur_cfg(cfg, cfg->next_cfg);
+ discover_types(cfg);
}
/* If we are completing our initial configuration for this run
HMAP_FOR_EACH (br, node, &all_bridges) {
ofproto_wait(br->ofproto);
}
-
- poll_timer_wait_until(stats_timer);
+ stats_update_wait();
+ status_update_wait();
}
- status_update_wait();
system_stats_wait();
}
bridge_aa_refresh_queued(struct bridge *br)
{
struct ovs_list *list = xmalloc(sizeof *list);
- struct bridge_aa_vlan *node;
+ struct bridge_aa_vlan *node, *next;
list_init(list);
ofproto_aa_vlan_get_queued(br->ofproto, list);
- LIST_FOR_EACH(node, list_node, list) {
+ LIST_FOR_EACH_SAFE (node, next, list_node, list) {
struct port *port;
VLOG_INFO("ifname=%s, vlan=%u, oper=%u", node->port_name, node->vlan,
ofpbuf_init(&queues_buf, 0);
- if (!qos || qos->type[0] == '\0' || qos->n_queues < 1) {
+ if (!qos || qos->type[0] == '\0') {
netdev_set_qos(iface->netdev, NULL, NULL);
} else {
const struct ovsdb_datum *queues;
}
netdev_set_policing(iface->netdev,
- iface->cfg->ingress_policing_rate,
- iface->cfg->ingress_policing_burst);
+ MIN(UINT32_MAX, iface->cfg->ingress_policing_rate),
+ MIN(UINT32_MAX, iface->cfg->ingress_policing_burst));
ofpbuf_uninit(&queues_buf);
}
ovsrec_mirror_set_statistics(m->cfg, keys, values, stat_cnt);
}
+
+/*
+ * Add registered netdev and dpif types to ovsdb to allow external
+ * applications to query the capabilities of the Open vSwitch instance
+ * running on the node.
+ */
+static void
+discover_types(const struct ovsrec_open_vswitch *cfg)
+{
+ struct sset types;
+
+ /* Datapath types. */
+ sset_init(&types);
+ dp_enumerate_types(&types);
+ const char **datapath_types = sset_array(&types);
+ ovsrec_open_vswitch_set_datapath_types(cfg, datapath_types,
+ sset_count(&types));
+ free(datapath_types);
+ sset_destroy(&types);
+
+ /* Port types. */
+ sset_init(&types);
+ netdev_enumerate_types(&types);
+ const char **iface_types = sset_array(&types);
+ ovsrec_open_vswitch_set_iface_types(cfg, iface_types, sset_count(&types));
+ free(iface_types);
+ sset_destroy(&types);
+}