nicira-ext: Add Nicira actions NXAST_STACK_PUSH and NXAST_STACK_POP.
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index a4d7e59..10e4e23 100644 (file)
@@ -216,6 +216,11 @@ struct action_xlate_ctx {
      * this flow when actions change header fields. */
     struct flow flow;
 
+    /* stack for the push and pop actions.
+     * Each stack element is of the type "union mf_subvalue". */
+    struct ofpbuf stack;
+    union mf_subvalue init_stack[1024 / sizeof(union mf_subvalue)];
+
     /* The packet corresponding to 'flow', or a null pointer if we are
      * revalidating without a packet to refer to. */
     const struct ofpbuf *packet;
@@ -341,11 +346,6 @@ struct subfacet {
     struct list list_node;      /* In struct facet's 'facets' list. */
     struct facet *facet;        /* Owning facet. */
 
-    /* Key.
-     *
-     * To save memory in the common case, 'key' is NULL if 'key_fitness' is
-     * ODP_FIT_PERFECT, that is, odp_flow_key_from_flow() can accurately
-     * regenerate the ODP flow key from ->facet->flow. */
     enum odp_key_fitness key_fitness;
     struct nlattr *key;
     int key_len;
@@ -384,14 +384,11 @@ static struct subfacet *subfacet_create(struct facet *, struct flow_miss *miss,
                                         long long int now);
 static struct subfacet *subfacet_find(struct ofproto_dpif *,
                                       const struct nlattr *key, size_t key_len,
-                                      uint32_t key_hash,
-                                      const struct flow *flow);
+                                      uint32_t key_hash);
 static void subfacet_destroy(struct subfacet *);
 static void subfacet_destroy__(struct subfacet *);
 static void subfacet_destroy_batch(struct ofproto_dpif *,
                                    struct subfacet **, int n);
-static void subfacet_get_key(struct subfacet *, struct odputil_keybuf *,
-                             struct ofpbuf *key);
 static void subfacet_reset_dp_stats(struct subfacet *,
                                     struct dpif_flow_stats *);
 static void subfacet_update_time(struct subfacet *, long long int used);
@@ -920,13 +917,13 @@ type_run(const char *type)
         backer->need_revalidate = 0;
 
         HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
-            struct facet *facet;
+            struct facet *facet, *next;
 
             if (ofproto->backer != backer) {
                 continue;
             }
 
-            HMAP_FOR_EACH (facet, hmap_node, &ofproto->facets) {
+            HMAP_FOR_EACH_SAFE (facet, next, hmap_node, &ofproto->facets) {
                 if (need_revalidate
                     || tag_set_intersects(&revalidate_set, facet->tags)) {
                     facet_revalidate(facet);
@@ -1786,43 +1783,22 @@ set_cfm(struct ofport *ofport_, const struct cfm_settings *s)
     return error;
 }
 
-static int
-get_cfm_fault(const struct ofport *ofport_)
-{
-    struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
-
-    return ofport->cfm ? cfm_get_fault(ofport->cfm) : -1;
-}
-
-static int
-get_cfm_opup(const struct ofport *ofport_)
-{
-    struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
-
-    return ofport->cfm ? cfm_get_opup(ofport->cfm) : -1;
-}
-
-static int
-get_cfm_remote_mpids(const struct ofport *ofport_, const uint64_t **rmps,
-                     size_t *n_rmps)
+static bool
+get_cfm_status(const struct ofport *ofport_,
+               struct ofproto_cfm_status *status)
 {
     struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
 
     if (ofport->cfm) {
-        cfm_get_remote_mpids(ofport->cfm, rmps, n_rmps);
-        return 0;
+        status->faults = cfm_get_fault(ofport->cfm);
+        status->remote_opstate = cfm_get_opup(ofport->cfm);
+        status->health = cfm_get_health(ofport->cfm);
+        cfm_get_remote_mpids(ofport->cfm, &status->rmps, &status->n_rmps);
+        return true;
     } else {
-        return -1;
+        return false;
     }
 }
-
-static int
-get_cfm_health(const struct ofport *ofport_)
-{
-    struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
-
-    return ofport->cfm ? cfm_get_health(ofport->cfm) : -1;
-}
 \f
 /* Spanning Tree. */
 
@@ -3296,7 +3272,6 @@ struct flow_miss {
 
 struct flow_miss_op {
     struct dpif_op dpif_op;
-    struct subfacet *subfacet;  /* Subfacet  */
     void *garbage;              /* Pointer to pass to free(), NULL if none. */
     uint64_t stub[1024 / 8];    /* Temporary buffer. */
 };
@@ -3386,7 +3361,6 @@ init_flow_miss_execute_op(struct flow_miss *miss, struct ofpbuf *packet,
         eth_pop_vlan(packet);
     }
 
-    op->subfacet = NULL;
     op->garbage = NULL;
     op->dpif_op.type = DPIF_OP_EXECUTE;
     op->dpif_op.u.execute.key = miss->key;
@@ -3530,7 +3504,6 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
             struct dpif_execute *execute = &op->dpif_op.u.execute;
 
             init_flow_miss_execute_op(miss, packet, op);
-            op->subfacet = subfacet;
             if (!subfacet->slow) {
                 execute->actions = subfacet->actions;
                 execute->actions_len = subfacet->actions_len;
@@ -3552,7 +3525,8 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
         struct flow_miss_op *op = &ops[(*n_ops)++];
         struct dpif_flow_put *put = &op->dpif_op.u.flow_put;
 
-        op->subfacet = subfacet;
+        subfacet->path = want_path;
+
         op->garbage = NULL;
         op->dpif_op.type = DPIF_OP_FLOW_PUT;
         put->flags = DPIF_FP_CREATE | DPIF_FP_MODIFY;
@@ -3858,25 +3832,9 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
     }
     dpif_operate(backer->dpif, dpif_ops, n_ops);
 
-    /* Free memory and update facets. */
+    /* Free memory. */
     for (i = 0; i < n_ops; i++) {
-        struct flow_miss_op *op = &flow_miss_ops[i];
-
-        switch (op->dpif_op.type) {
-        case DPIF_OP_EXECUTE:
-            break;
-
-        case DPIF_OP_FLOW_PUT:
-            if (!op->dpif_op.error) {
-                op->subfacet->path = subfacet_want_path(op->subfacet->slow);
-            }
-            break;
-
-        case DPIF_OP_FLOW_DEL:
-            NOT_REACHED();
-        }
-
-        free(op->garbage);
+        free(flow_miss_ops[i].garbage);
     }
     hmap_destroy(&todo);
 }
@@ -4153,7 +4111,7 @@ update_stats(struct dpif_backer *backer)
         }
 
         key_hash = odp_flow_key_hash(key, key_len);
-        subfacet = subfacet_find(ofproto, key, key_len, key_hash, &flow);
+        subfacet = subfacet_find(ofproto, key, key_len, key_hash);
         switch (subfacet ? subfacet->path : SF_NOT_INSTALLED) {
         case SF_FAST_PATH:
             update_subfacet_stats(subfacet, stats);
@@ -4608,6 +4566,9 @@ facet_lookup_valid(struct ofproto_dpif *ofproto, const struct flow *flow,
             || tag_set_intersects(&ofproto->backer->revalidate_set,
                                   facet->tags))) {
         facet_revalidate(facet);
+
+        /* facet_revalidate() may have destroyed 'facet'. */
+        facet = facet_find(ofproto, flow, hash);
     }
 
     return facet;
@@ -4693,9 +4654,7 @@ facet_check_consistency(struct facet *facet)
     ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub);
     LIST_FOR_EACH (subfacet, list_node, &facet->subfacets) {
         enum subfacet_path want_path;
-        struct odputil_keybuf keybuf;
         struct action_xlate_ctx ctx;
-        struct ofpbuf key;
         struct ds s;
 
         action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
@@ -4731,8 +4690,7 @@ facet_check_consistency(struct facet *facet)
         }
 
         ds_init(&s);
-        subfacet_get_key(subfacet, &keybuf, &key);
-        odp_flow_key_format(key.data, key.size, &s);
+        odp_flow_key_format(subfacet->key, subfacet->key_len, &s);
 
         ds_put_cstr(&s, ": inconsistency in subfacet");
         if (want_path != subfacet->path) {
@@ -4770,7 +4728,10 @@ facet_check_consistency(struct facet *facet)
  *     'facet' to the new rule and recompiles its actions.
  *
  *   - If the rule found is the same as 'facet''s current rule, leaves 'facet'
- *     where it is and recompiles its actions anyway. */
+ *     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. */
 static void
 facet_revalidate(struct facet *facet)
 {
@@ -4791,6 +4752,25 @@ facet_revalidate(struct facet *facet)
 
     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 = ofproto_receive(ofproto->backer, NULL, subfacet->key,
+                                subfacet->key_len, &recv_flow, NULL,
+                                &recv_ofproto, NULL, NULL);
+        if (error
+            || recv_ofproto != ofproto
+            || memcmp(&recv_flow, &facet->flow, sizeof recv_flow)) {
+            facet_remove(facet);
+            return;
+        }
+    }
+
     new_rule = rule_dpif_lookup(ofproto, &facet->flow);
 
     /* Calculate new datapath actions.
@@ -4948,17 +4928,14 @@ flow_push_stats(struct rule_dpif *rule,
 
 static struct subfacet *
 subfacet_find(struct ofproto_dpif *ofproto,
-              const struct nlattr *key, size_t key_len, uint32_t key_hash,
-              const struct flow *flow)
+              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,
                              &ofproto->subfacets) {
-        if (subfacet->key
-            ? (subfacet->key_len == key_len
-               && !memcmp(key, subfacet->key, key_len))
-            : flow_equal(flow, &subfacet->facet->flow)) {
+        if (subfacet->key_len == key_len
+            && !memcmp(key, subfacet->key, key_len)) {
             return subfacet;
         }
     }
@@ -4990,8 +4967,7 @@ subfacet_create(struct facet *facet, struct flow_miss *miss,
     if (list_is_empty(&facet->subfacets)) {
         subfacet = &facet->one_subfacet;
     } else {
-        subfacet = subfacet_find(ofproto, key, key_len, key_hash,
-                                 &facet->flow);
+        subfacet = subfacet_find(ofproto, key, key_len, key_hash);
         if (subfacet) {
             if (subfacet->facet == facet) {
                 return subfacet;
@@ -5009,13 +4985,8 @@ subfacet_create(struct facet *facet, struct flow_miss *miss,
     list_push_back(&facet->subfacets, &subfacet->list_node);
     subfacet->facet = facet;
     subfacet->key_fitness = key_fitness;
-    if (key_fitness != ODP_FIT_PERFECT) {
-        subfacet->key = xmemdup(key, key_len);
-        subfacet->key_len = key_len;
-    } else {
-        subfacet->key = NULL;
-        subfacet->key_len = 0;
-    }
+    subfacet->key = xmemdup(key, key_len);
+    subfacet->key_len = key_len;
     subfacet->used = now;
     subfacet->dp_packet_count = 0;
     subfacet->dp_byte_count = 0;
@@ -5068,18 +5039,15 @@ static void
 subfacet_destroy_batch(struct ofproto_dpif *ofproto,
                        struct subfacet **subfacets, int n)
 {
-    struct odputil_keybuf keybufs[SUBFACET_DESTROY_MAX_BATCH];
     struct dpif_op ops[SUBFACET_DESTROY_MAX_BATCH];
     struct dpif_op *opsp[SUBFACET_DESTROY_MAX_BATCH];
-    struct ofpbuf keys[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;
-        subfacet_get_key(subfacets[i], &keybufs[i], &keys[i]);
-        ops[i].u.flow_del.key = keys[i].data;
-        ops[i].u.flow_del.key_len = keys[i].size;
+        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];
     }
@@ -5092,24 +5060,6 @@ subfacet_destroy_batch(struct ofproto_dpif *ofproto,
     }
 }
 
-/* Initializes 'key' with the sequence of OVS_KEY_ATTR_* Netlink attributes
- * that can be used to refer to 'subfacet'.  The caller must provide 'keybuf'
- * for use as temporary storage. */
-static void
-subfacet_get_key(struct subfacet *subfacet, struct odputil_keybuf *keybuf,
-                 struct ofpbuf *key)
-{
-
-    if (!subfacet->key) {
-        struct flow *flow = &subfacet->facet->flow;
-
-        ofpbuf_use_stack(key, keybuf, sizeof *keybuf);
-        odp_flow_key_from_flow(key, flow, subfacet->odp_in_port);
-    } else {
-        ofpbuf_use_const(key, subfacet->key, subfacet->key_len);
-    }
-}
-
 /* Composes the datapath actions for 'subfacet' based on its rule's actions.
  * Translates the actions into 'odp_actions', which the caller must have
  * initialized and is responsible for uninitializing. */
@@ -5158,9 +5108,7 @@ subfacet_install(struct subfacet *subfacet,
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
     enum subfacet_path path = subfacet_want_path(slow);
     uint64_t slow_path_stub[128 / 8];
-    struct odputil_keybuf keybuf;
     enum dpif_flow_put_flags flags;
-    struct ofpbuf key;
     int ret;
 
     flags = DPIF_FP_CREATE | DPIF_FP_MODIFY;
@@ -5174,9 +5122,8 @@ subfacet_install(struct subfacet *subfacet,
                           &actions, &actions_len);
     }
 
-    subfacet_get_key(subfacet, &keybuf, &key);
-    ret = dpif_flow_put(ofproto->backer->dpif, flags, key.data, key.size,
-                        actions, actions_len, stats);
+    ret = dpif_flow_put(ofproto->backer->dpif, flags, subfacet->key,
+                        subfacet->key_len, actions, actions_len, stats);
 
     if (stats) {
         subfacet_reset_dp_stats(subfacet, stats);
@@ -5202,14 +5149,11 @@ subfacet_uninstall(struct subfacet *subfacet)
     if (subfacet->path != SF_NOT_INSTALLED) {
         struct rule_dpif *rule = subfacet->facet->rule;
         struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
-        struct odputil_keybuf keybuf;
         struct dpif_flow_stats stats;
-        struct ofpbuf key;
         int error;
 
-        subfacet_get_key(subfacet, &keybuf, &key);
-        error = dpif_flow_del(ofproto->backer->dpif,
-                              key.data, key.size, &stats);
+        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);
@@ -6098,6 +6042,38 @@ compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
     }
 }
 
+static bool
+execute_set_mpls_ttl_action(struct action_xlate_ctx *ctx, uint8_t ttl)
+{
+    if (!eth_type_mpls(ctx->flow.dl_type)) {
+        return true;
+    }
+
+    set_mpls_lse_ttl(&ctx->flow.mpls_lse, ttl);
+    return false;
+}
+
+static bool
+execute_dec_mpls_ttl_action(struct action_xlate_ctx *ctx)
+{
+    uint8_t ttl = mpls_lse_to_ttl(ctx->flow.mpls_lse);
+
+    if (!eth_type_mpls(ctx->flow.dl_type)) {
+        return false;
+    }
+
+    if (ttl > 0) {
+        ttl--;
+        set_mpls_lse_ttl(&ctx->flow.mpls_lse, ttl);
+        return false;
+    } else {
+        execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0);
+
+        /* Stop processing for current table. */
+        return true;
+    }
+}
+
 static void
 xlate_output_action(struct action_xlate_ctx *ctx,
                     uint16_t port, uint16_t max_len, bool may_packet_in)
@@ -6433,6 +6409,16 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             nxm_execute_reg_load(ofpact_get_REG_LOAD(a), &ctx->flow);
             break;
 
+        case OFPACT_STACK_PUSH:
+            nxm_execute_stack_push(ofpact_get_STACK_PUSH(a), &ctx->flow,
+                                   &ctx->stack);
+            break;
+
+        case OFPACT_STACK_POP:
+            nxm_execute_stack_pop(ofpact_get_STACK_POP(a), &ctx->flow,
+                                  &ctx->stack);
+            break;
+
         case OFPACT_PUSH_MPLS:
             execute_mpls_push_action(ctx, ofpact_get_PUSH_MPLS(a)->ethertype);
             break;
@@ -6441,6 +6427,18 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             execute_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype);
             break;
 
+        case OFPACT_SET_MPLS_TTL:
+            if (execute_set_mpls_ttl_action(ctx, ofpact_get_SET_MPLS_TTL(a)->ttl)) {
+                goto out;
+            }
+            break;
+
+        case OFPACT_DEC_MPLS_TTL:
+            if (execute_dec_mpls_ttl_action(ctx)) {
+                goto out;
+            }
+            break;
+
         case OFPACT_DEC_TTL:
             if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) {
                 goto out;
@@ -6590,6 +6588,8 @@ xlate_actions(struct action_xlate_ctx *ctx,
     ctx->table_id = 0;
     ctx->exit = false;
 
+    ofpbuf_use_stub(&ctx->stack, ctx->init_stack, sizeof ctx->init_stack);
+
     if (ctx->ofproto->has_mirrors || hit_resubmit_limit) {
         /* Do this conditionally because the copy is expensive enough that it
          * shows up in profiles. */
@@ -6674,6 +6674,8 @@ xlate_actions(struct action_xlate_ctx *ctx,
         }
         fix_sflow_action(ctx);
     }
+
+    ofpbuf_uninit(&ctx->stack);
 }
 
 /* Translates the 'ofpacts_len' bytes of "struct ofpact"s starting at 'ofpacts'
@@ -8064,11 +8066,7 @@ ofproto_unixctl_dpif_dump_flows(struct unixctl_conn *conn,
     update_stats(ofproto->backer);
 
     HMAP_FOR_EACH (subfacet, hmap_node, &ofproto->subfacets) {
-        struct odputil_keybuf keybuf;
-        struct ofpbuf key;
-
-        subfacet_get_key(subfacet, &keybuf, &key);
-        odp_flow_key_format(key.data, key.size, &ds);
+        odp_flow_key_format(subfacet->key, subfacet->key_len, &ds);
 
         ds_put_format(&ds, ", packets:%"PRIu64", bytes:%"PRIu64", used:",
                       subfacet->dp_packet_count, subfacet->dp_byte_count);
@@ -8414,10 +8412,7 @@ const struct ofproto_class ofproto_dpif_class = {
     get_netflow_ids,
     set_sflow,
     set_cfm,
-    get_cfm_fault,
-    get_cfm_opup,
-    get_cfm_remote_mpids,
-    get_cfm_health,
+    get_cfm_status,
     set_stp,
     get_stp_status,
     set_stp_port,