- ovs_rwlock_unlock(&ofproto->facets.rwlock);
- }
-
- rl = time_msec() + 100;
-}
-
-static void
-push_all_stats(void)
-{
- push_all_stats__(true);
-}
-
-void
-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;
- rule->up.used = MAX(rule->up.used, stats->used);
- ovs_mutex_unlock(&rule->stats_mutex);
-}
-
-bool
-rule_dpif_is_fail_open(const struct rule_dpif *rule)
-{
- return is_fail_open_rule(&rule->up);
-}
-
-bool
-rule_dpif_is_table_miss(const struct rule_dpif *rule)
-{
- return rule_is_table_miss(&rule->up);
-}
-
-ovs_be64
-rule_dpif_get_flow_cookie(const struct rule_dpif *rule)
- OVS_REQUIRES(rule->up.mutex)
-{
- 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);
-}
-
-/* Returns 'rule''s actions. The caller owns a reference on the returned
- * actions and must eventually release it (with rule_actions_unref()) to avoid
- * a memory leak. */
-struct rule_actions *
-rule_dpif_get_actions(const struct rule_dpif *rule)
-{
- return rule_get_actions(&rule->up);
-}
-\f
-/* Subfacets. */
-
-static struct subfacet *
-subfacet_find(struct dpif_backer *backer, const struct nlattr *key,
- size_t key_len, uint32_t key_hash)
-{
- struct subfacet *subfacet;
-
- HMAP_FOR_EACH_WITH_HASH (subfacet, hmap_node, key_hash,
- &backer->subfacets) {
- if (subfacet->key_len == key_len
- && !memcmp(key, subfacet->key, key_len)) {
- return subfacet;
- }
- }
-
- return NULL;
-}
-
-/* Creates and returns a new subfacet within 'facet' for the flow in 'miss'.
- * 'key_hash' must be a hash over miss->key. The caller must have already
- * ensured that no subfacet subfacet already exists. */
-static struct subfacet *
-subfacet_create(struct facet *facet, struct flow_miss *miss, uint32_t key_hash)
-{
- struct dpif_backer *backer = miss->ofproto->backer;
- const struct nlattr *key = miss->key;
- size_t key_len = miss->key_len;
- struct subfacet *subfacet;
-
- subfacet = (list_is_empty(&facet->subfacets)
- ? &facet->one_subfacet
- : xmalloc(sizeof *subfacet));
-
- COVERAGE_INC(subfacet_create);
- hmap_insert(&backer->subfacets, &subfacet->hmap_node, key_hash);
- list_push_back(&facet->subfacets, &subfacet->list_node);
- subfacet->facet = facet;
- subfacet->key = xmemdup(key, key_len);
- subfacet->key_len = key_len;
- subfacet->used = miss->stats.used;
- subfacet->created = subfacet->used;
- subfacet->dp_packet_count = 0;
- subfacet->dp_byte_count = 0;
- subfacet->path = SF_NOT_INSTALLED;
- subfacet->backer = backer;
-
- return subfacet;
-}
-
-/* Uninstalls 'subfacet' from the datapath, if it is installed, removes it from
- * its facet within 'ofproto', and frees it. */
-static void
-subfacet_destroy__(struct subfacet *subfacet)
-{
- struct facet *facet = subfacet->facet;
-
- COVERAGE_INC(subfacet_destroy);
- subfacet_uninstall(subfacet);
- hmap_remove(&subfacet->backer->subfacets, &subfacet->hmap_node);
- list_remove(&subfacet->list_node);
- free(subfacet->key);
- if (subfacet != &facet->one_subfacet) {
- free(subfacet);
- }
-}
-
-/* Destroys 'subfacet', as with subfacet_destroy__(), and then if this was the
- * last remaining subfacet in its facet destroys the facet too. */
-static void
-subfacet_destroy(struct subfacet *subfacet)
-{
- struct facet *facet = subfacet->facet;
-
- if (list_is_singleton(&facet->subfacets)) {
- /* facet_remove() needs at least one subfacet (it will remove it). */
- facet_remove(facet);
- } else {
- subfacet_destroy__(subfacet);
- }
-}
-
-static void
-subfacet_destroy_batch(struct dpif_backer *backer,
- struct subfacet **subfacets, int n)
-{
- struct dpif_op ops[SUBFACET_DESTROY_MAX_BATCH];
- struct dpif_op *opsp[SUBFACET_DESTROY_MAX_BATCH];
- struct dpif_flow_stats stats[SUBFACET_DESTROY_MAX_BATCH];
- int i;
-
- for (i = 0; i < n; i++) {
- ops[i].type = DPIF_OP_FLOW_DEL;
- ops[i].u.flow_del.key = subfacets[i]->key;
- ops[i].u.flow_del.key_len = subfacets[i]->key_len;
- ops[i].u.flow_del.stats = &stats[i];
- opsp[i] = &ops[i];
- }
-
- dpif_operate(backer->dpif, opsp, n);
- for (i = 0; i < n; i++) {
- subfacet_reset_dp_stats(subfacets[i], &stats[i]);
- subfacets[i]->path = SF_NOT_INSTALLED;
- subfacet_destroy(subfacets[i]);
- run_fast_rl();
- }
-}
-
-/* Updates 'subfacet''s datapath flow, setting its actions to 'actions_len'
- * bytes of actions in 'actions'. If 'stats' is non-null, statistics counters
- * in the datapath will be zeroed and 'stats' will be updated with traffic new
- * since 'subfacet' was last updated.
- *
- * Returns 0 if successful, otherwise a positive errno value. */
-static int
-subfacet_install(struct subfacet *subfacet, const struct ofpbuf *odp_actions,
- struct dpif_flow_stats *stats)
-{
- struct facet *facet = subfacet->facet;
- enum subfacet_path path = facet->xout.slow ? SF_SLOW_PATH : SF_FAST_PATH;
- const struct nlattr *actions = odp_actions->data;
- size_t actions_len = odp_actions->size;
- struct odputil_keybuf maskbuf;
- struct ofpbuf mask;
-
- uint64_t slow_path_stub[128 / 8];
- enum dpif_flow_put_flags flags;
- int ret;
-
- flags = subfacet->path == SF_NOT_INSTALLED ? DPIF_FP_CREATE
- : DPIF_FP_MODIFY;
- if (stats) {
- flags |= DPIF_FP_ZERO_STATS;
- }
-
- if (path == SF_SLOW_PATH) {
- compose_slow_path(facet->ofproto, &facet->flow, facet->xout.slow,
- slow_path_stub, sizeof slow_path_stub,
- &actions, &actions_len);
- }
-
- ofpbuf_use_stack(&mask, &maskbuf, sizeof maskbuf);
- if (enable_megaflows) {
- odp_flow_key_from_mask(&mask, &facet->xout.wc.masks,
- &facet->flow, UINT32_MAX);
- }
-
- ret = dpif_flow_put(subfacet->backer->dpif, flags, subfacet->key,
- subfacet->key_len, mask.data, mask.size,
- actions, actions_len, stats);
-
- if (stats) {
- subfacet_reset_dp_stats(subfacet, stats);
- }
-
- if (ret) {
- COVERAGE_INC(subfacet_install_fail);
- } else {
- subfacet->path = path;
- }
- return ret;
-}
-
-/* If 'subfacet' is installed in the datapath, uninstalls it. */
-static void
-subfacet_uninstall(struct subfacet *subfacet)
-{
- if (subfacet->path != SF_NOT_INSTALLED) {
- struct ofproto_dpif *ofproto = subfacet->facet->ofproto;
- struct dpif_flow_stats stats;
- int error;
-
- error = dpif_flow_del(ofproto->backer->dpif, subfacet->key,
- subfacet->key_len, &stats);
- subfacet_reset_dp_stats(subfacet, &stats);
- if (!error) {
- subfacet_update_stats(subfacet, &stats);
- }
- subfacet->path = SF_NOT_INSTALLED;
- } else {
- ovs_assert(subfacet->dp_packet_count == 0);
- ovs_assert(subfacet->dp_byte_count == 0);
- }
-}
-
-/* Resets 'subfacet''s datapath statistics counters. This should be called
- * when 'subfacet''s statistics are cleared in the datapath. If 'stats' is
- * non-null, it should contain the statistics returned by dpif when 'subfacet'
- * was reset in the datapath. 'stats' will be modified to include only
- * statistics new since 'subfacet' was last updated. */
-static void
-subfacet_reset_dp_stats(struct subfacet *subfacet,
- struct dpif_flow_stats *stats)
-{
- if (stats
- && subfacet->dp_packet_count <= stats->n_packets
- && subfacet->dp_byte_count <= stats->n_bytes) {
- stats->n_packets -= subfacet->dp_packet_count;
- stats->n_bytes -= subfacet->dp_byte_count;
- }
-
- subfacet->dp_packet_count = 0;
- subfacet->dp_byte_count = 0;
-}
-
-/* Folds the statistics from 'stats' into the counters in 'subfacet'.
- *
- * Because of the meaning of a subfacet's counters, it only makes sense to do
- * this if 'stats' are not tracked in the datapath, that is, if 'stats'
- * represents a packet that was sent by hand or if it represents statistics
- * that have been cleared out of the datapath. */
-static void
-subfacet_update_stats(struct subfacet *subfacet,
- const struct dpif_flow_stats *stats)
-{
- if (stats->n_packets || stats->used > subfacet->used) {
- struct facet *facet = subfacet->facet;
-
- subfacet->used = MAX(subfacet->used, stats->used);
- facet->used = MAX(facet->used, stats->used);
- facet->packet_count += stats->n_packets;
- facet->byte_count += stats->n_bytes;
- facet->tcp_flags |= stats->tcp_flags;
- }
-}
-\f
-/* Rules. */
-
-/* Lookup 'flow' in 'ofproto''s classifier. If 'wc' is non-null, sets
- * the fields that were relevant as part of the lookup. */
-void
-rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow,
- struct flow_wildcards *wc, struct rule_dpif **rule)
-{
- struct ofport_dpif *port;
-
- if (rule_dpif_lookup_in_table(ofproto, flow, wc, 0, rule)) {
- return;
- }
- 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);
- }
-
- 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)
-{
- const struct cls_rule *cls_rule;
- struct classifier *cls;
- bool frag;
-
- *rule = NULL;
- if (table_id >= N_TABLES) {
- return false;
- }
-
- if (wc) {
- memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
- wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
- }
-
- cls = &ofproto->up.tables[table_id].cls;
- ovs_rwlock_rdlock(&cls->rwlock);
- frag = (flow->nw_frag & FLOW_NW_FRAG_ANY) != 0;
- if (frag && ofproto->up.frag_handling == OFPC_FRAG_NORMAL) {
- /* We must pretend that transport ports are unavailable. */
- struct flow ofpc_normal_flow = *flow;
- ofpc_normal_flow.tp_src = htons(0);
- ofpc_normal_flow.tp_dst = htons(0);
- cls_rule = classifier_lookup(cls, &ofpc_normal_flow, wc);
- } else if (frag && ofproto->up.frag_handling == OFPC_FRAG_DROP) {
- cls_rule = &ofproto->drop_frags_rule->up.cr;
- /* Frag mask in wc already set above. */
- } else {
- cls_rule = classifier_lookup(cls, flow, wc);
- }
-
- *rule = rule_dpif_cast(rule_from_cls_rule(cls_rule));
- rule_dpif_ref(*rule);
- ovs_rwlock_unlock(&cls->rwlock);
-
- return *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. */
-void
-choose_miss_rule(enum ofputil_port_config config, struct rule_dpif *miss_rule,
- struct rule_dpif *no_packet_in_rule, struct rule_dpif **rule)
-{
- *rule = config & OFPUTIL_PC_NO_PACKET_IN ? no_packet_in_rule : miss_rule;
- rule_dpif_ref(*rule);
-}
-
-void
-rule_dpif_ref(struct rule_dpif *rule)
-{
- if (rule) {
- ofproto_rule_ref(&rule->up);