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_*. */
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 {
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_*. */
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
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 {
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));
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));
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);
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);
struct rule {
struct cls_rule cr;
+ uint64_t flow_cookie; /* Controller-issued identifier.
+ (Kept in network-byte order.) */
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? */
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 *);
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);
}
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 = xzalloc(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;
{
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
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 = 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);
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->cookie,
ofm->flags & htons(OFPFF_SEND_FLOW_REM));
cls_rule_from_match(&rule->cr, &ofm->match, ntohs(ofm->priority));
free(rule->actions);
rule->actions = xmemdup(ofm->actions, actions_len);
rule->n_actions = n_actions;
+ rule->flow_cookie = ofm->cookie;
if (rule->cr.wc.wildcards) {
COVERAGE_INC(ofproto_mod_wc_flow);
ofr = make_openflow(sizeof *ofr, OFPT_FLOW_REMOVED, &buf);
flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofr->match);
+ ofr->cookie = rule->flow_cookie;
ofr->priority = htons(rule->cr.priority);
ofr->reason = reason;
ofr->duration = htonl((now - rule->created) / 1000);
#include "timeval.h"
#include "util.h"
#include "vconn.h"
+#include "xtoxll.h"
#include "vlog.h"
#define THIS_MODULE VLM_ofctl
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;
if (hard_timeout) {
*hard_timeout = OFP_FLOW_PERMANENT;
}
+ if (cookie) {
+ *cookie = 0;
+ }
if (actions) {
char *act_str = strstr(string, "action");
if (!act_str) {
*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")) {
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);
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);
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);
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
uint16_t priority, idle_timeout, hard_timeout;
+ uint64_t cookie;
struct ofp_match match;
char *comment;
* call. */
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);
}
do_mod_flows(int argc OVS_UNUSED, char *argv[])
{
uint16_t priority, idle_timeout, hard_timeout;
+ uint64_t cookie;
struct vconn *vconn;
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
* '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 (strict) {
}
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);
/* 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 (strict) {
ofm->command = htons(OFPFC_DELETE_STRICT);
} else {
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);