[ovs-dev] [nxast_controller 2/2] Add ability to direct "packet-in"s to particular controllers.
Ethan Jackson
ethan at nicira.com
Wed Feb 22 02:16:36 UTC 2012
nicira-ext.h:
I'm surprised the zero padding is put before the 'controller_id' field
in struct nx_controller_id. Typically we've done it the other way
around, though I don't think it matters in particular. Was there a
specific reason for doing it this way?
ofp-errors.h:
I like the addition of OFPERR_NXBRC_MUST_BE_ZERO. This isn't the
appropriate place to do it, but I think we have a lot of other actions
which could benefit from returning this error. Is it worth taking the
time to find the places which could use it, i.e. sense it doesn't
actually get sent on the wire, are there other benefits?
ofp-util.def:
I think it may be cleaner to follow the precedent of
NXAST_RESUBMIT_TABLE and NXAST_OUTPUT_REG and create an OFPAT_ACTION
for controller, and an NXAST_ACTION for controller which uses NULL as
it's string. This may require some minor tweaks in the rest of the
patch.
Ethan
On Tue, Feb 7, 2012 at 15:06, Ben Pfaff <blp at nicira.com> wrote:
> Nicira's controllers are somewhat heterogeneous, so that particular
> "packet-in" messages should be directed to particular controllers. This
> new Nicira extension action allows designating a controller or controllers
> to receive the "packet-in" using a 16-bit integer ID.
>
> The new NXAST_CONTROLLER action also specifies the "reason" code to include
> in the "packet-in" message. This is particularly useful for simulating a
> "no-match" "packet-in" using a rule.
>
> Signed-off-by: Ben Pfaff <blp at nicira.com>
> ---
> DESIGN | 10 +++++++
> NEWS | 2 +
> include/openflow/nicira-ext.h | 42 ++++++++++++++++++++++++++++++
> include/openflow/openflow.h | 3 +-
> lib/learning-switch.c | 1 +
> lib/ofp-errors.h | 8 +++++-
> lib/ofp-parse.c | 57 +++++++++++++++++++++++++++++++++--------
> lib/ofp-print.c | 27 +++++++++++++++++++
> lib/ofp-util.c | 10 +++++++
> lib/ofp-util.def | 1 +
> lib/ofp-util.h | 2 +
> ofproto/connmgr.c | 15 ++++++++++-
> ofproto/connmgr.h | 2 +
> ofproto/ofproto-dpif.c | 16 +++++++++--
> ofproto/ofproto.c | 18 +++++++++++++
> tests/ofp-print.at | 10 +++++++
> tests/ofproto.at | 20 ++++++++++++--
> tests/ovs-ofctl.at | 2 +
> utilities/ovs-ofctl.8.in | 32 ++++++++++++++++++++---
> 19 files changed, 254 insertions(+), 24 deletions(-)
>
> diff --git a/DESIGN b/DESIGN
> index f383b65..2112925 100644
> --- a/DESIGN
> +++ b/DESIGN
> @@ -24,6 +24,16 @@ Second, OFPT_FLOW_REMOVED and NXT_FLOW_REMOVED messages are generated
> only if the flow that was removed had the OFPFF_SEND_FLOW_REM flag
> set.
>
> +Third, OFPT_PACKET_IN and NXT_PACKET_IN messages are sent only to
> +OpenFlow controller connections that have the correct connection ID
> +(see "struct nx_controller_id" and "struct nx_action_controller"):
> +
> + - For packet-in messages generated by a NXAST_CONTROLLER action,
> + the controller ID specified in the action.
> +
> + - For other packet-in messages, controller ID zero. (This is the
> + default ID when an OpenFlow controller does not configure one.)
> +
> Finally, Open vSwitch consults a per-connection table indexed by the
> message type, reason code, and current role. The following table
> shows how this table is initialized by default when an OpenFlow
> diff --git a/NEWS b/NEWS
> index 0f36224..15f4263 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -11,6 +11,8 @@ post-v1.5.0
> - OpenFlow:
> - Added support for bitwise matching on TCP and UDP ports.
> See ovs-ofctl(8) for more information.
> + - New Nicira action NXAST_CONTROLLER that offers additional features
> + over output to OFPP_CONTROLLER.
> - Logging to console and file will have UTC timestamp as a default for all
> the daemons. An example of the default format is 2012-01-27T16:35:17Z.
> ovs-appctl can be used to change the default format as before.
> diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
> index 00411bf..f09854f 100644
> --- a/include/openflow/nicira-ext.h
> +++ b/include/openflow/nicira-ext.h
> @@ -111,6 +111,7 @@ enum nicira_type {
> NXT_PACKET_IN = 17, /* Nicira Packet In. */
>
> NXT_SET_ASYNC_CONFIG = 18, /* struct nx_async_config. */
> + NXT_SET_CONTROLLER_ID = 19, /* struct nx_controller_id. */
> };
>
> /* Header for Nicira vendor stats request and reply messages. */
> @@ -330,6 +331,7 @@ enum nx_action_subtype {
> NXAST_LEARN, /* struct nx_action_learn */
> NXAST_EXIT, /* struct nx_action_header */
> NXAST_DEC_TTL, /* struct nx_action_header */
> + NXAST_CONTROLLER, /* struct nx_action_controller */
> };
>
> /* Header for Nicira-defined actions. */
> @@ -1851,5 +1853,45 @@ struct nx_aggregate_stats_reply {
> uint8_t pad[4]; /* Align to 64 bits. */
> };
> OFP_ASSERT(sizeof(struct nx_aggregate_stats_reply) == 48);
> +
> +/* NXT_SET_CONTROLLER_ID.
> + *
> + * Each OpenFlow controller connection has a 16-bit identifier that is
> + * initially 0. This message changes the connection's ID to 'id'.
> + *
> + * Controller connection IDs need not be unique.
> + *
> + * The NXAST_CONTROLLER action is the only current user of controller
> + * connection IDs. */
> +struct nx_controller_id {
> + struct nicira_header nxh;
> + uint8_t zero[6]; /* Must be zero. */
> + ovs_be16 controller_id; /* New controller connection ID. */
> +};
> +OFP_ASSERT(sizeof(struct nx_controller_id) == 24);
> +
> +/* 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:
> + *
> + * - 'reason': The reason code to use in the ofp_packet_in or nx_packet_in.
> + *
> + * - 'controller_id': The ID of the controller connection to which the
> + * ofp_packet_in should be sent. The ofp_packet_in or nx_packet_in is
> + * sent only to controllers that have the specified controller connection
> + * ID. See "struct nx_controller_id" for more information. */
> +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 controller_id; /* Controller ID to send packet-in. */
> + uint8_t reason; /* enum ofp_packet_in_reason (OFPR_*). */
> + uint8_t zero; /* Must be zero. */
> +};
> +OFP_ASSERT(sizeof(struct nx_action_controller) == 16);
>
> #endif /* openflow/nicira-ext.h */
> diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h
> index a707087..cfdb192 100644
> --- a/include/openflow/openflow.h
> +++ b/include/openflow/openflow.h
> @@ -294,7 +294,8 @@ OFP_ASSERT(sizeof(struct ofp_port_mod) == 32);
> enum ofp_packet_in_reason {
> OFPR_NO_MATCH, /* No matching flow. */
> OFPR_ACTION, /* Action explicitly output to controller. */
> - OFPR_INVALID_TTL /* Packet has invalid TTL. */
> + OFPR_INVALID_TTL, /* Packet has invalid TTL. */
> + OFPR_N_REASONS
> };
>
> /* Packet received on port (datapath -> controller). */
> diff --git a/lib/learning-switch.c b/lib/learning-switch.c
> index eec2532..7d775ee 100644
> --- a/lib/learning-switch.c
> +++ b/lib/learning-switch.c
> @@ -265,6 +265,7 @@ lswitch_process_packet(struct lswitch *sw, struct rconn *rconn,
> case OFPUTIL_NXT_FLOW_MOD:
> case OFPUTIL_NXT_FLOW_REMOVED:
> case OFPUTIL_NXT_SET_ASYNC_CONFIG:
> + case OFPUTIL_NXT_SET_CONTROLLER_ID:
> case OFPUTIL_NXST_FLOW_REQUEST:
> case OFPUTIL_NXST_AGGREGATE_REQUEST:
> case OFPUTIL_NXST_FLOW_REPLY:
> diff --git a/lib/ofp-errors.h b/lib/ofp-errors.h
> index fbd28e3..28fa112 100644
> --- a/lib/ofp-errors.h
> +++ b/lib/ofp-errors.h
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
> + * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks.
> *
> * Licensed under the Apache License, Version 2.0 (the "License");
> * you may not use this file except in compliance with the License.
> @@ -123,6 +123,9 @@ enum ofperr {
> /* NX(1,514). The in_port in an ofp_packet_out request is invalid. */
> OFPERR_NXBRC_BAD_IN_PORT,
>
> + /* NX(1,515). Must-be-zero field had nonzero value. */
> + OFPERR_NXBRC_MUST_BE_ZERO,
> +
> /* ## ---------------- ## */
> /* ## OFPET_BAD_ACTION ## */
> /* ## ---------------- ## */
> @@ -170,6 +173,9 @@ enum ofperr {
> /* OF1.1(2,12). Actions uses an unsupported tag/encap. */
> OFPERR_OFPBAC_BAD_TAG,
>
> + /* NX(2,256). Must-be-zero action argument had nonzero value. */
> + OFPERR_NXBAC_MUST_BE_ZERO,
> +
> /* ## --------------------- ## */
> /* ## OFPET_BAD_INSTRUCTION ## */
> /* ## --------------------- ## */
> diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
> index f96f817..8271466 100644
> --- a/lib/ofp-parse.c
> +++ b/lib/ofp-parse.c
> @@ -250,6 +250,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 controller_id = 0;
> + 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 (!ofputil_packet_in_reason_from_string(value, &reason)) {
> + ovs_fatal(0, "unknown reason \"%s\"", value);
> + }
> + } else if (!strcmp(name, "max_len")) {
> + max_len = str_to_u16(value, "max_len");
> + } else if (!strcmp(name, "id")) {
> + controller_id = str_to_u16(value, "id");
> + } else {
> + ovs_fatal(0, "unknown key \"%s\" parsing controller action",
> + name);
> + }
> + }
> + }
> +
> + if (reason == OFPR_ACTION && controller_id == 0) {
> + 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;
> + nac->controller_id = htons(controller_id);
> + }
> +}
> +
> +static void
> parse_named_action(enum ofputil_action_code code, const struct flow *flow,
> struct ofpbuf *b, char *arg)
> {
> @@ -367,6 +409,10 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
> case OFPUTIL_NXAST_DEC_TTL:
> ofputil_put_NXAST_DEC_TTL(b);
> break;
> +
> + case OFPUTIL_NXAST_CONTROLLER:
> + parse_controller(b, arg);
> + break;
> }
> }
>
> @@ -396,17 +442,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 ae7ed08..d5d4acf 100644
> --- a/lib/ofp-print.c
> +++ b/lib/ofp-print.c
> @@ -176,6 +176,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;
> struct mf_subfield subfield;
> uint16_t port;
>
> @@ -338,6 +339,23 @@ 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_cstr(s, "controller(");
> + if (nac->reason != OFPR_ACTION) {
> + ds_put_format(s, "reason=%s,",
> + ofputil_packet_in_reason_to_string(nac->reason));
> + }
> + if (nac->max_len != htons(UINT16_MAX)) {
> + ds_put_format(s, "max_len=%"PRIu16",", ntohs(nac->max_len));
> + }
> + if (nac->controller_id != htons(0)) {
> + ds_put_format(s, "id=%"PRIu16",", ntohs(nac->controller_id));
> + }
> + ds_chomp(s, ',');
> + ds_put_char(s, ')');
> + break;
> +
> default:
> break;
> }
> @@ -1370,6 +1388,13 @@ ofp_print_nxt_set_async_config(struct ds *string,
> }
>
> static void
> +ofp_print_nxt_set_controller_id(struct ds *string,
> + const struct nx_controller_id *nci)
> +{
> + ds_put_format(string, " id=%"PRIu16, ntohs(nci->controller_id));
> +}
> +
> +static void
> ofp_to_string__(const struct ofp_header *oh,
> const struct ofputil_msg_type *type, struct ds *string,
> int verbosity)
> @@ -1525,6 +1550,8 @@ ofp_to_string__(const struct ofp_header *oh,
> ofp_print_nxt_set_packet_in_format(string, msg);
> break;
>
> + case OFPUTIL_NXT_SET_CONTROLLER_ID:
> + ofp_print_nxt_set_controller_id(string, msg);
> break;
>
> case OFPUTIL_NXT_SET_ASYNC_CONFIG:
> diff --git a/lib/ofp-util.c b/lib/ofp-util.c
> index 704823a..e6ab5a6 100644
> --- a/lib/ofp-util.c
> +++ b/lib/ofp-util.c
> @@ -400,6 +400,10 @@ ofputil_decode_vendor(const struct ofp_header *oh, size_t length,
> { OFPUTIL_NXT_SET_ASYNC_CONFIG, OFP10_VERSION,
> NXT_SET_ASYNC_CONFIG, "NXT_SET_ASYNC_CONFIG",
> sizeof(struct nx_async_config), 0 },
> +
> + { OFPUTIL_NXT_SET_CONTROLLER_ID, OFP10_VERSION,
> + NXT_SET_CONTROLLER_ID, "NXT_SET_CONTROLLER_ID",
> + sizeof(struct nx_controller_id), 0 },
> };
>
> static const struct ofputil_msg_category nxt_category = {
> @@ -2499,6 +2503,12 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
> error = learn_check((const struct nx_action_learn *) a, flow);
> break;
>
> + case OFPUTIL_NXAST_CONTROLLER:
> + if (((const struct nx_action_controller *) a)->zero) {
> + error = OFPERR_NXBAC_MUST_BE_ZERO;
> + }
> + break;
> +
> case OFPUTIL_OFPAT_STRIP_VLAN:
> case OFPUTIL_OFPAT_SET_NW_SRC:
> case OFPUTIL_OFPAT_SET_NW_DST:
> diff --git a/lib/ofp-util.def b/lib/ofp-util.def
> index d05ec9d..d690389 100644
> --- a/lib/ofp-util.def
> +++ b/lib/ofp-util.def
> @@ -37,4 +37,5 @@ 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_DEC_TTL, nx_action_header, 0, "dec_ttl")
> +NXAST_ACTION(NXAST_CONTROLLER, nx_action_controller, 0, "controller")
> #undef NXAST_ACTION
> diff --git a/lib/ofp-util.h b/lib/ofp-util.h
> index 0ca1d99..33b9048 100644
> --- a/lib/ofp-util.h
> +++ b/lib/ofp-util.h
> @@ -80,6 +80,7 @@ enum ofputil_msg_code {
> OFPUTIL_NXT_SET_PACKET_IN_FORMAT,
> OFPUTIL_NXT_PACKET_IN,
> OFPUTIL_NXT_SET_ASYNC_CONFIG,
> + OFPUTIL_NXT_SET_CONTROLLER_ID,
>
> /* NXST_* stat requests. */
> OFPUTIL_NXST_FLOW_REQUEST,
> @@ -229,6 +230,7 @@ struct ofputil_packet_in {
> size_t packet_len;
>
> enum ofp_packet_in_reason reason; /* One of OFPRR_*. */
> + uint16_t controller_id; /* Controller ID to send to. */
> uint8_t table_id;
> ovs_be64 cookie;
>
> diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
> index 0cd7d53..69534c3 100644
> --- a/ofproto/connmgr.c
> +++ b/ofproto/connmgr.c
> @@ -73,6 +73,7 @@ struct ofconn {
> struct pinsched *schedulers[N_SCHEDULERS];
> struct pktbuf *pktbuf; /* OpenFlow packet buffers. */
> int miss_send_len; /* Bytes to send of buffered packets. */
> + uint16_t controller_id; /* Connection controller ID. */
>
> /* Number of OpenFlow messages queued on 'rconn' as replies to OpenFlow
> * requests, and the maximum number before we stop reading OpenFlow
> @@ -820,6 +821,16 @@ ofconn_set_packet_in_format(struct ofconn *ofconn,
> ofconn->packet_in_format = packet_in_format;
> }
>
> +/* Sets the controller connection ID for 'ofconn' to 'controller_id'.
> + *
> + * The connection controller ID is used for OFPP_CONTROLLER and
> + * NXAST_CONTROLLER actions. See "struct nx_action_controller" for details. */
> +void
> +ofconn_set_controller_id(struct ofconn *ofconn, uint16_t controller_id)
> +{
> + ofconn->controller_id = controller_id;
> +}
> +
> /* Returns true if the NXT_FLOW_MOD_TABLE_ID extension is enabled, false
> * otherwise.
> *
> @@ -1017,6 +1028,7 @@ ofconn_flush(struct ofconn *ofconn)
> ofconn->miss_send_len = (ofconn->type == OFCONN_PRIMARY
> ? OFP_DEFAULT_MISS_SEND_LEN
> : 0);
> + ofconn->controller_id = 0;
>
> rconn_packet_counter_destroy(ofconn->reply_counter);
> ofconn->reply_counter = rconn_packet_counter_create();
> @@ -1292,7 +1304,8 @@ connmgr_send_packet_in(struct connmgr *mgr,
> struct ofconn *ofconn;
>
> LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
> - if (ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, pin->reason)) {
> + if (ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, pin->reason)
> + && ofconn->controller_id == pin->controller_id) {
> schedule_packet_in(ofconn, *pin, flow);
> }
> }
> diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h
> index f9c9f4d..58564b3 100644
> --- a/ofproto/connmgr.h
> +++ b/ofproto/connmgr.h
> @@ -97,6 +97,8 @@ void ofconn_set_flow_format(struct ofconn *, enum nx_flow_format);
> enum nx_packet_in_format ofconn_get_packet_in_format(struct ofconn *);
> void ofconn_set_packet_in_format(struct ofconn *, enum nx_packet_in_format);
>
> +void ofconn_set_controller_id(struct ofconn *, uint16_t controller_id);
> +
> bool ofconn_get_flow_mod_table_id(const struct ofconn *);
> void ofconn_set_flow_mod_table_id(struct ofconn *, bool enable);
>
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index 28f0434..a600f0c 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -2440,6 +2440,7 @@ send_packet_in_miss(struct ofproto_dpif *ofproto, const struct ofpbuf *packet,
> pin.packet_len = packet->size;
> pin.total_len = packet->size;
> pin.reason = OFPR_NO_MATCH;
> + pin.controller_id = 0;
>
> pin.table_id = 0;
> pin.cookie = 0;
> @@ -4440,7 +4441,8 @@ flood_packets(struct action_xlate_ctx *ctx, bool all)
>
> static void
> execute_controller_action(struct action_xlate_ctx *ctx, int len,
> - enum ofp_packet_in_reason reason)
> + enum ofp_packet_in_reason reason,
> + uint16_t controller_id)
> {
> struct ofputil_packet_in pin;
> struct ofpbuf *packet;
> @@ -4486,6 +4488,7 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len,
> pin.packet = packet->data;
> pin.packet_len = packet->size;
> pin.reason = reason;
> + pin.controller_id = controller_id;
> pin.table_id = ctx->table_id;
> pin.cookie = ctx->rule ? ctx->rule->up.flow_cookie : 0;
>
> @@ -4510,7 +4513,7 @@ compose_dec_ttl(struct action_xlate_ctx *ctx)
> ctx->flow.nw_ttl--;
> return false;
> } else {
> - execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL);
> + execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0);
>
> /* Stop processing for current table. */
> return true;
> @@ -4542,7 +4545,7 @@ xlate_output_action__(struct action_xlate_ctx *ctx,
> flood_packets(ctx, true);
> break;
> case OFPP_CONTROLLER:
> - execute_controller_action(ctx, max_len, OFPR_ACTION);
> + execute_controller_action(ctx, max_len, OFPR_ACTION, 0);
> break;
> case OFPP_LOCAL:
> compose_output_action(ctx, OFPP_LOCAL);
> @@ -4760,6 +4763,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;
>
> @@ -4915,6 +4919,12 @@ 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;
> + execute_controller_action(ctx, ntohs(nac->max_len), nac->reason,
> + ntohs(nac->controller_id));
> + break;
> }
> }
>
> diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
> index c251475..95a81a4 100644
> --- a/ofproto/ofproto.c
> +++ b/ofproto/ofproto.c
> @@ -3122,6 +3122,21 @@ handle_nxt_set_async_config(struct ofconn *ofconn, const struct ofp_header *oh)
> }
>
> static enum ofperr
> +handle_nxt_set_controller_id(struct ofconn *ofconn,
> + const struct ofp_header *oh)
> +{
> + const struct nx_controller_id *nci;
> +
> + nci = (const struct nx_controller_id *) oh;
> + if (!is_all_zeros(nci->zero, sizeof nci->zero)) {
> + return OFPERR_NXBRC_MUST_BE_ZERO;
> + }
> +
> + ofconn_set_controller_id(ofconn, ntohs(nci->controller_id));
> + return 0;
> +}
> +
> +static enum ofperr
> handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh)
> {
> struct ofp_header *ob;
> @@ -3191,6 +3206,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
> case OFPUTIL_NXT_SET_PACKET_IN_FORMAT:
> return handle_nxt_set_packet_in_format(ofconn, oh);
>
> + case OFPUTIL_NXT_SET_CONTROLLER_ID:
> + return handle_nxt_set_controller_id(ofconn, oh);
> +
> case OFPUTIL_NXT_FLOW_MOD:
> return handle_flow_mod(ofconn, oh);
>
> diff --git a/tests/ofp-print.at b/tests/ofp-print.at
> index 27f878a..7345b58 100644
> --- a/tests/ofp-print.at
> +++ b/tests/ofp-print.at
> @@ -728,6 +728,16 @@ NXT_SET_ASYNC_CONFIG (xid=0x0):
> ])
> AT_CLEANUP
>
> +AT_SETUP([NXT_SET_CONTROLLER_ID])
> +AT_KEYWORDS([ofp-print])
> +AT_CHECK([ovs-ofctl ofp-print "\
> +01 04 00 18 00 00 00 03 00 00 23 20 00 00 00 13 \
> +00 00 00 00 00 00 00 7b \
> +"], [0], [dnl
> +NXT_SET_CONTROLLER_ID (xid=0x3): id=123
> +])
> +AT_CLEANUP
> +
> AT_SETUP([NXT_SET_FLOW_FORMAT])
> AT_KEYWORDS([ofp-print])
> AT_CHECK([ovs-ofctl ofp-print "\
> diff --git a/tests/ofproto.at b/tests/ofproto.at
> index fb53d16..1156ee4 100644
> --- a/tests/ofproto.at
> +++ b/tests/ofproto.at
> @@ -433,14 +433,21 @@ check_async () {
> ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
> : > expout
>
> - # OFPT_PACKET_IN, OFPR_ACTION
> + # OFPT_PACKET_IN, OFPR_ACTION (controller_id=0)
> ovs-ofctl -v packet-out br0 none controller '0001020304050010203040501234'
> if test X"$1" = X"OFPR_ACTION"; then shift;
> echo >>expout "OFPT_PACKET_IN: total_len=14 in_port=NONE (via action) data_len=14 (unbuffered)
> priority:0,tunnel:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 ip(0.0.0.0->0.0.0.0)"
> fi
>
> - # OFPT_PACKET_IN, OFPR_INVALID_TTL
> + # OFPT_PACKET_IN, OFPR_NO_MATCH (controller_id=123)
> + ovs-ofctl -v packet-out br0 none 'controller(reason=no_match,id=123)' '0001020304050010203040501234'
> + if test X"$1" = X"OFPR_NO_MATCH"; then shift;
> + echo >>expout "OFPT_PACKET_IN: total_len=14 in_port=NONE (via no_match) data_len=14 (unbuffered)
> +priority:0,tunnel:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 ip(0.0.0.0->0.0.0.0)"
> + fi
> +
> + # OFPT_PACKET_IN, OFPR_INVALID_TTL (controller_id=0)
> ovs-ofctl packet-out br0 none dec_ttl '002583dfb4000026b98cb0f908004500003fb7e200000011339bac11370dac100002d7730035002b8f6d86fb0100000100000000000006626c702d7873066e696369726103636f6d00000f00'
> if test X"$1" = X"OFPR_INVALID_TTL"; then shift;
> echo >>expout "OFPT_PACKET_IN: total_len=76 in_port=NONE (via invalid_ttl) data_len=76 (unbuffered)
> @@ -502,9 +509,16 @@ check_async 4 OFPPR_ADD OFPPR_DELETE
> ovs-appctl -t ovs-ofctl ofctl/send 01040028000000020000232000000012000000020000000500000005000000020000000200000005
> check_async 5 OFPR_INVALID_TTL OFPPR_DELETE OFPRR_DELETE
>
> +# Set controller ID 123.
> +ovs-appctl -t ovs-ofctl ofctl/send 01040018000000030000232000000013000000000000007b
> +check_async 6 OFPR_NO_MATCH OFPPR_DELETE OFPRR_DELETE
> +
> +# Restore controller ID 0.
> +ovs-appctl -t ovs-ofctl ofctl/send 010400180000000300002320000000130000000000000000
> +
> # Become master.
> ovs-appctl -t ovs-ofctl ofctl/send 0104001400000002000023200000000a00000001
> -check_async 6 OFPR_ACTION OFPPR_ADD
> +check_async 7 OFPR_ACTION OFPPR_ADD
>
> ovs-appctl -t ovs-ofctl exit
> AT_CLEANUP
> diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
> index e35fc73..edd47ee 100644
> --- a/tests/ovs-ofctl.at
> +++ b/tests/ovs-ofctl.at
> @@ -27,6 +27,7 @@ actions=output:1,bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[16..31],slaves:1),
> actions=resubmit:1,resubmit(2),resubmit(,3),resubmit(2,3)
> send_flow_rem,actions=output:1,output:NXM_NX_REG0[],output:2,output:NXM_NX_REG1[16..31],output:3
> check_overlap,actions=output:1,exit,output:2
> +actions=controller(max_len=123,reason=invalid_ttl,id=555)
> ]])
>
> AT_CHECK([ovs-ofctl parse-flows flows.txt
> @@ -58,6 +59,7 @@ NXT_FLOW_MOD: ADD table:255 actions=output:1,bundle_load(eth_src,0,hrw,ofport,NX
> NXT_FLOW_MOD: ADD table:255 actions=resubmit:1,resubmit:2,resubmit(,3),resubmit(2,3)
> NXT_FLOW_MOD: ADD table:255 send_flow_rem actions=output:1,output:NXM_NX_REG0[],output:2,output:NXM_NX_REG1[16..31],output:3
> NXT_FLOW_MOD: ADD table:255 check_overlap actions=output:1,exit,output:2
> +NXT_FLOW_MOD: ADD table:255 actions=controller(reason=invalid_ttl,max_len=123,id=555)
> ]])
> AT_CLEANUP
>
> diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
> index 3531626..3780f49 100644
> --- a/utilities/ovs-ofctl.8.in
> +++ b/utilities/ovs-ofctl.8.in
> @@ -764,11 +764,35 @@ 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), \fBno_match\fR, and \fBinvalid_ttl\fR.
> +.IP "\fBid=\fIcontroller-id\fR"
> +Specify \fIcontroller-id\fR, a 16-bit integer, as the connection ID of
> +the OpenFlow controller or controllers to which the ``packet in''
> +message should be sent. The default is zero. Zero is also the
> +default connection ID for each controller connection, and a given
> +controller connection will only have a nonzero connection ID if its
> +controller uses the \fBNXT_SET_CONTROLLER_ID\fR Nicira extension to
> +OpenFlow.
> +.RE
> +Any \fIreason\fR other than \fBaction\fR and any nonzero
> +\fIcontroller-id\fR uses a Nicira vendor extension that, as of this
> +writing, is only known to be implemented by Open vSwitch (version 1.6
> +or later).
> +.
> +.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
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
More information about the dev
mailing list