[ovs-dev] [PATCH 2/8] ofproto: Add support for flow cookies (OpenFlow 1.0)
Justin Pettit
jpettit at nicira.com
Fri Jan 22 09:09:07 UTC 2010
In OpenFlow 1.0, flows have been extended to include an opaque
identifier, referred to as a cookie. The cookie is specified by the
controller when the flow is installed; the cookie will be returned as
part of each flow stats and flow removed message.
NOTE: OVS at this point is not wire-compatible with OpenFlow 1.0 until
the final commit in this Openflow 1.0 set.
---
include/openflow/openflow.h | 12 +++++++-----
lib/ofp-print.c | 10 ++++++----
lib/vconn.c | 3 ++-
ofproto/ofproto.c | 17 +++++++++++------
utilities/ovs-ofctl.c | 36 ++++++++++++++++++++++++------------
5 files changed, 50 insertions(+), 28 deletions(-)
diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h
index 4835b8a..2847aed 100644
--- a/include/openflow/openflow.h
+++ b/include/openflow/openflow.h
@@ -543,6 +543,7 @@ enum ofp_flow_mod_flags {
struct ofp_flow_mod {
struct ofp_header header;
struct ofp_match match; /* Fields to match */
+ uint64_t cookie; /* Opaque controller-issued identifier. */
/* Flow actions. */
uint16_t command; /* One of OFPFC_*. */
@@ -556,12 +557,11 @@ struct ofp_flow_mod {
output port. A value of OFPP_NONE
indicates no restriction. */
uint16_t flags; /* One of OFPFF_*. */
- uint32_t reserved; /* Reserved for future use. */
struct ofp_action_header actions[0]; /* The action length is inferred
from the length field in the
header. */
};
-OFP_ASSERT(sizeof(struct ofp_flow_mod) == 68);
+OFP_ASSERT(sizeof(struct ofp_flow_mod) == 72);
/* Why was this flow removed? */
enum ofp_flow_removed_reason {
@@ -574,6 +574,7 @@ enum ofp_flow_removed_reason {
struct ofp_flow_removed {
struct ofp_header header;
struct ofp_match match; /* Description of fields. */
+ uint64_t cookie; /* Opaque controller-issued identifier. */
uint16_t priority; /* Priority level of flow entry. */
uint8_t reason; /* One of OFPRR_*. */
@@ -585,7 +586,7 @@ struct ofp_flow_removed {
uint64_t packet_count;
uint64_t byte_count;
};
-OFP_ASSERT(sizeof(struct ofp_flow_removed) == 80);
+OFP_ASSERT(sizeof(struct ofp_flow_removed) == 88);
/* 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
@@ -753,12 +754,13 @@ struct ofp_flow_stats {
when this is not an exact-match entry. */
uint16_t idle_timeout; /* Number of seconds idle before expiration. */
uint16_t hard_timeout; /* Number of seconds before expiration. */
- uint16_t pad2; /* Pad to 64 bits. */
+ uint8_t pad2[2]; /* Align to 64 bits. */
+ uint64_t cookie; /* Opaque controller-issued identifier. */
uint64_t packet_count; /* Number of packets in flow. */
uint64_t byte_count; /* Number of bytes in flow. */
struct ofp_action_header actions[0]; /* Actions. */
};
-OFP_ASSERT(sizeof(struct ofp_flow_stats) == 72);
+OFP_ASSERT(sizeof(struct ofp_flow_stats) == 80);
/* Body for ofp_stats_request of type OFPST_AGGREGATE. */
struct ofp_aggregate_stats_request {
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 1443842..25317f5 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -735,7 +735,8 @@ ofp_print_flow_mod(struct ds *string, const void *oh, size_t len,
default:
ds_put_format(string, " cmd:%d ", ntohs(ofm->command));
}
- ds_put_format(string, "idle:%d hard:%d pri:%d buf:%#x flags:%"PRIx16" ",
+ ds_put_format(string, "cookie:%"PRIx64" idle:%d hard:%d pri:%d "
+ "buf:%#x flags:%"PRIx16" ", ntohll(ofm->cookie),
ntohs(ofm->idle_timeout), ntohs(ofm->hard_timeout),
ofm->match.wildcards ? ntohs(ofm->priority) : (uint16_t)-1,
ntohl(ofm->buffer_id), ntohs(ofm->flags));
@@ -769,8 +770,8 @@ ofp_print_flow_removed(struct ds *string, const void *oh, size_t len UNUSED,
break;
}
ds_put_format(string,
- " pri%"PRIu16" secs%"PRIu32" idle%"PRIu16" pkts%"PRIu64
- " bytes%"PRIu64"\n",
+ " cookie%"PRIx64" pri%"PRIu16" secs%"PRIu32" idle%"PRIu16
+ " pkts%"PRIu64" bytes%"PRIu64"\n", ntohll(ofr->cookie),
ofr->match.wildcards ? ntohs(ofr->priority) : (uint16_t)-1,
ntohl(ofr->duration), ntohs(ofr->idle_timeout),
ntohll(ofr->packet_count), ntohll(ofr->byte_count));
@@ -984,7 +985,8 @@ ofp_flow_stats_reply(struct ds *string, const void *body_, size_t len,
break;
}
- ds_put_format(string, " duration=%"PRIu32"s, ", ntohl(fs->duration));
+ ds_put_format(string, " cookie=%"PRIu64"s, ", ntohll(fs->cookie));
+ ds_put_format(string, "duration=%"PRIu32"s, ", ntohl(fs->duration));
ds_put_format(string, "table_id=%"PRIu8", ", fs->table_id);
ds_put_format(string, "priority=%"PRIu16", ",
fs->match.wildcards ? ntohs(fs->priority) : (uint16_t)-1);
diff --git a/lib/vconn.c b/lib/vconn.c
index 533278b..15ccfea 100644
--- a/lib/vconn.c
+++ b/lib/vconn.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -859,6 +859,7 @@ make_flow_mod(uint16_t command, const flow_t *flow, size_t actions_len)
ofm->header.version = OFP_VERSION;
ofm->header.type = OFPT_FLOW_MOD;
ofm->header.length = htons(size);
+ ofm->cookie = 0;
ofm->match.wildcards = htonl(0);
ofm->match.in_port = htons(flow->in_port == ODPP_LOCAL ? OFPP_LOCAL
: flow->in_port);
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 335e6c0..8fbef48 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -89,6 +89,7 @@ struct rule {
uint16_t idle_timeout; /* In seconds from time of last use. */
uint16_t hard_timeout; /* In seconds from time of creation. */
+ uint64_t flow_cookie; /* Controller-issued identifier. */
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. */
@@ -148,7 +149,7 @@ rule_is_hidden(const struct rule *rule)
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,
- bool send_flow_removed);
+ uint64_t flow_cookie, 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 *);
@@ -1002,7 +1003,7 @@ ofproto_add_flow(struct ofproto *p,
struct rule *rule;
rule = rule_create(p, NULL, actions, n_actions,
idle_timeout >= 0 ? idle_timeout : 5 /* XXX */,
- 0, false);
+ 0, 0, false);
cls_rule_from_flow(&rule->cr, flow, wildcards, priority);
rule_insert(p, rule, NULL, 0);
}
@@ -1397,11 +1398,12 @@ 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,
- bool send_flow_removed)
+ uint64_t flow_cookie, bool send_flow_removed)
{
struct rule *rule = xcalloc(1, sizeof *rule);
rule->idle_timeout = idle_timeout;
rule->hard_timeout = hard_timeout;
+ rule->flow_cookie = flow_cookie;
rule->used = rule->created = time_msec();
rule->send_flow_removed = send_flow_removed;
rule->super = super;
@@ -1564,7 +1566,7 @@ rule_create_subrule(struct ofproto *ofproto, struct rule *rule,
{
struct rule *subrule = rule_create(ofproto, rule, NULL, 0,
rule->idle_timeout, rule->hard_timeout,
- false);
+ 0, false);
COVERAGE_INC(ofproto_subrule_create);
cls_rule_from_flow(&subrule->cr, flow, 0,
(rule->cr.priority <= UINT16_MAX ? UINT16_MAX
@@ -2558,10 +2560,11 @@ flow_stats_cb(struct cls_rule *rule_, void *cbdata_)
ofs->pad = 0;
flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofs->match);
ofs->duration = htonl((time_msec() - rule->created) / 1000);
+ ofs->cookie = htonll(rule->flow_cookie);
ofs->priority = htons(rule->cr.priority);
ofs->idle_timeout = htons(rule->idle_timeout);
ofs->hard_timeout = htons(rule->hard_timeout);
- ofs->pad2 = 0;
+ memset(ofs->pad2, 0, sizeof ofs->pad2);
ofs->packet_count = htonll(packet_count);
ofs->byte_count = htonll(byte_count);
memcpy(ofs->actions, rule->actions, act_len);
@@ -2812,7 +2815,7 @@ add_flow(struct ofproto *p, struct ofconn *ofconn,
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), ntohll(ofm->cookie),
ofm->flags & htons(OFPFF_SEND_FLOW_REM));
cls_rule_from_match(&rule->cr, &ofm->match, ntohs(ofm->priority));
@@ -2852,6 +2855,7 @@ modify_flow(struct ofproto *p, const struct ofp_flow_mod *ofm,
free(rule->actions);
rule->actions = xmemdup(ofm->actions, actions_len);
rule->n_actions = n_actions;
+ rule->flow_cookie = ntohll(ofm->cookie);
if (rule->cr.wc.wildcards) {
COVERAGE_INC(ofproto_mod_wc_flow);
@@ -3297,6 +3301,7 @@ compose_flow_removed(const struct rule *rule, long long int now, uint8_t reason)
ofr = make_openflow(sizeof *ofr, OFPT_FLOW_REMOVED, &buf);
flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofr->match);
+ ofr->cookie = htonll(rule->flow_cookie);
ofr->priority = htons(rule->cr.priority);
ofr->reason = reason;
ofr->duration = htonl((now - rule->created - last_used) / 1000);
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 7d6a600..712ac6c 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,6 +48,7 @@
#include "util.h"
#include "vconn-ssl.h"
#include "vconn.h"
+#include "xtoxll.h"
#include "vlog.h"
#define THIS_MODULE VLM_ofctl
@@ -719,7 +720,8 @@ parse_field(const char *name, const struct field **f_out)
static void
str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions,
uint8_t *table_idx, uint16_t *out_port, uint16_t *priority,
- uint16_t *idle_timeout, uint16_t *hard_timeout)
+ uint16_t *idle_timeout, uint16_t *hard_timeout,
+ uint64_t *cookie)
{
char *save_ptr = NULL;
char *name;
@@ -740,6 +742,9 @@ str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions,
if (hard_timeout) {
*hard_timeout = OFP_FLOW_PERMANENT;
}
+ if (cookie) {
+ *cookie = 0;
+ }
if (actions) {
char *act_str = strstr(string, "action");
if (!act_str) {
@@ -788,6 +793,8 @@ str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions,
*idle_timeout = atoi(value);
} else if (hard_timeout && !strcmp(name, "hard_timeout")) {
*hard_timeout = atoi(value);
+ } else if (cookie && !strcmp(name, "cookie")) {
+ *cookie = atoi(value);
} else if (parse_field(name, &f)) {
void *data = (char *) match + f->offset;
if (!strcmp(value, "*") || !strcmp(value, "ANY")) {
@@ -826,7 +833,7 @@ do_dump_flows(const struct settings *s UNUSED, int argc, char *argv[])
req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request);
str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL,
- &req->table_id, &out_port, NULL, NULL, NULL);
+ &req->table_id, &out_port, NULL, NULL, NULL, NULL);
memset(&req->pad, 0, sizeof req->pad);
req->out_port = htons(out_port);
@@ -842,7 +849,7 @@ do_dump_aggregate(const struct settings *s UNUSED, int argc, char *argv[])
req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request);
str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL,
- &req->table_id, &out_port, NULL, NULL, NULL);
+ &req->table_id, &out_port, NULL, NULL, NULL, NULL);
memset(&req->pad, 0, sizeof req->pad);
req->out_port = htons(out_port);
@@ -856,21 +863,23 @@ do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
uint16_t priority, idle_timeout, hard_timeout;
+ uint64_t cookie;
struct ofp_match match;
/* Parse and send. str_to_flow() will expand and reallocate the data in
* 'buffer', so we can't keep pointers to across the str_to_flow() call. */
make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
str_to_flow(argv[2], &match, buffer,
- NULL, NULL, &priority, &idle_timeout, &hard_timeout);
+ NULL, NULL, &priority, &idle_timeout, &hard_timeout,
+ &cookie);
ofm = buffer->data;
ofm->match = match;
ofm->command = htons(OFPFC_ADD);
+ ofm->cookie = htonll(cookie);
ofm->idle_timeout = htons(idle_timeout);
ofm->hard_timeout = htons(hard_timeout);
ofm->buffer_id = htonl(UINT32_MAX);
ofm->priority = htons(priority);
- ofm->reserved = htonl(0);
open_vconn(argv[1], &vconn);
send_openflow_buffer(vconn, buffer);
@@ -894,6 +903,7 @@ do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
uint16_t priority, idle_timeout, hard_timeout;
+ uint64_t cookie;
struct ofp_match match;
char *comment;
@@ -914,15 +924,16 @@ do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
* call. */
ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
str_to_flow(line, &match, buffer,
- NULL, NULL, &priority, &idle_timeout, &hard_timeout);
+ NULL, NULL, &priority, &idle_timeout, &hard_timeout,
+ &cookie);
ofm = buffer->data;
ofm->match = match;
ofm->command = htons(OFPFC_ADD);
+ ofm->cookie = htonll(cookie);
ofm->idle_timeout = htons(idle_timeout);
ofm->hard_timeout = htons(hard_timeout);
ofm->buffer_id = htonl(UINT32_MAX);
ofm->priority = htons(priority);
- ofm->reserved = htonl(0);
send_openflow_buffer(vconn, buffer);
}
@@ -934,6 +945,7 @@ static void
do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[])
{
uint16_t priority, idle_timeout, hard_timeout;
+ uint64_t cookie;
struct vconn *vconn;
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
@@ -943,7 +955,8 @@ do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[])
* 'buffer', so we can't keep pointers to across the str_to_flow() call. */
make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
str_to_flow(argv[2], &match, buffer,
- NULL, NULL, &priority, &idle_timeout, &hard_timeout);
+ NULL, NULL, &priority, &idle_timeout, &hard_timeout,
+ &cookie);
ofm = buffer->data;
ofm->match = match;
if (s->strict) {
@@ -953,9 +966,9 @@ do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[])
}
ofm->idle_timeout = htons(idle_timeout);
ofm->hard_timeout = htons(hard_timeout);
+ ofm->cookie = htonll(cookie);
ofm->buffer_id = htonl(UINT32_MAX);
ofm->priority = htons(priority);
- ofm->reserved = htonl(0);
open_vconn(argv[1], &vconn);
send_openflow_buffer(vconn, buffer);
@@ -973,7 +986,7 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[])
/* Parse and send. */
ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, NULL,
- &out_port, &priority, NULL, NULL);
+ &out_port, &priority, NULL, NULL, NULL);
if (s->strict) {
ofm->command = htons(OFPFC_DELETE_STRICT);
} else {
@@ -984,7 +997,6 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[])
ofm->buffer_id = htonl(UINT32_MAX);
ofm->out_port = htons(out_port);
ofm->priority = htons(priority);
- ofm->reserved = htonl(0);
open_vconn(argv[1], &vconn);
send_openflow_buffer(vconn, buffer);
--
1.5.5
More information about the dev
mailing list