The NXAST_OUTPUT_REG outputs to the OpenFlow port contained in a
supplied NXM field.
---
NEWS | 2 ++
include/openflow/nicira-ext.h | 31 ++++++++++++++++++++++++++++++-
lib/ofp-parse.c | 23 ++++++++++++++++++++++-
lib/ofp-print.c | 8 ++++++++
lib/ofp-util.c | 7 +++++++
lib/ofp-util.h | 3 ++-
ofproto/ofproto-dpif.c | 16 ++++++++++++++++
tests/ofproto-dpif.at | 16 ++++++++++++++++
tests/ovs-ofctl.at | 2 ++
utilities/ovs-ofctl.8.in | 8 +++++++-
10 files changed, 112 insertions(+), 4 deletions(-)
diff --git a/NEWS b/NEWS
index a55af13..0318d4a 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,7 @@
Post-v1.2.0
------------------------
+ - OpenFlow:
+ - "output" action now accepts NXM fields.
- ovs-appctl:
- New "version" command to determine version of running daemon
- ovs-vswitchd:
diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index bbe96b3..be73dbf 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -280,7 +280,8 @@ enum nx_action_subtype {
NXAST_AUTOPATH, /* struct nx_action_autopath */
NXAST_BUNDLE, /* struct nx_action_bundle */
NXAST_BUNDLE_LOAD, /* struct nx_action_bundle */
- NXAST_RESUBMIT_TABLE /* struct nx_action_resubmit */
+ NXAST_RESUBMIT_TABLE, /* struct nx_action_resubmit */
+ NXAST_OUTPUT_REG /* struct nx_action_output_reg */
};
/* Header for Nicira-defined actions. */
@@ -781,6 +782,34 @@ enum nx_bd_algorithm {
NX_BD_ALG_HRW /* Highest Random Weight. */
};
+/* Action structure for NXAST_OUTPUT_REG.
+ *
+ * Outputs to the OpenFlow port number written to src[ofs:ofs+nbits].
+ *
+ * The format and semantics of 'src' and 'ofs_nbits' are similar to those for
+ * the NXAST_REG_LOAD action.
+ *
+ * The acceptable nxm_header values for 'src' are the same as the acceptable
+ * nxm_header values for the 'src' field of NXAST_REG_MOVE.
+ *
+ * The 'max_len' field indicates the number of bytes to send when the chosen
+ * port is OFPP_CONTROLLER. It's semantics are equivalent to the 'max_len'
+ * field of OFPAT_OUTPUT. */
+struct nx_action_output_reg {
+ ovs_be16 type; /* OFPAT_VENDOR. */
+ ovs_be16 len; /* 24. */
+ ovs_be32 vendor; /* NX_VENDOR_ID. */
+ ovs_be16 subtype; /* NXAST_OUTPUT_REG. */
+
+ ovs_be16 ofs_nbits; /* (ofs << 6) | (n_bits - 1). */
+ ovs_be32 src; /* Source. */
+
+ ovs_be16 max_len; /* Max length to send to controller. */
+
+ uint8_t pad[6];
+};
+OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24);
+
/* Flexible flow specifications (aka NXM = Nicira Extended Match).
*
* OpenFlow 1.0 has "struct ofp_match" for specifying flow matches. This
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index c938400..0d5bb17 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -317,6 +317,27 @@ parse_port_name(const char *name, uint16_t *port)
}
static void
+parse_output(struct ofpbuf *b, char *arg)
+{
+ if (strchr(arg, '[')) {
+ struct nx_action_output_reg *naor;
+ int ofs, n_bits;
+ uint32_t src;
+
+ nxm_parse_field_bits(arg, &src, &ofs, &n_bits);
+
+ naor = put_action(b, sizeof *naor, OFPAT_VENDOR);
+ naor->vendor = htonl(NX_VENDOR_ID);
+ naor->subtype = htons(NXAST_OUTPUT_REG);
+ naor->ofs_nbits = nxm_encode_ofs_nbits(ofs, n_bits);
+ naor->src = htonl(src);
+ naor->max_len = htons(UINT16_MAX);
+ } else {
+ put_output_action(b, str_to_u32(arg));
+ }
+}
+
+static void
parse_resubmit(struct nx_action_resubmit *nar, char *arg)
{
char *in_port_s, *table_s;
@@ -541,7 +562,7 @@ str_to_action(char *str, struct ofpbuf *b)
} else if (!strcasecmp(act, "bundle_load")) {
bundle_parse_load(b, arg);
} else if (!strcasecmp(act, "output")) {
- put_output_action(b, str_to_u32(arg));
+ parse_output(b, arg);
} else if (!strcasecmp(act, "enqueue")) {
char *sp = NULL;
char *port_s = strtok_r(arg, ":q", &sp);
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index d1a661b..4c94ebb 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -218,6 +218,7 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
const struct nx_action_reg_load *load;
const struct nx_action_multipath *nam;
const struct nx_action_autopath *naa;
+ const struct nx_action_output_reg *naor;
uint16_t port;
switch (code) {
@@ -361,6 +362,13 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
bundle_format((const struct nx_action_bundle *) a, s);
break;
+ case OFPUTIL_NXAST_OUTPUT_REG:
+ naor = (const struct nx_action_output_reg *) a;
+ ds_put_cstr(s, "output:");
+ nxm_format_field_bits(s, ntohl(naor->src),
+ nxm_decode_ofs(naor->ofs_nbits),
+ nxm_decode_n_bits(naor->ofs_nbits));
+
default:
break;
}
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index b0aeaf4..9b317c3 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -1983,6 +1983,7 @@ int
validate_actions(const union ofp_action *actions, size_t n_actions,
const struct flow *flow, int max_ports)
{
+ const struct nx_action_output_reg *naor;
const union ofp_action *a;
size_t left;
@@ -2057,6 +2058,11 @@ validate_actions(const union ofp_action *actions, size_t
n_actions,
max_ports, flow);
break;
+ case OFPUTIL_NXAST_OUTPUT_REG:
+ naor = (const struct nx_action_output_reg *) a;
+ error = nxm_src_check(naor->src, naor->ofs_nbits, 16, flow);
+ break;
+
case OFPUTIL_NXAST_RESUBMIT_TABLE:
error = check_resubmit_table(
(const struct nx_action_resubmit *) a);
@@ -2170,6 +2176,7 @@ ofputil_decode_nxast_action(const union ofp_action *a)
NXAST_ACTION(NXAST_BUNDLE, struct nx_action_bundle, true);
NXAST_ACTION(NXAST_BUNDLE_LOAD, struct nx_action_bundle, true);
NXAST_ACTION(NXAST_RESUBMIT_TABLE, struct nx_action_resubmit, false);
+ NXAST_ACTION(NXAST_OUTPUT_REG, struct nx_action_output_reg, false);
#undef NXAST_ACTION
case NXAST_SNAT__OBSOLETE:
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 9f3685c..b110d71 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -304,7 +304,8 @@ enum ofputil_action_code {
OFPUTIL_NXAST_AUTOPATH,
OFPUTIL_NXAST_BUNDLE,
OFPUTIL_NXAST_BUNDLE_LOAD,
- OFPUTIL_NXAST_RESUBMIT_TABLE
+ OFPUTIL_NXAST_RESUBMIT_TABLE,
+ OFPUTIL_NXAST_OUTPUT_REG
};
int ofputil_decode_action(const union ofp_action *);
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 010d98b..b1f81f6 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -3020,6 +3020,16 @@ xlate_output_action__(struct action_xlate_ctx *ctx,
}
static void
+xlate_output_reg_action(struct action_xlate_ctx *ctx,
+ const struct nx_action_output_reg *naor)
+{
+ uint16_t ofp_port;
+
+ ofp_port = nxm_read_field(naor->src, naor->ofs_nbits, &ctx->flow);
+ xlate_output_action__(ctx, ofp_port, ntohs(naor->max_len));
+}
+
+static void
xlate_output_action(struct action_xlate_ctx *ctx,
const struct ofp_action_output *oao)
{
@@ -3154,6 +3164,7 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
const struct nx_action_multipath *nam;
const struct nx_action_autopath *naa;
const struct nx_action_bundle *nab;
+ const struct nx_action_output_reg *naor;
enum ofputil_action_code code;
ovs_be64 tun_id;
@@ -3279,6 +3290,11 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
bundle_execute_load(nab, &ctx->flow, slave_enabled_cb,
ctx->ofproto);
break;
+
+ case OFPUTIL_NXAST_OUTPUT_REG:
+ naor = (const struct nx_action_output_reg *) ia;
+ xlate_output_reg_action(ctx, naor);
+ break;
}
}
}
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 846eccb..657982e 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -17,3 +17,19 @@ AT_CHECK([tail -1 stdout], [0],
])
OFPROTO_STOP
AT_CLEANUP
+
+AT_SETUP([ofproto-dpif - output])
+OFPROTO_START
+AT_DATA([flows.txt], [dnl
+in_port=1 actions=resubmit:2,resubmit:3,resubmit:4
+in_port=2 actions=output:9
+in_port=3
actions=load:55->NXM_NX_REG0[[]],output:NXM_NX_REG0[[]],load:66->NXM_NX_REG1[[]]
+in_port=4
actions=output:10,output:NXM_NX_REG0[[]],output:NXM_NX_REG1[[]],output:11
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl -t test-openflowd ofproto/trace br0
'in_port(1),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),icmp(type=8,code=0)'],
[0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: 9,55,10,55,66,11
+])
+OFPROTO_STOP
+AT_CLEANUP
diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
index 1edfb62..d1acb6b 100644
--- a/tests/ovs-ofctl.at
+++ b/tests/ovs-ofctl.at
@@ -24,6 +24,7 @@
actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..15],slaves:2,3)
actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:)
actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],slaves:1),output:2
actions=resubmit:1,resubmit(2),resubmit(,3),resubmit(2,3)
+actions=output:1,output:NXM_NX_REG0[],output:2,output:NXM_NX_REG1[16..31],output:3
]])
AT_CHECK([ovs-ofctl parse-flows flows.txt
@@ -52,6 +53,7 @@ NXT_FLOW_MOD: ADD table:255
actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_N
NXT_FLOW_MOD: ADD table:255
actions=bundle_load(symmetric_l4,60,hrw,ofport,NXM_NX_REG0[0..30],slaves:)
NXT_FLOW_MOD: ADD table:255
actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],slaves:1),output:2
NXT_FLOW_MOD: ADD table:255
actions=resubmit:1,resubmit:2,resubmit(,3),resubmit(2,3)
+NXT_FLOW_MOD: ADD table:255
actions=output:1,output:NXM_NX_REG0[],output:2,output:NXM_NX_REG1[16..31],output:3
]])
AT_CLEANUP
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index aa37969..f0a2382 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -571,7 +571,13 @@ of the following keywords:
.
.RS
.IP \fBoutput\fR:\fIport\fR
-Outputs the packet on the port specified by \fIport\fR.
+.IQ \fBoutput\fR:\fIsrc\fR
+Outputs the packet. If \fIport\fR is an OpenFlow port number, outputs directly
+to it. Otherwise, outputs to the OpenFlow port number read from \fIsrc\fR
+which must be an NXM field as described above.
+.IP
+Example: \fBoutput:NXM_NX_REG0[16..31]\fR outputs to the OpenFlow port number
+written in the upper half of register 0.
.
.IP \fBenqueue\fR:\fIport\fB:\fIqueue\fR
Enqueues the packet on the specified \fIqueue\fR within port
--
1.7.6
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev