[ovs-dev] [PATCH] Add Nicira vendor extension actions NXAST_STACK_PUSH/POP

Andy Zhou azhou at nicira.com
Wed Feb 27 03:01:13 UTC 2013


nicira-ext: Add Nicira actions NXAST_STACK_PUSH and NXAST_STACK_POP.

The Push action takes a single parameter. Any source allowed by NXAST_REG_MOVE
is allowed to be pushed onto the stack. When the source is a bit field,  
its value will be right shifted to bit zero before being pushed onto the 
stack. The remaining bits will be set to zero.

The Pop action also takes a single parameter. Any destination allowed by
NXAST_REG_MOVE can be used as the destination of the action. The value, in
case of a bit field, will be taken from top of the stack, starting from
bit zero.

The stack size is not limited. The initial 8KB is statically allocated to 
efficiently handle most common use cases. When more stack space is 
required, the stack can grow using malloc(). 

Each stack element is big enough to store the value of any meta flow field.

Feature: #13861

Signed-off-by: azhou at nicira.com
---
 NEWS                          |    2 +
 include/openflow/nicira-ext.h |   16 ++++
 lib/nx-match.c                |  182 +++++++++++++++++++++++++++++++++++++++++
 lib/nx-match.h                |   28 +++++++
 lib/ofp-actions.c             |   38 +++++++++
 lib/ofp-actions.h             |   18 ++++
 lib/ofp-parse.c               |    6 ++
 lib/ofp-util.def              |    2 +
 ofproto/ofproto-dpif.c        |   36 ++++++++
 tests/ofproto-dpif.at         |   21 +++++
 tests/ovs-ofctl.at            |    2 +
 utilities/ovs-ofctl.8.in      |   14 ++++
 12 files changed, 365 insertions(+)

diff --git a/NEWS b/NEWS
index 35b9212..222f240 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,8 @@ post-v1.10.0
     - New support for the data encapsulation format of the LISP tunnel
       protocol (RFC 6830).  An external control plane or manual flow
       setup is required for EID-to-RLOC mapping.
+    - New "stack" extension for use in actions, to push and pop
+      from NXM fields.
 
 
 v1.10.0 - xx xxx xxxx
diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index c4ff904..607f9d9 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -306,6 +306,8 @@ enum nx_action_subtype {
     NXAST_WRITE_METADATA,       /* struct nx_action_write_metadata */
     NXAST_PUSH_MPLS,            /* struct nx_action_push_mpls */
     NXAST_POP_MPLS,             /* struct nx_action_pop_mpls */
+    NXAST_STACK_PUSH,           /* struct nx_action_stack */
+    NXAST_STACK_POP,            /* struct nx_action_stack */
 };
 
 /* Header for Nicira-defined actions. */
@@ -560,6 +562,20 @@ struct nx_action_reg_load {
 };
 OFP_ASSERT(sizeof(struct nx_action_reg_load) == 24);
 
+/* Action structure for NXAST_STACK_PUSH.
+ *
+ * Pushes value[ofs:ofs+n_bits] onto the top of the stack.
+ */
+struct nx_action_stack{
+    ovs_be16 type;                  /* OFPAT_VENDOR. */
+    ovs_be16 len;                   /* Length is 16. */
+    ovs_be32 vendor;                /* NX_VENDOR_ID. */
+    ovs_be16 subtype;               /* NXAST_REG_PUSH or NXAST_REG_POP. */
+    ovs_be16 ofs_nbits;             /* (ofs << 6) | (n_bits - 1). */
+    ovs_be32 reg;                   /* The register used for push or pop. */
+};
+OFP_ASSERT(sizeof(struct nx_action_stack) == 16);
+
 /* Action structure for NXAST_NOTE.
  *
  * This action has no effect.  It is variable length.  The switch does not
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 4ff516e..7b60bc8 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -1315,3 +1315,185 @@ nxm_reg_load(const struct mf_subfield *dst, uint64_t src_data,
                  sizeof src_data_be * 8);
     mf_write_subfield_flow(dst, &src_subvalue, flow);
 }
+
+/* nxm_parse_stack_push(), nxm_parse_stack_pop(). */
+void
+nxm_parse_stack_push(struct ofpact_stack_push *push, const char *s)
+{
+    s = mf_parse_subfield(&push->src, s);
+    if (*s != '\0') {
+        ovs_fatal(0, "%s: trailing garbage following push source", s);
+    }
+}
+
+void
+nxm_parse_stack_pop(struct ofpact_stack_pop *pop, const char *s)
+{
+    s = mf_parse_subfield(&pop->dst, s);
+    if (*s != '\0') {
+        ovs_fatal(0, "%s: trailing garbage following pop destination", s);
+    }
+}
+
+void
+nxm_format_stack_push(const struct ofpact_stack_push *push, struct ds *s)
+{
+    ds_put_cstr(s, "push:");
+    mf_format_subfield(&push->src, s);
+}
+
+void
+nxm_format_stack_pop(const struct ofpact_stack_pop *pop, struct ds *s)
+{
+    ds_put_cstr(s, "pop:");
+    mf_format_subfield(&pop->dst, s);
+}
+
+enum ofperr
+nxm_stack_push_from_openflow(const struct nx_action_stack *nasp,
+                             struct ofpbuf *ofpacts)
+{
+    struct ofpact_stack_push *push;
+
+    push = ofpact_put_STACK_PUSH(ofpacts);
+    push->src.field = mf_from_nxm_header(ntohl(nasp->reg));
+    push->src.ofs = nxm_decode_ofs(nasp->ofs_nbits);
+    push->src.n_bits = nxm_decode_n_bits(nasp->ofs_nbits);
+
+    return nxm_stack_push_check(push, NULL);
+}
+
+enum ofperr
+nxm_stack_pop_from_openflow(const struct nx_action_stack *nasp,
+                            struct ofpbuf *ofpacts)
+{
+    struct ofpact_stack_pop *pop;
+
+    pop = ofpact_put_STACK_POP(ofpacts);
+    pop->dst.field = mf_from_nxm_header(ntohl(nasp->reg));
+    pop->dst.ofs = nxm_decode_ofs(nasp->ofs_nbits);
+    pop->dst.n_bits = nxm_decode_n_bits(nasp->ofs_nbits);
+
+    return nxm_stack_pop_check(pop, NULL);
+}
+
+enum ofperr
+nxm_stack_push_check(const struct ofpact_stack_push *push,
+                     const struct flow *flow)
+{
+    return mf_check_src(&push->src, flow);
+}
+
+enum ofperr
+nxm_stack_pop_check(const struct ofpact_stack_pop *pop,
+                    const struct flow *flow)
+{
+    return mf_check_dst(&pop->dst, flow);
+}
+
+void
+nxm_stack_push_to_nxast(const struct ofpact_stack_push *push,
+                        struct ofpbuf *openflow)
+{
+    struct nx_action_stack *nasp;
+
+    nasp = ofputil_put_NXAST_STACK_PUSH(openflow);
+    nasp->ofs_nbits = nxm_encode_ofs_nbits(push->src.ofs, push->src.n_bits);
+    nasp->reg = htonl(push->src.field->nxm_header);
+}
+
+void
+nxm_stack_pop_to_nxast(const struct ofpact_stack_pop *pop,
+                      struct ofpbuf *openflow)
+{
+    struct nx_action_stack *nasp;
+
+    nasp = ofputil_put_NXAST_STACK_POP(openflow);
+    nasp->ofs_nbits = nxm_encode_ofs_nbits(pop->dst.ofs, pop->dst.n_bits);
+    nasp->reg = htonl(pop->dst.field->nxm_header);
+}
+
+/* nxm_execute_stack_push(), nxm_execute_stack_pop(). */
+static void
+nx_stack_push(struct ofpbuf* stack, union mf_value * v)
+{
+    /* Assume we have infinitely deep stack.  ofpbuf will dynamically
+       allocate memory to grow the stack if necessary */
+    ofpbuf_put(stack, v, sizeof *v);
+}
+
+static union mf_value*
+nx_stack_pop(struct ofpbuf* stack)
+{
+    union mf_value* v =  NULL;
+    if (stack->size) {
+        stack -> size -= sizeof *v;
+        v = (union mf_value*)((char*)stack->data + stack->size);
+    }
+
+    return v;
+}
+
+void
+nxm_execute_stack_push(const struct ofpact_stack_push *push,
+                       const struct flow *flow, struct ofpbuf *stack)
+{
+    union mf_value src_value;
+    union mf_value dst_value;
+
+    if (stack == NULL) {
+         char* flow_str = NULL;
+         flow_str = flow_to_string(flow);
+         VLOG_WARN_RL(&rl, "Push into a NULL stack. On flow \n"
+                           " %s", flow_str);
+         free(flow_str);
+         return;
+    }
+
+    mf_get_value(push->src.field, flow, &src_value);
+    memset(&dst_value, 0, sizeof dst_value);
+
+    /* Copy into the lower order bits. */
+    bitwise_copy(&src_value, push->src.field->n_bytes, push->src.ofs,
+                 &dst_value, sizeof dst_value, 0, push->src.n_bits);
+
+    /* Push onto the stack */
+    nx_stack_push(stack, &dst_value);
+}
+
+void
+nxm_execute_stack_pop(const struct ofpact_stack_pop *pop,
+                      struct flow *flow, struct ofpbuf *stack )
+{
+    /* Only pop if stack is not empty.  */
+    union mf_value* src_value;
+
+    if (stack == NULL) {
+         char* flow_str = NULL;
+         flow_str = flow_to_string(flow);
+         VLOG_WARN_RL(&rl, "Pop from a NULL stack. On flow \n"
+                           " %s", flow_str);
+         free(flow_str);
+         return;
+    }
+
+    src_value =  nx_stack_pop(stack);
+
+    if (src_value) {
+        union mf_value dst_value;
+
+         mf_get_value(pop->dst.field, flow, &dst_value);
+         /* Each stack element is uint32_t */
+         bitwise_copy(src_value, sizeof *src_value, 0,
+                 &dst_value, pop->dst.field->n_bytes, pop->dst.ofs,
+                 pop->dst.n_bits);
+
+         mf_set_flow_value(pop->dst.field, &dst_value, flow);
+    } else {
+         char* flow_str = NULL;
+         flow_str = flow_to_string(flow);
+         VLOG_WARN_RL(&rl, "Failed to pop from an empty stack. On flow \n"
+                           " %s", flow_str);
+         free(flow_str);
+    }
+}
diff --git a/lib/nx-match.h b/lib/nx-match.h
index 6a57297..b8c9b97 100644
--- a/lib/nx-match.h
+++ b/lib/nx-match.h
@@ -29,10 +29,13 @@ struct match;
 struct mf_subfield;
 struct ofpact_reg_move;
 struct ofpact_reg_load;
+struct ofpact_stack_push;
+struct ofpact_stack_pop;
 struct ofpbuf;
 struct nx_action_reg_load;
 struct nx_action_reg_move;
 
+
 /* Nicira Extended Match (NXM) flexible flow match helper functions.
  *
  * See include/openflow/nicira-ext.h for NXM specification.
@@ -83,6 +86,31 @@ void nxm_execute_reg_load(const struct ofpact_reg_load *, struct flow *);
 void nxm_reg_load(const struct mf_subfield *, uint64_t src_data,
                   struct flow *);
 
+void nxm_parse_stack_push(struct ofpact_stack_push *, const char *);
+void nxm_parse_stack_pop(struct ofpact_stack_pop *, const char *);
+
+void nxm_format_stack_push(const struct ofpact_stack_push *, struct ds *);
+void nxm_format_stack_pop(const struct ofpact_stack_pop *, struct ds *);
+
+enum ofperr nxm_stack_push_from_openflow(const struct nx_action_stack *,
+                                       struct ofpbuf *ofpacts);
+enum ofperr nxm_stack_pop_from_openflow(const struct nx_action_stack *,
+                                       struct ofpbuf *ofpacts);
+enum ofperr nxm_stack_push_check(const struct ofpact_stack_push *,
+                                 const  struct flow *);
+enum ofperr nxm_stack_pop_check(const struct ofpact_stack_pop *,
+                               const struct flow *);
+
+void nxm_stack_push_to_nxast(const struct ofpact_stack_push *,
+                           struct ofpbuf *openflow);
+void nxm_stack_pop_to_nxast(const struct ofpact_stack_pop *,
+                           struct ofpbuf *openflow);
+
+void nxm_execute_stack_push(const struct ofpact_stack_push *,
+                            const struct flow*, struct ofpbuf *);
+void nxm_execute_stack_pop(const struct ofpact_stack_pop *,
+                            struct flow*, struct ofpbuf *);
+
 int nxm_field_bytes(uint32_t header);
 int nxm_field_bits(uint32_t header);
 
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index d6fc429..d48b76e 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -339,6 +339,16 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
             (const struct nx_action_reg_load *) a, out);
         break;
 
+    case OFPUTIL_NXAST_STACK_PUSH:
+        error = nxm_stack_push_from_openflow(
+            (const struct nx_action_stack *) a, out);
+        break;
+
+    case OFPUTIL_NXAST_STACK_POP:
+        error = nxm_stack_pop_from_openflow(
+            (const struct nx_action_stack *) a, out);
+        break;
+
     case OFPUTIL_NXAST_NOTE:
         nan = (const struct nx_action_note *) a;
         note_from_openflow(nan, out);
@@ -1135,6 +1145,12 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports,
             return nxm_reg_load_check(ofpact_get_REG_LOAD(a), flow);
         }
 
+    case OFPACT_STACK_PUSH:
+            return nxm_stack_push_check(ofpact_get_STACK_PUSH(a), flow);
+
+    case OFPACT_STACK_POP:
+            return nxm_stack_pop_check(ofpact_get_STACK_POP(a), flow);
+
     case OFPACT_DEC_TTL:
     case OFPACT_SET_TUNNEL:
     case OFPACT_SET_QUEUE:
@@ -1379,6 +1395,14 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         nxm_reg_load_to_nxast(ofpact_get_REG_LOAD(a), out);
         break;
 
+    case OFPACT_STACK_PUSH:
+        nxm_stack_push_to_nxast(ofpact_get_STACK_PUSH(a), out);
+        break;
+
+    case OFPACT_STACK_POP:
+        nxm_stack_pop_to_nxast(ofpact_get_STACK_POP(a), out);
+        break;
+
     case OFPACT_DEC_TTL:
         ofpact_dec_ttl_to_nxast(ofpact_get_DEC_TTL(a), out);
         break;
@@ -1549,6 +1573,8 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_BUNDLE:
     case OFPACT_REG_MOVE:
     case OFPACT_REG_LOAD:
+    case OFPACT_STACK_PUSH:
+    case OFPACT_STACK_POP:
     case OFPACT_DEC_TTL:
     case OFPACT_SET_TUNNEL:
     case OFPACT_WRITE_METADATA:
@@ -1706,6 +1732,8 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_BUNDLE:
     case OFPACT_REG_MOVE:
     case OFPACT_REG_LOAD:
+    case OFPACT_STACK_PUSH:
+    case OFPACT_STACK_POP:
     case OFPACT_SET_TUNNEL:
     case OFPACT_POP_QUEUE:
     case OFPACT_FIN_TIMEOUT:
@@ -1825,6 +1853,8 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
     case OFPACT_SET_L4_DST_PORT:
     case OFPACT_REG_MOVE:
     case OFPACT_REG_LOAD:
+    case OFPACT_STACK_PUSH:
+    case OFPACT_STACK_POP:
     case OFPACT_DEC_TTL:
     case OFPACT_SET_TUNNEL:
     case OFPACT_WRITE_METADATA:
@@ -2044,6 +2074,14 @@ ofpact_format(const struct ofpact *a, struct ds *s)
         nxm_format_reg_load(ofpact_get_REG_LOAD(a), s);
         break;
 
+    case OFPACT_STACK_PUSH:
+        nxm_format_stack_push(ofpact_get_STACK_PUSH(a), s);
+        break;
+
+    case OFPACT_STACK_POP:
+        nxm_format_stack_pop(ofpact_get_STACK_POP(a), s);
+        break;
+
     case OFPACT_DEC_TTL:
         print_dec_ttl(ofpact_get_DEC_TTL(a), s);
         break;
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index c4e1b4a..01ed03f 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -70,6 +70,8 @@
     DEFINE_OFPACT(SET_L4_DST_PORT, ofpact_l4_port,       ofpact)    \
     DEFINE_OFPACT(REG_MOVE,        ofpact_reg_move,      ofpact)    \
     DEFINE_OFPACT(REG_LOAD,        ofpact_reg_load,      ofpact)    \
+    DEFINE_OFPACT(STACK_PUSH,      ofpact_stack_push,    ofpact)    \
+    DEFINE_OFPACT(STACK_POP,       ofpact_stack_pop,     ofpact)    \
     DEFINE_OFPACT(DEC_TTL,         ofpact_cnt_ids,       cnt_ids)   \
     DEFINE_OFPACT(PUSH_MPLS,       ofpact_push_mpls,     ofpact)    \
     DEFINE_OFPACT(POP_MPLS,        ofpact_pop_mpls,      ofpact)    \
@@ -302,6 +304,22 @@ struct ofpact_reg_move {
     struct mf_subfield dst;
 };
 
+/* OFPACT_STACK_PUSH.
+ *
+ * Used for NXAST_STACK_PUSH */
+struct ofpact_stack_push {
+    struct ofpact ofpact;
+    struct mf_subfield src;
+};
+
+/* OFPACT_STACK_POP.
+ *
+ * Used for NXAST_STACK_POP */
+struct ofpact_stack_pop {
+    struct ofpact ofpact;
+    struct mf_subfield dst;
+};
+
 /* OFPACT_REG_LOAD.
  *
  * Used for NXAST_REG_LOAD, OFPAT12_SET_FIELD. */
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 5fda08a..a5fc70e 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -569,6 +569,12 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         ofpact_put_POP_MPLS(ofpacts)->ethertype =
             htons(str_to_u16(arg, "pop_mpls"));
         break;
+    case OFPUTIL_NXAST_STACK_PUSH:
+        nxm_parse_stack_push(ofpact_put_STACK_PUSH(ofpacts), arg);
+        break;
+    case OFPUTIL_NXAST_STACK_POP:
+        nxm_parse_stack_pop(ofpact_put_STACK_POP(ofpacts), arg);
+        break;
     }
 }
 
diff --git a/lib/ofp-util.def b/lib/ofp-util.def
index ff7e1b3..552b3b0 100644
--- a/lib/ofp-util.def
+++ b/lib/ofp-util.def
@@ -48,6 +48,8 @@ NXAST_ACTION(NXAST_SET_QUEUE,       nx_action_set_queue,    0, "set_queue")
 NXAST_ACTION(NXAST_POP_QUEUE,       nx_action_pop_queue,    0, "pop_queue")
 NXAST_ACTION(NXAST_REG_MOVE,        nx_action_reg_move,     0, "move")
 NXAST_ACTION(NXAST_REG_LOAD,        nx_action_reg_load,     0, "load")
+NXAST_ACTION(NXAST_STACK_PUSH,      nx_action_stack,   0, "push")
+NXAST_ACTION(NXAST_STACK_POP,       nx_action_stack,    0, "pop")
 NXAST_ACTION(NXAST_NOTE,            nx_action_note,         1, "note")
 NXAST_ACTION(NXAST_SET_TUNNEL64,    nx_action_set_tunnel64, 0, "set_tunnel64")
 NXAST_ACTION(NXAST_MULTIPATH,       nx_action_multipath,    0, "multipath")
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index a4d7e59..d47e998 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -216,6 +216,19 @@ struct action_xlate_ctx {
      * this flow when actions change header fields. */
     struct flow flow;
 
+    /*
+       The stack for the push and pop actions.
+       Statically allocating 8KB byte stack within this structure.
+       This size should be sufficient for normal use. However, if necessary,
+       the stack can grow into larger size using malloc automatically.
+
+       Each stack element is of the type "union mf_value".
+
+       There are 8 bytes reserved at top of the stack for future use.
+    */
+    struct ofpbuf *stack;
+    OFPBUF_STACK_BUFFER(init_stack, 1024);  /* Statically allocated stack */
+
     /* The packet corresponding to 'flow', or a null pointer if we are
      * revalidating without a packet to refer to. */
     const struct ofpbuf *packet;
@@ -6433,6 +6446,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;
@@ -6543,6 +6566,7 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
     ctx->ofproto = ofproto;
     ctx->flow = *flow;
     memset(&ctx->flow.tunnel, 0, sizeof ctx->flow.tunnel);
+    ctx->stack = NULL;
     ctx->base_flow = ctx->flow;
     ctx->base_flow.vlan_tci = initial_tci;
     ctx->flow.tunnel.tun_id = initial_tun_id;
@@ -6570,12 +6594,19 @@ xlate_actions(struct action_xlate_ctx *ctx,
     enum slow_path_reason special;
     struct ofport_dpif *in_port;
     struct flow orig_flow;
+    struct ofpbuf action_stack;
+    OFPBUF_STACK_BUFFER(init_stack, 1024);  /* Statically
+                                               allocated stack */
 
     COVERAGE_INC(ofproto_dpif_xlate);
 
     ofpbuf_clear(odp_actions);
     ofpbuf_reserve(odp_actions, NL_A_U32_SIZE);
 
+    /* Set up action_stack, using the init_action_stack */
+    ofpbuf_use_stack(&action_stack, init_stack, sizeof init_stack);
+    ofpbuf_reserve(&action_stack, NL_A_U64_SIZE);
+
     ctx->odp_actions = odp_actions;
     ctx->tags = 0;
     ctx->slow = 0;
@@ -6589,6 +6620,7 @@ xlate_actions(struct action_xlate_ctx *ctx,
     ctx->orig_skb_priority = ctx->flow.skb_priority;
     ctx->table_id = 0;
     ctx->exit = false;
+    ctx->stack = &action_stack;
 
     if (ctx->ofproto->has_mirrors || hit_resubmit_limit) {
         /* Do this conditionally because the copy is expensive enough that it
@@ -6674,6 +6706,10 @@ xlate_actions(struct action_xlate_ctx *ctx,
         }
         fix_sflow_action(ctx);
     }
+
+    /* Clean up the action stack */
+    ofpbuf_uninit(&action_stack);
+    ctx -> stack = NULL;
 }
 
 /* Translates the 'ofpacts_len' bytes of "struct ofpact"s starting at 'ofpacts'
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 8f11b82..948f8ad 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -45,6 +45,7 @@ in_port=12 actions=load:0x10->NXM_NX_REG0[[]],load:0x11->NXM_NX_REG1[[]],load:0x
 in_port=13 actions=load:0x13->NXM_NX_REG3[[]],load:0x14->NXM_NX_REG4[[]],load:0x15->NXM_NX_REG5[[]]
 in_port=14 actions=load:0x16->NXM_NX_REG6[[]],load:0x17->NXM_NX_REG7[[]]
 in_port=15,reg0=0x10,reg1=0x11,reg2=0x12,reg3=0x13,reg4=0x14,reg5=0x15,reg6=0x16,reg7=0x17 actions=output:33
+
 ])
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
@@ -54,6 +55,26 @@ AT_CHECK([tail -1 stdout], [0],
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto-dpif - push-pop])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], [20], [21], [22], [33], [90])
+AT_DATA([flows.txt], [dnl
+in_port=90           actions=load:20->NXM_NX_REG0[[0..7]],load:21->NXM_NX_REG1[[0..7]],load:22->NXM_NX_REG2[[0..7]], load:33->NXM_NX_REG3[[0..7]], push:NXM_NX_REG0[[]], push:NXM_NX_REG1[[0..7]],push:NXM_NX_REG2[[0..15]], push:NXM_NX_REG3[[]], resubmit:2, resubmit:3, resubmit:4, resubmit:5
+
+in_port=2            actions=pop:NXM_NX_REG0[[0..7]],output:NXM_NX_REG0[[]]
+in_port=3            actions=pop:NXM_NX_REG1[[0..7]],output:NXM_NX_REG1[[]]
+in_port=4            actions=pop:NXM_NX_REG2[[0..15]],output:NXM_NX_REG2[[]]
+in_port=5            actions=pop:NXM_NX_REG3[[]],output:NXM_NX_REG3[[]]
+
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: 33,22,21,20
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([ofproto-dpif - output])
 OVS_VSWITCHD_START
 ADD_OF_PORTS([br0], [1], [9], [10], [11], [55], [66], [77], [88])
diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
index 7395fd1..075f2e4 100644
--- a/tests/ovs-ofctl.at
+++ b/tests/ovs-ofctl.at
@@ -243,6 +243,7 @@ tun_id=0x1234,cookie=0x5678,actions=flood
 actions=drop
 reg0=123,actions=move:NXM_NX_REG0[0..5]->NXM_NX_REG1[26..31],load:55->NXM_NX_REG2[0..31],move:NXM_NX_REG0[0..31]->NXM_NX_TUN_ID[0..31],move:NXM_NX_REG0[0..15]->NXM_OF_VLAN_TCI[]
 actions=move:OXM_OF_ETH_DST[]->OXM_OF_ETH_SRC[]
+actions=push:NXM_NX_REG0[0..31],pop:NXM_NX_REG0[]
 vlan_tci=0x1123/0x1fff,actions=drop
 ]])
 AT_CHECK([ovs-ofctl -F nxm -mmm parse-flows flows.txt], [0], [stdout], [stderr])
@@ -271,6 +272,7 @@ NXT_FLOW_MOD: ADD NXM_NX_TUN_ID(0000000000001234) cookie:0x5678 actions=FLOOD
 NXT_FLOW_MOD: ADD <any> actions=drop
 NXT_FLOW_MOD: ADD NXM_NX_REG0(0000007b) actions=move:NXM_NX_REG0[0..5]->NXM_NX_REG1[26..31],load:0x37->NXM_NX_REG2[],move:NXM_NX_REG0[]->NXM_NX_TUN_ID[0..31],move:NXM_NX_REG0[0..15]->NXM_OF_VLAN_TCI[]
 NXT_FLOW_MOD: ADD <any> actions=move:NXM_OF_ETH_DST[]->NXM_OF_ETH_SRC[]
+NXT_FLOW_MOD: ADD <any> actions=push:NXM_NX_REG0[],pop:NXM_NX_REG0[]
 NXT_FLOW_MOD: ADD NXM_OF_VLAN_TCI_W(1123/1fff) actions=drop
 ]])
 AT_CLEANUP
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 6589eff..fd3cec6 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -1050,6 +1050,20 @@ in field \fIdst\fR.
 Example: \fBload:55\->NXM_NX_REG2[0..5]\fR loads value 55 (bit pattern
 \fB110111\fR) into bits 0 through 5, inclusive, in register 2.
 .
+.IP "\fBpush:\fIsrc\fB[\fIstart\fB..\fIend\fB]"
+Pushes \fIstart\fR to \fIend\fR bits inclusive, in fields
+on top of the stack.
+.IP
+Example: \fBpush:\->NXM_NX_REG2[0..5]\fR push the vlaue stored register
+2 bits 0 through 5, inclusive, on to the internal stack.
+.
+.IP "\fBpop:\fIdst\fB[\fIstart\fB..\fIend\fB]"
+Pops from the top of the stack, retrive the \fIstart\fR to \fIend\fR bits inclusive, from the value poped and store them into the corresponding bits in \fIdst\fR. 
+.
+.IP
+Example: \fBpop:\->NXM_NX_REG2[0..5]\fR pop the value from top of the stack,
+Set register 2 bits 0 through 5, inclusive, based on bits 0 through 5 from the value just popd.
+.
 .IP "\fBset_field:\fIvalue\fB\->\fIdst"
 Writes the literal \fIvalue\fR into the field \fIdst\fR, which should
 be specified as a name used for matching.  (This is similar to
-- 
1.7.9.5




More information about the dev mailing list