Add support for dec_mpls_ttl action
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index a572f18..ea6104a 100644 (file)
@@ -912,13 +912,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);
@@ -3288,7 +3288,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. */
 };
@@ -3378,7 +3377,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;
@@ -3522,7 +3520,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;
@@ -3544,7 +3541,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;
@@ -3850,25 +3848,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);
 }
@@ -4600,6 +4582,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;
@@ -4759,7 +4744,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)
 {
@@ -4780,6 +4768,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.
@@ -6051,6 +6058,27 @@ compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
     }
 }
 
+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)
@@ -6394,6 +6422,12 @@ 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_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;