- * Returns true if 'facet' is still valid. False if 'facet' was removed. */
-static bool
-facet_revalidate(struct facet *facet)
-{
- struct ofproto_dpif *ofproto = facet->ofproto;
- struct rule_dpif *new_rule;
- struct subfacet *subfacet;
- struct flow_wildcards wc;
- struct xlate_out xout;
- struct xlate_in xin;
-
- COVERAGE_INC(facet_revalidate);
-
- /* Check that child subfacets still correspond to this facet. Tunnel
- * configuration changes could cause a subfacet's OpenFlow in_port to
- * change. */
- LIST_FOR_EACH (subfacet, list_node, &facet->subfacets) {
- struct ofproto_dpif *recv_ofproto;
- struct flow recv_flow;
- int error;
-
- 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)) {
- facet_remove(facet);
- return false;
- }
- }
-
- flow_wildcards_init_catchall(&wc);
- rule_dpif_lookup(ofproto, &facet->flow, &wc, &new_rule);
-
- /* Calculate new datapath actions.
- *
- * We do not modify any 'facet' state yet, because we might need to, e.g.,
- * emit a NetFlow expiration and, if so, we need to have the old state
- * around to properly compose it. */
- xlate_in_init(&xin, ofproto, &facet->flow, new_rule, 0, NULL);
- xlate_actions(&xin, &xout);
- flow_wildcards_or(&xout.wc, &xout.wc, &wc);
-
- /* A facet's slow path reason should only change under dramatic
- * circumstances. Rather than try to update everything, it's simpler to
- * remove the facet and start over.
- *
- * More importantly, if a facet's wildcards change, it will be relatively
- * difficult to figure out if its subfacets still belong to it, and if not
- * which facet they may belong to. Again, to avoid the complexity, we
- * simply give up instead. */
- if (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);
- return false;
- }
-
- if (!ofpbuf_equal(&facet->xout.odp_actions, &xout.odp_actions)) {
- LIST_FOR_EACH(subfacet, list_node, &facet->subfacets) {
- if (subfacet->path == SF_FAST_PATH) {
- struct dpif_flow_stats stats;
-
- subfacet_install(subfacet, &xout.odp_actions, &stats);
- subfacet_update_stats(subfacet, &stats);
- }
- }
-
- facet_flush_stats(facet);
-
- ofpbuf_clear(&facet->xout.odp_actions);
- ofpbuf_put(&facet->xout.odp_actions, xout.odp_actions.data,
- xout.odp_actions.size);
- }
-
- /* Update 'facet' now that we've taken care of all the old state. */
- facet->xout.slow = xout.slow;
- facet->xout.has_learn = xout.has_learn;
- facet->xout.has_normal = xout.has_normal;
- facet->xout.has_fin_timeout = xout.has_fin_timeout;
- facet->xout.nf_output_iface = xout.nf_output_iface;
- facet->xout.mirrors = xout.mirrors;
- facet->nf_flow.output_iface = facet->xout.nf_output_iface;
- facet->used = MAX(facet->used, new_rule->up.created);
-
- xlate_out_uninit(&xout);
- rule_release(new_rule);
- return true;
-}
-
-static void
-facet_reset_counters(struct facet *facet)
-{
- facet->packet_count = 0;
- facet->byte_count = 0;
- facet->prev_packet_count = 0;
- facet->prev_byte_count = 0;
- facet->accounted_bytes = 0;
-}
-
-static void
-flow_push_stats(struct ofproto_dpif *ofproto, struct flow *flow,
- struct dpif_flow_stats *stats, bool may_learn)
-{
- struct ofport_dpif *in_port;
- struct rule_dpif *rule;
- struct xlate_in xin;
-
- in_port = get_ofp_port(ofproto, flow->in_port.ofp_port);
- if (in_port && in_port->is_tunnel) {
- netdev_vport_inc_rx(in_port->up.netdev, stats);
- }
-
- rule_dpif_lookup(ofproto, flow, NULL, &rule);
- rule_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);
-}
-
-static void
-facet_push_stats(struct facet *facet, bool may_learn)
-{
- struct dpif_flow_stats stats;
-
- ovs_assert(facet->packet_count >= facet->prev_packet_count);
- ovs_assert(facet->byte_count >= facet->prev_byte_count);
- ovs_assert(facet->used >= facet->prev_used);
-
- stats.n_packets = facet->packet_count - facet->prev_packet_count;
- stats.n_bytes = facet->byte_count - facet->prev_byte_count;
- stats.used = facet->used;
- stats.tcp_flags = facet->tcp_flags;
-
- if (may_learn || stats.n_packets || facet->used > facet->prev_used) {
- facet->prev_packet_count = facet->packet_count;
- facet->prev_byte_count = facet->byte_count;
- facet->prev_used = facet->used;
-
- netflow_flow_update_time(facet->ofproto->netflow, &facet->nf_flow,
- facet->used);
- netflow_flow_update_flags(&facet->nf_flow, facet->tcp_flags);
- mirror_update_stats(facet->ofproto->mbridge, facet->xout.mirrors,
- stats.n_packets, stats.n_bytes);
- flow_push_stats(facet->ofproto, &facet->flow, &stats, may_learn);
- }
-}
-
-static void
-push_all_stats__(bool run_fast)
-{
- static long long int rl = LLONG_MIN;
- struct ofproto_dpif *ofproto;
-
- if (time_msec() < rl) {
- return;
- }
-
- HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
- 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);
- if (run_fast) {
- run_fast_rl();
- }
- }
- ovs_rwlock_unlock(&ofproto->facets.rwlock);
- }
-
- rl = time_msec() + 100;
-}
-
-static void
-push_all_stats(void)
-{
- push_all_stats__(true);
-}
-
-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. */
-
-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;
-}