#include "bfd.h"
#include "bitmap.h"
#include "cfm.h"
+#include "connectivity.h"
#include "coverage.h"
#include "daemon.h"
#include "dirs.h"
#include "ofproto/bond.h"
#include "ofproto/ofproto.h"
#include "poll-loop.h"
+#include "seq.h"
#include "sha1.h"
#include "shash.h"
#include "smap.h"
/* Most recently processed IDL sequence number. */
static unsigned int idl_seqno;
+/* Track changes to port connectivity. */
+static uint64_t connectivity_seqno = LLONG_MIN;
+
/* Each time this timer expires, the bridge fetches interface and mirror
* statistics and pushes them into the database. */
#define IFACE_STATS_INTERVAL (5 * 1000) /* In milliseconds. */
#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_destroy(struct bridge *);
static struct bridge *bridge_lookup(const char *name);
static void iface_refresh_stats(struct iface *);
static void iface_refresh_status(struct iface *);
static bool iface_is_synthetic(const struct iface *);
+static ofp_port_t iface_get_requested_ofp_port(
+ 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.)
COVERAGE_INC(bridge_reconfigure);
- ofproto_set_flow_eviction_threshold(
- smap_get_int(&ovs_cfg->other_config, "flow-eviction-threshold",
- OFPROTO_FLOW_EVICTION_THRESHOLD_DEFAULT));
+ ofproto_set_flow_limit(smap_get_int(&ovs_cfg->other_config, "flow-limit",
+ OFPROTO_FLOW_LIMIT_DEFAULT));
- ofproto_set_n_handler_threads(
- smap_get_int(&ovs_cfg->other_config, "n-handler-threads", 0));
+ ofproto_set_threads(
+ smap_get_int(&ovs_cfg->other_config, "n-handler-threads", 0),
+ smap_get_int(&ovs_cfg->other_config, "n-revalidator-threads", 0));
bridge_configure_flow_miss_model(smap_get(&ovs_cfg->other_config,
"force-miss-model"));
}
}
free(managers);
+
+ /* The ofproto-dpif provider does some final reconfiguration in its
+ * ->type_run() function. We have to call it before notifying the database
+ * client that reconfiguration is complete, otherwise there is a very
+ * narrow race window in which e.g. ofproto/trace will not recognize the
+ * new configuration (sometimes this causes unit test failures). */
+ bridge_run__();
}
/* Delete ofprotos which aren't configured or have the wrong type. Create
n = allocated = 0;
OFPROTO_PORT_FOR_EACH (&ofproto_port, &dump, br->ofproto) {
+ ofp_port_t requested_ofp_port;
struct iface *iface;
iface = iface_lookup(br, ofproto_port.name);
goto delete;
}
+ /* If the requested OpenFlow port for 'iface' changed, and it's not
+ * already the correct port, then we might want to temporarily delete
+ * this interface, so we can add it back again with the new OpenFlow
+ * port number. */
+ requested_ofp_port = iface_get_requested_ofp_port(iface->cfg);
+ if (iface->ofp_port != OFPP_LOCAL &&
+ requested_ofp_port != OFPP_NONE &&
+ requested_ofp_port != iface->ofp_port) {
+ ofp_port_t victim_request;
+ struct iface *victim;
+
+ /* Check for an existing OpenFlow port currently occupying
+ * 'iface''s requested port number. If there isn't one, then
+ * delete this port. Otherwise we need to consider further. */
+ victim = iface_from_ofp_port(br, requested_ofp_port);
+ if (!victim) {
+ goto delete;
+ }
+
+ /* 'victim' is a port currently using 'iface''s requested port
+ * number. Unless 'victim' specifically requested that port
+ * number, too, then we can delete both 'iface' and 'victim'
+ * temporarily. (We'll add both of them back again later with new
+ * OpenFlow port numbers.)
+ *
+ * If 'victim' did request port number 'requested_ofp_port', just
+ * like 'iface', then that's a configuration inconsistency that we
+ * can't resolve. We might as well let it keep its current port
+ * number. */
+ victim_request = iface_get_requested_ofp_port(victim->cfg);
+ if (victim_request != requested_ofp_port) {
+ del = add_ofp_port(victim->ofp_port, del, &n, &allocated);
+ iface_destroy(victim);
+ goto delete;
+ }
+ }
+
/* Keep it. */
continue;
}
static void
-bridge_add_ports(struct bridge *br, const struct shash *wanted_ports)
+bridge_add_ports__(struct bridge *br, const struct shash *wanted_ports,
+ bool with_requested_port)
{
struct shash_node *port_node;
for (i = 0; i < port_cfg->n_interfaces; i++) {
const struct ovsrec_interface *iface_cfg = port_cfg->interfaces[i];
- struct iface *iface = iface_lookup(br, iface_cfg->name);
+ ofp_port_t requested_ofp_port;
+
+ requested_ofp_port = iface_get_requested_ofp_port(iface_cfg);
+ if ((requested_ofp_port != OFPP_NONE) == with_requested_port) {
+ struct iface *iface = iface_lookup(br, iface_cfg->name);
- if (!iface) {
- iface_create(br, iface_cfg, port_cfg);
+ if (!iface) {
+ iface_create(br, iface_cfg, port_cfg);
+ }
}
}
}
}
+static void
+bridge_add_ports(struct bridge *br, const struct shash *wanted_ports)
+{
+ /* First add interfaces that request a particular port number. */
+ bridge_add_ports__(br, wanted_ports, true);
+
+ /* Then add interfaces that want automatic port number assignment.
+ * We add these afterward to avoid accidentally taking a specifically
+ * requested port number. */
+ bridge_add_ports__(br, wanted_ports, false);
+}
+
static void
port_configure(struct port *port)
{
enum ofproto_flow_miss_model model = OFPROTO_HANDLE_MISS_AUTO;
if (opt) {
- if (strcmp(opt, "with-facets")) {
+ if (!strcmp(opt, "with-facets")) {
model = OFPROTO_HANDLE_MISS_WITH_FACETS;
- } else if (strcmp(opt, "without-facets")) {
+ } else if (!strcmp(opt, "without-facets")) {
model = OFPROTO_HANDLE_MISS_WITHOUT_FACETS;
}
}
return netdev_set_config(netdev, &iface_cfg->options);
}
-/* Opens a network device for 'if_cfg' and configures it. If '*ofp_portp'
- * is OFPP_NONE, adds the network device to br->ofproto and stores the OpenFlow
- * port number in '*ofp_portp'; otherwise leaves br->ofproto and '*ofp_portp'
- * untouched.
+/* Opens a network device for 'if_cfg' and configures it. Adds the network
+ * device to br->ofproto and stores the OpenFlow port number in '*ofp_portp'.
*
* If successful, returns 0 and stores the network device in '*netdevp'. On
* failure, returns a positive errno value and stores NULL in '*netdevp'. */
struct port *port;
int error;
- /* Do the bits that can fail up front.
- *
- * It's a bit dangerous to call bridge_run_fast() here as ofproto's
- * internal datastructures may not be consistent. Eventually, when port
- * additions and deletions are cheaper, these calls should be removed. */
- bridge_run_fast();
+ /* 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);
- bridge_run_fast();
if (error) {
iface_set_ofport(iface_cfg, OFPP_NONE);
iface_clear_db_record(iface_cfg);
error = netdev_open(port->name, "internal", &netdev);
if (!error) {
- ofp_port_t fake_ofp_port = iface_pick_ofport(iface_cfg);
+ ofp_port_t fake_ofp_port = OFPP_NONE;
ofproto_port_add(br->ofproto, netdev, &fake_ofp_port);
netdev_close(netdev);
} else {
}
}
-static inline const char *
+static const char *
ofp12_controller_role_to_str(enum ofp12_controller_role role)
{
switch (role) {
if (!instant_txn) {
struct bridge *br;
+ uint64_t seq;
if (time_msec() < instant_next_txn) {
return;
}
instant_next_txn = time_msec() + INSTANT_INTERVAL_MSEC;
+ seq = seq_read(connectivity_seq_get());
+ if (seq == connectivity_seqno) {
+ return;
+ }
+ connectivity_seqno = seq;
+
instant_txn = ovsdb_idl_txn_create(idl);
HMAP_FOR_EACH (br, node, &all_bridges) {
struct iface *iface;
}
}
\f
-/* Performs periodic activity required by bridges that needs to be done with
- * the least possible latency.
- *
- * It makes sense to call this function a couple of times per poll loop, to
- * provide a significant performance boost on some benchmarks with ofprotos
- * that use the ofproto-dpif implementation. */
-void
-bridge_run_fast(void)
+static void
+bridge_run__(void)
{
+ struct bridge *br;
struct sset types;
const char *type;
- struct bridge *br;
+ /* Let each datapath type do the work that it needs to do. */
sset_init(&types);
ofproto_enumerate_types(&types);
SSET_FOR_EACH (type, &types) {
- ofproto_type_run_fast(type);
+ ofproto_type_run(type);
}
sset_destroy(&types);
+ /* Let each bridge do the work that it needs to do. */
HMAP_FOR_EACH (br, node, &all_bridges) {
- ofproto_run_fast(br->ofproto);
+ ofproto_run(br->ofproto);
}
}
{
static struct ovsrec_open_vswitch null_cfg;
const struct ovsrec_open_vswitch *cfg;
- struct sset types;
- const char *type;
bool vlan_splinters_changed;
struct bridge *br;
"flow-restore-wait", false));
}
- /* Let each datapath type do the work that it needs to do. */
- sset_init(&types);
- ofproto_enumerate_types(&types);
- SSET_FOR_EACH (type, &types) {
- ofproto_type_run(type);
- }
- sset_destroy(&types);
-
- /* Let each bridge do the work that it needs to do. */
- HMAP_FOR_EACH (br, node, &all_bridges) {
- ofproto_run(br->ofproto);
- }
+ bridge_run__();
/* Re-configure SSL. We do this on every trip through the main loop,
* instead of just when the database changes, because the contents of the
bridge_get_memory_usage(struct simap *usage)
{
struct bridge *br;
+ struct sset types;
+ const char *type;
+
+ sset_init(&types);
+ ofproto_enumerate_types(&types);
+ SSET_FOR_EACH (type, &types) {
+ ofproto_type_get_memory_usage(type, usage);
+ }
+ sset_destroy(&types);
HMAP_FOR_EACH (br, node, &all_bridges) {
ofproto_get_memory_usage(br->ofproto, usage);
}
static ofp_port_t
-iface_pick_ofport(const struct ovsrec_interface *cfg)
+iface_validate_ofport__(size_t n, int64_t *ofport)
{
- ofp_port_t ofport = cfg->n_ofport ? u16_to_ofp(*cfg->ofport)
- : OFPP_NONE;
- return cfg->n_ofport_request ? u16_to_ofp(*cfg->ofport_request)
- : ofport;
+ return (n && *ofport >= 1 && *ofport < ofp_to_u16(OFPP_MAX)
+ ? u16_to_ofp(*ofport)
+ : OFPP_NONE);
}
+static ofp_port_t
+iface_get_requested_ofp_port(const struct ovsrec_interface *cfg)
+{
+ return iface_validate_ofport__(cfg->n_ofport_request, cfg->ofport_request);
+}
+
+static ofp_port_t
+iface_pick_ofport(const struct ovsrec_interface *cfg)
+{
+ ofp_port_t requested_ofport = iface_get_requested_ofp_port(cfg);
+ return (requested_ofport != OFPP_NONE
+ ? requested_ofport
+ : iface_validate_ofport__(cfg->n_ofport, cfg->ofport));
+}
\f
/* Port mirroring. */