Patchwork [3/4] Allow recirculation without facets

login
register
mail settings
Submitter Simon Horman
Date April 8, 2013, 6:43 a.m.
Message ID <1365403431-18102-4-git-send-email-horms@verge.net.au>
Download mbox | patch
Permalink /patch/234586/
State Not Applicable
Delegated to: David Miller
Headers show

Comments

Simon Horman - April 8, 2013, 6:43 a.m.
This covers the following cases:

* Handle flow miss without facet
  - Previously the use of facets was forced if there was
    any chance of a recirculation action. That is, for
    all flows misses of MPLS packets.
* Packet Out

Signed-off-by: Simon Horman <horms@verge.net.au>

---

This patch depends on the patch "Move execute_set_action to lib/odp-util.c"

v5
* Use RECIRCULATION_ID_DUMMY

rfc4
* Initial post
---
 ofproto/ofproto-dpif.c |  132 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 111 insertions(+), 21 deletions(-)

Patch

diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 5129da1..67121f2 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -3571,6 +3571,64 @@  flow_miss_find(struct hmap *todo, const struct ofproto_dpif *ofproto,
     return NULL;
 }
 
+static void
+execute_actions_for_recircualtion(struct ofpbuf *packet,
+                                  const struct nlattr *actions,
+                                  size_t actions_len, uint32_t *skb_mark)
+{
+    const struct nlattr *a;
+    unsigned int left;
+
+    NL_ATTR_FOR_EACH_UNSAFE (a, left, actions, actions_len) {
+        int type = nl_attr_type(a);
+
+        switch ((enum ovs_action_attr) type) {
+
+        case OVS_ACTION_ATTR_PUSH_VLAN: {
+            const struct ovs_action_push_vlan *vlan = nl_attr_get(a);
+            eth_push_vlan(packet, vlan->vlan_tci);
+            break;
+        }
+
+        case OVS_ACTION_ATTR_POP_VLAN:
+            eth_pop_vlan(packet);
+            break;
+
+        case OVS_ACTION_ATTR_PUSH_MPLS: {
+            const struct ovs_action_push_mpls *mpls = nl_attr_get(a);
+            push_mpls(packet, mpls->mpls_ethertype, mpls->mpls_lse);
+            break;
+         }
+
+        case OVS_ACTION_ATTR_POP_MPLS:
+            pop_mpls(packet, nl_attr_get_be16(a));
+            break;
+
+        case OVS_ACTION_ATTR_SET:
+            execute_set_action(packet, nl_attr_get(a), skb_mark);
+            break;
+
+        case OVS_ACTION_ATTR_RECIRCULATE:
+            if (packet->l2) {
+                ofpbuf_push_uninit(packet, (char *)packet->l2 -
+                                   (char *)packet->data);
+            }
+            return;
+
+        case OVS_ACTION_ATTR_OUTPUT:
+        case OVS_ACTION_ATTR_USERSPACE:
+        case OVS_ACTION_ATTR_SAMPLE:
+        case OVS_ACTION_ATTR_UNSPEC:
+        case __OVS_ACTION_ATTR_MAX:
+            NOT_REACHED();
+        }
+    }
+
+    /* There should always be a OVS_ACTION_ATTR_RECIRCULATE present
+     * in actions if this function is called */
+    NOT_REACHED();
+}
+
 /* Partially Initializes 'op' as an "execute" operation for 'miss' and
  * 'packet'.  The caller must initialize op->actions and op->actions_len.  If
  * 'miss' is associated with a subfacet the caller must also initialize the
@@ -3632,15 +3690,6 @@  static bool
 flow_miss_should_make_facet(struct ofproto_dpif *ofproto,
                             struct flow_miss *miss, uint32_t hash)
 {
-    /* A facet is currently required to handle recirculation.
-     * There currently isn't a good way to detect if recirculation will
-     * occur or not. So in the mean time assume that it can't occur
-     * for non-MPLS packets and it may occur for MPLS packets
-     */
-    if (eth_type_mpls(miss->flow.dl_type)) {
-        return true;
-    }
-
     if (!ofproto->governor) {
         size_t n_subfacets;
 
@@ -3656,6 +3705,50 @@  flow_miss_should_make_facet(struct ofproto_dpif *ofproto,
                                         list_size(&miss->packets));
 }
 
+static const struct flow *
+xlate_with_recirculate(struct ofproto_dpif *ofproto, struct rule_dpif *rule,
+                       const struct flow *flow, struct flow *flow_storage,
+                       const struct initial_vals *initial_vals,
+                       const struct ofpact *ofpacts, size_t ofpacts_len,
+                       struct ofpbuf *odp_actions,
+                       struct dpif_flow_stats *stats, struct ofpbuf *packet)
+{
+    struct initial_vals initial_vals_ = *initial_vals;
+
+    while (1) {
+        struct action_xlate_ctx ctx;
+        uint32_t skb_mark = flow->skb_mark;
+
+        ofpbuf_clear(odp_actions);
+        action_xlate_ctx_init(&ctx, ofproto, flow, &initial_vals_,
+                              rule, stats->tcp_flags, packet,
+                              RECIRCULATION_ID_DUMMY);
+        ctx.resubmit_stats = stats;
+        xlate_actions(&ctx, ofpacts, ofpacts_len, odp_actions);
+
+        if (!ctx.recircualted) {
+            break;
+        }
+
+        /* Update the packet */
+        execute_actions_for_recircualtion(packet, odp_actions->data,
+                                          odp_actions->size, &skb_mark);
+        ofpbuf_clear(odp_actions);
+
+        /* Replace the flow */
+        flow_extract(packet, flow->skb_priority, skb_mark,
+                     NULL, flow->in_port, flow_storage);
+        flow = flow_storage;
+        initial_vals_.vlan_tci = flow->vlan_tci;
+        initial_vals_.tunnel_ip_tos = flow->tunnel.ip_tos;
+
+        ofpacts = ofpact_end(ofpacts, ctx.ofpacts_len);
+        ofpacts_len -= ctx.ofpacts_len;
+    }
+
+    return flow;
+}
+
 /* 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'. */
@@ -3666,8 +3759,8 @@  handle_flow_miss_without_facet(struct flow_miss *miss, struct rule_dpif *rule,
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
     long long int now = time_msec();
-    struct action_xlate_ctx ctx;
     struct ofpbuf *packet;
+    struct flow flow_storage;
 
     LIST_FOR_EACH (packet, list_node, &miss->packets) {
         struct flow_miss_op *op = &ops[*n_ops];
@@ -3681,11 +3774,9 @@  handle_flow_miss_without_facet(struct flow_miss *miss, struct rule_dpif *rule,
         dpif_flow_stats_extract(&miss->flow, packet, now, &stats);
         rule_credit_stats(rule, &stats);
 
-        action_xlate_ctx_init(&ctx, ofproto, &miss->flow,
-                              &miss->initial_vals, rule, 0, packet,
-                              RECIRCULATION_ID_DUMMY);
-        ctx.resubmit_stats = &stats;
-        xlate_actions(&ctx, ofpacts, ofpacts_len, &odp_actions);
+        xlate_with_recirculate(ofproto, rule, &miss->flow, &flow_storage,
+                               &miss->initial_vals, ofpacts, ofpacts_len,
+                               &odp_actions, &stats, packet);
 
         if (odp_actions.size) {
             struct dpif_execute *execute = &op->dpif_op.u.execute;
@@ -7937,10 +8028,10 @@  packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
     struct initial_vals initial_vals;
     struct odputil_keybuf keybuf;
     struct dpif_flow_stats stats;
+    struct flow flow_storage;
 
     struct ofpbuf key;
 
-    struct action_xlate_ctx ctx;
     uint64_t odp_actions_stub[1024 / 8];
     struct ofpbuf odp_actions;
 
@@ -7952,14 +8043,13 @@  packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
 
     initial_vals.vlan_tci = flow->vlan_tci;
     initial_vals.tunnel_ip_tos = 0;
-    action_xlate_ctx_init(&ctx, ofproto, flow, &initial_vals, NULL,
-                          packet_get_tcp_flags(packet, flow), packet,
-                          RECIRCULATION_ID_DUMMY);
-    ctx.resubmit_stats = &stats;
 
     ofpbuf_use_stub(&odp_actions,
                     odp_actions_stub, sizeof odp_actions_stub);
-    xlate_actions(&ctx, ofpacts, ofpacts_len, &odp_actions);
+    flow = xlate_with_recirculate(ofproto, NULL, flow, &flow_storage,
+                                  &initial_vals, ofpacts, ofpacts_len,
+                                  &odp_actions, &stats, packet);
+
     dpif_execute(ofproto->backer->dpif, key.data, key.size,
                  odp_actions.data, odp_actions.size, packet);
     ofpbuf_uninit(&odp_actions);