netflow: Fold netflow_expire() into netflow_flow_clear().
[cascardo/ovs.git] / ofproto / ofproto-dpif-xlate.c
index 248382f..b4a1ed4 100644 (file)
@@ -192,6 +192,10 @@ struct xlate_ctx {
     uint16_t user_cookie_offset;/* Used for user_action_cookie fixup. */
     bool exit;                  /* No further actions should be processed. */
 
+    bool use_recirc;            /* Should generate recirc? */
+    struct xlate_recirc recirc; /* Information used for generating
+                                 * recirculation actions */
+
     /* OpenFlow 1.1+ action set.
      *
      * 'action_set' accumulates "struct ofpact"s added by OFPACT_WRITE_ACTIONS.
@@ -263,7 +267,8 @@ struct xc_entry {
         } bond;
         struct {
             struct ofproto_dpif *ofproto;
-            struct rule_dpif *rule;
+            struct ofputil_flow_mod *fm;
+            struct ofpbuf *ofpacts;
         } learn;
         struct {
             struct ofproto_dpif *ofproto;
@@ -770,8 +775,9 @@ xport_stp_listen_state(const struct xport *xport)
 static bool
 stp_should_process_flow(const struct flow *flow, struct flow_wildcards *wc)
 {
+    /* is_stp() also checks dl_type, but dl_type is always set in 'wc'. */
     memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
-    return eth_addr_equals(flow->dl_dst, eth_addr_stp);
+    return is_stp(flow);
 }
 
 static void
@@ -970,9 +976,10 @@ lookup_input_bundle(const struct xbridge *xbridge, ofp_port_t in_port,
         return xport->xbundle;
     }
 
-    /* Special-case OFPP_NONE, which a controller may use as the ingress
-     * port for traffic that it is sourcing. */
-    if (in_port == OFPP_NONE) {
+    /* Special-case OFPP_NONE (OF1.0) and OFPP_CONTROLLER (OF1.1+),
+     * which a controller may use as the ingress port for traffic that
+     * it is sourcing. */
+    if (in_port == OFPP_CONTROLLER || in_port == OFPP_NONE) {
         return &ofpp_none_bundle;
     }
 
@@ -1207,19 +1214,19 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle,
         /* Partially configured bundle with no slaves.  Drop the packet. */
         return;
     } else if (!out_xbundle->bond) {
-        ctx->xout->use_recirc = false;
+        ctx->use_recirc = false;
         xport = CONTAINER_OF(list_front(&out_xbundle->xports), struct xport,
                              bundle_node);
     } else {
         struct ofport_dpif *ofport;
-        struct xlate_recirc *xr = &ctx->xout->recirc;
+        struct xlate_recirc *xr = &ctx->recirc;
         struct flow_wildcards *wc = &ctx->xout->wc;
 
         if (ctx->xbridge->enable_recirc) {
-            ctx->xout->use_recirc = bond_may_recirc(
+            ctx->use_recirc = bond_may_recirc(
                 out_xbundle->bond, &xr->recirc_id, &xr->hash_basis);
 
-            if (ctx->xout->use_recirc) {
+            if (ctx->use_recirc) {
                 /* Only TCP mode uses recirculation. */
                 xr->hash_alg = OVS_HASH_ALG_L4;
                 bond_update_post_recirc_rules(out_xbundle->bond, false);
@@ -1240,7 +1247,7 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle,
 
         /* If ctx->xout->use_recirc is set, the main thread will handle stats
          * accounting for this bond. */
-        if (!ctx->xout->use_recirc) {
+        if (!ctx->use_recirc) {
             if (ctx->xin->resubmit_stats) {
                 bond_account(out_xbundle->bond, &ctx->xin->flow, vid,
                              ctx->xin->resubmit_stats->n_bytes);
@@ -1547,7 +1554,7 @@ xlate_normal(struct xlate_ctx *ctx)
 
         /* Save enough info to update mac learning table later. */
         entry = xlate_cache_add_entry(ctx->xin->xcache, XC_NORMAL);
-        entry->u.normal.ofproto = ctx->xin->ofproto;
+        entry->u.normal.ofproto = ctx->xbridge->ofproto;
         entry->u.normal.flow = xmemdup(flow, sizeof *flow);
         entry->u.normal.vlan = vlan;
     }
@@ -1772,11 +1779,7 @@ process_special(struct xlate_ctx *ctx, const struct flow *flow,
             bfd_process_packet(xport->bfd, flow, packet);
             /* If POLL received, immediately sends FINAL back. */
             if (bfd_should_send_packet(xport->bfd)) {
-                if (xport->peer) {
-                    ofproto_dpif_monitor_port_send_soon(xport->ofport);
-                } else {
-                    ofproto_dpif_monitor_port_send_soon_safe(xport->ofport);
-                }
+                ofproto_dpif_monitor_port_send_soon(xport->ofport);
             }
         }
         return SLOW_BFD;
@@ -1820,7 +1823,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
         xlate_report(ctx, "OFPPC_NO_FWD set, skipping output");
         return;
     } else if (check_stp) {
-        if (eth_addr_equals(ctx->base_flow.dl_dst, eth_addr_stp)) {
+        if (is_stp(&ctx->base_flow)) {
             if (!xport_stp_listen_state(xport)) {
                 xlate_report(ctx, "STP not in listening state, "
                              "skipping bpdu output");
@@ -1950,9 +1953,9 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
                                               &ctx->xout->odp_actions,
                                               &ctx->xout->wc);
 
-        if (ctx->xout->use_recirc) {
+        if (ctx->use_recirc) {
             struct ovs_action_hash *act_hash;
-            struct xlate_recirc *xr = &ctx->xout->recirc;
+            struct xlate_recirc *xr = &ctx->recirc;
 
             /* Hash action. */
             act_hash = nl_msg_put_unspec_uninit(&ctx->xout->odp_actions,
@@ -1991,18 +1994,11 @@ static void
 xlate_recursively(struct xlate_ctx *ctx, struct rule_dpif *rule)
 {
     struct rule_dpif *old_rule = ctx->rule;
-    struct rule_actions *actions;
+    const struct rule_actions *actions;
 
     if (ctx->xin->resubmit_stats) {
         rule_dpif_credit_stats(rule, ctx->xin->resubmit_stats);
     }
-    if (ctx->xin->xcache) {
-        struct xc_entry *entry;
-
-        entry = xlate_cache_add_entry(ctx->xin->xcache, XC_RULE);
-        entry->u.rule = rule;
-        rule_dpif_ref(rule);
-    }
 
     ctx->resubmits++;
     ctx->recurse++;
@@ -2057,7 +2053,8 @@ xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id,
                                               !skip_wildcards
                                               ? &ctx->xout->wc : NULL,
                                               honor_table_miss,
-                                              &ctx->table_id, &rule);
+                                              &ctx->table_id, &rule,
+                                              ctx->xin->xcache != NULL);
         ctx->xin->flow.in_port.ofp_port = old_in_port;
 
         if (ctx->xin->resubmit_hook) {
@@ -2090,12 +2087,22 @@ xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id,
         }
 
         choose_miss_rule(config, ctx->xbridge->miss_rule,
-                         ctx->xbridge->no_packet_in_rule, &rule);
+                         ctx->xbridge->no_packet_in_rule, &rule,
+                         ctx->xin->xcache != NULL);
 
 match:
         if (rule) {
+            /* Fill in the cache entry here instead of xlate_recursively
+             * to make the reference counting more explicit.  We take a
+             * reference in the lookups above if we are going to cache the
+             * rule. */
+            if (ctx->xin->xcache) {
+                struct xc_entry *entry;
+
+                entry = xlate_cache_add_entry(ctx->xin->xcache, XC_RULE);
+                entry->u.rule = rule;
+            }
             xlate_recursively(ctx, rule);
-            rule_dpif_unref(rule);
         }
 
         ctx->table_id = old_table_id;
@@ -2628,33 +2635,38 @@ xlate_bundle_action(struct xlate_ctx *ctx,
 }
 
 static void
-xlate_learn_action(struct xlate_ctx *ctx,
-                   const struct ofpact_learn *learn)
+xlate_learn_action__(struct xlate_ctx *ctx, const struct ofpact_learn *learn,
+                     struct ofputil_flow_mod *fm, struct ofpbuf *ofpacts)
 {
-    uint64_t ofpacts_stub[1024 / 8];
-    struct ofputil_flow_mod fm;
-    struct ofpbuf ofpacts;
+    learn_execute(learn, &ctx->xin->flow, fm, ofpacts);
+    if (ctx->xin->may_learn) {
+        ofproto_dpif_flow_mod(ctx->xbridge->ofproto, fm);
+    }
+}
 
+static void
+xlate_learn_action(struct xlate_ctx *ctx, const struct ofpact_learn *learn)
+{
     ctx->xout->has_learn = true;
-
     learn_mask(learn, &ctx->xout->wc);
 
-    if (!ctx->xin->may_learn) {
-        return;
-    }
-
-    ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
-    learn_execute(learn, &ctx->xin->flow, &fm, &ofpacts);
-    ofproto_dpif_flow_mod(ctx->xbridge->ofproto, &fm);
-    ofpbuf_uninit(&ofpacts);
-
     if (ctx->xin->xcache) {
         struct xc_entry *entry;
 
         entry = xlate_cache_add_entry(ctx->xin->xcache, XC_LEARN);
-        entry->u.learn.ofproto = ctx->xin->ofproto;
-        rule_dpif_lookup(ctx->xbridge->ofproto, &ctx->xin->flow, NULL,
-                         &entry->u.learn.rule);
+        entry->u.learn.ofproto = ctx->xbridge->ofproto;
+        entry->u.learn.fm = xmalloc(sizeof *entry->u.learn.fm);
+        entry->u.learn.ofpacts = ofpbuf_new(64);
+        xlate_learn_action__(ctx, learn, entry->u.learn.fm,
+                             entry->u.learn.ofpacts);
+    } else if (ctx->xin->may_learn) {
+        uint64_t ofpacts_stub[1024 / 8];
+        struct ofputil_flow_mod fm;
+        struct ofpbuf ofpacts;
+
+        ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
+        xlate_learn_action__(ctx, learn, &fm, &ofpacts);
+        ofpbuf_uninit(&ofpacts);
     }
 }
 
@@ -2678,10 +2690,11 @@ xlate_fin_timeout(struct xlate_ctx *ctx,
             struct xc_entry *entry;
 
             entry = xlate_cache_add_entry(ctx->xin->xcache, XC_FIN_TIMEOUT);
+            /* XC_RULE already holds a reference on the rule, none is taken
+             * here. */
             entry->u.fin.rule = ctx->rule;
             entry->u.fin.idle = oft->fin_idle_timeout;
             entry->u.fin.hard = oft->fin_hard_timeout;
-            rule_dpif_ref(ctx->rule);
         }
     }
 }
@@ -2717,7 +2730,7 @@ xlate_sample_action(struct xlate_ctx *ctx,
 static bool
 may_receive(const struct xport *xport, struct xlate_ctx *ctx)
 {
-    if (xport->config & (eth_addr_equals(ctx->xin->flow.dl_dst, eth_addr_stp)
+    if (xport->config & (is_stp(&ctx->xin->flow)
                          ? OFPUTIL_PC_NO_RECV_STP
                          : OFPUTIL_PC_NO_RECV)) {
         return false;
@@ -3183,7 +3196,7 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout)
     struct flow *flow = &xin->flow;
     struct rule_dpif *rule = NULL;
 
-    struct rule_actions *actions = NULL;
+    const struct rule_actions *actions = NULL;
     enum slow_path_reason special;
     const struct ofpact *ofpacts;
     struct xport *in_port;
@@ -3230,7 +3243,7 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout)
 
     ctx.xbridge = xbridge_lookup(xin->ofproto);
     if (!ctx.xbridge) {
-        goto out;
+        return;
     }
 
     ctx.rule = xin->rule;
@@ -3259,11 +3272,12 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout)
     ctx.orig_skb_priority = flow->skb_priority;
     ctx.table_id = 0;
     ctx.exit = false;
+    ctx.use_recirc = false;
 
     if (!xin->ofpacts && !ctx.rule) {
         ctx.table_id = rule_dpif_lookup(ctx.xbridge->ofproto, flow,
                                         !xin->skip_wildcards ? wc : NULL,
-                                        &rule);
+                                        &rule, ctx.xin->xcache != NULL);
         if (ctx.xin->resubmit_stats) {
             rule_dpif_credit_stats(rule, ctx.xin->resubmit_stats);
         }
@@ -3271,13 +3285,11 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout)
             struct xc_entry *entry;
 
             entry = xlate_cache_add_entry(ctx.xin->xcache, XC_RULE);
-            rule_dpif_ref(rule);
             entry->u.rule = rule;
         }
         ctx.rule = rule;
     }
     xout->fail_open = ctx.rule && rule_dpif_is_fail_open(ctx.rule);
-    xout->use_recirc = false;
 
     if (xin->ofpacts) {
         ofpacts = xin->ofpacts;
@@ -3309,7 +3321,7 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout)
             break;
 
         case OFPC_FRAG_DROP:
-            goto out;
+            return;
 
         case OFPC_FRAG_REASM:
             OVS_NOT_REACHED();
@@ -3409,9 +3421,6 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout)
     }
 
     if (ctx.xbridge->netflow) {
-        const struct ofpact *ofpacts = actions->ofpacts;
-        size_t ofpacts_len = actions->ofpacts_len;
-
         /* Only update netflow if we don't have controller flow.  We don't
          * report NetFlow expiration messages for such facets because they
          * are just part of the control logic for the network, not real
@@ -3456,9 +3465,6 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout)
         wc->masks.tp_src &= htons(UINT8_MAX);
         wc->masks.tp_dst &= htons(UINT8_MAX);
     }
-
-out:
-    rule_dpif_unref(rule);
 }
 
 /* Sends 'packet' out 'ofport'.
@@ -3577,12 +3583,8 @@ xlate_push_stats(struct xlate_cache *xcache, bool may_learn,
             break;
         case XC_LEARN:
             if (may_learn) {
-                struct rule_dpif *rule = entry->u.learn.rule;
-
-                /* Reset the modified time for a rule that is equivalent to
-                 * the currently cached rule. If the rule is not the exact
-                 * rule wehave cached, update the reference that we have. */
-                    entry->u.learn.rule = ofproto_dpif_refresh_rule(rule);
+                ofproto_dpif_flow_mod(entry->u.learn.ofproto,
+                                      entry->u.learn.fm);
             }
             break;
         case XC_NORMAL:
@@ -3616,7 +3618,6 @@ xlate_dev_unref(struct xc_entry *entry)
 static void
 xlate_cache_clear_netflow(struct netflow *netflow, struct flow *flow)
 {
-    netflow_expire(netflow, flow);
     netflow_flow_clear(netflow, flow);
     netflow_unref(netflow);
     free(flow);
@@ -3651,13 +3652,15 @@ xlate_cache_clear(struct xlate_cache *xcache)
             mbridge_unref(entry->u.mirror.mbridge);
             break;
         case XC_LEARN:
-            rule_dpif_unref(entry->u.learn.rule);
+            free(entry->u.learn.fm);
+            ofpbuf_delete(entry->u.learn.ofpacts);
             break;
         case XC_NORMAL:
             free(entry->u.normal.flow);
             break;
         case XC_FIN_TIMEOUT:
-            rule_dpif_unref(entry->u.fin.rule);
+            /* 'u.fin.rule' is always already held as a XC_RULE, which
+             * has already released it's reference above. */
             break;
         default:
             OVS_NOT_REACHED();