[ovs-dev] [bug 7550 7/9] New action NXAST_CONTROLLER.
Ben Pfaff
blp at nicira.com
Wed Dec 21 21:03:55 UTC 2011
This action makes it possible for an OpenFlow action to send a packet
to the OpenFlow controller with OFPR_NO_MATCH as the reason. There
are multiple reasons this is useful:
- It makes it possible to implement flow table misses as OpenFlow
flows internally without inventing a special case action that is
only understood internally to Open vSwitch.
- OpenFlow 1.3 may implement such behavior (see EXT-108 in the
Open Networking Foundation bug tracker).
- It gives us a place to add a specification for a subset of
controllers to which the packet should be sent. (This is not
yet implemented.)
Signed-off-by: Ben Pfaff <blp at nicira.com>
---
NEWS | 3 ++
include/openflow/nicira-ext.h | 26 ++++++++++++++++++-
lib/ofp-parse.c | 57 +++++++++++++++++++++++++++++++++--------
lib/ofp-print.c | 14 ++++++++++
lib/ofp-util.c | 1 +
lib/ofp-util.def | 1 +
ofproto/ofproto-dpif.c | 13 +++++++--
utilities/ovs-ofctl.8.in | 22 +++++++++++++---
8 files changed, 118 insertions(+), 19 deletions(-)
diff --git a/NEWS b/NEWS
index eae3a97..1c67186 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
port-v1.4.0
------------------------
+ - OpenFlow:
+ - New Nicira action NXAST_CONTROLLER that offers additional features over
+ output to OFPP_CONTROLLER.
v1.4.0 - xx xxx xxxx
diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index f449329..2a39f0d 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -296,7 +296,8 @@ enum nx_action_subtype {
NXAST_RESUBMIT_TABLE, /* struct nx_action_resubmit */
NXAST_OUTPUT_REG, /* struct nx_action_output_reg */
NXAST_LEARN, /* struct nx_action_learn */
- NXAST_EXIT /* struct nx_action_header */
+ NXAST_EXIT, /* struct nx_action_header */
+ NXAST_CONTROLLER /* struct nx_action_controller */
};
/* Header for Nicira-defined actions. */
@@ -1785,5 +1786,28 @@ struct nx_aggregate_stats_reply {
uint8_t pad[4]; /* Align to 64 bits. */
};
OFP_ASSERT(sizeof(struct nx_aggregate_stats_reply) == 48);
+
+/* Action structure for NXAST_CONTROLLER.
+ *
+ * This generalizes using OFPAT_OUTPUT to send a packet to OFPP_CONTROLLER. In
+ * addition to the 'max_len' that OFPAT_OUTPUT supports, it also allows
+ * specifying:
+ *
+ * - The reason to use in the ofp_packet_in.
+ *
+ * - The controllers to which the ofp_packet_in should be sent. This
+ * feature is not yet implemented. Controllers should set 'controllers'
+ * to 0 to ensure forward compatilibility. */
+struct nx_action_controller {
+ ovs_be16 type; /* OFPAT_VENDOR. */
+ ovs_be16 len; /* Length is 16. */
+ ovs_be32 vendor; /* NX_VENDOR_ID. */
+ ovs_be16 subtype; /* NXAST_CONTROLLER. */
+ ovs_be16 max_len; /* Maximum length to send to controller. */
+ ovs_be16 controllers; /* Controllers to send packet-in. */
+ uint8_t reason; /* enum ofp_packet_in_reason (OFPR_*). */
+ uint8_t pad; /* Pad to 64 bits. */
+};
+OFP_ASSERT(sizeof(struct nx_action_controller) == 16);
#endif /* openflow/nicira-ext.h */
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 4021551..79baa6e 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -251,6 +251,48 @@ parse_note(struct ofpbuf *b, const char *arg)
}
static void
+parse_controller(struct ofpbuf *b, char *arg)
+{
+ enum ofp_packet_in_reason reason = OFPR_ACTION;
+ uint16_t max_len = UINT16_MAX;
+
+ if (!arg[0]) {
+ /* Use defaults. */
+ } else if (strspn(arg, "0123456789") == strlen(arg)) {
+ max_len = str_to_u16(arg, "max_len");
+ } else {
+ char *name, *value;
+
+ while (ofputil_parse_key_value(&arg, &name, &value)) {
+ if (!strcmp(name, "reason")) {
+ if (!strcmp(value, "action")) {
+ reason = OFPR_ACTION;
+ } else if (!strcmp(value, "no_match")) {
+ reason = OFPR_NO_MATCH;
+ } else {
+ ovs_fatal(0, "unknown reason \"%s\"", value);
+ }
+ } else if (!strcmp(name, "max_len")) {
+ max_len = str_to_u16(value, "max_len");
+ } else {
+ ovs_fatal(0, "unknown key \"%s\" parsing controller action",
+ name);
+ }
+ }
+ }
+
+ if (reason == OFPR_ACTION) {
+ put_output_action(b, OFPP_CONTROLLER)->max_len = htons(max_len);
+ } else {
+ struct nx_action_controller *nac;
+
+ nac = ofputil_put_NXAST_CONTROLLER(b);
+ nac->max_len = htons(max_len);
+ nac->reason = reason;
+ }
+}
+
+static void
parse_named_action(enum ofputil_action_code code, const struct flow *flow,
struct ofpbuf *b, char *arg)
{
@@ -364,6 +406,10 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
case OFPUTIL_NXAST_EXIT:
ofputil_put_NXAST_EXIT(b);
break;
+
+ case OFPUTIL_NXAST_CONTROLLER:
+ parse_controller(b, arg);
+ break;
}
}
@@ -393,17 +439,6 @@ str_to_action(const struct flow *flow, char *str, struct ofpbuf *b)
"actions");
}
break;
- } else if (!strcasecmp(act, "CONTROLLER")) {
- struct ofp_action_output *oao;
- oao = put_output_action(b, OFPP_CONTROLLER);
-
- /* Unless a numeric argument is specified, we send the whole
- * packet to the controller. */
- if (arg[0] && (strspn(arg, "0123456789") == strlen(arg))) {
- oao->max_len = htons(str_to_u32(arg));
- } else {
- oao->max_len = htons(UINT16_MAX);
- }
} else if (ofputil_port_from_string(act, &port)) {
put_output_action(b, port);
} else {
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index fe852b4..8de9363 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -183,6 +183,7 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
const struct nx_action_multipath *nam;
const struct nx_action_autopath *naa;
const struct nx_action_output_reg *naor;
+ const struct nx_action_controller *nac;
uint16_t port;
switch (code) {
@@ -342,6 +343,19 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
ds_put_cstr(s, "exit");
break;
+ case OFPUTIL_NXAST_CONTROLLER:
+ nac = (const struct nx_action_controller *) a;
+ ds_put_format(s, "controller(%s",
+ (nac->reason == OFPR_ACTION ? ""
+ : nac->reason == OFPR_NO_MATCH ? "reason=no_match,"
+ : "reason=<error>,"));
+ if (nac->max_len != htons(UINT16_MAX)) {
+ ds_put_format(s, "max_len=%"PRIu16",", ntohs(nac->max_len));
+ }
+ ds_chomp(s, ',');
+ ds_put_char(s, ')');
+ break;
+
default:
break;
}
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 11b0f15..a8b29bf 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -2272,6 +2272,7 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
case OFPUTIL_NXAST_NOTE:
case OFPUTIL_NXAST_SET_TUNNEL64:
case OFPUTIL_NXAST_EXIT:
+ case OFPUTIL_NXAST_CONTROLLER:
break;
}
diff --git a/lib/ofp-util.def b/lib/ofp-util.def
index 2958eb6..08a641a 100644
--- a/lib/ofp-util.def
+++ b/lib/ofp-util.def
@@ -36,4 +36,5 @@ NXAST_ACTION(NXAST_RESUBMIT_TABLE, nx_action_resubmit, 0, NULL)
NXAST_ACTION(NXAST_OUTPUT_REG, nx_action_output_reg, 0, NULL)
NXAST_ACTION(NXAST_LEARN, nx_action_learn, 1, "learn")
NXAST_ACTION(NXAST_EXIT, nx_action_header, 0, "exit")
+NXAST_ACTION(NXAST_CONTROLLER, nx_action_controller, 0, "controller")
#undef NXAST_ACTION
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index e725f28..47c7e60 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -4231,7 +4231,8 @@ flood_packets(struct action_xlate_ctx *ctx, bool all)
}
static void
-compose_controller_action(struct action_xlate_ctx *ctx, int len)
+compose_controller_action(struct action_xlate_ctx *ctx,
+ enum ofp_packet_in_reason reason, int len)
{
union user_action_cookie cookie;
@@ -4239,7 +4240,7 @@ compose_controller_action(struct action_xlate_ctx *ctx, int len)
memset(&cookie, 0, sizeof cookie);
cookie.controller.type = USER_ACTION_COOKIE_CONTROLLER;
- cookie.controller.reason = OFPR_ACTION;
+ cookie.controller.reason = reason;
cookie.controller.max_len = len;
put_userspace_action(ctx->ofproto, ctx->odp_actions, &ctx->flow, &cookie);
}
@@ -4269,7 +4270,7 @@ xlate_output_action__(struct action_xlate_ctx *ctx,
flood_packets(ctx, true);
break;
case OFPP_CONTROLLER:
- compose_controller_action(ctx, max_len);
+ compose_controller_action(ctx, OFPR_ACTION, max_len);
break;
case OFPP_LOCAL:
compose_output_action(ctx, OFPP_LOCAL);
@@ -4480,6 +4481,7 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
const struct nx_action_autopath *naa;
const struct nx_action_bundle *nab;
const struct nx_action_output_reg *naor;
+ const struct nx_action_controller *nac;
enum ofputil_action_code code;
ovs_be64 tun_id;
@@ -4626,6 +4628,11 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
case OFPUTIL_NXAST_EXIT:
ctx->exit = true;
break;
+
+ case OFPUTIL_NXAST_CONTROLLER:
+ nac = (const struct nx_action_controller *) ia;
+ compose_controller_action(ctx, nac->reason, ntohs(nac->max_len));
+ break;
}
}
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 932c204..40e173a 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -686,11 +686,25 @@ tree protocol).
Outputs the packet on all switch physical ports other than the port on
which it was received.
.
-.IP \fBcontroller\fR:\fImax_len\fR
+.IP \fBcontroller(\fIkey\fB=\fIvalue\fR...\fB)
Sends the packet to the OpenFlow controller as a ``packet in''
-message. If \fImax_len\fR is a number, then it specifies the maximum
-number of bytes that should be sent. If \fImax_len\fR is \fBALL\fR or
-omitted, then the entire packet is sent.
+message. The supported key-value pairs are:
+.RS
+.IP "\fBmax_len=\fInbytes\fR"
+Limit to \fInbytes\fR the number of bytes of the packet to send to
+the controller. By default the entire packet is sent.
+.IP "\fBreason=\fIreason\fR"
+Specify \fIreason\fR as the reason for sending the message in the
+``packet in'' message. The supported reasons are \fBaction\fR (the
+default) and \fBno_match\fR. Any reason other than \fBaction\fR uses
+a Nicira vendor extension that, as of this writing, is only known to
+be implemented by Open vSwitch.
+.RE
+.
+.IP \fBcontroller\fR
+.IQ \fBcontroller\fR[\fB:\fInbytes\fR]
+Shorthand for \fBcontroller()\fR or
+\fBcontroller(max_len=\fInbytes\fB)\fR, respectively.
.
.IP \fBlocal\fR
Outputs the packet on the ``local port,'' which corresponds to the
--
1.7.2.5
More information about the dev
mailing list