summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
70e7beb)
In OpenFlow 0.9, flow "expiration" messages are sent when flows are
explicitly removed by a delete action. As such, the message is renamed
from Flow Expired to Flow Removed. This commit adds that support as well
as supporting the ability to choose sending these messages on a per flow
basis.
NOTE: OVS at this point is not wire-compatible with OpenFlow 0.9 until the
final commit in this OpenFlow 0.9 set.
/* Asynchronous messages. */
OFPT_PACKET_IN, /* Async message */
/* Asynchronous messages. */
OFPT_PACKET_IN, /* Async message */
- OFPT_FLOW_EXPIRED, /* Async message */
+ OFPT_FLOW_REMOVED, /* Async message */
OFPT_PORT_STATUS, /* Async message */
/* Controller command messages. */
OFPT_PORT_STATUS, /* Async message */
/* Controller command messages. */
#define OFP_DEFAULT_MISS_SEND_LEN 128
enum ofp_config_flags {
#define OFP_DEFAULT_MISS_SEND_LEN 128
enum ofp_config_flags {
- /* Tells datapath to notify the controller of expired flow entries. */
- OFPC_SEND_FLOW_EXP = 1 << 0,
-
/* Handling of IP fragments. */
OFPC_FRAG_NORMAL = 0 << 1, /* No special handling for fragments. */
OFPC_FRAG_DROP = 1 << 1, /* Drop fragments. */
/* Handling of IP fragments. */
OFPC_FRAG_NORMAL = 0 << 1, /* No special handling for fragments. */
OFPC_FRAG_DROP = 1 << 1, /* Drop fragments. */
};
OFP_ASSERT(sizeof(struct ofp_flow_mod) == 68);
};
OFP_ASSERT(sizeof(struct ofp_flow_mod) == 68);
-/* Why did this flow expire? */
-enum ofp_flow_expired_reason {
- OFPER_IDLE_TIMEOUT, /* Flow idle time exceeded idle_timeout. */
- OFPER_HARD_TIMEOUT /* Time exceeded hard_timeout. */
+/* Why was this flow removed? */
+enum ofp_flow_removed_reason {
+ OFPRR_IDLE_TIMEOUT, /* Flow idle time exceeded idle_timeout. */
+ OFPRR_HARD_TIMEOUT, /* Time exceeded hard_timeout. */
+ OFPRR_DELETE /* Evicted by a DELETE flow mod. */
-/* Flow expiration (datapath -> controller). */
-struct ofp_flow_expired {
+/* Flow removed (datapath -> controller). */
+struct ofp_flow_removed {
struct ofp_header header;
struct ofp_match match; /* Description of fields. */
uint16_t priority; /* Priority level of flow entry. */
struct ofp_header header;
struct ofp_match match; /* Description of fields. */
uint16_t priority; /* Priority level of flow entry. */
- uint8_t reason; /* One of OFPER_*. */
+ uint8_t reason; /* One of OFPRR_*. */
uint8_t pad[1]; /* Align to 32-bits. */
uint32_t duration; /* Time flow was alive in seconds. */
uint8_t pad[1]; /* Align to 32-bits. */
uint32_t duration; /* Time flow was alive in seconds. */
- uint8_t pad2[4]; /* Align to 64-bits. */
+ uint16_t idle_timeout; /* Idle timeout from original flow mod. */
+ uint8_t pad2[6]; /* Align to 64-bits. */
uint64_t packet_count;
uint64_t byte_count;
};
uint64_t packet_count;
uint64_t byte_count;
};
-OFP_ASSERT(sizeof(struct ofp_flow_expired) == 76);
+OFP_ASSERT(sizeof(struct ofp_flow_removed) == 80);
/* Values for 'type' in ofp_error_message. These values are immutable: they
* will not change in future versions of the protocol (although new values may
/* Values for 'type' in ofp_error_message. These values are immutable: they
* will not change in future versions of the protocol (although new values may
- OFPT_FLOW_EXPIRED,
- sizeof(struct ofp_flow_expired),
+ OFPT_FLOW_REMOVED,
+ sizeof(struct ofp_flow_removed),
/* Send OFPT_SET_CONFIG. */
osc = make_openflow(sizeof *osc, OFPT_SET_CONFIG, &b);
/* Send OFPT_SET_CONFIG. */
osc = make_openflow(sizeof *osc, OFPT_SET_CONFIG, &b);
- osc->flags = htons(OFPC_SEND_FLOW_EXP);
osc->miss_send_len = htons(OFP_DEFAULT_MISS_SEND_LEN);
queue_tx(sw, rconn, b);
osc->miss_send_len = htons(OFP_DEFAULT_MISS_SEND_LEN);
queue_tx(sw, rconn, b);
uint16_t flags;
flags = ntohs(osc->flags);
uint16_t flags;
flags = ntohs(osc->flags);
- if (flags & OFPC_SEND_FLOW_EXP) {
- flags &= ~OFPC_SEND_FLOW_EXP;
- ds_put_format(string, " (sending flow expirations)");
- }
if (flags) {
ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags);
}
if (flags) {
ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags);
}
default:
ds_put_format(string, " cmd:%d ", ntohs(ofm->command));
}
default:
ds_put_format(string, " cmd:%d ", ntohs(ofm->command));
}
- ds_put_format(string, "idle:%d hard:%d pri:%d buf:%#x",
+ ds_put_format(string, "idle:%d hard:%d pri:%d buf:%#x flags:%"PRIx16" ",
ntohs(ofm->idle_timeout), ntohs(ofm->hard_timeout),
ofm->match.wildcards ? ntohs(ofm->priority) : (uint16_t)-1,
ntohs(ofm->idle_timeout), ntohs(ofm->hard_timeout),
ofm->match.wildcards ? ntohs(ofm->priority) : (uint16_t)-1,
- ntohl(ofm->buffer_id));
+ ntohl(ofm->buffer_id), ntohs(ofm->flags));
ofp_print_actions(string, ofm->actions,
len - offsetof(struct ofp_flow_mod, actions));
ds_put_char(string, '\n');
}
ofp_print_actions(string, ofm->actions,
len - offsetof(struct ofp_flow_mod, actions));
ds_put_char(string, '\n');
}
-/* Pretty-print the OFPT_FLOW_EXPIRED packet of 'len' bytes at 'oh' to 'string'
+/* Pretty-print the OFPT_FLOW_REMOVED packet of 'len' bytes at 'oh' to 'string'
* at the given 'verbosity' level. */
static void
* at the given 'verbosity' level. */
static void
-ofp_print_flow_expired(struct ds *string, const void *oh, size_t len UNUSED,
+ofp_print_flow_removed(struct ds *string, const void *oh, size_t len UNUSED,
- const struct ofp_flow_expired *ofe = oh;
+ const struct ofp_flow_removed *ofr = oh;
- ofp_print_match(string, &ofe->match, verbosity);
+ ofp_print_match(string, &ofr->match, verbosity);
ds_put_cstr(string, " reason=");
ds_put_cstr(string, " reason=");
- switch (ofe->reason) {
- case OFPER_IDLE_TIMEOUT:
+ switch (ofr->reason) {
+ case OFPRR_IDLE_TIMEOUT:
ds_put_cstr(string, "idle");
break;
ds_put_cstr(string, "idle");
break;
- case OFPER_HARD_TIMEOUT:
+ case OFPRR_HARD_TIMEOUT:
ds_put_cstr(string, "hard");
break;
ds_put_cstr(string, "hard");
break;
+ case OFPRR_DELETE:
+ ds_put_cstr(string, "delete");
+ break;
- ds_put_format(string, "**%"PRIu8"**", ofe->reason);
+ ds_put_format(string, "**%"PRIu8"**", ofr->reason);
break;
}
ds_put_format(string,
break;
}
ds_put_format(string,
- " pri%"PRIu16" secs%"PRIu32" pkts%"PRIu64" bytes%"PRIu64"\n",
- ofe->match.wildcards ? ntohs(ofe->priority) : (uint16_t)-1,
- ntohl(ofe->duration), ntohll(ofe->packet_count),
- ntohll(ofe->byte_count));
+ " pri%"PRIu16" secs%"PRIu32" idle%"PRIu16" pkts%"PRIu64
+ " bytes%"PRIu64"\n",
+ ofr->match.wildcards ? ntohs(ofr->priority) : (uint16_t)-1,
+ ntohl(ofr->duration), ntohs(ofr->idle_timeout),
+ ntohll(ofr->packet_count), ntohll(ofr->byte_count));
- OFPT_FLOW_EXPIRED,
- "flow_expired",
- sizeof (struct ofp_flow_expired),
- ofp_print_flow_expired,
+ OFPT_FLOW_REMOVED,
+ "flow_removed",
+ sizeof (struct ofp_flow_removed),
+ ofp_print_flow_removed,
uint16_t idle_timeout; /* In seconds from time of last use. */
uint16_t hard_timeout; /* In seconds from time of creation. */
uint16_t idle_timeout; /* In seconds from time of last use. */
uint16_t hard_timeout; /* In seconds from time of creation. */
+ bool send_flow_removed; /* Send a flow removed message? */
long long int used; /* Last-used time (0 if never used). */
long long int created; /* Creation time. */
uint64_t packet_count; /* Number of packets received. */
long long int used; /* Last-used time (0 if never used). */
long long int created; /* Creation time. */
uint64_t packet_count; /* Number of packets received. */
static struct rule *rule_create(struct ofproto *, struct rule *super,
const union ofp_action *, size_t n_actions,
static struct rule *rule_create(struct ofproto *, struct rule *super,
const union ofp_action *, size_t n_actions,
- uint16_t idle_timeout, uint16_t hard_timeout);
+ uint16_t idle_timeout, uint16_t hard_timeout,
+ bool send_flow_removed);
static void rule_free(struct rule *);
static void rule_destroy(struct ofproto *, struct rule *);
static struct rule *rule_from_cls_rule(const struct cls_rule *);
static void rule_free(struct rule *);
static void rule_destroy(struct ofproto *, struct rule *);
static struct rule *rule_from_cls_rule(const struct cls_rule *);
struct rule *displaced_rule);
static void rule_uninstall(struct ofproto *, struct rule *);
static void rule_post_uninstall(struct ofproto *, struct rule *);
struct rule *displaced_rule);
static void rule_uninstall(struct ofproto *, struct rule *);
static void rule_post_uninstall(struct ofproto *, struct rule *);
+static void send_flow_removed(struct ofproto *p, struct rule *rule,
+ long long int now, uint8_t reason);
struct ofconn {
struct list node;
struct rconn *rconn;
struct pktbuf *pktbuf;
struct ofconn {
struct list node;
struct rconn *rconn;
struct pktbuf *pktbuf;
int miss_send_len;
struct rconn_packet_counter *packet_in_counter;
int miss_send_len;
struct rconn_packet_counter *packet_in_counter;
{
struct rule *rule;
rule = rule_create(p, NULL, actions, n_actions,
{
struct rule *rule;
rule = rule_create(p, NULL, actions, n_actions,
- idle_timeout >= 0 ? idle_timeout : 5 /* XXX */, 0);
+ idle_timeout >= 0 ? idle_timeout : 5 /* XXX */,
+ 0, false);
cls_rule_from_flow(&rule->cr, flow, wildcards, priority);
rule_insert(p, rule, NULL, 0);
}
cls_rule_from_flow(&rule->cr, flow, wildcards, priority);
rule_insert(p, rule, NULL, 0);
}
list_push_back(&p->all_conns, &ofconn->node);
ofconn->rconn = rconn;
ofconn->pktbuf = NULL;
list_push_back(&p->all_conns, &ofconn->node);
ofconn->rconn = rconn;
ofconn->pktbuf = NULL;
- ofconn->send_flow_exp = false;
ofconn->miss_send_len = 0;
ofconn->packet_in_counter = rconn_packet_counter_create ();
ofconn->reply_counter = rconn_packet_counter_create ();
ofconn->miss_send_len = 0;
ofconn->packet_in_counter = rconn_packet_counter_create ();
ofconn->reply_counter = rconn_packet_counter_create ();
static struct rule *
rule_create(struct ofproto *ofproto, struct rule *super,
const union ofp_action *actions, size_t n_actions,
static struct rule *
rule_create(struct ofproto *ofproto, struct rule *super,
const union ofp_action *actions, size_t n_actions,
- uint16_t idle_timeout, uint16_t hard_timeout)
+ uint16_t idle_timeout, uint16_t hard_timeout,
+ bool send_flow_removed)
{
struct rule *rule = xcalloc(1, sizeof *rule);
rule->idle_timeout = idle_timeout;
rule->hard_timeout = hard_timeout;
rule->used = rule->created = time_msec();
{
struct rule *rule = xcalloc(1, sizeof *rule);
rule->idle_timeout = idle_timeout;
rule->hard_timeout = hard_timeout;
rule->used = rule->created = time_msec();
+ rule->send_flow_removed = send_flow_removed;
rule->super = super;
if (super) {
list_push_back(&super->list, &rule->list);
rule->super = super;
if (super) {
list_push_back(&super->list, &rule->list);
const flow_t *flow)
{
struct rule *subrule = rule_create(ofproto, rule, NULL, 0,
const flow_t *flow)
{
struct rule *subrule = rule_create(ofproto, rule, NULL, 0,
- rule->idle_timeout, rule->hard_timeout);
+ rule->idle_timeout, rule->hard_timeout,
+ false);
COVERAGE_INC(ofproto_subrule_create);
cls_rule_from_flow(&subrule->cr, flow, 0,
(rule->cr.priority <= UINT16_MAX ? UINT16_MAX
COVERAGE_INC(ofproto_subrule_create);
cls_rule_from_flow(&subrule->cr, flow, 0,
(rule->cr.priority <= UINT16_MAX ? UINT16_MAX
/* Figure out flags. */
dpif_get_drop_frags(p->dpif, &drop_frags);
flags = drop_frags ? OFPC_FRAG_DROP : OFPC_FRAG_NORMAL;
/* Figure out flags. */
dpif_get_drop_frags(p->dpif, &drop_frags);
flags = drop_frags ? OFPC_FRAG_DROP : OFPC_FRAG_NORMAL;
- if (ofconn->send_flow_exp) {
- flags |= OFPC_SEND_FLOW_EXP;
- }
/* Send reply. */
osc = make_openflow_xid(sizeof *osc, OFPT_GET_CONFIG_REPLY, oh->xid, &buf);
/* Send reply. */
osc = make_openflow_xid(sizeof *osc, OFPT_GET_CONFIG_REPLY, oh->xid, &buf);
}
flags = ntohs(osc->flags);
}
flags = ntohs(osc->flags);
- ofconn->send_flow_exp = (flags & OFPC_SEND_FLOW_EXP) != 0;
-
if (ofconn == p->controller) {
switch (flags & OFPC_FRAG_MASK) {
case OFPC_FRAG_NORMAL:
if (ofconn == p->controller) {
switch (flags & OFPC_FRAG_MASK) {
case OFPC_FRAG_NORMAL:
rule = rule_create(p, NULL, (const union ofp_action *) ofm->actions,
n_actions, ntohs(ofm->idle_timeout),
rule = rule_create(p, NULL, (const union ofp_action *) ofm->actions,
n_actions, ntohs(ofm->idle_timeout),
- ntohs(ofm->hard_timeout));
+ ntohs(ofm->hard_timeout),
+ ofm->flags & htons(OFPFF_SEND_FLOW_REM));
cls_rule_from_match(&rule->cr, &ofm->match, ntohs(ofm->priority));
packet = NULL;
cls_rule_from_match(&rule->cr, &ofm->match, ntohs(ofm->priority));
packet = NULL;
}
if (command == OFPFC_DELETE) {
}
if (command == OFPFC_DELETE) {
+ long long int now = time_msec();
+ send_flow_removed(p, rule, now, OFPRR_DELETE);
rule_remove(p, rule);
} else {
size_t actions_len = n_actions * sizeof *rule->actions;
rule_remove(p, rule);
} else {
size_t actions_len = n_actions * sizeof *rule->actions;
-compose_flow_exp(const struct rule *rule, long long int now, uint8_t reason)
+compose_flow_removed(const struct rule *rule, long long int now, uint8_t reason)
- struct ofp_flow_expired *ofe;
+ struct ofp_flow_removed *ofr;
struct ofpbuf *buf;
long long int last_used = rule->used ? now - rule->used : 0;
struct ofpbuf *buf;
long long int last_used = rule->used ? now - rule->used : 0;
- ofe = make_openflow(sizeof *ofe, OFPT_FLOW_EXPIRED, &buf);
- flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofe->match);
- ofe->priority = htons(rule->cr.priority);
- ofe->reason = reason;
- ofe->duration = htonl((now - rule->created - last_used) / 1000);
- ofe->packet_count = htonll(rule->packet_count);
- ofe->byte_count = htonll(rule->byte_count);
+ ofr = make_openflow(sizeof *ofr, OFPT_FLOW_REMOVED, &buf);
+ flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofr->match);
+ ofr->priority = htons(rule->cr.priority);
+ ofr->reason = reason;
+ ofr->duration = htonl((now - rule->created - last_used) / 1000);
+ ofr->idle_timeout = htons(rule->idle_timeout);
+ ofr->packet_count = htonll(rule->packet_count);
+ ofr->byte_count = htonll(rule->byte_count);
return buf;
}
static void
return buf;
}
static void
-send_flow_exp(struct ofproto *p, struct rule *rule,
- long long int now, uint8_t reason)
+uninstall_idle_flow(struct ofproto *ofproto, struct rule *rule)
+{
+ assert(rule->installed);
+ assert(!rule->cr.wc.wildcards);
+
+ if (rule->super) {
+ rule_remove(ofproto, rule);
+ } else {
+ rule_uninstall(ofproto, rule);
+ }
+}
+static void
+send_flow_removed(struct ofproto *p, struct rule *rule,
+ long long int now, uint8_t reason)
{
struct ofconn *ofconn;
struct ofconn *prev;
{
struct ofconn *ofconn;
struct ofconn *prev;
prev = NULL;
LIST_FOR_EACH (ofconn, struct ofconn, node, &p->all_conns) {
prev = NULL;
LIST_FOR_EACH (ofconn, struct ofconn, node, &p->all_conns) {
- if (ofconn->send_flow_exp && rconn_is_connected(ofconn->rconn)) {
+ if (rule->send_flow_removed && rconn_is_connected(ofconn->rconn)) {
if (prev) {
queue_tx(ofpbuf_clone(buf), prev, prev->reply_counter);
} else {
if (prev) {
queue_tx(ofpbuf_clone(buf), prev, prev->reply_counter);
} else {
- buf = compose_flow_exp(rule, now, reason);
+ buf = compose_flow_removed(rule, now, reason);
-static void
-uninstall_idle_flow(struct ofproto *ofproto, struct rule *rule)
-{
- assert(rule->installed);
- assert(!rule->cr.wc.wildcards);
-
- if (rule->super) {
- rule_remove(ofproto, rule);
- } else {
- rule_uninstall(ofproto, rule);
- }
-}
static void
expire_rule(struct cls_rule *cls_rule, void *p_)
static void
expire_rule(struct cls_rule *cls_rule, void *p_)
}
if (!rule_is_hidden(rule)) {
}
if (!rule_is_hidden(rule)) {
- send_flow_exp(p, rule, now,
- (now >= hard_expire
- ? OFPER_HARD_TIMEOUT : OFPER_IDLE_TIMEOUT));
+ send_flow_removed(p, rule, now,
+ (now >= hard_expire
+ ? OFPRR_HARD_TIMEOUT : OFPRR_IDLE_TIMEOUT));
}
rule_remove(p, rule);
}
}
rule_remove(p, rule);
}
syntax of \fIflows\fR.
.TP
syntax of \fIflows\fR.
.TP
-\fBmonitor \fIswitch\fR [\fImiss-len\fR [\fIsend-exp]]
+\fBmonitor \fIswitch\fR [\fImiss-len\fR]
Connects to \fIswitch\fR and prints to the console all OpenFlow
messages received. Usually, \fIswitch\fR should specify a connection
named on \fBovs\-openflowd\fR(8)'s \fB-l\fR or \fB--listen\fR command line
Connects to \fIswitch\fR and prints to the console all OpenFlow
messages received. Usually, \fIswitch\fR should specify a connection
named on \fBovs\-openflowd\fR(8)'s \fB-l\fR or \fB--listen\fR command line
\fBovs\-ofctl monitor\fR client connection unless a nonzero value is
specified on this argument.
\fBovs\-ofctl monitor\fR client connection unless a nonzero value is
specified on this argument.
-If \fIsend-exp\fR is specified as \fB1\fR, \fBovs\-ofctl\fR will also
-request to be sent flow expiration messages. If this argument is
-omitted, or \fB0\fR is specified, then \fRovs\-ofctl\fR will not request
-flow expirations.
-
This command may be useful for debugging switch or controller
implementations.
This command may be useful for debugging switch or controller
implementations.
open_vconn(argv[1], &vconn);
if (argc > 2) {
int miss_send_len = atoi(argv[2]);
open_vconn(argv[1], &vconn);
if (argc > 2) {
int miss_send_len = atoi(argv[2]);
- int send_flow_exp = argc > 3 ? atoi(argv[3]) : 0;
struct ofp_switch_config *osc;
struct ofpbuf *buf;
osc = make_openflow(sizeof *osc, OFPT_SET_CONFIG, &buf);
struct ofp_switch_config *osc;
struct ofpbuf *buf;
osc = make_openflow(sizeof *osc, OFPT_SET_CONFIG, &buf);
- osc->flags = htons(send_flow_exp ? OFPC_SEND_FLOW_EXP : 0);
osc->miss_send_len = htons(miss_send_len);
send_openflow_buffer(vconn, buf);
}
osc->miss_send_len = htons(miss_send_len);
send_openflow_buffer(vconn, buf);
}