COVERAGE_DEFINE(facet_unexpected);
COVERAGE_DEFINE(facet_suppress);
COVERAGE_DEFINE(subfacet_install_fail);
+COVERAGE_DEFINE(packet_in_overflow);
COVERAGE_DEFINE(flow_mod_overflow);
/* Number of implemented OpenFlow tables. */
int vid;
};
-static bool vsp_adjust_flow(const struct ofproto_dpif *, struct flow *);
static void vsp_remove(struct ofport_dpif *);
static void vsp_add(struct ofport_dpif *, ofp_port_t realdev_ofp_port, int vid);
int refcount;
struct dpif *dpif;
struct timer next_expiration;
- struct hmap odp_to_ofport_map; /* ODP port to ofport mapping. */
+
+ struct ovs_rwlock odp_to_ofport_lock;
+ struct hmap odp_to_ofport_map OVS_GUARDED; /* ODP port to ofport map. */
struct simap tnl_backers; /* Set of dpif ports backing tunnels. */
static struct shash all_dpif_backers = SHASH_INITIALIZER(&all_dpif_backers);
static void drop_key_clear(struct dpif_backer *);
-static struct ofport_dpif *
-odp_port_to_ofport(const struct dpif_backer *, odp_port_t odp_port);
static void update_moving_averages(struct dpif_backer *backer);
struct ofproto_dpif {
long long int stp_last_tick;
/* VLAN splinters. */
- struct hmap realdev_vid_map; /* (realdev,vid) -> vlandev. */
- struct hmap vlandev_map; /* vlandev -> (realdev,vid). */
+ struct ovs_mutex vsp_mutex;
+ struct hmap realdev_vid_map OVS_GUARDED; /* (realdev,vid) -> vlandev. */
+ struct hmap vlandev_map OVS_GUARDED; /* vlandev -> (realdev,vid). */
/* Ports. */
struct sset ports; /* Set of standard port names. */
struct ovs_mutex flow_mod_mutex;
struct list flow_mods OVS_GUARDED;
size_t n_flow_mods OVS_GUARDED;
+
+ struct ovs_mutex pin_mutex;
+ struct list pins OVS_GUARDED;
+ size_t n_pins OVS_GUARDED;
};
/* Defer flow mod completion until "ovs-appctl ofproto/unclog"? (Useful only
static struct ofport_dpif *get_ofp_port(const struct ofproto_dpif *ofproto,
ofp_port_t ofp_port);
+static void ofproto_trace(struct ofproto_dpif *, const struct flow *,
+ const struct ofpbuf *packet, struct ds *);
/* Upcalls. */
#define FLOW_MISS_MAX_BATCH 50
ofproto_dpif_send_packet_in(struct ofproto_dpif *ofproto,
struct ofputil_packet_in *pin)
{
- connmgr_send_packet_in(ofproto->up.connmgr, pin);
+ ovs_mutex_lock(&ofproto->pin_mutex);
+ if (ofproto->n_pins > 1024) {
+ ovs_mutex_unlock(&ofproto->pin_mutex);
+ COVERAGE_INC(packet_in_overflow);
+ free(CONST_CAST(void *, pin->packet));
+ free(pin);
+ return;
+ }
+
+ list_push_back(&ofproto->pins, &pin->list_node);
+ ofproto->n_pins++;
+ ovs_mutex_unlock(&ofproto->pin_mutex);
}
\f
/* Factory functions. */
continue;
}
- xlate_ofproto_set(ofproto, ofproto->up.name, ofproto->ml,
+ ovs_rwlock_wrlock(&xlate_rwlock);
+ xlate_ofproto_set(ofproto, ofproto->up.name,
+ ofproto->backer->dpif, ofproto->miss_rule,
+ ofproto->no_packet_in_rule, ofproto->ml,
ofproto->stp, ofproto->mbridge,
ofproto->sflow, ofproto->ipfix,
ofproto->up.frag_handling,
ofport->up.pp.config, ofport->is_tunnel,
ofport->may_enable);
}
+ ovs_rwlock_unlock(&xlate_rwlock);
+ /* Only ofproto-dpif cares about the facet classifier so we just
+ * lock cls_cursor_init() to appease the thread safety analysis. */
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
cls_cursor_init(&cursor, &ofproto->facets, NULL);
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
CLS_CURSOR_FOR_EACH_SAFE (facet, next, cr, &cursor) {
facet_revalidate(facet);
run_fast_rl();
/* 'ofport''s datapath port number has changed from
* 'ofport->odp_port' to 'port.port_no'. Update our internal data
* structures to match. */
+ ovs_rwlock_wrlock(&backer->odp_to_ofport_lock);
hmap_remove(&backer->odp_to_ofport_map, &ofport->odp_port_node);
ofport->odp_port = port.port_no;
hmap_insert(&backer->odp_to_ofport_map, &ofport->odp_port_node,
hash_odp_port(port.port_no));
+ ovs_rwlock_unlock(&backer->odp_to_ofport_lock);
backer->need_revalidate = REV_RECONFIGURE;
}
}
hmap_destroy(&backer->drop_keys);
simap_destroy(&backer->tnl_backers);
+ ovs_rwlock_destroy(&backer->odp_to_ofport_lock);
hmap_destroy(&backer->odp_to_ofport_map);
node = shash_find(&all_dpif_backers, backer->type);
free(backer->type);
backer->governor = NULL;
backer->refcount = 1;
hmap_init(&backer->odp_to_ofport_map);
+ ovs_rwlock_init(&backer->odp_to_ofport_lock);
hmap_init(&backer->drop_keys);
hmap_init(&backer->subfacets);
timer_set_duration(&backer->next_expiration, 1000);
ofproto->ml = mac_learning_create(MAC_ENTRY_DEFAULT_IDLE_TIME);
ofproto->mbridge = mbridge_create();
ofproto->has_bonded_bundles = false;
+ ovs_mutex_init(&ofproto->vsp_mutex, PTHREAD_MUTEX_NORMAL);
classifier_init(&ofproto->facets);
ofproto->consistency_rl = LLONG_MIN;
ofproto->n_flow_mods = 0;
ovs_mutex_unlock(&ofproto->flow_mod_mutex);
+ ovs_mutex_init(&ofproto->pin_mutex, PTHREAD_MUTEX_NORMAL);
+ ovs_mutex_lock(&ofproto->pin_mutex);
+ list_init(&ofproto->pins);
+ ofproto->n_pins = 0;
+ ovs_mutex_unlock(&ofproto->pin_mutex);
+
ofproto_dpif_unixctl_init();
hmap_init(&ofproto->vlandev_map);
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
struct rule_dpif *rule, *next_rule;
+ struct ofputil_flow_mod *pin, *next_pin;
struct ofputil_flow_mod *fm, *next_fm;
struct oftable *table;
ofproto->backer->need_revalidate = REV_RECONFIGURE;
+ ovs_rwlock_wrlock(&xlate_rwlock);
xlate_remove_ofproto(ofproto);
+ ovs_rwlock_unlock(&xlate_rwlock);
hmap_remove(&all_ofproto_dpifs, &ofproto->all_ofproto_dpifs_node);
complete_operations(ofproto);
OFPROTO_FOR_EACH_TABLE (table, &ofproto->up) {
struct cls_cursor cursor;
+ ovs_rwlock_wrlock(&table->cls.rwlock);
cls_cursor_init(&cursor, &table->cls, NULL);
CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, up.cr, &cursor) {
- ofproto_rule_destroy(&rule->up);
+ ofproto_rule_destroy(&ofproto->up, &table->cls, &rule->up);
}
+ ovs_rwlock_unlock(&table->cls.rwlock);
}
ovs_mutex_lock(&ofproto->flow_mod_mutex);
ovs_mutex_unlock(&ofproto->flow_mod_mutex);
ovs_mutex_destroy(&ofproto->flow_mod_mutex);
+ ovs_mutex_lock(&ofproto->pin_mutex);
+ LIST_FOR_EACH_SAFE (pin, next_pin, list_node, &ofproto->pins) {
+ list_remove(&pin->list_node);
+ ofproto->n_pins--;
+ free(pin->ofpacts);
+ free(pin);
+ }
+ ovs_mutex_unlock(&ofproto->pin_mutex);
+ ovs_mutex_destroy(&ofproto->pin_mutex);
+
mbridge_unref(ofproto->mbridge);
netflow_destroy(ofproto->netflow);
sset_destroy(&ofproto->ghost_ports);
sset_destroy(&ofproto->port_poll_set);
+ ovs_mutex_destroy(&ofproto->vsp_mutex);
+
close_dpif_backer(ofproto->backer);
}
run_fast(struct ofproto *ofproto_)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
- struct ofputil_flow_mod *fm, *next;
+ struct ofputil_packet_in *pin, *next_pin;
+ struct ofputil_flow_mod *fm, *next_fm;
+ struct list flow_mods, pins;
struct ofport_dpif *ofport;
- struct list flow_mods;
/* Do not perform any periodic activity required by 'ofproto' while
* waiting for flow restore to complete. */
}
ovs_mutex_unlock(&ofproto->flow_mod_mutex);
- LIST_FOR_EACH_SAFE (fm, next, list_node, &flow_mods) {
+ LIST_FOR_EACH_SAFE (fm, next_fm, list_node, &flow_mods) {
int error = ofproto_flow_mod(&ofproto->up, fm);
if (error && !VLOG_DROP_WARN(&rl)) {
VLOG_WARN("learning action failed to modify flow table (%s)",
free(fm);
}
+ ovs_mutex_lock(&ofproto->pin_mutex);
+ if (ofproto->n_pins) {
+ pins = ofproto->pins;
+ list_moved(&pins);
+ list_init(&ofproto->pins);
+ ofproto->n_pins = 0;
+ } else {
+ list_init(&pins);
+ }
+ ovs_mutex_unlock(&ofproto->pin_mutex);
+
+ LIST_FOR_EACH_SAFE (pin, next_pin, list_node, &pins) {
+ connmgr_send_packet_in(ofproto->up.connmgr, pin);
+ list_remove(&pin->list_node);
+ free(CONST_CAST(void *, pin->packet));
+ free(pin);
+ }
+
HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
port_run_fast(ofport);
}
ovs_rwlock_unlock(&ofproto->ml->rwlock);
/* Check the consistency of a random facet, to aid debugging. */
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
if (time_msec() >= ofproto->consistency_rl
&& !classifier_is_empty(&ofproto->facets)
&& !ofproto->backer->need_revalidate) {
ofproto->backer->need_revalidate = REV_INCONSISTENCY;
}
}
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
return 0;
}
size_t n_subfacets = 0;
struct facet *facet;
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
simap_increase(usage, "facets", classifier_count(&ofproto->facets));
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
cls_cursor_init(&cursor, &ofproto->facets, NULL);
CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
n_subfacets += list_size(&facet->subfacets);
}
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
simap_increase(usage, "subfacets", n_subfacets);
}
return EBUSY;
}
+ ovs_rwlock_wrlock(&ofproto->backer->odp_to_ofport_lock);
hmap_insert(&ofproto->backer->odp_to_ofport_map, &port->odp_port_node,
hash_odp_port(port->odp_port));
+ ovs_rwlock_unlock(&ofproto->backer->odp_to_ofport_lock);
}
dpif_port_destroy(&dpif_port);
const char *dp_port_name;
ofproto->backer->need_revalidate = REV_RECONFIGURE;
+ ovs_rwlock_wrlock(&xlate_rwlock);
xlate_ofport_remove(port);
+ ovs_rwlock_unlock(&xlate_rwlock);
dp_port_name = netdev_vport_get_dpif_port(port->up.netdev, namebuf,
sizeof namebuf);
}
if (port->odp_port != ODPP_NONE && !port->is_tunnel) {
+ ovs_rwlock_wrlock(&ofproto->backer->odp_to_ofport_lock);
hmap_remove(&ofproto->backer->odp_to_ofport_map, &port->odp_port_node);
+ ovs_rwlock_unlock(&ofproto->backer->odp_to_ofport_lock);
}
tnl_port_del(port);
}
}
\f
-int
-ofproto_dpif_queue_to_priority(const struct ofproto_dpif *ofproto,
- uint32_t queue_id, uint32_t *priority)
-{
- return dpif_queue_to_priority(ofproto->backer->dpif, queue_id, priority);
-}
-
static int
set_queues(struct ofport *ofport_, const struct ofproto_port_queue *qdscp,
size_t n_qdscp)
ofproto = bundle->ofproto;
mbridge_unregister_bundle(ofproto->mbridge, bundle->aux);
+ ovs_rwlock_wrlock(&xlate_rwlock);
xlate_bundle_remove(bundle);
+ ovs_rwlock_unlock(&xlate_rwlock);
LIST_FOR_EACH_SAFE (port, next_port, bundle_node, &bundle->ports) {
bundle_del_port(port);
}
}
-/* Given a datpath, packet, and flow metadata ('backer', 'packet', and 'key'
- * respectively), populates 'flow' with the result of odp_flow_key_to_flow().
- * Optionally, if nonnull, populates 'fitnessp' with the fitness of 'flow' as
- * returned by odp_flow_key_to_flow(). Also, optionally populates 'ofproto'
- * with the ofproto_dpif, and 'odp_in_port' with the datapath in_port, that
- * 'packet' ingressed.
- *
- * If 'ofproto' is nonnull, requires 'flow''s in_port to exist. Otherwise sets
- * 'flow''s in_port to OFPP_NONE.
- *
- * This function does post-processing on data returned from
- * odp_flow_key_to_flow() to help make VLAN splinters transparent to the rest
- * of the upcall processing logic. In particular, if the extracted in_port is
- * a VLAN splinter port, it replaces flow->in_port by the "real" port, sets
- * flow->vlan_tci correctly for the VLAN of the VLAN splinter port, and pushes
- * a VLAN header onto 'packet' (if it is nonnull).
- *
- * Similarly, this function also includes some logic to help with tunnels. It
- * may modify 'flow' as necessary to make the tunneling implementation
- * transparent to the upcall processing logic.
- *
- * Returns 0 if successful, ENODEV if the parsed flow has no associated ofport,
- * or some other positive errno if there are other problems. */
-static int
-ofproto_receive(const struct dpif_backer *backer, struct ofpbuf *packet,
- const struct nlattr *key, size_t key_len,
- struct flow *flow, enum odp_key_fitness *fitnessp,
- struct ofproto_dpif **ofproto, odp_port_t *odp_in_port)
-{
- const struct ofport_dpif *port;
- enum odp_key_fitness fitness;
- int error = ENODEV;
-
- fitness = odp_flow_key_to_flow(key, key_len, flow);
- if (fitness == ODP_FIT_ERROR) {
- error = EINVAL;
- goto exit;
- }
-
- if (odp_in_port) {
- *odp_in_port = flow->in_port.odp_port;
- }
-
- port = (tnl_port_should_receive(flow)
- ? tnl_port_receive(flow)
- : odp_port_to_ofport(backer, flow->in_port.odp_port));
- flow->in_port.ofp_port = port ? port->up.ofp_port : OFPP_NONE;
- if (!port) {
- goto exit;
- }
-
- /* XXX: Since the tunnel module is not scoped per backer, for a tunnel port
- * it's theoretically possible that we'll receive an ofport belonging to an
- * entirely different datapath. In practice, this can't happen because no
- * platforms has two separate datapaths which each support tunneling. */
- ovs_assert(ofproto_dpif_cast(port->up.ofproto)->backer == backer);
-
- if (vsp_adjust_flow(ofproto_dpif_cast(port->up.ofproto), flow)) {
- if (packet) {
- /* Make the packet resemble the flow, so that it gets sent to
- * an OpenFlow controller properly, so that it looks correct
- * for sFlow, and so that flow_extract() will get the correct
- * vlan_tci if it is called on 'packet'.
- *
- * The allocated space inside 'packet' probably also contains
- * 'key', that is, both 'packet' and 'key' are probably part of
- * a struct dpif_upcall (see the large comment on that
- * structure definition), so pushing data on 'packet' is in
- * general not a good idea since it could overwrite 'key' or
- * free it as a side effect. However, it's OK in this special
- * case because we know that 'packet' is inside a Netlink
- * attribute: pushing 4 bytes will just overwrite the 4-byte
- * "struct nlattr", which is fine since we don't need that
- * header anymore. */
- eth_push_vlan(packet, flow->vlan_tci);
- }
- /* We can't reproduce 'key' from 'flow'. */
- fitness = fitness == ODP_FIT_PERFECT ? ODP_FIT_TOO_MUCH : fitness;
- }
- error = 0;
-
- if (ofproto) {
- *ofproto = ofproto_dpif_cast(port->up.ofproto);
- }
-
-exit:
- if (fitnessp) {
- *fitnessp = fitness;
- }
- return error;
-}
-
static void
handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
size_t n_upcalls)
uint32_t hash;
int error;
- error = ofproto_receive(backer, upcall->packet, upcall->key,
- upcall->key_len, &flow, &miss->key_fitness,
- &ofproto, &odp_in_port);
+ error = xlate_receive(backer, upcall->packet, upcall->key,
+ upcall->key_len, &flow, &miss->key_fitness,
+ &ofproto, &odp_in_port);
if (error == ENODEV) {
struct drop_key *drop_key;
struct flow flow;
odp_port_t odp_in_port;
- if (ofproto_receive(backer, upcall->packet, upcall->key, upcall->key_len,
- &flow, NULL, &ofproto, &odp_in_port)
+ if (xlate_receive(backer, upcall->packet, upcall->key, upcall->key_len,
+ &flow, NULL, &ofproto, &odp_in_port)
|| !ofproto->sflow) {
return;
}
union user_action_cookie cookie;
struct flow flow;
- if (ofproto_receive(backer, upcall->packet, upcall->key, upcall->key_len,
- &flow, NULL, &ofproto, NULL)
+ if (xlate_receive(backer, upcall->packet, upcall->key, upcall->key_len,
+ &flow, NULL, &ofproto, NULL)
|| !ofproto->ipfix) {
return;
}
struct ofproto_dpif *ofproto;
struct flow flow;
- if (ofproto_receive(backer, upcall->packet, upcall->key, upcall->key_len,
- &flow, NULL, &ofproto, NULL)
+ if (xlate_receive(backer, upcall->packet, upcall->key, upcall->key_len,
+ &flow, NULL, &ofproto, NULL)
|| !ofproto->ipfix) {
return;
}
/* Expire OpenFlow flows whose idle_timeout or hard_timeout
* has passed. */
+ ovs_mutex_lock(&ofproto->up.expirable_mutex);
LIST_FOR_EACH_SAFE (rule, next_rule, expirable,
&ofproto->up.expirable) {
rule_expire(rule_dpif_cast(rule));
}
+ ovs_mutex_unlock(&ofproto->up.expirable_mutex);
/* All outstanding data in existing flows has been accounted, so it's a
* good time to do bond rebalancing. */
static void
rule_expire(struct rule_dpif *rule)
{
+ uint16_t idle_timeout, hard_timeout;
long long int now;
uint8_t reason;
return;
}
+ ovs_mutex_lock(&rule->up.timeout_mutex);
+ hard_timeout = rule->up.hard_timeout;
+ idle_timeout = rule->up.idle_timeout;
+ ovs_mutex_unlock(&rule->up.timeout_mutex);
+
/* Has 'rule' expired? */
now = time_msec();
- if (rule->up.hard_timeout
- && now > rule->up.modified + rule->up.hard_timeout * 1000) {
+ if (hard_timeout && now > rule->up.modified + hard_timeout * 1000) {
reason = OFPRR_HARD_TIMEOUT;
- } else if (rule->up.idle_timeout
- && now > rule->up.used + rule->up.idle_timeout * 1000) {
+ } else if (idle_timeout && now > rule->up.used + idle_timeout * 1000) {
reason = OFPRR_IDLE_TIMEOUT;
} else {
return;
match_init(&match, &facet->flow, &facet->xout.wc);
cls_rule_init(&facet->cr, &match, OFP_DEFAULT_PRIORITY);
+ ovs_rwlock_wrlock(&ofproto->facets.rwlock);
classifier_insert(&ofproto->facets, &facet->cr);
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
facet->nf_flow.output_iface = facet->xout.nf_output_iface;
facet->fail_open = rule->up.cr.priority == FAIL_OPEN_PRIORITY;
&facet->subfacets) {
subfacet_destroy__(subfacet);
}
+ ovs_rwlock_wrlock(&facet->ofproto->facets.rwlock);
classifier_remove(&facet->ofproto->facets, &facet->cr);
+ ovs_rwlock_unlock(&facet->ofproto->facets.rwlock);
cls_rule_destroy(&facet->cr);
facet_free(facet);
}
static struct facet *
facet_find(struct ofproto_dpif *ofproto, const struct flow *flow)
{
- struct cls_rule *cr = classifier_lookup(&ofproto->facets, flow, NULL);
+ struct cls_rule *cr;
+
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
+ cr = classifier_lookup(&ofproto->facets, flow, NULL);
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
return cr ? CONTAINER_OF(cr, struct facet, cr) : NULL;
}
* where it is and recompiles its actions anyway.
*
* - If any of 'facet''s subfacets correspond to a new flow according to
- * ofproto_receive(), 'facet' is removed.
+ * xlate_receive(), 'facet' is removed.
*
* Returns true if 'facet' is still valid. False if 'facet' was removed. */
static bool
struct flow recv_flow;
int error;
- error = ofproto_receive(ofproto->backer, NULL, subfacet->key,
- subfacet->key_len, &recv_flow, NULL,
- &recv_ofproto, NULL);
+ error = xlate_receive(ofproto->backer, NULL, subfacet->key,
+ subfacet->key_len, &recv_flow, NULL,
+ &recv_ofproto, NULL);
if (error
|| recv_ofproto != ofproto
|| facet != facet_find(ofproto, &recv_flow)) {
struct cls_cursor cursor;
struct facet *facet;
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
cls_cursor_init(&cursor, &ofproto->facets, NULL);
CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
facet_push_stats(facet, false);
run_fast_rl();
}
}
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
}
rl = time_msec() + 100;
void
rule_credit_stats(struct rule_dpif *rule, const struct dpif_flow_stats *stats)
{
+ ovs_mutex_lock(&rule->stats_mutex);
rule->packet_count += stats->n_packets;
rule->byte_count += stats->n_bytes;
ofproto_rule_update_used(&rule->up, stats->used);
+ ovs_mutex_unlock(&rule->stats_mutex);
}
\f
/* Subfacets. */
rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow,
struct flow_wildcards *wc)
{
+ struct ofport_dpif *port;
struct rule_dpif *rule;
rule = rule_dpif_lookup_in_table(ofproto, flow, wc, 0);
if (rule) {
return rule;
}
+ port = get_ofp_port(ofproto, flow->in_port.ofp_port);
+ if (!port) {
+ VLOG_WARN_RL(&rl, "packet-in on unknown OpenFlow port %"PRIu16,
+ flow->in_port.ofp_port);
+ }
- return rule_dpif_miss_rule(ofproto, flow);
+ return choose_miss_rule(port ? port->up.pp.config : 0, ofproto->miss_rule,
+ ofproto->no_packet_in_rule);
}
struct rule_dpif *
struct flow ofpc_normal_flow = *flow;
ofpc_normal_flow.tp_src = htons(0);
ofpc_normal_flow.tp_dst = htons(0);
+ ovs_rwlock_rdlock(&cls->rwlock);
cls_rule = classifier_lookup(cls, &ofpc_normal_flow, wc);
+ ovs_rwlock_unlock(&cls->rwlock);
} else if (frag && ofproto->up.frag_handling == OFPC_FRAG_DROP) {
cls_rule = &ofproto->drop_frags_rule->up.cr;
if (wc) {
flow_wildcards_init_exact(wc);
}
} else {
+ ovs_rwlock_rdlock(&cls->rwlock);
cls_rule = classifier_lookup(cls, flow, wc);
+ ovs_rwlock_unlock(&cls->rwlock);
}
return rule_dpif_cast(rule_from_cls_rule(cls_rule));
}
+/* Given a port configuration (specified as zero if there's no port), chooses
+ * which of 'miss_rule' and 'no_packet_in_rule' should be used in case of a
+ * flow table miss. */
struct rule_dpif *
-rule_dpif_miss_rule(struct ofproto_dpif *ofproto, const struct flow *flow)
+choose_miss_rule(enum ofputil_port_config config, struct rule_dpif *miss_rule,
+ struct rule_dpif *no_packet_in_rule)
{
- struct ofport_dpif *port;
-
- port = get_ofp_port(ofproto, flow->in_port.ofp_port);
- if (!port) {
- VLOG_WARN_RL(&rl, "packet-in on unknown OpenFlow port %"PRIu16,
- flow->in_port.ofp_port);
- return ofproto->miss_rule;
- }
-
- if (port->up.pp.config & OFPUTIL_PC_NO_PACKET_IN) {
- return ofproto->no_packet_in_rule;
- }
- return ofproto->miss_rule;
+ return config & OFPUTIL_PC_NO_PACKET_IN ? no_packet_in_rule : miss_rule;
}
static void
rule_construct(struct rule *rule_)
{
struct rule_dpif *rule = rule_dpif_cast(rule_);
+ ovs_mutex_init(&rule->stats_mutex, PTHREAD_MUTEX_NORMAL);
+ ovs_mutex_lock(&rule->stats_mutex);
rule->packet_count = 0;
rule->byte_count = 0;
+ ovs_mutex_unlock(&rule->stats_mutex);
complete_operation(rule);
return 0;
}
static void
-rule_destruct(struct rule *rule)
+rule_destruct(struct rule *rule_)
{
- complete_operation(rule_dpif_cast(rule));
+ struct rule_dpif *rule = rule_dpif_cast(rule_);
+ complete_operation(rule);
+ ovs_mutex_destroy(&rule->stats_mutex);
}
static void
/* Start from historical data for 'rule' itself that are no longer tracked
* in facets. This counts, for example, facets that have expired. */
+ ovs_mutex_lock(&rule->stats_mutex);
*packets = rule->packet_count;
*bytes = rule->byte_count;
+ ovs_mutex_unlock(&rule->stats_mutex);
}
static void
ODPP_NONE);
odp_put_userspace_action(pid, &cookie, sizeof cookie.slow_path, &buf);
} else {
- put_userspace_action(ofproto, &buf, flow, &cookie,
- sizeof cookie.slow_path);
+ odp_port_t odp_port;
+ uint32_t pid;
+
+ odp_port = ofp_port_to_odp_port(ofproto, flow->in_port.ofp_port);
+ pid = dpif_port_get_pid(ofproto->backer->dpif, odp_port);
+ odp_put_userspace_action(pid, &cookie, sizeof cookie.slow_path, &buf);
}
*actionsp = buf.data;
*actions_lenp = buf.size;
}
-
-size_t
-put_userspace_action(const struct ofproto_dpif *ofproto,
- struct ofpbuf *odp_actions,
- const struct flow *flow,
- const union user_action_cookie *cookie,
- const size_t cookie_size)
-{
- uint32_t pid;
-
- pid = dpif_port_get_pid(ofproto->backer->dpif,
- ofp_port_to_odp_port(ofproto,
- flow->in_port.ofp_port));
-
- return odp_put_userspace_action(pid, cookie, cookie_size, odp_actions);
-}
\f
static bool
set_frag_handling(struct ofproto *ofproto_,
struct cls_cursor cursor;
struct facet *facet;
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
cls_cursor_init(&cursor, &ofproto->facets, NULL);
CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
send_active_timeout(ofproto, facet);
}
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
}
\f
static struct ofproto_dpif *
backer = node->data;
}
- /* Extract the ofproto_dpif object from the ofproto_receive()
- * function. */
- if (ofproto_receive(backer, NULL, odp_key.data,
- odp_key.size, &flow, NULL, &ofproto, NULL)) {
+ if (xlate_receive(backer, NULL, odp_key.data, odp_key.size, &flow,
+ NULL, &ofproto, NULL)) {
unixctl_command_reply_error(conn, "Invalid datapath flow");
goto exit;
}
ofpbuf_uninit(&odp_mask);
}
-void
+static void
ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
const struct ofpbuf *packet, struct ds *ds)
{
int errors;
errors = 0;
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
cls_cursor_init(&cursor, &ofproto->facets, NULL);
CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
if (!facet_check_consistency(facet)) {
errors++;
}
}
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
if (errors) {
ofproto->backer->need_revalidate = REV_INCONSISTENCY;
}
return;
}
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
cls_cursor_init(&cursor, &ofproto->facets, NULL);
CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
cls_rule_format(&facet->cr, &ds);
}
ds_put_cstr(&ds, "\n");
}
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
ds_chomp(&ds, '\n');
unixctl_command_reply(conn, ds_cstr(&ds));
}
odp_flow_format(subfacet->key, subfacet->key_len,
- mask.data, mask.size, &ds);
+ mask.data, mask.size, &ds, false);
ds_put_format(&ds, ", packets:%"PRIu64", bytes:%"PRIu64", used:",
subfacet->dp_packet_count, subfacet->dp_byte_count);
bool
ofproto_has_vlan_splinters(const struct ofproto_dpif *ofproto)
+ OVS_EXCLUDED(ofproto->vsp_mutex)
{
- return !hmap_is_empty(&ofproto->realdev_vid_map);
+ bool ret;
+
+ ovs_mutex_lock(&ofproto->vsp_mutex);
+ ret = !hmap_is_empty(&ofproto->realdev_vid_map);
+ ovs_mutex_unlock(&ofproto->vsp_mutex);
+ return ret;
}
-/* Returns the OFP port number of the Linux VLAN device that corresponds to
- * 'vlan_tci' on the network device with port number 'realdev_ofp_port' in
- * 'struct ofport_dpif'. For example, given 'realdev_ofp_port' of eth0 and
- * 'vlan_tci' 9, it would return the port number of eth0.9.
- *
- * Unless VLAN splinters are enabled for port 'realdev_ofp_port', this
- * function just returns its 'realdev_ofp_port' argument. */
-ofp_port_t
-vsp_realdev_to_vlandev(const struct ofproto_dpif *ofproto,
- ofp_port_t realdev_ofp_port, ovs_be16 vlan_tci)
+static ofp_port_t
+vsp_realdev_to_vlandev__(const struct ofproto_dpif *ofproto,
+ ofp_port_t realdev_ofp_port, ovs_be16 vlan_tci)
+ OVS_REQUIRES(ofproto->vsp_mutex)
{
if (!hmap_is_empty(&ofproto->realdev_vid_map)) {
int vid = vlan_tci_to_vid(vlan_tci);
return realdev_ofp_port;
}
+/* Returns the OFP port number of the Linux VLAN device that corresponds to
+ * 'vlan_tci' on the network device with port number 'realdev_ofp_port' in
+ * 'struct ofport_dpif'. For example, given 'realdev_ofp_port' of eth0 and
+ * 'vlan_tci' 9, it would return the port number of eth0.9.
+ *
+ * Unless VLAN splinters are enabled for port 'realdev_ofp_port', this
+ * function just returns its 'realdev_ofp_port' argument. */
+ofp_port_t
+vsp_realdev_to_vlandev(const struct ofproto_dpif *ofproto,
+ ofp_port_t realdev_ofp_port, ovs_be16 vlan_tci)
+ OVS_EXCLUDED(ofproto->vsp_mutex)
+{
+ ofp_port_t ret;
+
+ ovs_mutex_lock(&ofproto->vsp_mutex);
+ ret = vsp_realdev_to_vlandev__(ofproto, realdev_ofp_port, vlan_tci);
+ ovs_mutex_unlock(&ofproto->vsp_mutex);
+ return ret;
+}
+
static struct vlan_splinter *
vlandev_find(const struct ofproto_dpif *ofproto, ofp_port_t vlandev_ofp_port)
{
static ofp_port_t
vsp_vlandev_to_realdev(const struct ofproto_dpif *ofproto,
ofp_port_t vlandev_ofp_port, int *vid)
+ OVS_REQUIRES(ofproto->vsp_mutex)
{
if (!hmap_is_empty(&ofproto->vlandev_map)) {
const struct vlan_splinter *vsp;
* 'flow->vlan_tci' to the VLAN VID, and returns true. Otherwise (which is
* always the case unless VLAN splinters are enabled), returns false without
* making any changes. */
-static bool
+bool
vsp_adjust_flow(const struct ofproto_dpif *ofproto, struct flow *flow)
+ OVS_EXCLUDED(ofproto->vsp_mutex)
{
ofp_port_t realdev;
int vid;
+ ovs_mutex_lock(&ofproto->vsp_mutex);
realdev = vsp_vlandev_to_realdev(ofproto, flow->in_port.ofp_port, &vid);
+ ovs_mutex_unlock(&ofproto->vsp_mutex);
if (!realdev) {
return false;
}
struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
struct vlan_splinter *vsp;
+ ovs_mutex_lock(&ofproto->vsp_mutex);
vsp = vlandev_find(ofproto, port->up.ofp_port);
if (vsp) {
hmap_remove(&ofproto->vlandev_map, &vsp->vlandev_node);
} else {
VLOG_ERR("missing vlan device record");
}
+ ovs_mutex_unlock(&ofproto->vsp_mutex);
}
static void
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
+ ovs_mutex_lock(&ofproto->vsp_mutex);
if (!vsp_vlandev_to_realdev(ofproto, port->up.ofp_port, NULL)
- && (vsp_realdev_to_vlandev(ofproto, realdev_ofp_port, htons(vid))
+ && (vsp_realdev_to_vlandev__(ofproto, realdev_ofp_port, htons(vid))
== realdev_ofp_port)) {
struct vlan_splinter *vsp;
vsp = xmalloc(sizeof *vsp);
- hmap_insert(&ofproto->vlandev_map, &vsp->vlandev_node,
- hash_ofp_port(port->up.ofp_port));
- hmap_insert(&ofproto->realdev_vid_map, &vsp->realdev_vid_node,
- hash_realdev_vid(realdev_ofp_port, vid));
vsp->realdev_ofp_port = realdev_ofp_port;
vsp->vlandev_ofp_port = port->up.ofp_port;
vsp->vid = vid;
port->realdev_ofp_port = realdev_ofp_port;
+
+ hmap_insert(&ofproto->vlandev_map, &vsp->vlandev_node,
+ hash_ofp_port(port->up.ofp_port));
+ hmap_insert(&ofproto->realdev_vid_map, &vsp->realdev_vid_node,
+ hash_realdev_vid(realdev_ofp_port, vid));
} else {
VLOG_ERR("duplicate vlan device record");
}
+ ovs_mutex_unlock(&ofproto->vsp_mutex);
}
static odp_port_t
return ofport ? ofport->odp_port : ODPP_NONE;
}
-static struct ofport_dpif *
+struct ofport_dpif *
odp_port_to_ofport(const struct dpif_backer *backer, odp_port_t odp_port)
{
struct ofport_dpif *port;
+ ovs_rwlock_rdlock(&backer->odp_to_ofport_lock);
HMAP_FOR_EACH_IN_BUCKET (port, odp_port_node, hash_odp_port(odp_port),
&backer->odp_to_ofport_map) {
if (port->odp_port == odp_port) {
+ ovs_rwlock_unlock(&backer->odp_to_ofport_lock);
return port;
}
}
+ ovs_rwlock_unlock(&backer->odp_to_ofport_lock);
return NULL;
}