ofpbuf: Fix trivial spelling typo.
[cascardo/ovs.git] / ofproto / ofproto-dpif-rid.h
index a614a4d..8ada532 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015 Nicira, Inc.
+ * Copyright (c) 2014, 2015, 2016 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include "cmap.h"
 #include "list.h"
 #include "ofp-actions.h"
+#include "ofproto-dpif-mirror.h"
 #include "ovs-thread.h"
+#include "uuid.h"
 
 struct ofproto_dpif;
 struct rule;
 
 /*
- * Recirculation
- * =============
+ * Freezing and recirculation
+ * ==========================
+ *
+ * Freezing is a technique for halting and checkpointing packet translation in
+ * a way that it can be restarted again later.  This file has a couple of data
+ * structures related to freezing in general; their names begin with "frozen".
+ *
+ * Recirculation is the use of freezing to allow a frame to re-enter the
+ * datapath packet processing path to achieve more flexible packet processing,
+ * such as modifying header fields after MPLS POP action and selecting a slave
+ * port for bond ports.
  *
- * Recirculation is a technique to allow a frame to re-enter the datapath
- * packet processing path for one or multiple times to achieve more flexible
- * packet processing, such modifying header fields after MPLS POP action and
- * selecting bond a slave port for bond ports.
  *
  * Data path and user space interface
  * -----------------------------------
  *
  * Recirculation uses two uint32_t fields, recirc_id and dp_hash, and a RECIRC
- * action.  The value recirc_id is used to select the next packet processing
- * steps among multiple instances of recirculation.  When a packet initially
- * enters the data path it is assigned with recirc_id 0, which indicates no
- * recirculation.  Recirc_ids are managed by the user space, opaque to the
- * data path.
- *
- * On the other hand, dp_hash can only be computed by the data path, opaque to
- * the user space.  In fact, user space may not able to recompute the hash
- * value.  The dp_hash value should be wildcarded for a newly received
- * packet.  HASH action specifies whether the hash is computed, and if
- * computed, how many fields are to be included in the hash computation.  The
- * computed hash value is stored into the dp_hash field prior to recirculation.
+ * action.  recirc_id is used to select the next packet processing steps among
+ * multiple instances of recirculation.  When a packet initially enters the
+ * datapath it is assigned with recirc_id 0, which indicates no recirculation.
+ * Recirc_ids are managed by the user space, opaque to the datapath.
+ *
+ * On the other hand, dp_hash can only be computed by the datapath, opaque to
+ * the user space, as the datapath is free to choose the hashing algorithm
+ * without informing user space about it.  The dp_hash value should be
+ * wildcarded for newly received packets.  HASH action specifies whether the
+ * hash is computed, and if computed, how many fields are to be included in the
+ * hash computation.  The computed hash value is stored into the dp_hash field
+ * prior to recirculation.
  *
  * The RECIRC action sets the recirc_id field and then reprocesses the packet
- * as if it was received on the same input port.  RECIRC action works like a
- * function call; actions listed behind the RECIRC action will be executed
- * after its execution.  RECIRC action can be nested, data path implementation
- * limits the number of recirculation executed to prevent unreasonable nesting
- * depth or infinite loop.
+ * as if it was received again on the same input port.  RECIRC action works
+ * like a function call; actions listed after the RECIRC action will be
+ * executed after recirculation.  RECIRC action can be nested, but datapath
+ * implementation limits the number of nested recirculations to prevent
+ * unreasonable nesting depth or infinite loop.
  *
  * User space recirculation context
  * ---------------------------------
  *
- * Recirculation is hidden from the OpenFlow controllers.  Action translation
- * code deduces when recirculation is necessary and issues a data path
- * recirculation action.  All OpenFlow actions to be performed after
+ * Recirculation is usually hidden from the OpenFlow controllers.  Action
+ * translation code deduces when recirculation is necessary and issues a
+ * datapath recirculation action.  All OpenFlow actions to be performed after
  * recirculation are derived from the OpenFlow pipeline and are stored with the
  * recirculation ID.  When the OpenFlow tables are changed in a way affecting
  * the recirculation flows, new recirculation ID with new metadata and actions
@@ -75,9 +82,10 @@ struct rule;
  * Recirculation ID pool
  * ----------------------
  *
- * Recirculation ID needs to be unique for all data paths.  Recirculation ID
- * pool keeps track recirculation ids and stores OpenFlow pipeline translation
- * context so that flow processing may continue after recirculation.
+ * Recirculation ID needs to be unique for all datapaths.  Recirculation ID
+ * pool keeps track of recirculation ids and stores OpenFlow pipeline
+ * translation context so that flow processing may continue after
+ * recirculation.
  *
  * A Recirculation ID can be any uint32_t value, except for that the value 0 is
  * reserved for 'no recirculation' case.
@@ -91,43 +99,66 @@ struct rule;
 /* Metadata for restoring pipeline context after recirculation.  Helpers
  * are inlined below to keep them together with the definition for easier
  * updates. */
-BUILD_ASSERT_DECL(FLOW_WC_SEQ == 33);
+BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
 
-struct recirc_metadata {
+struct frozen_metadata {
     /* Metadata in struct flow. */
-    struct flow_tnl tunnel;       /* Encapsulating tunnel parameters. */
+    const struct flow_tnl *tunnel; /* Encapsulating tunnel parameters. */
     ovs_be64 metadata;            /* OpenFlow Metadata. */
     uint64_t regs[FLOW_N_XREGS];  /* Registers. */
     ofp_port_t in_port;           /* Incoming port. */
-    ofp_port_t actset_output;     /* Output port in action set. */
 };
 
 static inline void
-recirc_metadata_from_flow(struct recirc_metadata *md,
+frozen_metadata_from_flow(struct frozen_metadata *md,
                           const struct flow *flow)
 {
     memset(md, 0, sizeof *md);
-    md->tunnel = flow->tunnel;
+    md->tunnel = &flow->tunnel;
     md->metadata = flow->metadata;
     memcpy(md->regs, flow->regs, sizeof md->regs);
     md->in_port = flow->in_port.ofp_port;
-    md->actset_output = flow->actset_output;
 }
 
 static inline void
-recirc_metadata_to_flow(const struct recirc_metadata *md,
+frozen_metadata_to_flow(const struct frozen_metadata *md,
                         struct flow *flow)
 {
-    flow->tunnel = md->tunnel;
+    if (md->tunnel && flow_tnl_dst_is_set(md->tunnel)) {
+        flow->tunnel = *md->tunnel;
+    } else {
+        memset(&flow->tunnel, 0, sizeof flow->tunnel);
+    }
     flow->metadata = md->metadata;
     memcpy(flow->regs, md->regs, sizeof flow->regs);
     flow->in_port.ofp_port = md->in_port;
-    flow->actset_output = md->actset_output;
 }
 
-/* Pool node fields should NOT be modified after placing the node in the pool.
- */
+/* State that flow translation can save, to restore when translation
+ * resumes.  */
+struct frozen_state {
+    /* Initial table for processing when thawing. */
+    uint8_t table_id;
+
+    /* Pipeline context for processing when thawing. */
+    struct uuid ofproto_uuid;     /* Bridge to resume from. */
+    struct frozen_metadata metadata; /* Flow metadata. */
+    union mf_subvalue *stack;     /* Stack if any. */
+    size_t n_stack;
+    mirror_mask_t mirrors;        /* Mirrors already output. */
+    bool conntracked;             /* Conntrack occurred prior to freeze. */
+
+    /* Actions to be translated when thawing. */
+    struct ofpact *ofpacts;
+    size_t ofpacts_len;           /* Size of 'ofpacts', in bytes. */
+    struct ofpact *action_set;
+    size_t action_set_len;        /* Size of 'action_set', in bytes. */
+};
+
+/* This maps a recirculation ID to saved state that flow translation can
+ * restore when recirculation occurs. */
 struct recirc_id_node {
+    /* Index data. */
     struct ovs_list exp_node OVS_GUARDED;
     struct cmap_node id_node;
     struct cmap_node metadata_node;
@@ -135,19 +166,14 @@ struct recirc_id_node {
     uint32_t hash;
     struct ovs_refcount refcount;
 
-    /* Initial table for post-recirculation processing. */
-    uint8_t table_id;
-
-    /* Pipeline context for post-recirculation processing. */
-    struct ofproto_dpif *ofproto; /* Post-recirculation bridge. */
-    struct recirc_metadata metadata; /* Flow metadata. */
-    struct ofpbuf *stack;         /* Stack if any. */
+    /* Saved state.
+     *
+     * This state should not be modified after inserting a node in the pool,
+     * hence the 'const' to emphasize that. */
+    const struct frozen_state state;
 
-    /* Actions to be translated on recirculation. */
-    uint32_t action_set_len;      /* How much of 'ofpacts' consists of an
-                                   * action set? */
-    uint32_t ofpacts_len;         /* Size of 'ofpacts', in bytes. */
-    struct ofpact ofpacts[];      /* Sequence of "struct ofpacts". */
+    /* Storage for tunnel metadata. */
+    struct flow_tnl state_metadata_tunnel;
 };
 
 void recirc_init(void);
@@ -156,19 +182,19 @@ void recirc_init(void);
  * updated to use this mechanism instead of internal rules. */
 uint32_t recirc_alloc_id(struct ofproto_dpif *);
 
-uint32_t recirc_alloc_id_ctx(struct ofproto_dpif *, uint8_t table_id,
-                             struct recirc_metadata *, struct ofpbuf *stack,
-                             uint32_t action_set_len, uint32_t ofpacts_len,
-                             const struct ofpact *);
-uint32_t recirc_find_id(struct ofproto_dpif *, uint8_t table_id,
-                        struct recirc_metadata *, struct ofpbuf *stack,
-                        uint32_t action_set_len, uint32_t ofpacts_len,
-                        const struct ofpact *);
+uint32_t recirc_alloc_id_ctx(const struct frozen_state *);
+uint32_t recirc_find_id(const struct frozen_state *);
 void recirc_free_id(uint32_t recirc_id);
 void recirc_free_ofproto(struct ofproto_dpif *, const char *ofproto_name);
 
 const struct recirc_id_node *recirc_id_node_find(uint32_t recirc_id);
 
+static inline struct recirc_id_node *
+recirc_id_node_from_state(const struct frozen_state *state)
+{
+    return CONTAINER_OF(state, struct recirc_id_node, state);
+}
+
 static inline bool recirc_id_node_try_ref_rcu(const struct recirc_id_node *n_)
 {
     struct recirc_id_node *node = CONST_CAST(struct recirc_id_node *, n_);
@@ -180,4 +206,67 @@ void recirc_id_node_unref(const struct recirc_id_node *);
 
 void recirc_run(void);
 
+/* Recirculation IDs on which references are held. */
+struct recirc_refs {
+    unsigned n_recircs;
+    union {
+        uint32_t recirc[2];   /* When n_recircs == 1 or 2 */
+        uint32_t *recircs;    /* When 'n_recircs' > 2 */
+    };
+};
+
+#define RECIRC_REFS_EMPTY_INITIALIZER ((struct recirc_refs) \
+                                       { 0, { { 0, 0 } } })
+/* Helpers to abstract the recirculation union away. */
+static inline void
+recirc_refs_init(struct recirc_refs *rr)
+{
+    *rr = RECIRC_REFS_EMPTY_INITIALIZER;
+}
+
+static inline void
+recirc_refs_add(struct recirc_refs *rr, uint32_t id)
+{
+    if (OVS_LIKELY(rr->n_recircs < ARRAY_SIZE(rr->recirc))) {
+        rr->recirc[rr->n_recircs++] = id;
+    } else {
+        if (rr->n_recircs == ARRAY_SIZE(rr->recirc)) {
+            uint32_t *recircs = xmalloc(sizeof rr->recirc + sizeof id);
+
+            memcpy(recircs, rr->recirc, sizeof rr->recirc);
+            rr->recircs = recircs;
+        } else {
+            rr->recircs = xrealloc(rr->recircs,
+                                   (rr->n_recircs + 1) * sizeof id);
+        }
+        rr->recircs[rr->n_recircs++] = id;
+    }
+}
+
+static inline void
+recirc_refs_swap(struct recirc_refs *a, struct recirc_refs *b)
+{
+    struct recirc_refs tmp;
+
+    tmp = *a;
+    *a = *b;
+    *b = tmp;
+}
+
+static inline void
+recirc_refs_unref(struct recirc_refs *rr)
+{
+    if (OVS_LIKELY(rr->n_recircs <= ARRAY_SIZE(rr->recirc))) {
+        for (int i = 0; i < rr->n_recircs; i++) {
+            recirc_free_id(rr->recirc[i]);
+        }
+    } else {
+        for (int i = 0; i < rr->n_recircs; i++) {
+            recirc_free_id(rr->recircs[i]);
+        }
+        free(rr->recircs);
+    }
+    rr->n_recircs = 0;
+}
+
 #endif