VLOG_DEFINE_THIS_MODULE(ofproto);
-COVERAGE_DEFINE(ofproto_error);
COVERAGE_DEFINE(ofproto_flush);
-COVERAGE_DEFINE(ofproto_no_packet_in);
COVERAGE_DEFINE(ofproto_packet_out);
COVERAGE_DEFINE(ofproto_queue_req);
COVERAGE_DEFINE(ofproto_recv_openflow);
COVERAGE_DEFINE(ofproto_reinit_ports);
-COVERAGE_DEFINE(ofproto_uninstallable);
COVERAGE_DEFINE(ofproto_update_port);
enum ofproto_state {
static int init_ports(struct ofproto *);
static void reinit_ports(struct ofproto *);
+static long long int ofport_get_usage(const struct ofproto *,
+ ofp_port_t ofp_port);
+static void ofport_set_usage(struct ofproto *, ofp_port_t ofp_port,
+ long long int last_used);
+
+/* Ofport usage.
+ *
+ * Keeps track of the currently used and recently used ofport values and is
+ * used to prevent immediate recycling of ofport values. */
+struct ofport_usage {
+ struct hmap_node hmap_node; /* In struct ofproto's "ofport_usage" hmap. */
+ ofp_port_t ofp_port; /* OpenFlow port number. */
+ long long int last_used; /* Last time the 'ofp_port' was used. LLONG_MAX
+ represents in-use ofports. */
+};
+
/* rule. */
static void ofproto_rule_destroy__(struct rule *);
static void ofproto_rule_send_removed(struct rule *, uint8_t reason);
ofproto->dp_desc = NULL;
ofproto->frag_handling = OFPC_FRAG_NORMAL;
hmap_init(&ofproto->ports);
+ hmap_init(&ofproto->ofport_usage);
shash_init(&ofproto->port_by_name);
simap_init(&ofproto->ofp_requests);
ofproto->max_ports = ofp_to_u16(OFPP_MAX);
return error;
}
- /* The "max_ports" member should have been set by ->construct(ofproto).
- * Port 0 is not a valid OpenFlow port, so mark that as unavailable. */
- ofproto->ofp_port_ids = bitmap_allocate(ofproto->max_ports);
- bitmap_set1(ofproto->ofp_port_ids, 0);
-
/* Check that hidden tables, if any, are at the end. */
ovs_assert(ofproto->n_tables);
for (i = 0; i + 1 < ofproto->n_tables; i++) {
free(ofproto->serial_desc);
free(ofproto->dp_desc);
hmap_destroy(&ofproto->ports);
+ hmap_destroy(&ofproto->ofport_usage);
shash_destroy(&ofproto->port_by_name);
- bitmap_free(ofproto->ofp_port_ids);
simap_destroy(&ofproto->ofp_requests);
OFPROTO_FOR_EACH_TABLE (table, ofproto) {
OVS_EXCLUDED(ofproto_mutex)
{
struct ofport *ofport, *next_ofport;
+ struct ofport_usage *usage, *next_usage;
if (!p) {
return;
ofport_destroy(ofport);
}
+ HMAP_FOR_EACH_SAFE (usage, next_usage, hmap_node, &p->ofport_usage) {
+ hmap_remove(&p->ofport_usage, &usage->hmap_node);
+ free(usage);
+ }
+
p->ofproto_class->destruct(p);
ofproto_destroy__(p);
}
port_idx = port_idx ? port_idx : UINT16_MAX;
if (port_idx >= ofproto->max_ports
- || bitmap_is_set(ofproto->ofp_port_ids, port_idx)) {
- uint16_t end_port_no = ofproto->alloc_port_no;
+ || ofport_get_usage(ofproto, u16_to_ofp(port_idx)) == LLONG_MAX) {
+ uint16_t lru_ofport = 0, end_port_no = ofproto->alloc_port_no;
+ long long int last_used_at, lru = LLONG_MAX;
/* Search for a free OpenFlow port number. We try not to
* immediately reuse them to prevent problems due to old
* flows. */
for (;;) {
if (++ofproto->alloc_port_no >= ofproto->max_ports) {
- ofproto->alloc_port_no = 0;
+ ofproto->alloc_port_no = 1;
}
- if (!bitmap_is_set(ofproto->ofp_port_ids,
- ofproto->alloc_port_no)) {
+ last_used_at = ofport_get_usage(ofproto,
+ u16_to_ofp(ofproto->alloc_port_no));
+ if (!last_used_at) {
port_idx = ofproto->alloc_port_no;
break;
+ } else if (last_used_at < lru) {
+ lru = last_used_at;
+ lru_ofport = ofproto->alloc_port_no;
}
+
if (ofproto->alloc_port_no == end_port_no) {
+ if (lru_ofport) {
+ port_idx = lru_ofport;
+ break;
+ }
return OFPP_NONE;
}
}
}
- bitmap_set1(ofproto->ofp_port_ids, port_idx);
+ ofport_set_usage(ofproto, u16_to_ofp(port_idx), LLONG_MAX);
return u16_to_ofp(port_idx);
}
static void
-dealloc_ofp_port(const struct ofproto *ofproto, ofp_port_t ofp_port)
+dealloc_ofp_port(struct ofproto *ofproto, ofp_port_t ofp_port)
{
if (ofp_to_u16(ofp_port) < ofproto->max_ports) {
- bitmap_set0(ofproto->ofp_port_ids, ofp_to_u16(ofp_port));
+ ofport_set_usage(ofproto, ofp_port, time_msec());
}
}
return NULL;
}
+static long long int
+ofport_get_usage(const struct ofproto *ofproto, ofp_port_t ofp_port)
+{
+ struct ofport_usage *usage;
+
+ HMAP_FOR_EACH_IN_BUCKET (usage, hmap_node, hash_ofp_port(ofp_port),
+ &ofproto->ofport_usage) {
+ if (usage->ofp_port == ofp_port) {
+ return usage->last_used;
+ }
+ }
+ return 0;
+}
+
+static void
+ofport_set_usage(struct ofproto *ofproto, ofp_port_t ofp_port,
+ long long int last_used)
+{
+ struct ofport_usage *usage;
+ HMAP_FOR_EACH_IN_BUCKET (usage, hmap_node, hash_ofp_port(ofp_port),
+ &ofproto->ofport_usage) {
+ if (usage->ofp_port == ofp_port) {
+ usage->last_used = last_used;
+ return;
+ }
+ }
+ ovs_assert(last_used == LLONG_MAX);
+
+ usage = xmalloc(sizeof *usage);
+ usage->ofp_port = ofp_port;
+ usage->last_used = last_used;
+ hmap_insert(&ofproto->ofport_usage, &usage->hmap_node,
+ hash_ofp_port(ofp_port));
+}
+
int
ofproto_port_get_stats(const struct ofport *port, struct netdev_stats *stats)
{
rule->ofproto->ofproto_class->rule_dealloc(rule);
}
+static uint32_t get_provider_meter_id(const struct ofproto *,
+ uint32_t of_meter_id);
+
/* Creates and returns a new 'struct rule_actions', with a ref_count of 1,
* whose actions are a copy of from the 'ofpacts_len' bytes of 'ofpacts'. */
struct rule_actions *
-rule_actions_create(const struct ofpact *ofpacts, size_t ofpacts_len)
+rule_actions_create(const struct ofproto *ofproto,
+ const struct ofpact *ofpacts, size_t ofpacts_len)
{
struct rule_actions *actions;
atomic_init(&actions->ref_count, 1);
actions->ofpacts = xmemdup(ofpacts, ofpacts_len);
actions->ofpacts_len = ofpacts_len;
- actions->meter_id = ofpacts_get_meter(ofpacts, ofpacts_len);
+ actions->provider_meter_id
+ = get_provider_meter_id(ofproto,
+ ofpacts_get_meter(ofpacts, ofpacts_len));
+
return actions;
}
atomic_sub(&actions->ref_count, 1, &orig);
if (orig == 1) {
+ free(actions->ofpacts);
free(actions);
} else {
ovs_assert(orig != 0);
}
mid = ofpacts_get_meter(ofpacts, ofpacts_len);
- if (mid && ofproto_get_provider_meter_id(ofproto, mid) == UINT32_MAX) {
+ if (mid && get_provider_meter_id(ofproto, mid) == UINT32_MAX) {
return OFPERR_OFPMMFC_INVALID_METER;
}
return 0;
ots[i].apply_actions = htonl(OFPAT11_OUTPUT);
ots[i].write_setfields = htonll(OFPXMT13_MASK);
ots[i].apply_setfields = htonll(OFPXMT13_MASK);
- ots[i].metadata_match = htonll(UINT64_MAX);
- ots[i].metadata_write = htonll(UINT64_MAX);
+ ots[i].metadata_match = OVS_BE64_MAX;
+ ots[i].metadata_write = OVS_BE64_MAX;
ots[i].instructions = htonl(OFPIT11_ALL);
ots[i].config = htonl(OFPTC11_TABLE_MISS_MASK);
ots[i].max_entries = htonl(1000000); /* An arbitrary big number. */
struct rule_collection *rules)
OVS_REQUIRES(ofproto_mutex)
{
- if (ofproto_rule_is_hidden(rule)) {
+ /* We ordinarily want to skip hidden rules, but there has to be a way for
+ * code internal to OVS to modify and delete them, so if the criteria
+ * specify a priority that can only be for a hidden flow, then allow hidden
+ * rules to be selected. (This doesn't allow OpenFlow clients to meddle
+ * with hidden flows because OpenFlow uses only a 16-bit field to specify
+ * priority.) */
+ if (ofproto_rule_is_hidden(rule) && c->cr.priority <= UINT16_MAX) {
return 0;
} else if (rule->pending) {
return OFPROTO_POSTPONE;
goto exit;
}
- if (criteria->cookie_mask == htonll(UINT64_MAX)) {
+ if (criteria->cookie_mask == OVS_BE64_MAX) {
struct rule *rule;
HINDEX_FOR_EACH_WITH_HASH (rule, cookie_node,
goto exit;
}
- if (criteria->cookie_mask == htonll(UINT64_MAX)) {
+ if (criteria->cookie_mask == OVS_BE64_MAX) {
struct rule *rule;
HINDEX_FOR_EACH_WITH_HASH (rule, cookie_node,
ds_put_format(results, "table_id=%"PRIu8", ", rule->table_id);
}
ds_put_format(results, "duration=%llds, ", (time_msec() - created) / 1000);
- ds_put_format(results, "priority=%u, ", rule->cr.priority);
ds_put_format(results, "n_packets=%"PRIu64", ", packet_count);
ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count);
cls_rule_format(&rule->cr, results);
*CONST_CAST(uint8_t *, &rule->table_id) = table - ofproto->tables;
rule->flags = fm->flags & OFPUTIL_FF_STATE;
- rule->actions = rule_actions_create(fm->ofpacts, fm->ofpacts_len);
+ rule->actions = rule_actions_create(ofproto, fm->ofpacts, fm->ofpacts_len);
list_init(&rule->meter_list_node);
rule->eviction_group = NULL;
list_init(&rule->expirable);
op = ofoperation_create(group, rule, type, 0);
- if (fm->modify_cookie && fm->new_cookie != htonll(UINT64_MAX)) {
+ if (fm->modify_cookie && fm->new_cookie != OVS_BE64_MAX) {
ofproto_rule_change_cookie(ofproto, rule, fm->new_cookie);
}
if (type == OFOPERATION_REPLACE) {
struct rule_actions *new_actions;
op->actions = rule->actions;
- new_actions = rule_actions_create(fm->ofpacts, fm->ofpacts_len);
+ new_actions = rule_actions_create(ofproto,
+ fm->ofpacts, fm->ofpacts_len);
ovs_mutex_lock(&rule->mutex);
rule->actions = new_actions;
struct ofputil_flow_mod *fm, const struct ofp_header *request)
OVS_REQUIRES(ofproto_mutex)
{
- if (fm->cookie_mask != htonll(0) || fm->new_cookie == htonll(UINT64_MAX)) {
+ if (fm->cookie_mask != htonll(0) || fm->new_cookie == OVS_BE64_MAX) {
return 0;
}
return add_flow(ofproto, ofconn, fm, request);
return 0;
error:
- ovs_mutex_unlock(&ofproto_mutex);
-
for (i = 0; i < n_monitors; i++) {
ofmonitor_destroy(monitors[i]);
}
free(monitors);
+ ovs_mutex_unlock(&ofproto_mutex);
+
return error;
}
/*
* This is used in instruction validation at flow set-up time,
* as flows may not use non-existing meters.
- * This is also used by ofproto-providers to translate OpenFlow meter_ids
- * in METER instructions to the corresponding provider meter IDs.
* Return value of UINT32_MAX signifies an invalid meter.
*/
-uint32_t
-ofproto_get_provider_meter_id(const struct ofproto * ofproto,
- uint32_t of_meter_id)
+static uint32_t
+get_provider_meter_id(const struct ofproto *ofproto, uint32_t of_meter_id)
{
if (of_meter_id && of_meter_id <= ofproto->meter_features.max_meters) {
const struct meter *meter = ofproto->meters[of_meter_id];
{
struct meter *meter = ofproto->meters[mm->meter.meter_id];
enum ofperr error;
+ uint32_t provider_meter_id;
if (!meter) {
return OFPERR_OFPMMFC_UNKNOWN_METER;
}
+ provider_meter_id = meter->provider_meter_id.uint32;
error = ofproto->ofproto_class->meter_set(ofproto,
&meter->provider_meter_id,
&mm->meter);
- ovs_assert(meter->provider_meter_id.uint32 != UINT32_MAX);
+ ovs_assert(meter->provider_meter_id.uint32 == provider_meter_id);
if (!error) {
meter_update(meter, &mm->meter);
}
cookies_insert(ofproto, rule);
- if (rule->actions->meter_id) {
- struct meter *meter = ofproto->meters[rule->actions->meter_id];
+ if (rule->actions->provider_meter_id != UINT32_MAX) {
+ uint32_t meter_id = ofpacts_get_meter(rule->actions->ofpacts,
+ rule->actions->ofpacts_len);
+ struct meter *meter = ofproto->meters[meter_id];
list_insert(&meter->rules, &rule->meter_list_node);
}
ovs_rwlock_wrlock(&table->cls.rwlock);