[ovs-dev] [PATCH 19/19] ofproto: Allow actions richer maches based on actions

Simon Horman horms at verge.net.au
Mon Dec 24 02:35:25 UTC 2012


If the actions of a flow allow further decoding of L3 and L4 data to
provide a richer match then use this richer match.

For example:

In the case of MPLS, L3 and L4 information may not initially be decoded
from the frame as the ethernet type of the frame is an MPLS type and no
information is known about the type of the inner frame.

However, the type of the inner frame may be provided by an mpls_pop action
in which case L3 and L4 information may be decoded providing a finer
grained match than is otherwise possible.

Signed-off-by: Simon Horman <horms at verge.net.au>
---
 ofproto/ofproto-dpif.c |  119 +++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 112 insertions(+), 7 deletions(-)

diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 3ba76f4..0e931dd 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -399,7 +399,8 @@ static void subfacet_update_stats(struct subfacet *,
                                   const struct dpif_flow_stats *);
 static void subfacet_make_actions(struct subfacet *,
                                   const struct ofpbuf *packet,
-                                  struct ofpbuf *odp_actions);
+                                  struct ofpbuf *odp_actions,
+                                  const struct flow *flow);
 static int subfacet_install(struct subfacet *,
                             const struct nlattr *actions, size_t actions_len,
                             struct dpif_flow_stats *, enum slow_path_reason);
@@ -3083,12 +3084,14 @@ struct flow_miss {
     struct list packets;
     enum dpif_upcall_type upcall_type;
     uint32_t odp_in_port;
+    bool singleton;
 };
 
 struct flow_miss_op {
     struct dpif_op dpif_op;
     struct subfacet *subfacet;  /* Subfacet  */
     void *garbage;              /* Pointer to pass to free(), NULL if none. */
+    void *garbage2;              /* Pointer to pass to free(), NULL if none. */
     uint64_t stub[1024 / 8];    /* Temporary buffer. */
 };
 
@@ -3146,6 +3149,20 @@ process_special(struct ofproto_dpif *ofproto, const struct flow *flow,
     return 0;
 }
 
+static bool flow_miss_is_singleton(const struct flow *flow)
+{
+    /* The decoding of the L3 and L4 components of an MPLS frame
+     * may only occur if there is a pop_mpls action present in
+     * which case the ethernet type of the internel frame becomes
+     * known. For this reason the decoding of the L3 and L4
+     * components of an MPLS frame is delayed and the match is
+     * at this point incomplete. Treat it as a singleton to
+     * avoid a single miss covering multiple flows
+     */
+    return flow->dl_type == htons(ETH_TYPE_MPLS) ||
+           flow->dl_type == htons(ETH_TYPE_MPLS_MCAST);
+}
+
 static struct flow_miss *
 flow_miss_find(struct hmap *todo, const struct flow *flow, uint32_t hash)
 {
@@ -3237,6 +3254,40 @@ flow_miss_should_make_facet(struct ofproto_dpif *ofproto,
                                         list_size(&miss->packets));
 }
 
+static ovs_be16
+handle_flow_miss_l3_extraction(struct flow_miss *miss,
+                               struct rule_dpif *rule,
+                               struct ofpbuf *packet,
+                               struct flow **flowp,
+                               struct ofpbuf *inner_key)
+{
+    struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
+    ovs_be16 encap_dl_type;
+    struct flow *inner_flow;
+
+    encap_dl_type = actions_allow_l3_extraction(rule->up.ofpacts,
+                                                rule->up.ofpacts_len);
+    if (!encap_dl_type) {
+        return encap_dl_type;
+    }
+
+    assert(miss->singleton);
+
+    inner_flow = xmemdup(*flowp, sizeof **flowp);
+    inner_flow->encap_dl_type = encap_dl_type;
+    flow_extract_l3_onwards(packet, inner_flow);
+
+    ofpbuf_reinit(inner_key, 128);
+    odp_flow_key_from_flow(inner_key, inner_flow,
+                            ofp_port_to_odp_port(ofproto, inner_flow->in_port),
+                            encap_dl_type);
+    miss->key = inner_key->data;
+    miss->key_len = inner_key->size;
+
+    *flowp = inner_flow;
+    return encap_dl_type;
+}
+
 /* Handles 'miss', which matches 'rule', without creating a facet or subfacet
  * or creating any datapath flow.  May add an "execute" operation to 'ops' and
  * increment '*n_ops'. */
@@ -3254,20 +3305,32 @@ handle_flow_miss_without_facet(struct flow_miss *miss,
         struct flow_miss_op *op = &ops[*n_ops];
         struct dpif_flow_stats stats;
         struct ofpbuf odp_actions;
+        struct flow *flow = &miss->flow;
+        struct ofpbuf inner_key;
+        __be16 encap_dl_type;
 
         COVERAGE_INC(facet_suppress);
 
         ofpbuf_use_stub(&odp_actions, op->stub, sizeof op->stub);
+        ofpbuf_init(&inner_key, 0);
 
         dpif_flow_stats_extract(&miss->flow, packet, now, &stats);
         rule_credit_stats(rule, &stats);
 
-        action_xlate_ctx_init(&ctx, ofproto, &miss->flow, miss->initial_tci,
+        encap_dl_type = handle_flow_miss_l3_extraction(miss, rule,
+                                                       packet, &flow,
+                                                       &inner_key);
+
+        action_xlate_ctx_init(&ctx, ofproto, flow, miss->initial_tci,
                               rule, 0, packet);
         ctx.resubmit_stats = &stats;
         xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len,
                       &odp_actions);
 
+        if (encap_dl_type) {
+            free(flow);
+        }
+
         if (odp_actions.size) {
             struct dpif_execute *execute = &op->dpif_op.u.execute;
 
@@ -3275,10 +3338,12 @@ handle_flow_miss_without_facet(struct flow_miss *miss,
             execute->actions = odp_actions.data;
             execute->actions_len = odp_actions.size;
             op->garbage = ofpbuf_get_uninit_pointer(&odp_actions);
+            op->garbage2 = ofpbuf_get_uninit_pointer(&inner_key);
 
             (*n_ops)++;
         } else {
             ofpbuf_uninit(&odp_actions);
+            ofpbuf_uninit(&inner_key);
         }
     }
 }
@@ -3301,8 +3366,13 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
     enum subfacet_path want_path;
     struct subfacet *subfacet;
     struct ofpbuf *packet;
+    struct ofpbuf inner_key;
+    ovs_be16 encap_dl_type = htons(0);
+    struct flow *flow = &facet->flow;
+    size_t base_op = *n_ops;
 
     subfacet = subfacet_create(facet, miss, now);
+    ofpbuf_init(&inner_key, 0);
 
     LIST_FOR_EACH (packet, list_node, &miss->packets) {
         struct flow_miss_op *op = &ops[*n_ops];
@@ -3311,14 +3381,30 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
 
         handle_flow_miss_common(facet->rule, packet, &miss->flow);
 
+        encap_dl_type = handle_flow_miss_l3_extraction(miss, facet->rule,
+                                                       packet, &flow,
+                                                       &inner_key);
+        if (encap_dl_type) {
+            struct facet *inner_facet;
+            uint32_t inner_hash;
+
+            inner_hash = flow_hash(flow, 0);
+            inner_facet = facet_create(facet->rule, flow, inner_hash);
+            facet = inner_facet;
+        }
+
         ofpbuf_use_stub(&odp_actions, op->stub, sizeof op->stub);
         if (!subfacet->actions || subfacet->slow) {
-            subfacet_make_actions(subfacet, packet, &odp_actions);
+            subfacet_make_actions(subfacet, packet, &odp_actions, flow);
         }
 
-        dpif_flow_stats_extract(&facet->flow, packet, now, &stats);
+        dpif_flow_stats_extract(flow, packet, now, &stats);
         subfacet_update_stats(subfacet, &stats);
 
+        if (encap_dl_type) {
+            free(flow);
+        }
+
         if (subfacet->actions_len) {
             struct dpif_execute *execute = &op->dpif_op.u.execute;
 
@@ -3333,6 +3419,7 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
                 execute->actions_len = odp_actions.size;
                 op->garbage = ofpbuf_get_uninit_pointer(&odp_actions);
             }
+            op->garbage2 = NULL;
 
             (*n_ops)++;
         } else {
@@ -3346,7 +3433,7 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
         struct dpif_flow_put *put = &op->dpif_op.u.flow_put;
 
         op->subfacet = subfacet;
-        op->garbage = NULL;
+        op->garbage = op->garbage2 = NULL;
         op->dpif_op.type = DPIF_OP_FLOW_PUT;
         put->flags = DPIF_FP_CREATE | DPIF_FP_MODIFY;
         put->key = miss->key;
@@ -3361,6 +3448,14 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
         }
         put->stats = NULL;
     }
+
+    if (base_op != *n_ops) {
+        struct flow_miss_op *op = &ops[(*n_ops) - 1];
+        op->garbage2 = ofpbuf_get_uninit_pointer(&inner_key);
+    } else {
+        ofpbuf_uninit(&inner_key);
+    }
+
 }
 
 /* Handles flow miss 'miss'.  May add any required datapath operations
@@ -3518,6 +3613,7 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
             miss->key_len = upcall->key_len;
             miss->upcall_type = upcall->type;
             miss->odp_in_port = odp_in_port;
+            miss->singleton = flow_miss_is_singleton(&miss->flow);
             list_init(&miss->packets);
 
             n_misses++;
@@ -3560,6 +3656,7 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
         }
 
         free(op->garbage);
+        free(op->garbage2);
     }
     hmap_destroy(&todo);
 }
@@ -4419,6 +4516,14 @@ facet_check_consistency(struct facet *facet)
             continue;
         }
 
+        if (actions_allow_l3_extraction(facet->rule->up.ofpacts,
+                                        facet->rule->up.ofpacts_len)) {
+            /* The actions for flows that depend on actions for evaluation
+             * may legitimately vary from one packet to the next.
+             * We're done. */
+            continue;
+        }
+
         if (!subfacet_should_install(subfacet, subfacet->slow, &odp_actions)) {
             continue;
         }
@@ -4819,7 +4924,7 @@ subfacet_get_key(struct subfacet *subfacet, struct odputil_keybuf *keybuf,
  * initialized and is responsible for uninitializing. */
 static void
 subfacet_make_actions(struct subfacet *subfacet, const struct ofpbuf *packet,
-                      struct ofpbuf *odp_actions)
+                      struct ofpbuf *odp_actions, const struct flow *flow)
 {
     struct facet *facet = subfacet->facet;
     struct rule_dpif *rule = facet->rule;
@@ -4827,7 +4932,7 @@ subfacet_make_actions(struct subfacet *subfacet, const struct ofpbuf *packet,
 
     struct action_xlate_ctx ctx;
 
-    action_xlate_ctx_init(&ctx, ofproto, &facet->flow, subfacet->initial_tci,
+    action_xlate_ctx_init(&ctx, ofproto, flow, subfacet->initial_tci,
                           rule, 0, packet);
     xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len, odp_actions);
     facet->tags = ctx.tags;
-- 
1.7.10.4




More information about the dev mailing list