Skip to content

Commit

Permalink
ofproto: Implement OpenFlow extension to allow control over async mes…
Browse files Browse the repository at this point in the history
…sages.

Until now, the rules that cover the asynchronous messages that Open vSwitch
sends to a controller have been ad hoc.  The new NXT_SET_ASYNC_CONFIG
message provides systematic, precise control.

Feature #7086.
Signed-off-by: Ben Pfaff <[email protected]>
  • Loading branch information
blp committed Feb 9, 2012
1 parent bb638b9 commit 80d5aef
Show file tree
Hide file tree
Showing 12 changed files with 432 additions and 96 deletions.
49 changes: 47 additions & 2 deletions DESIGN
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,53 @@ successful deployment. The end of this document contains contact
information that can be used to let us know how we can make Open vSwitch
more generally useful.

OpenFlow
========
Asynchronous Messages
=====================

Over time, Open vSwitch has added many knobs that control whether a
given controller receives OpenFlow asynchronous messages. This
section describes how all of these features interact.

First, a service controller never receives any asynchronous messages
unless it explicitly configures a miss_send_len greater than zero with
an OFPT_SET_CONFIG message.

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.

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
connection is made. An entry labeled "yes" means that the message is
sent, an entry labeled "---" means that the message is suppressed.

master/
message and reason code other slave
---------------------------------------- ------- -----
OFPT_PACKET_IN / NXT_PACKET_IN
OFPR_NO_MATCH yes ---
OFPR_ACTION yes ---
OFPR_INVALID_TTL --- ---

OFPT_FLOW_REMOVED / NXT_FLOW_REMOVED
OFPRR_IDLE_TIMEOUT yes ---
OFPRR_HARD_TIMEOUT yes ---
OFPRR_DELETE yes ---

OFPT_PORT_STATUS
OFPPR_ADD yes yes
OFPPR_DELETE yes yes
OFPPR_MODIFY yes yes

The NXT_SET_ASYNC_CONFIG message directly sets all of the values in
this table for the current connection. The
OFPC_INVALID_TTL_TO_CONTROLLER bit in the OFPT_SET_CONFIG message
controls the setting for OFPR_INVALID_TTL for the "master" role.


OFPAT_ENQUEUE
=============

The OpenFlow 1.0 specification requires the output port of the OFPAT_ENQUEUE
action to "refer to a valid physical port (i.e. < OFPP_MAX) or OFPP_IN_PORT".
Expand Down
11 changes: 7 additions & 4 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@ post-v1.5.0
- OpenFlow:
- Added support for bitwise matching on TCP and UDP ports.
See ovs-ofctl(8) for more information.
- NXM flow dumps now include times elapsed toward idle and hard
timeouts.
- Added an OpenFlow extension NXT_SET_ASYNC_CONFIG that allows
controllers more precise control over which OpenFlow messages they
receive asynchronously.
- The default MAC learning timeout has been increased from 60 seconds
to 300 seconds. The MAC learning timeout is now configurable.
- 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.
- New support for limiting the number of flows in an OpenFlow flow
table, with configurable policy for evicting flows upon
overflow. See the Flow_Table table in ovs-vswitch.conf.db(5)
for more information.
- OpenFlow:
- NXM flow dumps now include times elapsed toward idle and hard timeouts.
- ofproto-provider interface:
- "struct rule" has a new member "used" that ofproto implementations
should maintain by updating with ofproto_rule_update_used().
- The default MAC learning timeout has been increased from 60 seconds
to 300 seconds. The MAC learning timeout is now configurable.
- ovsdb-client:
- The new option --timestamp causes the "monitor" command to print
a timestamp with every update.
Expand Down
24 changes: 24 additions & 0 deletions include/openflow/nicira-ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ enum nicira_type {
* If so, the switch does not reply to this message (which consists only of
* a "struct nicira_header"). If not, the switch sends an error reply. */
NXT_FLOW_AGE = 18,

NXT_SET_ASYNC_CONFIG = 19, /* struct nx_async_config. */
};

/* Header for Nicira vendor stats request and reply messages. */
Expand Down Expand Up @@ -288,6 +290,28 @@ enum nx_role {
NX_ROLE_MASTER, /* Full access, at most one. */
NX_ROLE_SLAVE /* Read-only access. */
};

/* NXT_SET_ASYNC_CONFIG.
*
* Sent by a controller, this message configures the asynchronous messages that
* the controller wants to receive. Element 0 in each array specifies messages
* of interest when the controller has an "other" or "master" role; element 1,
* when the controller has a "slave" role.
*
* Each array element is a bitmask in which a 0-bit disables receiving a
* particular message and a 1-bit enables receiving it. Each bit controls the
* message whose 'reason' corresponds to the bit index. For example, the bit
* with value 1<<2 == 4 in port_status_mask[1] determines whether the
* controller will receive OFPT_PORT_STATUS messages with reason OFPPR_MODIFY
* (value 2) when the controller has a "slave" role.
*/
struct nx_async_config {
struct nicira_header nxh;
ovs_be32 packet_in_mask[2]; /* Bitmasks of OFPR_* values. */
ovs_be32 port_status_mask[2]; /* Bitmasks of OFPRR_* values. */
ovs_be32 flow_removed_mask[2]; /* Bitmasks of OFPPR_* values. */
};
OFP_ASSERT(sizeof(struct nx_async_config) == 40);

/* Nicira vendor flow actions. */

Expand Down
1 change: 1 addition & 0 deletions lib/learning-switch.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_FLOW_AGE:
case OFPUTIL_NXT_SET_ASYNC_CONFIG:
case OFPUTIL_NXST_FLOW_REQUEST:
case OFPUTIL_NXST_AGGREGATE_REQUEST:
case OFPUTIL_NXST_FLOW_REPLY:
Expand Down
142 changes: 113 additions & 29 deletions lib/ofp-print.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,24 @@ ofp_packet_to_string(const void *data, size_t len)
return ds_cstr(&ds);
}

static const char *
ofp_packet_in_reason_to_string(enum ofp_packet_in_reason reason)
{
static char s[32];

switch (reason) {
case OFPR_NO_MATCH:
return "no_match";
case OFPR_ACTION:
return "action";
case OFPR_INVALID_TTL:
return "invalid_ttl";
default:
sprintf(s, "%d", (int) reason);
return s;
}
}

static void
ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
int verbosity)
Expand Down Expand Up @@ -121,20 +139,8 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
}
}

switch (pin.reason) {
case OFPR_NO_MATCH:
ds_put_cstr(string, " (via no_match)");
break;
case OFPR_ACTION:
ds_put_cstr(string, " (via action)");
break;
case OFPR_INVALID_TTL:
ds_put_cstr(string, " (via invalid_ttl)");
break;
default:
ds_put_format(string, " (***reason %"PRIu8"***)", pin.reason);
break;
}
ds_put_format(string, " (via %s)",
ofp_packet_in_reason_to_string(pin.reason));

ds_put_format(string, " data_len=%zu", pin.packet_len);
if (pin.buffer_id == UINT32_MAX) {
Expand Down Expand Up @@ -870,6 +876,24 @@ ofp_print_duration(struct ds *string, unsigned int sec, unsigned int nsec)
ds_put_char(string, 's');
}

static const char *
ofp_flow_removed_reason_to_string(enum ofp_flow_removed_reason reason)
{
static char s[32];

switch (reason) {
case OFPRR_IDLE_TIMEOUT:
return "idle";
case OFPRR_HARD_TIMEOUT:
return "hard";
case OFPRR_DELETE:
return "delete";
default:
sprintf(s, "%d", (int) reason);
return s;
}
}

static void
ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh)
{
Expand All @@ -885,21 +909,8 @@ ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh)
ds_put_char(string, ' ');
cls_rule_format(&fr.rule, string);

ds_put_cstr(string, " reason=");
switch (fr.reason) {
case OFPRR_IDLE_TIMEOUT:
ds_put_cstr(string, "idle");
break;
case OFPRR_HARD_TIMEOUT:
ds_put_cstr(string, "hard");
break;
case OFPRR_DELETE:
ds_put_cstr(string, "delete");
break;
default:
ds_put_format(string, "**%"PRIu8"**", fr.reason);
break;
}
ds_put_format(string, " reason=%s",
ofp_flow_removed_reason_to_string(fr.reason));

if (fr.cookie != htonll(0)) {
ds_put_format(string, " cookie:0x%"PRIx64, ntohll(fr.cookie));
Expand Down Expand Up @@ -1313,6 +1324,75 @@ ofp_print_nxt_set_packet_in_format(struct ds *string,
}
}

static const char *
ofp_port_reason_to_string(enum ofp_port_reason reason)
{
static char s[32];

switch (reason) {
case OFPPR_ADD:
return "add";

case OFPPR_DELETE:
return "delete";

case OFPPR_MODIFY:
return "modify";

default:
sprintf(s, "%d", (int) reason);
return s;
}
}

static void
ofp_print_nxt_set_async_config(struct ds *string,
const struct nx_async_config *nac)
{
int i;

for (i = 0; i < 2; i++) {
int j;

ds_put_format(string, "\n %s:\n", i == 0 ? "master" : "slave");

ds_put_cstr(string, " PACKET_IN:");
for (j = 0; j < 32; j++) {
if (nac->packet_in_mask[i] & htonl(1u << j)) {
ds_put_format(string, " %s",
ofp_packet_in_reason_to_string(j));
}
}
if (!nac->packet_in_mask[i]) {
ds_put_cstr(string, " (off)");
}
ds_put_char(string, '\n');

ds_put_cstr(string, " PORT_STATUS:");
for (j = 0; j < 32; j++) {
if (nac->port_status_mask[i] & htonl(1u << j)) {
ds_put_format(string, " %s", ofp_port_reason_to_string(j));
}
}
if (!nac->port_status_mask[i]) {
ds_put_cstr(string, " (off)");
}
ds_put_char(string, '\n');

ds_put_cstr(string, " FLOW_REMOVED:");
for (j = 0; j < 32; j++) {
if (nac->flow_removed_mask[i] & htonl(1u << j)) {
ds_put_format(string, " %s",
ofp_flow_removed_reason_to_string(j));
}
}
if (!nac->flow_removed_mask[i]) {
ds_put_cstr(string, " (off)");
}
ds_put_char(string, '\n');
}
}

static void
ofp_to_string__(const struct ofp_header *oh,
const struct ofputil_msg_type *type, struct ds *string,
Expand Down Expand Up @@ -1472,6 +1552,10 @@ ofp_to_string__(const struct ofp_header *oh,
case OFPUTIL_NXT_FLOW_AGE:
break;

case OFPUTIL_NXT_SET_ASYNC_CONFIG:
ofp_print_nxt_set_async_config(string, msg);
break;

case OFPUTIL_NXST_AGGREGATE_REPLY:
ofp_print_stats_reply(string, oh);
ofp_print_nxst_aggregate_reply(string, msg);
Expand Down
4 changes: 4 additions & 0 deletions lib/ofp-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,10 @@ ofputil_decode_vendor(const struct ofp_header *oh, size_t length,
{ OFPUTIL_NXT_FLOW_AGE, OFP10_VERSION,
NXT_FLOW_AGE, "NXT_FLOW_AGE",
sizeof(struct nicira_header), 0 },

{ OFPUTIL_NXT_SET_ASYNC_CONFIG, OFP10_VERSION,
NXT_SET_ASYNC_CONFIG, "NXT_SET_ASYNC_CONFIG",
sizeof(struct nx_async_config), 0 },
};

static const struct ofputil_msg_category nxt_category = {
Expand Down
1 change: 1 addition & 0 deletions lib/ofp-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ enum ofputil_msg_code {
OFPUTIL_NXT_SET_PACKET_IN_FORMAT,
OFPUTIL_NXT_PACKET_IN,
OFPUTIL_NXT_FLOW_AGE,
OFPUTIL_NXT_SET_ASYNC_CONFIG,

/* NXST_* stat requests. */
OFPUTIL_NXST_FLOW_REQUEST,
Expand Down
Loading

0 comments on commit 80d5aef

Please sign in to comment.