Added OFPFC_MODIFY_STRICT flow mod command.
authorJustin Pettit <jpettit@nicira.com>
Tue, 16 Sep 2008 23:07:25 +0000 (16:07 -0700)
committerJustin Pettit <jpettit@nicira.com>
Tue, 16 Sep 2008 23:07:41 +0000 (16:07 -0700)
This cleans up the handling of modifying existing flows.  There now exists
OFPFC_MODIFY and OFPFC_MODIFY_STRICT commands, which have the same matching
characteristics to their OFPFC_DELETE* counterparts.  When adding a flow that
already exists, the counters and timers are now reset (ie, its treated as a
new flow).  This commit also adds the "--strict" option to dpctl to allow
strict matching for "mod-flows" and "del-flows".

21 files changed:
datapath/chain.c
datapath/chain.h
datapath/flow.c
datapath/flow.h
datapath/forward.c
datapath/hwtable_dummy/hwtable_dummy.c
datapath/table-hash.c
datapath/table-linear.c
datapath/table.h
include/openflow.h
lib/ofp-print.c
switch/chain.c
switch/chain.h
switch/datapath.c
switch/switch-flow.c
switch/switch-flow.h
switch/table-hash.c
switch/table-linear.c
switch/table.h
utilities/dpctl.8
utilities/dpctl.c

index 36749f306cfacbe36609c638abef3b7bff825d21..865f908d7d00cf468cc52861b5427b2e3049d9bb 100644 (file)
@@ -101,14 +101,15 @@ int chain_insert(struct sw_chain *chain, struct sw_flow *flow)
        return -ENOBUFS;
 }
 
-/* Modifies actions in 'chain' that match 'key'.  Returns the number of 
- * flows that were modified.
+/* Modifies actions in 'chain' that match 'key'.  If 'strict' set, wildcards 
+ * and priority must match.  Returns the number of flows that were modified.
  *
  * Expensive in the general case as currently implemented, since it requires
  * iterating through the entire contents of each table for keys that contain
  * wildcards.  Relatively cheap for fully specified keys. */
 int
 chain_modify(struct sw_chain *chain, const struct sw_flow_key *key, 
+               uint16_t priority, int strict,
                const struct ofp_action *actions, int n_actions)
 {
        int count = 0;
@@ -116,14 +117,15 @@ chain_modify(struct sw_chain *chain, const struct sw_flow_key *key,
 
        for (i = 0; i < chain->n_tables; i++) {
                struct sw_table *t = chain->tables[i];
-               count += t->modify(t, key, actions, n_actions);
+               count += t->modify(t, key, priority, strict, actions, n_actions);
        }
 
        return count;
 }
 
-/* Deletes from 'chain' any and all flows that match 'key'.  Returns the number
- * of flows that were deleted.
+/* Deletes from 'chain' any and all flows that match 'key'.  If 'strict' set, 
+ * wildcards and priority must match.  Returns the number of flows that were 
+ * deleted.
  *
  * Expensive in the general case as currently implemented, since it requires
  * iterating through the entire contents of each table for keys that contain
index dbbae416ac88e3cece7cb77a9494e713a950a15f..a7d044eee612273fc338f146b20a7b05bd36d75f 100644 (file)
@@ -26,7 +26,7 @@ struct sw_chain *chain_create(struct datapath *);
 struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *);
 int chain_insert(struct sw_chain *, struct sw_flow *);
 int chain_modify(struct sw_chain *, const struct sw_flow_key *, 
-               const struct ofp_action *, int);
+               uint16_t, int, const struct ofp_action *, int);
 int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, int);
 int chain_timeout(struct sw_chain *);
 void chain_destroy(struct sw_chain *);
index 2093dbba276d90eb3c69ffab312cf115f64a6d84..ae2f78792d8bc6a0b3c4c90b481d9a0873ea344b 100644 (file)
@@ -66,17 +66,18 @@ int flow_matches_2wild(const struct sw_flow_key *a,
 EXPORT_SYMBOL(flow_matches_2wild);
 
 /* Returns nonzero if 't' (the table entry's key) and 'd' (the key
- * describing the deletion) match, that is, if their fields are
+ * describing the match) match, that is, if their fields are
  * equal modulo wildcards, zero otherwise.  If 'strict' is nonzero, the
  * wildcards must match in both 't_key' and 'd_key'.  Note that the
  * table's wildcards are ignored unless 'strict' is set. */
-int flow_del_matches(const struct sw_flow_key *t, const struct sw_flow_key *d, int strict)
+int flow_matches_desc(const struct sw_flow_key *t, const struct sw_flow_key *d, 
+               int strict)
 {
        if (strict && d->wildcards != t->wildcards)
                return 0;
        return flow_matches_1wild(t, d);
 }
-EXPORT_SYMBOL(flow_del_matches);
+EXPORT_SYMBOL(flow_matches_desc);
 
 static uint32_t make_nw_mask(int n_wild_bits)
 {
index 3b25ad5d63f3b7b3efc6ee7e7470c1b242db8964..8c0c27feed228374b5fb18bf551749b5ea3b53cf 100644 (file)
@@ -99,7 +99,7 @@ struct sw_flow {
 
 int flow_matches_1wild(const struct sw_flow_key *, const struct sw_flow_key *);
 int flow_matches_2wild(const struct sw_flow_key *, const struct sw_flow_key *);
-int flow_del_matches(const struct sw_flow_key *, const struct sw_flow_key *, 
+int flow_matches_desc(const struct sw_flow_key *, const struct sw_flow_key *, 
                int);
 struct sw_flow *flow_alloc(int n_actions, gfp_t flags);
 void flow_free(struct sw_flow *);
index 7d7757167d7c4cd525491fdf79b1dfdb9df035d8..b63dfefb079169e78a37b6518a12983fe934b1ab 100644 (file)
@@ -495,6 +495,8 @@ mod_flow(struct sw_chain *chain, const struct ofp_flow_mod *ofm)
        int i;
        int n_actions;
        struct sw_flow_key key;
+       uint16_t priority;
+       int strict;
 
        /* To prevent loops, make sure there's no action to send to the
         * OFP_TABLE virtual port.
@@ -514,7 +516,9 @@ mod_flow(struct sw_chain *chain, const struct ofp_flow_mod *ofm)
        }
 
        flow_extract_match(&key, &ofm->match);
-       chain_modify(chain, &key, ofm->actions, n_actions);
+       priority = key.wildcards ? ntohs(ofm->priority) : -1;
+       strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0;
+       chain_modify(chain, &key, priority, strict, ofm->actions, n_actions);
 
        if (ntohl(ofm->buffer_id) != (uint32_t) -1) {
                struct sk_buff *skb = retrieve_skb(ntohl(ofm->buffer_id));
@@ -543,7 +547,7 @@ recv_flow(struct sw_chain *chain, const struct sender *sender, const void *msg)
 
        if (command == OFPFC_ADD) {
                return add_flow(chain, ofm);
-       } else if (command == OFPFC_MODIFY) {
+       } else if ((command == OFPFC_MODIFY) || (command == OFPFC_MODIFY_STRICT)) {
                return mod_flow(chain, ofm);
        }  else if (command == OFPFC_DELETE) {
                struct sw_flow_key key;
index b78d364315efe07eb14cef5f31155c23572cdd4b..1edb83af4898a8cca9f5092ea01c8f79382c3048 100644 (file)
@@ -98,7 +98,7 @@ static int table_dummy_insert(struct sw_table *swt, struct sw_flow *flow)
 }
 
 static int table_dummy_modify(struct sw_table *swt, 
-               const struct sw_flow_key *key,
+               const struct sw_flow_key *key, uint16_t priority, int strict,
                const struct ofp_action *actions, int n_actions)
 {
        struct sw_table_dummy *td = (struct sw_table_dummy *) swt;
@@ -106,7 +106,8 @@ static int table_dummy_modify(struct sw_table *swt,
        unsigned int count = 0;
 
        list_for_each_entry (flow, &td->flows, node) {
-               if (flow_matches_1wild(&flow->key, key)) {
+               if (flow_matches_desc(&flow->key, key, strict)
+                               && (!strict || (flow->priority == priority))) {
                        flow_replace_acts(flow, actions, n_actions);
                        /* xxx Do whatever is necessary to modify the entry in hardware */
                        count++;
@@ -135,7 +136,7 @@ static int table_dummy_delete(struct sw_table *swt,
        unsigned int count = 0;
 
        list_for_each_entry (flow, &td->flows, node) {
-               if (flow_del_matches(&flow->key, key, strict)
+               if (flow_matches_desc(&flow->key, key, strict)
                    && (!strict || (flow->priority == priority)))
                        count += do_delete(swt, flow);
        }
index f6a41de5c5424070b6c91952585434f92f4778fc..29d205943acb68955e4a500f3017f348c43a5ed8 100644 (file)
@@ -60,11 +60,6 @@ static int table_hash_insert(struct sw_table *swt, struct sw_flow *flow)
        } else {
                struct sw_flow *old_flow = *bucket;
                if (flow_keys_equal(&old_flow->key, &flow->key)) {
-                       /* Keep stats from the original flow */
-                       flow->init_time = old_flow->init_time;
-                       flow->packet_count = old_flow->packet_count;
-                       flow->byte_count = old_flow->byte_count;
-
                        rcu_assign_pointer(*bucket, flow);
                        flow_deferred_free(old_flow);
                        retval = 1;
@@ -76,7 +71,7 @@ static int table_hash_insert(struct sw_table *swt, struct sw_flow *flow)
 }
 
 static int table_hash_modify(struct sw_table *swt, 
-               const struct sw_flow_key *key, 
+               const struct sw_flow_key *key, uint16_t priority, int strict,
                const struct ofp_action *actions, int n_actions) 
 {
        struct sw_table_hash *th = (struct sw_table_hash *) swt;
@@ -85,7 +80,8 @@ static int table_hash_modify(struct sw_table *swt,
        if (key->wildcards == 0) {
                struct sw_flow **bucket = find_bucket(swt, key);
                struct sw_flow *flow = *bucket;
-               if (flow && flow_matches_1wild(&flow->key, key)) {
+               if (flow && flow_matches_desc(&flow->key, key, strict)
+                               && (!strict || (flow->priority == priority))) {
                        flow_replace_acts(flow, actions, n_actions);
                        count = 1;
                }
@@ -95,7 +91,8 @@ static int table_hash_modify(struct sw_table *swt,
                for (i = 0; i <= th->bucket_mask; i++) {
                        struct sw_flow **bucket = &th->buckets[i];
                        struct sw_flow *flow = *bucket;
-                       if (flow && flow_matches_1wild(&flow->key, key)) {
+                       if (flow && flow_matches_desc(&flow->key, key, strict)
+                                       && (!strict || (flow->priority == priority))) {
                                flow_replace_acts(flow, actions, n_actions);
                                count++;
                        }
@@ -133,7 +130,7 @@ static int table_hash_delete(struct sw_table *swt,
                for (i = 0; i <= th->bucket_mask; i++) {
                        struct sw_flow **bucket = &th->buckets[i];
                        struct sw_flow *flow = *bucket;
-                       if (flow && flow_del_matches(&flow->key, key, strict))
+                       if (flow && flow_matches_desc(&flow->key, key, strict))
                                count += do_delete(bucket, flow);
                }
        }
@@ -291,12 +288,14 @@ static int table_hash2_insert(struct sw_table *swt, struct sw_flow *flow)
 }
 
 static int table_hash2_modify(struct sw_table *swt, 
-               const struct sw_flow_key *key,
+               const struct sw_flow_key *key, uint16_t priority, int strict,
                const struct ofp_action *actions, int n_actions)
 {
        struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
-       return (table_hash_modify(t2->subtable[0], key, actions, n_actions)
-                       + table_hash_modify(t2->subtable[1], key, actions, n_actions));
+       return (table_hash_modify(t2->subtable[0], key, priority, strict, 
+                                       actions, n_actions)
+                       + table_hash_modify(t2->subtable[1], key, priority, strict, 
+                                       actions, n_actions));
 }
 
 static int table_hash2_delete(struct sw_table *swt,
index 4a10df550373a2cee35d84734a66404218d74f32..89f5c3c4cb3814f4ae0d96e740f6c5acda65bb73 100644 (file)
@@ -48,11 +48,6 @@ static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow)
                if (f->priority == flow->priority
                                && f->key.wildcards == flow->key.wildcards
                                && flow_matches_2wild(&f->key, &flow->key)) {
-                       /* Keep stats from the original flow */
-                       flow->init_time = f->init_time;
-                       flow->packet_count = f->packet_count;
-                       flow->byte_count = f->byte_count;
-
                        flow->serial = f->serial;
                        list_replace_rcu(&f->node, &flow->node);
                        list_replace_rcu(&f->iter_node, &flow->iter_node);
@@ -78,7 +73,7 @@ static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow)
 }
 
 static int table_linear_modify(struct sw_table *swt,
-                               const struct sw_flow_key *key,
+                               const struct sw_flow_key *key, uint16_t priority, int strict,
                                const struct ofp_action *actions, int n_actions)
 {
        struct sw_table_linear *tl = (struct sw_table_linear *) swt;
@@ -86,7 +81,8 @@ static int table_linear_modify(struct sw_table *swt,
        unsigned int count = 0;
 
        list_for_each_entry (flow, &tl->flows, node) {
-               if (flow_matches_1wild(&flow->key, key)) {
+               if (flow_matches_desc(&flow->key, key, strict)
+                               && (!strict || (flow->priority == priority))) {
                        flow_replace_acts(flow, actions, n_actions);
                        count++;
                }
@@ -110,7 +106,7 @@ static int table_linear_delete(struct sw_table *swt,
        unsigned int count = 0;
 
        list_for_each_entry (flow, &tl->flows, node) {
-               if (flow_del_matches(&flow->key, key, strict)
+               if (flow_matches_desc(&flow->key, key, strict)
                                && (!strict || (flow->priority == priority)))
                        count += do_delete(swt, flow);
        }
index 8cbcfb7a6d0880d7d4013748923e88b47e04cd20..3dda2769bd31b04359b1348d8abfd3364a654bb6 100644 (file)
@@ -55,9 +55,11 @@ struct sw_table {
         * retained by the caller. */
        int (*insert)(struct sw_table *table, struct sw_flow *flow);
 
-       /* Modifies the actions in 'table' that match 'key'.  Returns the
-        * number of flows that were modified. */
+       /* Modifies the actions in 'table' that match 'key'.  If 'strict'
+        * set, wildcards and priority must match.  Returns the number of flows 
+        * that were modified. */
        int (*modify)(struct sw_table *table, const struct sw_flow_key *key,
+                       uint16_t priority, int strict,
                        const struct ofp_action *actions, int n_actions);
 
        /* Deletes from 'table' any and all flows that match 'key' from
index e04cfbedb8f33af53052e48911cfe728969d9785..528efeb89fe791c63341dabd784def53cfa66d52 100644 (file)
@@ -353,6 +353,7 @@ OFP_ASSERT(sizeof(struct ofp_packet_out) == 16);
 enum ofp_flow_mod_command {
     OFPFC_ADD,              /* New flow. */
     OFPFC_MODIFY,           /* Modify all matching flows. */
+    OFPFC_MODIFY_STRICT,    /* Modify entry strictly matching wildcards */
     OFPFC_DELETE,           /* Delete all matching flows. */
     OFPFC_DELETE_STRICT     /* Strictly match wildcards and priority. */
 };
index bbe4d49b3b7cbfa4f9754df84bfe18aaed45a4fa..65c7d07219844d48a57ea842d52cba422d9ce220 100644 (file)
@@ -565,6 +565,9 @@ ofp_print_flow_mod(struct ds *string, const void *oh, size_t len,
     case OFPFC_MODIFY:
         ds_put_cstr(string, " MOD: ");
         break;
+    case OFPFC_MODIFY_STRICT:
+        ds_put_cstr(string, " MOD_STRICT: ");
+        break;
     case OFPFC_DELETE:
         ds_put_cstr(string, " DEL: ");
         break;
index 0388951da8ff9ff9dd0f7ec180470b1582562435..c591cdbfc2e7c238436340c237f107a0db548fc1 100644 (file)
@@ -114,14 +114,15 @@ chain_insert(struct sw_chain *chain, struct sw_flow *flow)
     return -ENOBUFS;
 }
 
-/* Modifies actions in 'chain' that match 'key'.  Returns the number of 
- * flows that were modified.
+/* Modifies actions in 'chain' that match 'key'.  If 'strict' set, wildcards 
+ * and priority must match.  Returns the number of flows that were modified.
  *
  * Expensive in the general case as currently implemented, since it requires
  * iterating through the entire contents of each table for keys that contain
  * wildcards.  Relatively cheap for fully specified keys. */
 int
 chain_modify(struct sw_chain *chain, const struct sw_flow_key *key,
+        uint16_t priority, int strict,
         const struct ofp_action *actions, int n_actions)
 {
     int count = 0;
@@ -129,14 +130,15 @@ chain_modify(struct sw_chain *chain, const struct sw_flow_key *key,
 
     for (i = 0; i < chain->n_tables; i++) {
         struct sw_table *t = chain->tables[i];
-        count += t->modify(t, key, actions, n_actions);
+        count += t->modify(t, key, priority, strict, actions, n_actions);
     }
 
     return count;
 }
 
-/* Deletes from 'chain' any and all flows that match 'key'.  Returns the number
- * of flows that were deleted.
+/* Deletes from 'chain' any and all flows that match 'key'.   If 'strict' set, 
+ * wildcards and priority must match.  Returns the number of flows that were 
+ * deleted.
  *
  * Expensive in the general case as currently implemented, since it requires
  * iterating through the entire contents of each table for keys that contain
index eaccad41f0eeb35b2ff35eafc765362ba242c1f5..9ad54d0eee779f685fcf0cc14f100d7e4e146036 100644 (file)
@@ -57,7 +57,7 @@ struct sw_chain *chain_create(void);
 struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *);
 int chain_insert(struct sw_chain *, struct sw_flow *);
 int chain_modify(struct sw_chain *, const struct sw_flow_key *, 
-        const struct ofp_action *, int);
+        uint16_t, int, const struct ofp_action *, int);
 int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, int);
 void chain_timeout(struct sw_chain *, struct list *deleted);
 void chain_destroy(struct sw_chain *);
index e5a2440f486871d68b7a4afa293876f3af9ad451..032b7ec7afbe00bfcb2a076351a06fded31b52f6 100644 (file)
@@ -1224,6 +1224,8 @@ mod_flow(struct datapath *dp, const struct ofp_flow_mod *ofm)
     int n_actions;
     int i;
     struct sw_flow_key key;
+    uint16_t priority;
+    int strict;
 
 
     /* To prevent loops, make sure there's no action to send to the
@@ -1244,7 +1246,9 @@ mod_flow(struct datapath *dp, const struct ofp_flow_mod *ofm)
     }
 
     flow_extract_match(&key, &ofm->match);
-    chain_modify(dp->chain, &key, ofm->actions, n_actions);
+    priority = key.wildcards ? ntohs(ofm->priority) : -1;
+    strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0;
+    chain_modify(dp->chain, &key, priority, strict, ofm->actions, n_actions);
 
     if (ntohl(ofm->buffer_id) != UINT32_MAX) {
         struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id));
@@ -1275,7 +1279,7 @@ recv_flow(struct datapath *dp, const struct sender *sender UNUSED,
 
     if (command == OFPFC_ADD) {
         return add_flow(dp, ofm);
-    } else if (command == OFPFC_MODIFY) {
+    } else if ((command == OFPFC_MODIFY) || (command == OFPFC_MODIFY_STRICT)) {
         return mod_flow(dp, ofm);
     }  else if (command == OFPFC_DELETE) {
         struct sw_flow_key key;
index e0410afc445323db4adee3d98dcb1e4058189d68..a42d00fb32e60da9cd9b335b942423724723da87 100644 (file)
@@ -85,12 +85,13 @@ flow_matches_2wild(const struct sw_flow_key *a, const struct sw_flow_key *b)
 }
 
 /* Returns nonzero if 't' (the table entry's key) and 'd' (the key 
- * describing the deletion) match, that is, if their fields are 
+ * describing the match) match, that is, if their fields are 
  * equal modulo wildcards, zero otherwise.  If 'strict' is nonzero, the
  * wildcards must match in both 't_key' and 'd_key'.  Note that the
  * table's wildcards are ignored unless 'strict' is set. */
 int
-flow_del_matches(const struct sw_flow_key *t, const struct sw_flow_key *d, int strict)
+flow_matches_desc(const struct sw_flow_key *t, const struct sw_flow_key *d, 
+        int strict)
 {
     if (strict && d->wildcards != t->wildcards) {
         return 0;
index 16066cbf349db7de66d4d3a949380daf973ff27e..817998c7f7017cce0391214ce4df6a1944f71dd1 100644 (file)
@@ -76,7 +76,7 @@ struct sw_flow {
 
 int flow_matches_1wild(const struct sw_flow_key *, const struct sw_flow_key *);
 int flow_matches_2wild(const struct sw_flow_key *, const struct sw_flow_key *);
-int flow_del_matches(const struct sw_flow_key *, const struct sw_flow_key *, 
+int flow_matches_desc(const struct sw_flow_key *, const struct sw_flow_key *, 
                      int);
 struct sw_flow *flow_alloc(int n_actions);
 void flow_free(struct sw_flow *);
index 34cba7ad564e69f05ada0bf8cde9a8e495b5230f..0960082b3cc2cfb8642247925cb75349412df1e9 100644 (file)
@@ -82,12 +82,6 @@ static int table_hash_insert(struct sw_table *swt, struct sw_flow *flow)
     } else {
         struct sw_flow *old_flow = *bucket;
         if (!flow_compare(&old_flow->key.flow, &flow->key.flow)) {
-            /* Keep stats from the original flow */
-            flow->used = old_flow->used;
-            flow->created = old_flow->created;
-            flow->packet_count = old_flow->packet_count;
-            flow->byte_count = old_flow->byte_count;
-
             *bucket = flow;
             flow_free(old_flow);
             retval = 1;
@@ -99,7 +93,7 @@ static int table_hash_insert(struct sw_table *swt, struct sw_flow *flow)
 }
 
 static int table_hash_modify(struct sw_table *swt, 
-        const struct sw_flow_key *key,
+        const struct sw_flow_key *key, uint16_t priority, int strict,
         const struct ofp_action *actions, int n_actions) 
 {
     struct sw_table_hash *th = (struct sw_table_hash *) swt;
@@ -108,7 +102,8 @@ static int table_hash_modify(struct sw_table *swt,
     if (key->wildcards == 0) {
         struct sw_flow **bucket = find_bucket(swt, key);
         struct sw_flow *flow = *bucket;
-        if (flow && flow_matches_1wild(&flow->key, key)) {
+        if (flow && flow_matches_desc(&flow->key, key, strict)
+                && (!strict || (flow->priority == priority))) {
             flow_replace_acts(flow, actions, n_actions);
             count = 1;
         }
@@ -118,7 +113,8 @@ static int table_hash_modify(struct sw_table *swt,
         for (i = 0; i <= th->bucket_mask; i++) {
             struct sw_flow **bucket = &th->buckets[i];
             struct sw_flow *flow = *bucket;
-            if (flow && flow_matches_1wild(&flow->key, key)) {
+            if (flow && flow_matches_desc(&flow->key, key, strict)
+                    && (!strict || (flow->priority == priority))) {
                 flow_replace_acts(flow, actions, n_actions);
                 count++;
             }
@@ -158,7 +154,7 @@ static int table_hash_delete(struct sw_table *swt,
         for (i = 0; i <= th->bucket_mask; i++) {
             struct sw_flow **bucket = &th->buckets[i];
             struct sw_flow *flow = *bucket;
-            if (flow && flow_del_matches(&flow->key, key, strict)) {
+            if (flow && flow_matches_desc(&flow->key, key, strict)) {
                 do_delete(bucket);
                 count++;
             }
@@ -307,12 +303,14 @@ static int table_hash2_insert(struct sw_table *swt, struct sw_flow *flow)
 }
 
 static int table_hash2_modify(struct sw_table *swt, 
-        const struct sw_flow_key *key,
+        const struct sw_flow_key *key, uint16_t priority, int strict,
         const struct ofp_action *actions, int n_actions) 
 {
     struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
-    return (table_hash_modify(t2->subtable[0], key, actions, n_actions)
-            + table_hash_modify(t2->subtable[1], key, actions, n_actions));
+    return (table_hash_modify(t2->subtable[0], key, priority, strict,
+                    actions, n_actions)
+            + table_hash_modify(t2->subtable[1], key, priority, strict,
+                    actions, n_actions));
 }
 
 static int table_hash2_delete(struct sw_table *swt,
index d1a040389a375d61cc1f6dc9ab18b4228366227f..9a7a06cc855cafb69c36f9c1c9ce67b2259f478f 100644 (file)
@@ -75,12 +75,6 @@ static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow)
         if (f->priority == flow->priority
                 && f->key.wildcards == flow->key.wildcards
                 && flow_matches_2wild(&f->key, &flow->key)) {
-            /* Keep stats from the original flow */
-            flow->used = f->used;
-            flow->created = f->created;
-            flow->packet_count = f->packet_count;
-            flow->byte_count = f->byte_count;
-
             flow->serial = f->serial;
             list_replace(&flow->node, &f->node);
             list_replace(&flow->iter_node, &f->iter_node);
@@ -107,7 +101,7 @@ static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow)
 }
 
 static int table_linear_modify(struct sw_table *swt,
-                const struct sw_flow_key *key,
+                const struct sw_flow_key *key, uint16_t priority, int strict,
                 const struct ofp_action *actions, int n_actions)
 {
     struct sw_table_linear *tl = (struct sw_table_linear *) swt;
@@ -115,7 +109,8 @@ static int table_linear_modify(struct sw_table *swt,
     unsigned int count = 0;
 
     LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) {
-        if (flow_matches_1wild(&flow->key, key)) {
+        if (flow_matches_desc(&flow->key, key, strict)
+                && (!strict || (flow->priority == priority))) {
             flow_replace_acts(flow, actions, n_actions);
             count++;
         }
@@ -140,7 +135,7 @@ static int table_linear_delete(struct sw_table *swt,
     unsigned int count = 0;
 
     LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) {
-        if (flow_del_matches(&flow->key, key, strict)
+        if (flow_matches_desc(&flow->key, key, strict)
                 && (!strict || (flow->priority == priority))) {
             do_delete(flow);
             count++;
index 9a48c4b5d1705d56e997be132e2027aab05077a5..aacaa63fd280ee118c876e5cdac2e0eb5b5aeb4c 100644 (file)
@@ -84,9 +84,11 @@ struct sw_table {
      * retained by the caller. */
     int (*insert)(struct sw_table *table, struct sw_flow *flow);
 
-    /* Modifies entries in 'table' that match 'key'.  Returns the
-     * number of flows that were modified. */
+    /* Modifies the actions in 'table' that match 'key'.  If 'strict'
+     * set, wildcards and priority must match.  Returns the number of flows 
+     * that were modified. */
     int (*modify)(struct sw_table *table, const struct sw_flow_key *key,
+            uint16_t priority, int strict,
             const struct ofp_action *actions, int n_actions);
 
     /* Deletes from 'table' any and all flows that match 'key' from
index 870ffb907210d0c574dd4ca1ba649fb387f1e0af..014b2b1ba4f5301103634526468c2910b9d4cba3 100644 (file)
@@ -172,15 +172,18 @@ described in \fBFLOW SYNTAX\fR, below.
 .TP
 \fBmod-flows \fIswitch flow\fR
 Modify the actions in entries from the datapath \fIswitch\fR's tables 
-that match \fIflow\fR.  See \fBFLOW SYNTAX\fR, below, for the syntax 
-of \fIflows\fR.
+that match \fIflow\fR.  When invoked with the \fB--strict\fR option,
+wildcards are not treated as active for matching purposes.  See 
+\fBFLOW SYNTAX\fR, below, for the syntax of \fIflows\fR.
 
 .TP
 \fBdel-flows \fIswitch \fR[\fIflow\fR]
 Deletes entries from the datapath \fIswitch\fR's tables that match
-\fIflow\fR.  If \fIflow\fR is omitted, all flows in the datapath's
-tables are removed.  See \fBFLOW SYNTAX\fR, below, for the syntax of
-\fIflows\fR.
+\fIflow\fR.  When invoked with the \fB--strict\fR option, wildcards are 
+not treated as active for matching purposes.  If \fIflow\fR is 
+omitted and the \fB--strict\fR option is not used, all flows in the 
+datapath's tables are removed.  See \fBFLOW SYNTAX\fR, below, for the 
+syntax of \fIflows\fR.
 
 .TP
 \fBmonitor \fIswitch\fR
@@ -388,6 +391,10 @@ If this field is not specified, or if \fInumber\fR is given as
 \fB255\fR, statistics are gathered about flows from all tables.
 
 .SH OPTIONS
+.TP
+\fB--strict\fR
+Uses strict matching when running flow modification commands.
+
 .TP
 \fB-t\fR, \fB--timeout=\fIsecs\fR
 Limits \fBdpctl\fR runtime to approximately \fIsecs\fR seconds.  If
index f957b8225f3c8adee01e2ffe49fc1e2412c69638..58e5e56bf15ab49da7a4270cbcfb70e1cbe323e9 100644 (file)
 #define MOD_PORT_CMD_FLOOD   "flood"
 #define MOD_PORT_CMD_NOFLOOD "noflood"
 
+
+/* Settings that may be configured by the user. */
+struct settings {
+    bool strict;        /* Use strict matching for flow mod commands */
+};
+
 struct command {
     const char *name;
     int min_args;
     int max_args;
-    void (*handler)(int argc, char *argv[]);
+    void (*handler)(const struct settings *, int argc, char *argv[]);
 };
 
 static struct command all_commands[];
 
 static void usage(void) NO_RETURN;
-static void parse_options(int argc, char *argv[]);
+static void parse_options(int argc, char *argv[], struct settings *);
 
 int main(int argc, char *argv[])
 {
+    struct settings s;
     struct command *p;
 
     set_program_name(argv[0]);
     time_init();
     vlog_init();
-    parse_options(argc, argv);
+    parse_options(argc, argv, &s);
     signal(SIGPIPE, SIG_IGN);
 
     argc -= optind;
@@ -113,7 +120,7 @@ int main(int argc, char *argv[])
                 ofp_fatal(0, "'%s' command takes at most %d arguments",
                           p->name, p->max_args);
             else {
-                p->handler(argc, argv);
+                p->handler(&s, argc, argv);
                 exit(0);
             }
         }
@@ -124,11 +131,15 @@ int main(int argc, char *argv[])
 }
 
 static void
-parse_options(int argc, char *argv[])
+parse_options(int argc, char *argv[], struct settings *s)
 {
+    enum {
+        OPT_STRICT = UCHAR_MAX + 1
+    };
     static struct option long_options[] = {
         {"timeout", required_argument, 0, 't'},
         {"verbose", optional_argument, 0, 'v'},
+        {"strict", no_argument, 0, OPT_STRICT},
         {"help", no_argument, 0, 'h'},
         {"version", no_argument, 0, 'V'},
         VCONN_SSL_LONG_OPTIONS
@@ -136,6 +147,9 @@ parse_options(int argc, char *argv[])
     };
     char *short_options = long_options_to_short_options(long_options);
 
+    /* Set defaults that we can figure out before parsing options. */
+    s->strict = false;
+
     for (;;) {
         unsigned long int timeout;
         int c;
@@ -167,6 +181,10 @@ parse_options(int argc, char *argv[])
             vlog_set_verbosity(optarg);
             break;
 
+        case OPT_STRICT:
+            s->strict = true;
+            break;
+
         VCONN_SSL_OPTION_HANDLERS
 
         case '?':
@@ -215,6 +233,7 @@ usage(void)
            program_name, program_name);
     vconn_usage(true, false, false);
     printf("\nOptions:\n"
+           "  --strict                    use strict match for flow commands\n"
            "  -t, --timeout=SECS          give up after SECS seconds\n"
            "  -v, --verbose=MODULE[:FACILITY[:LEVEL]]  set logging levels\n"
            "  -v, --verbose               set maximum verbosity level\n"
@@ -271,7 +290,7 @@ static void open_nl_vconn(const char *name, bool subscribe, struct dpif *dpif)
     run(dpif_open(atoi(name + 3), subscribe, dpif), "opening datapath");
 }
 
-static void do_add_dp(int argc UNUSED, char *argv[])
+static void do_add_dp(const struct settings *s, int argc UNUSED, char *argv[])
 {
     struct dpif dp;
     open_nl_vconn(argv[1], false, &dp);
@@ -279,7 +298,7 @@ static void do_add_dp(int argc UNUSED, char *argv[])
     dpif_close(&dp);
 }
 
-static void do_del_dp(int argc UNUSED, char *argv[])
+static void do_del_dp(const struct settings *s, int argc UNUSED, char *argv[])
 {
     struct dpif dp;
     open_nl_vconn(argv[1], false, &dp);
@@ -316,12 +335,14 @@ static int ifup_and_add_port(struct dpif *dpif, const char *netdev)
     return retval ? retval : dpif_add_port(dpif, netdev);
 }
 
-static void do_add_port(int argc UNUSED, char *argv[])
+static void do_add_port(const struct settings *s, int argc UNUSED, 
+        char *argv[])
 {
     add_del_ports(argc, argv, ifup_and_add_port, "add", "to");
 }
 
-static void do_del_port(int argc UNUSED, char *argv[])
+static void do_del_port(const struct settings *s, int argc UNUSED, 
+        char *argv[])
 {
     add_del_ports(argc, argv, dpif_del_port, "remove", "from");
 }
@@ -414,14 +435,14 @@ dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type)
 }
 
 static void
-do_show(int argc UNUSED, char *argv[])
+do_show(const struct settings *s, int argc UNUSED, char *argv[])
 {
     dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST);
     dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST);
 }
 
 static void
-do_status(int argc, char *argv[])
+do_status(const struct settings *s, int argc, char *argv[])
 {
     struct nicira_header *request, *reply;
     struct vconn *vconn;
@@ -452,13 +473,13 @@ do_status(int argc, char *argv[])
 }
 
 static void
-do_dump_desc(int argc, char *argv[])
+do_dump_desc(const struct settings *s, int argc, char *argv[])
 {
     dump_trivial_stats_transaction(argv[1], OFPST_DESC);
 }
 
 static void
-do_dump_tables(int argc, char *argv[])
+do_dump_tables(const struct settings *s, int argc, char *argv[])
 {
     dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
 }
@@ -767,7 +788,7 @@ str_to_flow(char *string, struct ofp_match *match,
     match->wildcards = htonl(wildcards);
 }
 
-static void do_dump_flows(int argc, char *argv[])
+static void do_dump_flows(const struct settings *s, int argc, char *argv[])
 {
     struct ofp_flow_stats_request *req;
     struct ofpbuf *request;
@@ -780,7 +801,8 @@ static void do_dump_flows(int argc, char *argv[])
     dump_stats_transaction(argv[1], request);
 }
 
-static void do_dump_aggregate(int argc, char *argv[])
+static void do_dump_aggregate(const struct settings *s, int argc, 
+        char *argv[])
 {
     struct ofp_aggregate_stats_request *req;
     struct ofpbuf *request;
@@ -793,7 +815,7 @@ static void do_dump_aggregate(int argc, char *argv[])
     dump_stats_transaction(argv[1], request);
 }
 
-static void do_add_flow(int argc, char *argv[])
+static void do_add_flow(const struct settings *s, int argc, char *argv[])
 {
     struct vconn *vconn;
     struct ofpbuf *buffer;
@@ -822,7 +844,7 @@ static void do_add_flow(int argc, char *argv[])
     vconn_close(vconn);
 }
 
-static void do_add_flows(int argc, char *argv[])
+static void do_add_flows(const struct settings *s, int argc, char *argv[])
 {
     struct vconn *vconn;
     FILE *file;
@@ -875,9 +897,9 @@ static void do_add_flows(int argc, char *argv[])
     fclose(file);
 }
 
-static void do_mod_flows(int argc, char *argv[])
+static void do_mod_flows(const struct settings *s, int argc, char *argv[])
 {
-    uint16_t idle_timeout, hard_timeout;
+    uint16_t priority, idle_timeout, hard_timeout;
     struct vconn *vconn;
     struct ofpbuf *buffer;
     struct ofp_flow_mod *ofm;
@@ -888,12 +910,16 @@ static void do_mod_flows(int argc, char *argv[])
     size = sizeof *ofm + (sizeof ofm->actions[0] * MAX_ADD_ACTS);
     ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
     str_to_flow(argv[2], &ofm->match, &ofm->actions[0], &n_actions, 
-                NULL, NULL, &idle_timeout, &hard_timeout);
-    ofm->command = htons(OFPFC_MODIFY);
+                NULL, &priority, &idle_timeout, &hard_timeout);
+    if (s->strict) {
+        ofm->command = htons(OFPFC_MODIFY_STRICT);
+    } else {
+        ofm->command = htons(OFPFC_MODIFY);
+    }
     ofm->idle_timeout = htons(idle_timeout);
     ofm->hard_timeout = htons(hard_timeout);
     ofm->buffer_id = htonl(UINT32_MAX);
-    ofm->priority = htons(0);
+    ofm->priority = htons(priority);
     ofm->reserved = htonl(0);
 
     /* xxx Should we use the buffer library? */
@@ -904,7 +930,7 @@ static void do_mod_flows(int argc, char *argv[])
     vconn_close(vconn);
 }
 
-static void do_del_flows(int argc, char *argv[])
+static void do_del_flows(const struct settings *s, int argc, char *argv[])
 {
     struct vconn *vconn;
     uint16_t priority;
@@ -917,7 +943,11 @@ static void do_del_flows(int argc, char *argv[])
     ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
     str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, 0, NULL, 
                 &priority, NULL, NULL);
-    ofm->command = htons(OFPFC_DELETE);
+    if (s->strict) {
+        ofm->command = htons(OFPFC_DELETE_STRICT);
+    } else {
+        ofm->command = htons(OFPFC_DELETE);
+    }
     ofm->idle_timeout = htons(0);
     ofm->hard_timeout = htons(0);
     ofm->buffer_id = htonl(UINT32_MAX);
@@ -930,7 +960,7 @@ static void do_del_flows(int argc, char *argv[])
 }
 
 static void
-do_monitor(int argc UNUSED, char *argv[])
+do_monitor(const struct settings *s, int argc UNUSED, char *argv[])
 {
     struct vconn *vconn;
     const char *name;
@@ -953,13 +983,13 @@ do_monitor(int argc UNUSED, char *argv[])
 }
 
 static void
-do_dump_ports(int argc, char *argv[])
+do_dump_ports(const struct settings *s, int argc, char *argv[])
 {
     dump_trivial_stats_transaction(argv[1], OFPST_PORT);
 }
 
 static void
-do_probe(int argc, char *argv[])
+do_probe(const struct settings *s, int argc, char *argv[])
 {
     struct ofpbuf *request;
     struct vconn *vconn;
@@ -976,7 +1006,7 @@ do_probe(int argc, char *argv[])
 }
 
 static void
-do_mod_port(int argc, char *argv[])
+do_mod_port(const struct settings *s, int argc, char *argv[])
 {
     struct ofpbuf *request, *reply;
     struct ofp_switch_features *osf;
@@ -1054,7 +1084,7 @@ do_mod_port(int argc, char *argv[])
 }
 
 static void
-do_ping(int argc, char *argv[])
+do_ping(const struct settings *s, int argc, char *argv[])
 {
     size_t max_payload = 65535 - sizeof(struct ofp_header);
     unsigned int payload;
@@ -1101,7 +1131,7 @@ do_ping(int argc, char *argv[])
 }
 
 static void
-do_benchmark(int argc, char *argv[])
+do_benchmark(const struct settings *s, int argc, char *argv[])
 {
     size_t max_payload = 65535 - sizeof(struct ofp_header);
     struct timeval start, end;
@@ -1143,7 +1173,8 @@ do_benchmark(int argc, char *argv[])
            count * message_size / (duration / 1000.0));
 }
 
-static void do_help(int argc UNUSED, char *argv[] UNUSED)
+static void do_help(const struct settings *s, int argc UNUSED, 
+        char *argv[] UNUSED)
 {
     usage();
 }