2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-27 15:18:06 +00:00

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>
This commit is contained in:
Andy Zhou
2013-03-05 16:27:55 -08:00
committed by Ben Pfaff
parent 9a9e3786b3
commit bd85dac14e
12 changed files with 307 additions and 0 deletions

2
NEWS
View File

@@ -9,6 +9,8 @@ post-v1.10.0
- OpenFlow:
* The "dec_mpls_ttl" and "set_mpls_ttl" actions from OpenFlow
1.1 and later are now implemented.
* New "stack" extension for use in actions, to push and pop from
NXM fields.
v1.10.0 - xx xxx xxxx

View File

@@ -308,6 +308,8 @@ enum nx_action_subtype {
NXAST_POP_MPLS, /* struct nx_action_pop_mpls */
NXAST_SET_MPLS_TTL, /* struct nx_action_ttl */
NXAST_DEC_MPLS_TTL, /* struct nx_action_header */
NXAST_STACK_PUSH, /* struct nx_action_stack */
NXAST_STACK_POP, /* struct nx_action_stack */
};
/* Header for Nicira-defined actions. */
@@ -562,6 +564,23 @@ struct nx_action_reg_load {
};
OFP_ASSERT(sizeof(struct nx_action_reg_load) == 24);
/* Action structure for NXAST_STACK_PUSH and NXAST_STACK_POP.
*
* Pushes (or pops) field[offset: offset + n_bits] to (or from)
* 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 offset; /* Bit offset into the field. */
ovs_be32 field; /* The field used for push or pop. */
ovs_be16 n_bits; /* (n_bits + 1) bits of the field. */
uint8_t zero[6]; /* Reserved, must be zero. */
};
OFP_ASSERT(sizeof(struct nx_action_stack) == 24);
/* Action structure for NXAST_NOTE.
*
* This action has no effect. It is variable length. The switch does not

View File

@@ -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);
}
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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. */

View File

@@ -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;
}
}

View File

@@ -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")

View File

@@ -216,6 +216,11 @@ struct action_xlate_ctx {
* this flow when actions change header fields. */
struct flow flow;
/* stack for the push and pop actions.
* Each stack element is of the type "union mf_subvalue". */
struct ofpbuf stack;
union mf_subvalue init_stack[1024 / sizeof(union mf_subvalue)];
/* The packet corresponding to 'flow', or a null pointer if we are
* revalidating without a packet to refer to. */
const struct ofpbuf *packet;
@@ -6404,6 +6409,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;
@@ -6573,6 +6588,8 @@ xlate_actions(struct action_xlate_ctx *ctx,
ctx->table_id = 0;
ctx->exit = false;
ofpbuf_use_stub(&ctx->stack, ctx->init_stack, sizeof ctx->init_stack);
if (ctx->ofproto->has_mirrors || hit_resubmit_limit) {
/* Do this conditionally because the copy is expensive enough that it
* shows up in profiles. */
@@ -6657,6 +6674,8 @@ xlate_actions(struct action_xlate_ctx *ctx,
}
fix_sflow_action(ctx);
}
ofpbuf_uninit(&ctx->stack);
}
/* Translates the 'ofpacts_len' bytes of "struct ofpact"s starting at 'ofpacts'

View File

@@ -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,25 @@ 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])

View File

@@ -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

View File

@@ -1063,6 +1063,23 @@ 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 value stored in 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, retrieves the \fIstart\fR to \fIend\fR bits
inclusive, from the value popped and store them into the corresponding
bits in \fIdst\fR.
.
.IP
Example: \fBpop:NXM_NX_REG2[0..5]\fR pops 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 popped.
.
.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