struct flow_miss;
struct facet;
+struct rule_dpif {
+ struct rule up;
+
+ /* These statistics:
+ *
+ * - Do include packets and bytes from facets that have been deleted or
+ * whose own statistics have been folded into the rule.
+ *
+ * - Do include packets and bytes sent "by hand" that were accounted to
+ * the rule without any facet being involved (this is a rare corner
+ * case in rule_execute()).
+ *
+ * - Do not include packet or bytes that can be obtained from any facet's
+ * packet_count or byte_count member or that can be obtained from the
+ * datapath by, e.g., dpif_flow_get() for any subfacet.
+ */
+ struct ovs_mutex stats_mutex;
+ uint64_t packet_count OVS_GUARDED; /* Number of packets received. */
+ uint64_t byte_count OVS_GUARDED; /* Number of bytes received. */
+};
+
static void rule_get_stats(struct rule *, uint64_t *packets, uint64_t *bytes);
+static struct rule_dpif *rule_dpif_cast(const struct rule *);
struct ofbundle {
struct hmap_node hmap_node; /* In struct ofproto's "bundles" hmap. */
if (rule_dpif_lookup_in_table(ofproto, &fm.match.flow, NULL, TBL_INTERNAL,
rulep)) {
- ovs_rwlock_unlock(&(*rulep)->up.evict);
+ rule_dpif_release(*rulep);
} else {
NOT_REACHED();
}
}
ovs_mutex_lock(&ofproto->flow_mod_mutex);
- if (ofproto->n_flow_mods) {
- flow_mods = ofproto->flow_mods;
- list_moved(&flow_mods);
- list_init(&ofproto->flow_mods);
- ofproto->n_flow_mods = 0;
- } else {
- list_init(&flow_mods);
- }
+ list_move(&flow_mods, &ofproto->flow_mods);
+ list_init(&ofproto->flow_mods);
+ ofproto->n_flow_mods = 0;
ovs_mutex_unlock(&ofproto->flow_mod_mutex);
LIST_FOR_EACH_SAFE (fm, next_fm, list_node, &flow_mods) {
}
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);
- }
+ list_move(&pins, &ofproto->pins);
+ list_init(&ofproto->pins);
+ ofproto->n_pins = 0;
ovs_mutex_unlock(&ofproto->pin_mutex);
LIST_FOR_EACH_SAFE (pin, next_pin, list_node, &pins) {
bundle_send_learning_packets(struct ofbundle *bundle)
{
struct ofproto_dpif *ofproto = bundle->ofproto;
+ struct ofpbuf *learning_packet;
int error, n_packets, n_errors;
struct mac_entry *e;
+ struct list packets;
- error = n_packets = n_errors = 0;
+ list_init(&packets);
ovs_rwlock_rdlock(&ofproto->ml->rwlock);
LIST_FOR_EACH (e, lru_node, &ofproto->ml->lrus) {
if (e->port.p != bundle) {
- struct ofpbuf *learning_packet;
- struct ofport_dpif *port;
void *port_void;
- int ret;
- /* The assignment to "port" is unnecessary but makes "grep"ing for
- * struct ofport_dpif more effective. */
learning_packet = bond_compose_learning_packet(bundle->bond,
e->mac, e->vlan,
&port_void);
- port = port_void;
- ret = send_packet(port, learning_packet);
- ofpbuf_delete(learning_packet);
- if (ret) {
- error = ret;
- n_errors++;
- }
- n_packets++;
+ learning_packet->private_p = port_void;
+ list_push_back(&packets, &learning_packet->list_node);
}
}
ovs_rwlock_unlock(&ofproto->ml->rwlock);
+ error = n_packets = n_errors = 0;
+ LIST_FOR_EACH (learning_packet, list_node, &packets) {
+ int ret;
+
+ ret = send_packet(learning_packet->private_p, learning_packet);
+ if (ret) {
+ error = ret;
+ n_errors++;
+ }
+ n_packets++;
+ }
+ ofpbuf_list_delete(&packets);
+
if (n_errors) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
VLOG_WARN_RL(&rl, "bond %s: %d errors sending %d gratuitous learning "
is_controller = ofpacts_len > 0
&& ofpacts->type == OFPACT_CONTROLLER
&& ofpact_next(ofpacts) >= ofpact_end(ofpacts, ofpacts_len);
- rule_release(rule);
+ rule_dpif_release(rule);
return is_controller;
}
return false;
rule_dpif_lookup(facet->ofproto, &facet->flow, NULL, &rule);
xlate_in_init(&xin, facet->ofproto, &facet->flow, rule, 0, NULL);
xlate_actions(&xin, &xout);
- rule_release(rule);
+ rule_dpif_release(rule);
ok = ofpbuf_equal(&facet->xout.odp_actions, &xout.odp_actions)
&& facet->xout.slow == xout.slow;
|| memcmp(&facet->xout.wc, &xout.wc, sizeof xout.wc)) {
facet_remove(facet);
xlate_out_uninit(&xout);
- rule_release(new_rule);
+ rule_dpif_release(new_rule);
return false;
}
facet->used = MAX(facet->used, new_rule->up.created);
xlate_out_uninit(&xout);
- rule_release(new_rule);
+ rule_dpif_release(new_rule);
return true;
}
}
rule_dpif_lookup(ofproto, flow, NULL, &rule);
- rule_credit_stats(rule, stats);
+ rule_dpif_credit_stats(rule, stats);
xlate_in_init(&xin, ofproto, flow, rule, stats->tcp_flags, NULL);
xin.resubmit_stats = stats;
xin.may_learn = may_learn;
xlate_actions_for_side_effects(&xin);
- rule_release(rule);
+ rule_dpif_release(rule);
}
static void
}
void
-rule_credit_stats(struct rule_dpif *rule, const struct dpif_flow_stats *stats)
+rule_dpif_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);
+ rule->up.used = MAX(rule->up.used, stats->used);
ovs_mutex_unlock(&rule->stats_mutex);
}
+
+bool
+rule_dpif_fail_open(const struct rule_dpif *rule)
+{
+ return rule->up.cr.priority == FAIL_OPEN_PRIORITY;
+}
+
+ovs_be64
+rule_dpif_get_flow_cookie(const struct rule_dpif *rule)
+{
+ return rule->up.flow_cookie;
+}
+
+void
+rule_dpif_reduce_timeouts(struct rule_dpif *rule, uint16_t idle_timeout,
+ uint16_t hard_timeout)
+{
+ ofproto_rule_reduce_timeouts(&rule->up, idle_timeout, hard_timeout);
+}
+
+void
+rule_dpif_get_actions(const struct rule_dpif *rule,
+ const struct ofpact **ofpacts, size_t *ofpacts_len)
+{
+ *ofpacts = rule->up.ofpacts;
+ *ofpacts_len = rule->up.ofpacts_len;
+}
\f
/* Subfacets. */
flow->in_port.ofp_port);
}
- *rule = choose_miss_rule(port ? port->up.pp.config : 0, ofproto->miss_rule,
- ofproto->no_packet_in_rule);
- ovs_rwlock_rdlock(&(*rule)->up.evict);
+ choose_miss_rule(port ? port->up.pp.config : 0, ofproto->miss_rule,
+ ofproto->no_packet_in_rule, rule);
}
bool
rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto,
const struct flow *flow, struct flow_wildcards *wc,
uint8_t table_id, struct rule_dpif **rule)
- OVS_TRY_RDLOCK(true, (*rule)->up.evict)
+ OVS_TRY_RDLOCK(true, (*rule)->up.rwlock)
{
struct cls_rule *cls_rule;
struct classifier *cls;
}
*rule = rule_dpif_cast(rule_from_cls_rule(cls_rule));
- if (*rule && ovs_rwlock_tryrdlock(&(*rule)->up.evict)) {
+ if (*rule && ovs_rwlock_tryrdlock(&(*rule)->up.rwlock)) {
/* The rule is in the process of being removed. Best we can do is
* pretend it isn't there. */
*rule = NULL;
/* 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 *
+void
choose_miss_rule(enum ofputil_port_config config, struct rule_dpif *miss_rule,
- struct rule_dpif *no_packet_in_rule)
+ struct rule_dpif *no_packet_in_rule, struct rule_dpif **rule)
+ OVS_NO_THREAD_SAFETY_ANALYSIS
{
- return config & OFPUTIL_PC_NO_PACKET_IN ? no_packet_in_rule : miss_rule;
+ *rule = config & OFPUTIL_PC_NO_PACKET_IN ? no_packet_in_rule : miss_rule;
+ ovs_rwlock_rdlock(&(*rule)->up.rwlock);
}
void
-rule_release(struct rule_dpif *rule)
+rule_dpif_release(struct rule_dpif *rule)
OVS_NO_THREAD_SAFETY_ANALYSIS
{
if (rule) {
- ovs_rwlock_unlock(&rule->up.evict);
+ ovs_rwlock_unlock(&rule->up.rwlock);
}
}
}
}
+static struct rule_dpif *rule_dpif_cast(const struct rule *rule)
+{
+ return rule ? CONTAINER_OF(rule, struct rule_dpif, up) : NULL;
+}
+
static struct rule *
rule_alloc(void)
{
struct xlate_in xin;
dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
- rule_credit_stats(rule, &stats);
+ rule_dpif_credit_stats(rule, &stats);
xlate_in_init(&xin, ofproto, flow, rule, stats.tcp_flags, packet);
xin.resubmit_stats = &stats;
xlate_out_uninit(&trace.xout);
}
- rule_release(rule);
+ rule_dpif_release(rule);
}
static void