aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/learn.c5
-rw-r--r--lib/ofp-parse.c24
-rw-r--r--lib/ofp-print.c8
-rw-r--r--lib/ofp-util.c36
-rw-r--r--lib/ofp-util.h24
5 files changed, 66 insertions, 31 deletions
diff --git a/lib/learn.c b/lib/learn.c
index e995c29c..ba33287a 100644
--- a/lib/learn.c
+++ b/lib/learn.c
@@ -204,8 +204,9 @@ learn_execute(const struct nx_action_learn *learn, const struct flow *flow,
struct ofpbuf actions;
cls_rule_init_catchall(&fm->cr, ntohs(learn->priority));
- fm->cookie = learn->cookie;
- fm->cookie_mask = htonll(UINT64_MAX);
+ fm->cookie = htonll(0);
+ fm->cookie_mask = htonll(0);
+ fm->new_cookie = learn->cookie;
fm->table_id = learn->table_id;
fm->command = OFPFC_MODIFY_STRICT;
fm->idle_timeout = ntohs(learn->idle_timeout);
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 034a6de6..dac13769 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -589,6 +589,12 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
cls_rule_init_catchall(&fm->cr, OFP_DEFAULT_PRIORITY);
fm->cookie = htonll(0);
fm->cookie_mask = htonll(0);
+ if (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT) {
+ /* For modify, by default, don't update the cookie. */
+ fm->new_cookie = htonll(UINT64_MAX);
+ } else{
+ fm->new_cookie = htonll(0);
+ }
fm->table_id = 0xff;
fm->command = command;
fm->idle_timeout = OFP_FLOW_PERMANENT;
@@ -643,17 +649,24 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
fm->hard_timeout = str_to_u16(value, name);
} else if (!strcmp(name, "cookie")) {
char *mask = strchr(value, '/');
+
if (mask) {
+ /* A mask means we're searching for a cookie. */
if (command == OFPFC_ADD) {
ofp_fatal(str_, verbose, "flow additions cannot use "
"a cookie mask");
}
*mask = '\0';
+ fm->cookie = htonll(str_to_u64(value));
fm->cookie_mask = htonll(str_to_u64(mask+1));
} else {
- fm->cookie_mask = htonll(UINT64_MAX);
+ /* No mask means that the cookie is being set. */
+ if (command != OFPFC_ADD && command != OFPFC_MODIFY
+ && command != OFPFC_MODIFY_STRICT) {
+ ofp_fatal(str_, verbose, "cannot set cookie");
+ }
+ fm->new_cookie = htonll(str_to_u64(value));
}
- fm->cookie = htonll(str_to_u64(value));
} else if (mf_from_name(name)) {
parse_field(mf_from_name(name), value, &fm->cr);
} else if (!strcmp(name, "duration")
@@ -667,6 +680,13 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
}
}
}
+ if (!fm->cookie_mask && fm->new_cookie == htonll(UINT64_MAX)
+ && (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT)) {
+ /* On modifies without a mask, we are supposed to add a flow if
+ * one does not exist. If a cookie wasn't been specified, use a
+ * default of zero. */
+ fm->new_cookie = htonll(0);
+ }
if (fields & F_ACTIONS) {
struct ofpbuf actions;
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 7479bf22..e5327ab8 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -977,8 +977,12 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh,
if (ds_last(s) != ' ') {
ds_put_char(s, ' ');
}
- if (fm.cookie != htonll(0)) {
- ds_put_format(s, "cookie:0x%"PRIx64" ", ntohll(fm.cookie));
+ if (fm.new_cookie != htonll(0)) {
+ ds_put_format(s, "cookie:0x%"PRIx64" ", ntohll(fm.new_cookie));
+ }
+ if (fm.cookie_mask != htonll(0)) {
+ ds_put_format(s, "cookie:0x%"PRIx64"/0x%"PRIx64" ",
+ ntohll(fm.cookie), ntohll(fm.cookie_mask));
}
if (fm.idle_timeout != OFP_FLOW_PERMANENT) {
ds_put_format(s, "idle:%"PRIu16" ", fm.idle_timeout);
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 501ccab2..15de6076 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -1402,9 +1402,10 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
ofputil_normalize_rule(&fm->cr);
/* Translate the message. */
- fm->cookie = ofm->cookie;
- fm->cookie_mask = htonll(UINT64_MAX);
command = ntohs(ofm->command);
+ fm->cookie = htonll(0);
+ fm->cookie_mask = htonll(0);
+ fm->new_cookie = ofm->cookie;
fm->idle_timeout = ntohs(ofm->idle_timeout);
fm->hard_timeout = ntohs(ofm->hard_timeout);
fm->buffer_id = ntohl(ofm->buffer_id);
@@ -1429,17 +1430,12 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
/* Translate the message. */
command = ntohs(nfm->command);
- if (command == OFPFC_ADD) {
- if (fm->cookie_mask) {
- /* The "NXM_NX_COOKIE*" matches are not valid for flow
- * additions. Additions must use the "cookie" field of
- * the "nx_flow_mod" structure. */
- return OFPERR_NXBRC_NXM_INVALID;
- } else {
- fm->cookie = nfm->cookie;
- fm->cookie_mask = htonll(UINT64_MAX);
- }
+ if ((command & 0xff) == OFPFC_ADD && fm->cookie_mask) {
+ /* Flow additions may only set a new cookie, not match an
+ * existing cookie. */
+ return OFPERR_NXBRC_NXM_INVALID;
}
+ fm->new_cookie = nfm->cookie;
fm->idle_timeout = ntohs(nfm->idle_timeout);
fm->hard_timeout = ntohs(nfm->hard_timeout);
fm->buffer_id = ntohl(nfm->buffer_id);
@@ -1486,7 +1482,7 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
msg = ofpbuf_new(sizeof *ofm + actions_len);
ofm = put_openflow(sizeof *ofm, OFPT10_FLOW_MOD, msg);
ofputil_cls_rule_to_match(&fm->cr, &ofm->match);
- ofm->cookie = fm->cookie;
+ ofm->cookie = fm->new_cookie;
ofm->command = htons(command);
ofm->idle_timeout = htons(fm->idle_timeout);
ofm->hard_timeout = htons(fm->hard_timeout);
@@ -1502,14 +1498,8 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
put_nxmsg(sizeof *nfm, NXT_FLOW_MOD, msg);
nfm = msg->data;
nfm->command = htons(command);
- if (command == OFPFC_ADD) {
- nfm->cookie = fm->cookie;
- match_len = nx_put_match(msg, &fm->cr, 0, 0);
- } else {
- nfm->cookie = 0;
- match_len = nx_put_match(msg, &fm->cr,
- fm->cookie, fm->cookie_mask);
- }
+ nfm->cookie = fm->new_cookie;
+ match_len = nx_put_match(msg, &fm->cr, fm->cookie, fm->cookie_mask);
nfm->idle_timeout = htons(fm->idle_timeout);
nfm->hard_timeout = htons(fm->hard_timeout);
nfm->priority = htons(fm->cr.priority);
@@ -1548,7 +1538,9 @@ ofputil_flow_mod_usable_protocols(const struct ofputil_flow_mod *fms,
if (fm->table_id != 0xff) {
usable_protocols &= OFPUTIL_P_TID;
}
- if (fm->command != OFPFC_ADD && fm->cookie_mask != htonll(0)) {
+
+ /* Matching of the cookie is only supported through NXM. */
+ if (fm->cookie_mask != htonll(0)) {
usable_protocols &= OFPUTIL_P_NXM_ANY;
}
}
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index e6716636..3aa1e095 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -197,11 +197,29 @@ struct ofpbuf *ofputil_make_set_packet_in_format(enum nx_packet_in_format);
/* NXT_FLOW_MOD_TABLE_ID extension. */
struct ofpbuf *ofputil_make_flow_mod_table_id(bool flow_mod_table_id);
-/* Protocol-independent flow_mod. */
+/* Protocol-independent flow_mod.
+ *
+ * The handling of cookies across multiple versions of OpenFlow is a bit
+ * confusing. A full description of Open vSwitch's cookie handling is
+ * in the DESIGN file. The following table shows the expected values of
+ * the cookie-related fields for the different flow_mod commands in
+ * OpenFlow 1.0 ("OF10") and NXM. "<used>" and "-" indicate a value
+ * that may be populated and an ignored field, respectively.
+ *
+ * cookie cookie_mask new_cookie
+ * ====== =========== ==========
+ * OF10 Add - 0 <used>
+ * OF10 Modify - 0 <used>
+ * OF10 Delete - 0 -
+ * NXM Add - 0 <used>
+ * NXM Modify <used> <used> <used>
+ * NXM Delete <used> <used> -
+ */
struct ofputil_flow_mod {
struct cls_rule cr;
- ovs_be64 cookie;
- ovs_be64 cookie_mask;
+ ovs_be64 cookie; /* Cookie bits to match. */
+ ovs_be64 cookie_mask; /* 1-bit in each 'cookie' bit to match. */
+ ovs_be64 new_cookie; /* New cookie to install or -1. */
uint8_t table_id;
uint16_t command;
uint16_t idle_timeout;