aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAndy Zhou <azhou@nicira.com>2013-03-05 16:27:55 -0800
committerBen Pfaff <blp@nicira.com>2013-03-06 13:40:28 -0800
commitbd85dac14ed7fa42d5804592fd4e903826d9e899 (patch)
tree958da5acb0c2bfdf435846965a52d82f4155c064 /lib
parent9a9e3786b3a8065723887ab009aedb7f6d2667aa (diff)
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(). Signed-off-by: Andy Zhou <azhou@nicira.com> Signed-off-by: Ben Pfaff <blp@nicira.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/nx-match.c146
-rw-r--r--lib/nx-match.h26
-rw-r--r--lib/ofp-actions.c38
-rw-r--r--lib/ofp-actions.h10
-rw-r--r--lib/ofp-parse.c6
-rw-r--r--lib/ofp-util.def2
6 files changed, 228 insertions, 0 deletions
diff --git a/lib/nx-match.c b/lib/nx-match.c
index e5545dea..6efc94df 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -1312,3 +1312,149 @@ 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_action, works for both push() and pop(). */
+void
+nxm_parse_stack_action(struct ofpact_stack *stack_action, const char *s)
+{
+ s = mf_parse_subfield(&stack_action->subfield, s);
+ if (*s != '\0') {
+ ovs_fatal(0, "%s: trailing garbage following push or pop", s);
+ }
+}
+
+void
+nxm_format_stack_push(const struct ofpact_stack *push, struct ds *s)
+{
+ ds_put_cstr(s, "push:");
+ mf_format_subfield(&push->subfield, s);
+}
+
+void
+nxm_format_stack_pop(const struct ofpact_stack *pop, struct ds *s)
+{
+ ds_put_cstr(s, "pop:");
+ mf_format_subfield(&pop->subfield, s);
+}
+
+/* Common set for both push and pop actions. */
+static void
+stack_action_from_openflow__(const struct nx_action_stack *nasp,
+ struct ofpact_stack *stack_action)
+{
+ stack_action->subfield.field = mf_from_nxm_header(ntohl(nasp->field));
+ stack_action->subfield.ofs = ntohs(nasp->offset);
+ stack_action->subfield.n_bits = ntohs(nasp->n_bits);
+}
+
+static void
+nxm_stack_to_nxast__(const struct ofpact_stack *stack_action,
+ struct nx_action_stack *nasp)
+{
+ nasp->offset = htons(stack_action->subfield.ofs);
+ nasp->n_bits = htons(stack_action->subfield.n_bits);
+ nasp->field = htonl(stack_action->subfield.field->nxm_header);
+}
+
+enum ofperr
+nxm_stack_push_from_openflow(const struct nx_action_stack *nasp,
+ struct ofpbuf *ofpacts)
+{
+ struct ofpact_stack *push;
+
+ push = ofpact_put_STACK_PUSH(ofpacts);
+ stack_action_from_openflow__(nasp, push);
+
+ 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 = ofpact_put_STACK_POP(ofpacts);
+ stack_action_from_openflow__(nasp, pop);
+
+ return nxm_stack_pop_check(pop, NULL);
+}
+
+enum ofperr
+nxm_stack_push_check(const struct ofpact_stack *push,
+ const struct flow *flow)
+{
+ return mf_check_src(&push->subfield, flow);
+}
+
+enum ofperr
+nxm_stack_pop_check(const struct ofpact_stack *pop,
+ const struct flow *flow)
+{
+ return mf_check_dst(&pop->subfield, flow);
+}
+
+void
+nxm_stack_push_to_nxast(const struct ofpact_stack *stack,
+ struct ofpbuf *openflow)
+{
+ nxm_stack_to_nxast__(stack, ofputil_put_NXAST_STACK_PUSH(openflow));
+}
+
+void
+nxm_stack_pop_to_nxast(const struct ofpact_stack *stack,
+ struct ofpbuf *openflow)
+{
+ nxm_stack_to_nxast__(stack, ofputil_put_NXAST_STACK_POP(openflow));
+}
+
+/* nxm_execute_stack_push(), nxm_execute_stack_pop(). */
+static void
+nx_stack_push(struct ofpbuf *stack, union mf_subvalue *v)
+{
+ ofpbuf_put(stack, v, sizeof *v);
+}
+
+static union mf_subvalue *
+nx_stack_pop(struct ofpbuf *stack)
+{
+ union mf_subvalue *v = NULL;
+
+ if (stack->size) {
+ stack->size -= sizeof *v;
+ v = (union mf_subvalue *) ofpbuf_tail(stack);
+ }
+
+ return v;
+}
+
+void
+nxm_execute_stack_push(const struct ofpact_stack *push,
+ const struct flow *flow, struct ofpbuf *stack)
+{
+ union mf_subvalue dst_value;
+
+ mf_read_subfield(&push->subfield, flow, &dst_value);
+ nx_stack_push(stack, &dst_value);
+}
+
+void
+nxm_execute_stack_pop(const struct ofpact_stack *pop,
+ struct flow *flow, struct ofpbuf *stack)
+{
+ union mf_subvalue *src_value;
+
+ src_value = nx_stack_pop(stack);
+
+ /* Only pop if stack is not empty. Otherwise, give warning. */
+ if (src_value) {
+ mf_write_subfield_flow(&pop->subfield, src_value, flow);
+ } else {
+ if (!VLOG_DROP_WARN(&rl)) {
+ char *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 6a57297c..7d316d80 100644
--- a/lib/nx-match.h
+++ b/lib/nx-match.h
@@ -29,10 +29,12 @@ struct match;
struct mf_subfield;
struct ofpact_reg_move;
struct ofpact_reg_load;
+struct ofpact_stack;
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 +85,30 @@ 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_action(struct ofpact_stack *, const char *);
+
+void nxm_format_stack_push(const struct ofpact_stack *, struct ds *);
+void nxm_format_stack_pop(const struct ofpact_stack *, 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 *,
+ const struct flow *);
+enum ofperr nxm_stack_pop_check(const struct ofpact_stack *,
+ const struct flow *);
+
+void nxm_stack_push_to_nxast(const struct ofpact_stack *,
+ struct ofpbuf *openflow);
+void nxm_stack_pop_to_nxast(const struct ofpact_stack *,
+ struct ofpbuf *openflow);
+
+void nxm_execute_stack_push(const struct ofpact_stack *,
+ const struct flow *, struct ofpbuf *);
+void nxm_execute_stack_pop(const struct ofpact_stack *,
+ 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 6dabc5a4..d405d2d4 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);
@@ -1155,6 +1165,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_MPLS_TTL:
case OFPACT_DEC_MPLS_TTL:
@@ -1401,6 +1417,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;
@@ -1580,6 +1604,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_MPLS_TTL:
case OFPACT_DEC_MPLS_TTL:
@@ -1748,6 +1774,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:
@@ -1867,6 +1895,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_MPLS_TTL:
case OFPACT_DEC_MPLS_TTL:
@@ -2088,6 +2118,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 2d934f98..0189c8ae 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, ofpact) \
+ DEFINE_OFPACT(STACK_POP, ofpact_stack, ofpact) \
DEFINE_OFPACT(DEC_TTL, ofpact_cnt_ids, cnt_ids) \
DEFINE_OFPACT(SET_MPLS_TTL, ofpact_mpls_ttl, ofpact) \
DEFINE_OFPACT(DEC_MPLS_TTL, ofpact_null, ofpact) \
@@ -304,6 +306,14 @@ struct ofpact_reg_move {
struct mf_subfield dst;
};
+/* OFPACT_STACK_PUSH.
+ *
+ * Used for NXAST_STACK_PUSH and NXAST_STACK_POP. */
+struct ofpact_stack {
+ struct ofpact ofpact;
+ struct mf_subfield subfield;
+};
+
/* OFPACT_REG_LOAD.
*
* Used for NXAST_REG_LOAD, OFPAT12_SET_FIELD. */
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index f1802048..e8abc9f6 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -591,6 +591,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_action(ofpact_put_STACK_PUSH(ofpacts), arg);
+ break;
+ case OFPUTIL_NXAST_STACK_POP:
+ nxm_parse_stack_action(ofpact_put_STACK_POP(ofpacts), arg);
+ break;
}
}
diff --git a/lib/ofp-util.def b/lib/ofp-util.def
index 439d34ed..b7dde483 100644
--- a/lib/ofp-util.def
+++ b/lib/ofp-util.def
@@ -50,6 +50,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")