[ovs-dev] [PATCH 2/2] Add ability to restrict flow mods and flow stats requests to cookies.

Justin Pettit jpettit at nicira.com
Fri Dec 23 21:53:14 UTC 2011


With this commit, it is possible to limit flow deletions and
modifications to specific cookies.  It also provides the ability to
dump flows based on their cookies.

Signed-off-by: Justin Pettit <jpettit at nicira.com>
---
 include/openflow/nicira-ext.h |   30 +++++++++++++-
 lib/nx-match.c                |   44 +++++++++++++++++++-
 lib/nx-match.h                |    5 +-
 lib/ofp-parse.c               |   26 ++++++++++--
 lib/ofp-util.c                |   38 ++++++++++++-----
 lib/ofp-util.h                |    3 +
 ofproto/ofproto.c             |   40 ++++++++++++------
 tests/ofproto.at              |   88 +++++++++++++++++++++++++++++++++++++++++
 tests/ovs-ofctl.at            |    8 ++++
 utilities/ovs-ofctl.8.in      |   20 ++++++---
 utilities/ovs-ofctl.c         |    9 +++-
 11 files changed, 265 insertions(+), 46 deletions(-)

diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index f449329..bccde56 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -1641,6 +1641,21 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24);
  * Masking: Not maskable. */
 #define NXM_NX_IP_TTL      NXM_HEADER  (0x0001, 29, 1)
 
+/* Flow cookie.
+ *
+ * This may be used to gain the OpenFlow 1.1-like ability to restrict
+ * certain NXM-based Flow Mod and Flow Stats Request messages to flows
+ * with specific cookies.  See the "nx_flow_mod" and "nx_flow_stats_request"
+ * structure definitions for more details.  This match is otherwise ignored.
+ *
+ * Prereqs: None.
+ *
+ * Format: 64-bit integer in network byte order.
+ *
+ * Masking: Arbitrary masks. */
+#define NXM_NX_COOKIE     NXM_HEADER  (0x0001, 30, 8)
+#define NXM_NX_COOKIE_W   NXM_HEADER_W(0x0001, 30, 8)
+
 /* ## --------------------- ## */
 /* ## Requests and replies. ## */
 /* ## --------------------- ## */
@@ -1659,7 +1674,14 @@ struct nxt_set_flow_format {
 };
 OFP_ASSERT(sizeof(struct nxt_set_flow_format) == 20);
 
-/* NXT_FLOW_MOD (analogous to OFPT_FLOW_MOD). */
+/* NXT_FLOW_MOD (analogous to OFPT_FLOW_MOD).
+ *
+ * It is possible to limit flow deletions and modifications to certain
+ * cookies by using the NXM_NX_COOKIE and NXM_NX_COOKIE_W matches.  For
+ * these commands, the "cookie" field is always ignored.  Flow additions
+ * make use of the "cookie" field and ignore any NXM_NX_COOKIE*
+ * definitions.
+ */
 struct nx_flow_mod {
     struct nicira_header nxh;
     ovs_be64 cookie;              /* Opaque controller-issued identifier. */
@@ -1708,7 +1730,11 @@ struct nx_flow_removed {
 OFP_ASSERT(sizeof(struct nx_flow_removed) == 56);
 
 /* Nicira vendor stats request of type NXST_FLOW (analogous to OFPST_FLOW
- * request). */
+ * request).
+ *
+ * It is possible to limit matches to certain cookies by using the
+ * NXM_NX_COOKIE and NXM_NX_COOKIE_W matches.
+ */
 struct nx_flow_stats_request {
     struct nicira_stats_msg nsm;
     ovs_be16 out_port;        /* Require matching entries to include this
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 9b3c1e0..86b3658 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -98,7 +98,8 @@ nx_entry_ok(const void *p, unsigned int match_len)
 
 int
 nx_pull_match(struct ofpbuf *b, unsigned int match_len, uint16_t priority,
-              struct cls_rule *rule)
+              struct cls_rule *rule,
+              ovs_be64 *cookie, ovs_be64 *cookie_mask)
 {
     uint32_t header;
     uint8_t *p;
@@ -112,6 +113,9 @@ nx_pull_match(struct ofpbuf *b, unsigned int match_len, uint16_t priority,
     }
 
     cls_rule_init_catchall(rule, priority);
+    if (cookie && cookie_mask) {
+        *cookie = *cookie_mask = 0;
+    }
     while ((header = nx_entry_ok(p, match_len)) != 0) {
         unsigned length = NXM_LENGTH(header);
         const struct mf_field *mf;
@@ -147,6 +151,24 @@ nx_pull_match(struct ofpbuf *b, unsigned int match_len, uint16_t priority,
             }
         }
 
+        /* Check if the match is for a cookie rather than a classifier rule. */
+        if ((header == NXM_NX_COOKIE || header == NXM_NX_COOKIE_W)
+                && cookie && cookie_mask) {
+            if (*cookie_mask) {
+                error = NXM_DUP_TYPE;
+            } else {
+                unsigned int width = sizeof *cookie;
+
+                memcpy(cookie, p + 4, width);
+                if (NXM_HASMASK(header)) {
+                    memcpy(cookie_mask, p + 4 + width, width);
+                } else {
+                    *cookie_mask = htonll(UINT64_MAX);
+                }
+                error = 0;
+            }
+        }
+
         if (error) {
             char *msg = ofputil_error_to_string(error);
             VLOG_DBG_RL(&rl, "bad nxm_entry %#08"PRIx32" (vendor=%"PRIu32", "
@@ -367,7 +389,9 @@ nxm_put_frag(struct ofpbuf *b, const struct cls_rule *cr)
 
 /* Appends to 'b' the nx_match format that expresses 'cr' (except for
  * 'cr->priority', because priority is not part of nx_match), plus enough
- * zero bytes to pad the nx_match out to a multiple of 8.
+ * zero bytes to pad the nx_match out to a multiple of 8.  For Flow Mod
+ * and Flow Stats Requests messages, a 'cookie' and 'cookie_mask' may be
+ * supplied.  Otherwise, 'cookie_mask' should be zero.
  *
  * This function can cause 'b''s data to be reallocated.
  *
@@ -376,7 +400,8 @@ nxm_put_frag(struct ofpbuf *b, const struct cls_rule *cr)
  * If 'cr' is a catch-all rule that matches every packet, then this function
  * appends nothing to 'b' and returns 0. */
 int
-nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
+nx_put_match(struct ofpbuf *b, const struct cls_rule *cr,
+             ovs_be64 cookie, ovs_be64 cookie_mask)
 {
     const flow_wildcards_t wc = cr->wc.wildcards;
     const struct flow *flow = &cr->flow;
@@ -556,6 +581,9 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
                     htonl(flow->regs[i]), htonl(cr->wc.reg_masks[i]));
     }
 
+    /* Cookie. */
+    nxm_put_64m(b, NXM_NX_COOKIE, cookie, cookie_mask);
+
     match_len = b->size - start_len;
     ofpbuf_put_zeros(b, ROUND_UP(match_len, 8) - match_len);
     return match_len;
@@ -625,6 +653,10 @@ format_nxm_field_name(struct ds *s, uint32_t header)
         if (NXM_HASMASK(header)) {
             ds_put_cstr(s, "_W");
         }
+    } else if (header == NXM_NX_COOKIE) {
+        ds_put_cstr(s, "NXM_NX_COOKIE");
+    } else if (header == NXM_NX_COOKIE_W) {
+        ds_put_cstr(s, "NXM_NX_COOKIE_W");
     } else {
         ds_put_format(s, "%d:%d", NXM_VENDOR(header), NXM_FIELD(header));
     }
@@ -652,6 +684,12 @@ parse_nxm_field_name(const char *name, int name_len)
             } else if (mf->maskable != MFM_NONE) {
                 return NXM_MAKE_WILD_HEADER(mf->nxm_header);
             }
+        } else if (!strncmp("NXM_NX_COOKIE", name, name_len)) {
+            if (!wild) {
+                return NXM_NX_COOKIE;
+            } else {
+                return NXM_NX_COOKIE_W;
+            }
         }
     }
 
diff --git a/lib/nx-match.h b/lib/nx-match.h
index faeacd6..c7ee0f8 100644
--- a/lib/nx-match.h
+++ b/lib/nx-match.h
@@ -35,8 +35,9 @@ struct nx_action_reg_move;
  */
 
 int nx_pull_match(struct ofpbuf *, unsigned int match_len, uint16_t priority,
-                  struct cls_rule *);
-int nx_put_match(struct ofpbuf *, const struct cls_rule *);
+                  struct cls_rule *, ovs_be64 *cookie, ovs_be64 *cookie_mask);
+int nx_put_match(struct ofpbuf *, const struct cls_rule *,
+                 ovs_be64 cookie, ovs_be64 cookie_mask);
 
 char *nx_match_to_string(const uint8_t *, unsigned int match_len);
 int nx_match_from_string(const char *, struct ofpbuf *);
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 4021551..38c3dab 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -488,7 +488,6 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
     enum {
         F_OUT_PORT = 1 << 0,
         F_ACTIONS = 1 << 1,
-        F_COOKIE = 1 << 2,
         F_TIMEOUT = 1 << 3,
         F_PRIORITY = 1 << 4
     } fields;
@@ -503,7 +502,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
         break;
 
     case OFPFC_ADD:
-        fields = F_ACTIONS | F_COOKIE | F_TIMEOUT | F_PRIORITY;
+        fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY;
         break;
 
     case OFPFC_DELETE:
@@ -515,11 +514,11 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
         break;
 
     case OFPFC_MODIFY:
-        fields = F_ACTIONS | F_COOKIE;
+        fields = F_ACTIONS;
         break;
 
     case OFPFC_MODIFY_STRICT:
-        fields = F_ACTIONS | F_COOKIE | F_PRIORITY;
+        fields = F_ACTIONS | F_PRIORITY;
         break;
 
     default:
@@ -528,6 +527,7 @@ 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);
     fm->table_id = 0xff;
     fm->command = command;
     fm->idle_timeout = OFP_FLOW_PERMANENT;
@@ -576,7 +576,18 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
                 fm->idle_timeout = str_to_u16(value, name);
             } else if (fields & F_TIMEOUT && !strcmp(name, "hard_timeout")) {
                 fm->hard_timeout = str_to_u16(value, name);
-            } else if (fields & F_COOKIE && !strcmp(name, "cookie")) {
+            } else if (!strcmp(name, "cookie")) {
+                char *mask = strchr(value, '/');
+                if (mask) {
+                    if (command == OFPFC_ADD) {
+                        ofp_fatal(str_, verbose, "flow additions cannot use "
+                                  "a cookie mask");
+                    }
+                    *mask = '\0';
+                    fm->cookie_mask = htonll(str_to_u64(mask+1));
+                } else {
+                    fm->cookie_mask = htonll(UINT64_MAX);
+                }
                 fm->cookie = htonll(str_to_u64(value));
             } else if (mf_from_name(name)) {
                 parse_field(mf_from_name(name), value, &fm->cr);
@@ -625,6 +636,9 @@ parse_ofp_flow_mod_str(struct list *packets, enum nx_flow_format *cur_format,
     parse_ofp_str(&fm, command, string, verbose);
 
     min_format = ofputil_min_flow_format(&fm.cr);
+    if (command != OFPFC_ADD && fm.cookie_mask != htonll(0)) {
+        min_format = NXFF_NXM;
+    }
     next_format = MAX(*cur_format, min_format);
     if (next_format != *cur_format) {
         struct ofpbuf *sff = ofputil_make_set_flow_format(next_format);
@@ -678,6 +692,8 @@ parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr,
 
     parse_ofp_str(&fm, -1, string, false);
     fsr->aggregate = aggregate;
+    fsr->cookie = fm.cookie;
+    fsr->cookie_mask = fm.cookie_mask;
     fsr->match = fm.cr;
     fsr->out_port = fm.out_port;
     fsr->table_id = fm.table_id;
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 11b0f15..6b3e5f0 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -987,6 +987,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
 
         /* Translate the message. */
         fm->cookie = ofm->cookie;
+        fm->cookie_mask = htonll(0);
         command = ntohs(ofm->command);
         fm->idle_timeout = ntohs(ofm->idle_timeout);
         fm->hard_timeout = ntohs(ofm->hard_timeout);
@@ -1001,7 +1002,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
         /* Dissect the message. */
         nfm = ofpbuf_pull(&b, sizeof *nfm);
         error = nx_pull_match(&b, ntohs(nfm->match_len), ntohs(nfm->priority),
-                              &fm->cr);
+                              &fm->cr, &fm->cookie, &fm->cookie_mask);
         if (error) {
             return error;
         }
@@ -1011,8 +1012,14 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
         }
 
         /* Translate the message. */
-        fm->cookie = nfm->cookie;
         command = ntohs(nfm->command);
+        if (command == OFPFC_ADD) {
+            /* In NXM, the "cookie" field from the Flow Mod is only
+             * valid for flow additions.  In that case, we don't use the
+             * NXM_NX_COOKIE definition. */
+            fm->cookie = nfm->cookie;
+            fm->cookie_mask = htonll(UINT64_MAX);
+        }
         fm->idle_timeout = ntohs(nfm->idle_timeout);
         fm->hard_timeout = ntohs(nfm->hard_timeout);
         fm->buffer_id = ntohl(nfm->buffer_id);
@@ -1071,11 +1078,16 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
 
         msg = ofpbuf_new(sizeof *nfm + NXM_TYPICAL_LEN + actions_len);
         put_nxmsg(sizeof *nfm, NXT_FLOW_MOD, msg);
-        match_len = nx_put_match(msg, &fm->cr);
-
         nfm = msg->data;
-        nfm->cookie = fm->cookie;
         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->idle_timeout = htons(fm->idle_timeout);
         nfm->hard_timeout = htons(fm->hard_timeout);
         nfm->priority = htons(fm->cr.priority);
@@ -1104,6 +1116,7 @@ ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr,
     ofputil_cls_rule_from_match(&ofsr->match, 0, &fsr->match);
     fsr->out_port = ntohs(ofsr->out_port);
     fsr->table_id = ofsr->table_id;
+    fsr->cookie = fsr->cookie_mask = htonll(0);
 
     return 0;
 }
@@ -1120,7 +1133,8 @@ ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr,
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
 
     nfsr = ofpbuf_pull(&b, sizeof *nfsr);
-    error = nx_pull_match(&b, ntohs(nfsr->match_len), 0, &fsr->match);
+    error = nx_pull_match(&b, ntohs(nfsr->match_len), 0, &fsr->match,
+                          &fsr->cookie, &fsr->cookie_mask);
     if (error) {
         return error;
     }
@@ -1194,7 +1208,8 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
 
         subtype = fsr->aggregate ? NXST_AGGREGATE : NXST_FLOW;
         ofputil_make_stats_request(sizeof *nfsr, OFPST_VENDOR, subtype, &msg);
-        match_len = nx_put_match(msg, &fsr->match);
+        match_len = nx_put_match(msg, &fsr->match,
+                                 fsr->cookie, fsr->cookie_mask);
 
         nfsr = msg->data;
         nfsr->out_port = htons(fsr->out_port);
@@ -1290,7 +1305,8 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
                          "claims invalid length %zu", match_len, length);
             return EINVAL;
         }
-        if (nx_pull_match(msg, match_len, ntohs(nfs->priority), &fs->rule)) {
+        if (nx_pull_match(msg, match_len, ntohs(nfs->priority), &fs->rule,
+                          NULL, NULL)) {
             return EINVAL;
         }
 
@@ -1374,7 +1390,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
         nfs->priority = htons(fs->rule.priority);
         nfs->idle_timeout = htons(fs->idle_timeout);
         nfs->hard_timeout = htons(fs->hard_timeout);
-        nfs->match_len = htons(nx_put_match(msg, &fs->rule));
+        nfs->match_len = htons(nx_put_match(msg, &fs->rule, 0, 0));
         memset(nfs->pad2, 0, sizeof nfs->pad2);
         nfs->cookie = fs->cookie;
         nfs->packet_count = htonll(fs->packet_count);
@@ -1453,7 +1469,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
 
         nfr = ofpbuf_pull(&b, sizeof *nfr);
         error = nx_pull_match(&b, ntohs(nfr->match_len), ntohs(nfr->priority),
-                              &fr->rule);
+                              &fr->rule, NULL, NULL);
         if (error) {
             return error;
         }
@@ -1503,7 +1519,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
         int match_len;
 
         make_nxmsg_xid(sizeof *nfr, NXT_FLOW_REMOVED, htonl(0), &msg);
-        match_len = nx_put_match(msg, &fr->rule);
+        match_len = nx_put_match(msg, &fr->rule, 0, 0);
 
         nfr = msg->data;
         nfr->cookie = fr->cookie;
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 909467f..8fa729e 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -131,6 +131,7 @@ struct ofpbuf *ofputil_make_flow_mod_table_id(bool flow_mod_table_id);
 struct ofputil_flow_mod {
     struct cls_rule cr;
     ovs_be64 cookie;
+    ovs_be64 cookie_mask;
     uint8_t table_id;
     uint16_t command;
     uint16_t idle_timeout;
@@ -152,6 +153,8 @@ struct ofpbuf *ofputil_encode_flow_mod(const struct ofputil_flow_mod *,
 struct ofputil_flow_stats_request {
     bool aggregate;             /* Aggregate results? */
     struct cls_rule match;
+    ovs_be64 cookie;
+    ovs_be64 cookie_mask;
     uint16_t out_port;
     uint8_t table_id;
 };
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 521533b..cb06a4d 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -2081,8 +2081,9 @@ next_matching_table(struct ofproto *ofproto,
  * Returns 0 on success, otherwise an OpenFlow error code. */
 static int
 collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
-                    const struct cls_rule *match, uint16_t out_port,
-                    struct list *rules)
+                    const struct cls_rule *match,
+                    ovs_be64 cookie, ovs_be64 cookie_mask,
+                    uint16_t out_port, struct list *rules)
 {
     struct classifier *cls;
     int error;
@@ -2102,7 +2103,9 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
             if (rule->pending) {
                 return OFPROTO_POSTPONE;
             }
-            if (!rule_is_hidden(rule) && rule_has_out_port(rule, out_port)) {
+            if (!rule_is_hidden(rule) && rule_has_out_port(rule, out_port)
+                    && (rule->flow_cookie & cookie_mask)
+                        == (cookie & cookie_mask)) {
                 list_push_back(rules, &rule->ofproto_node);
             }
         }
@@ -2123,8 +2126,9 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
  * Returns 0 on success, otherwise an OpenFlow error code. */
 static int
 collect_rules_strict(struct ofproto *ofproto, uint8_t table_id,
-                     const struct cls_rule *match, uint16_t out_port,
-                     struct list *rules)
+                     const struct cls_rule *match,
+                     ovs_be64 cookie, ovs_be64 cookie_mask,
+                     uint16_t out_port, struct list *rules)
 {
     struct classifier *cls;
     int error;
@@ -2143,7 +2147,9 @@ collect_rules_strict(struct ofproto *ofproto, uint8_t table_id,
             if (rule->pending) {
                 return OFPROTO_POSTPONE;
             }
-            if (!rule_is_hidden(rule) && rule_has_out_port(rule, out_port)) {
+            if (!rule_is_hidden(rule) && rule_has_out_port(rule, out_port)
+                    && (rule->flow_cookie & cookie_mask)
+                        == (cookie & cookie_mask)) {
                 list_push_back(rules, &rule->ofproto_node);
             }
         }
@@ -2168,6 +2174,7 @@ handle_flow_stats_request(struct ofconn *ofconn,
     }
 
     error = collect_rules_loose(ofproto, fsr.table_id, &fsr.match,
+                                fsr.cookie, fsr.cookie_mask,
                                 fsr.out_port, &rules);
     if (error) {
         return error;
@@ -2298,6 +2305,7 @@ handle_aggregate_stats_request(struct ofconn *ofconn,
     }
 
     error = collect_rules_loose(ofproto, request.table_id, &request.match,
+                                request.cookie, request.cookie_mask,
                                 request.out_port, &rules);
     if (error) {
         return error;
@@ -2593,8 +2601,9 @@ modify_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn,
     struct list rules;
     int error;
 
-    error = collect_rules_loose(ofproto, fm->table_id, &fm->cr, OFPP_NONE,
-                                &rules);
+    error = collect_rules_loose(ofproto, fm->table_id, &fm->cr,
+                                fm->cookie, fm->cookie_mask,
+                                OFPP_NONE, &rules);
     return (error ? error
             : list_is_empty(&rules) ? add_flow(ofproto, ofconn, fm, request)
             : modify_flows__(ofproto, ofconn, fm, request, &rules));
@@ -2613,8 +2622,9 @@ modify_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn,
     struct list rules;
     int error;
 
-    error = collect_rules_strict(ofproto, fm->table_id, &fm->cr, OFPP_NONE,
-                                 &rules);
+    error = collect_rules_strict(ofproto, fm->table_id, &fm->cr,
+                                 fm->cookie, fm->cookie_mask,
+                                 OFPP_NONE, &rules);
     return (error ? error
             : list_is_empty(&rules) ? add_flow(ofproto, ofconn, fm, request)
             : list_is_singleton(&rules) ? modify_flows__(ofproto, ofconn,
@@ -2656,8 +2666,9 @@ delete_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn,
     struct list rules;
     int error;
 
-    error = collect_rules_loose(ofproto, fm->table_id, &fm->cr, fm->out_port,
-                                &rules);
+    error = collect_rules_loose(ofproto, fm->table_id, &fm->cr,
+                                fm->cookie, fm->cookie_mask,
+                                fm->out_port, &rules);
     return (error ? error
             : !list_is_empty(&rules) ? delete_flows__(ofproto, ofconn, request,
                                                       &rules)
@@ -2673,8 +2684,9 @@ delete_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn,
     struct list rules;
     int error;
 
-    error = collect_rules_strict(ofproto, fm->table_id, &fm->cr, fm->out_port,
-                                 &rules);
+    error = collect_rules_strict(ofproto, fm->table_id, &fm->cr,
+                                 fm->cookie, fm->cookie_mask,
+                                 fm->out_port, &rules);
     return (error ? error
             : list_is_singleton(&rules) ? delete_flows__(ofproto, ofconn,
                                                          request, &rules)
diff --git a/tests/ofproto.at b/tests/ofproto.at
index e430800..b54d1dd 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -113,3 +113,91 @@ AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | STRIP_XIDS], [0], [OFPST_FLOW
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
+
+AT_SETUP([ofproto - dump flows with cookie])
+OVS_VSWITCHD_START
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=0])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=0])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=0])
+AT_CHECK([ovs-ofctl dump-flows br0 | STRIP_XIDS | STRIP_DURATION | sort], [0], [dnl
+ cookie=0x1, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=1 actions=output:0
+ cookie=0x2, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=2 actions=output:0
+ cookie=0x3, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=3 actions=output:0
+NXST_FLOW reply:
+])
+AT_CHECK([ovs-ofctl dump-aggregate br0 table=0 | STRIP_XIDS], [0], [dnl
+NXST_AGGREGATE reply: packet_count=0 byte_count=0 flow_count=3
+])
+AT_CHECK([ovs-ofctl dump-flows br0 cookie=0x3 | STRIP_XIDS | STRIP_DURATION | sort], [0], [dnl
+ cookie=0x3, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=3 actions=output:0
+NXST_FLOW reply:
+])
+AT_CHECK([ovs-ofctl dump-aggregate br0 cookie=0x3 | STRIP_XIDS], [0], [dnl
+NXST_AGGREGATE reply: packet_count=0 byte_count=0 flow_count=1
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto - dump flows with cookie mask])
+OVS_VSWITCHD_START
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=0])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=0])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=0])
+AT_CHECK([ovs-ofctl dump-flows br0 | STRIP_XIDS | STRIP_DURATION | sort], [0], [dnl
+ cookie=0x1, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=1 actions=output:0
+ cookie=0x2, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=2 actions=output:0
+ cookie=0x3, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=3 actions=output:0
+NXST_FLOW reply:
+])
+AT_CHECK([ovs-ofctl dump-aggregate br0 table=0 | STRIP_XIDS], [0], [dnl
+NXST_AGGREGATE reply: packet_count=0 byte_count=0 flow_count=3
+])
+AT_CHECK([ovs-ofctl dump-flows br0 cookie=0x3/0x1 | STRIP_XIDS | STRIP_DURATION | sort], [0], [dnl
+ cookie=0x1, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=1 actions=output:0
+ cookie=0x3, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=3 actions=output:0
+NXST_FLOW reply:
+])
+AT_CHECK([ovs-ofctl dump-aggregate br0 cookie=0x3/0x1 | STRIP_XIDS], [0], [dnl
+NXST_AGGREGATE reply: packet_count=0 byte_count=0 flow_count=2
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto - del flows with cookie])
+OVS_VSWITCHD_START
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=0])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=0])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=0])
+AT_CHECK([ovs-ofctl dump-flows br0 | STRIP_XIDS | STRIP_DURATION | sort], [0], [dnl
+ cookie=0x1, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=1 actions=output:0
+ cookie=0x2, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=2 actions=output:0
+ cookie=0x3, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=3 actions=output:0
+NXST_FLOW reply:
+])
+AT_CHECK([ovs-ofctl del-flows br0 cookie=0x3])
+AT_CHECK([ovs-ofctl dump-flows br0 | STRIP_XIDS | STRIP_DURATION | sort], [0], [dnl
+ cookie=0x1, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=1 actions=output:0
+ cookie=0x2, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=2 actions=output:0
+NXST_FLOW reply:
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto - del flows with cookie mask])
+OVS_VSWITCHD_START
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=0])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=0])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=0])
+AT_CHECK([ovs-ofctl dump-flows br0 | STRIP_XIDS | STRIP_DURATION | sort], [0], [dnl
+ cookie=0x1, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=1 actions=output:0
+ cookie=0x2, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=2 actions=output:0
+ cookie=0x3, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=3 actions=output:0
+NXST_FLOW reply:
+])
+AT_CHECK([ovs-ofctl del-flows br0 cookie=0x3/0x1])
+AT_CHECK([ovs-ofctl dump-flows br0 | STRIP_XIDS | STRIP_DURATION | sort], [0], [dnl
+ cookie=0x2, duration=?s, table=0, n_packets=0, n_bytes=0, in_port=2 actions=output:0
+NXST_FLOW reply:
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
index 2a458c8..d89d398 100644
--- a/tests/ovs-ofctl.at
+++ b/tests/ovs-ofctl.at
@@ -346,6 +346,10 @@ NXM_OF_ETH_TYPE(86dd) NXM_NX_IP_FRAG_W(02/02)
 NXM_OF_ETH_TYPE(86dd) NXM_NX_IP_FRAG_W(03/03)
 NXM_OF_ETH_TYPE(86dd) NXM_NX_IP_FRAG(f3)
 
+# Flow cookie.
+NXM_NX_COOKIE(00000000abcdef01)
+NXM_NX_COOKIE_W(84200000abcdef01/84200000FFFFFFFF)
+
 # Tunnel ID.
 NXM_NX_TUN_ID(00000000abcdef01)
 NXM_NX_TUN_ID_W(84200000abcdef01/84200000FFFFFFFF)
@@ -535,6 +539,10 @@ NXM_OF_ETH_TYPE(86dd), NXM_NX_IP_FRAG_W(02/02)
 NXM_OF_ETH_TYPE(86dd), NXM_NX_IP_FRAG(03)
 nx_pull_match() returned error 44010102 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_VALUE)
 
+# Flow cookie.
+NXM_NX_COOKIE(00000000abcdef01)
+NXM_NX_COOKIE_W(84200000abcdef01/84200000ffffffff)
+
 # Tunnel ID.
 NXM_NX_TUN_ID(00000000abcdef01)
 NXM_NX_TUN_ID_W(84200000abcdef01/84200000ffffffff)
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 5fcc60b..12207f8 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -933,15 +933,21 @@ further actions, including those which may be in other tables, or different
 levels of the \fBresubmit\fR call stack, are ignored.
 .
 .PP
-The \fBadd\-flow\fR, \fBadd\-flows\fR, and \fBmod\-flows\fR commands
-support an additional optional field:
+An opaque identifier called a cookie can be associated with a flow:
+.
+.IP \fBcookie=\fIvalue\fR[\fB/\fImask\fR]
 .
-.IP \fBcookie=\fIvalue\fR
+A cookie can be associated with a flow with the \fBadd-flow\fR and
+\fBadd-flows\fR commands.  When using NXM, the cookie can be used as a
+handle for querying, modifying, and deleting flows.  \fIvalue\fR can be
+any 64-bit number and need not be unique among flows.  If this field is
+omitted, a default cookie value of 0 is used.
 .
-A cookie is an opaque identifier that can be associated with the flow.
-\fIvalue\fR can be any 64-bit number and need not be unique among
-flows.  If this field is omitted, these commands set a default cookie
-value of 0.
+When using NXM, an optional \fImask\fR may be supplied for the
+\fBdel-flows\fR, \fBmod-flows\fR, \fBdump-flows\fR, and
+\fBdump-aggregate\fR commands to limit matching cookies.  A 1-bit in
+\fImask\fR indicates that the corresponding bit in \fIcookie\fR must
+match exactly, and a 0-bit wildcards that bit.
 .
 .PP
 The following additional field sets the priority for flows added by
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index cf77300..edeadfb 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -586,6 +586,9 @@ do_dump_flows__(int argc, char *argv[], bool aggregate)
 
     open_vconn(argv[1], &vconn);
     min_flow_format = ofputil_min_flow_format(&fsr.match);
+    if (fsr.cookie_mask != htonll(0)) {
+        min_flow_format = NXFF_NXM;
+    }
     flow_format = negotiate_highest_flow_format(vconn, min_flow_format);
     request = ofputil_encode_flow_stats_request(&fsr, flow_format);
     dump_stats_transaction(argv[1], request);
@@ -1455,6 +1458,7 @@ do_parse_nx_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
     while (!ds_get_line(&in, stdin)) {
         struct ofpbuf nx_match;
         struct cls_rule rule;
+        ovs_be64 cookie, cookie_mask;
         int match_len;
         int error;
         char *s;
@@ -1478,14 +1482,15 @@ do_parse_nx_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         match_len = nx_match_from_string(ds_cstr(&in), &nx_match);
 
         /* Convert nx_match to cls_rule. */
-        error = nx_pull_match(&nx_match, match_len, 0, &rule);
+        error = nx_pull_match(&nx_match, match_len, 0, &rule,
+                              &cookie, &cookie_mask);
         if (!error) {
             char *out;
 
             /* Convert cls_rule back to nx_match. */
             ofpbuf_uninit(&nx_match);
             ofpbuf_init(&nx_match, 0);
-            match_len = nx_put_match(&nx_match, &rule);
+            match_len = nx_put_match(&nx_match, &rule, cookie, cookie_mask);
 
             /* Convert nx_match to string. */
             out = nx_match_to_string(nx_match.data, match_len);
-- 
1.7.4.1




More information about the dev mailing list