- Add support for flow entry priorities.
authorJustin Pettit <jpettit@nicira.com>
Fri, 25 Apr 2008 21:00:15 +0000 (14:00 -0700)
committerJustin Pettit <jpettit@nicira.com>
Sat, 26 Apr 2008 21:08:41 +0000 (14:08 -0700)
- Fix "flow-add" action for dpctl.

13 files changed:
ChangeLog
README
configure.ac
datapath/datapath.c
datapath/flow.h
datapath/forward.c
datapath/table-linear.c
include/openflow.h
lib/ofp-print.c
switch/datapath.c
switch/switch-flow.h
switch/table-linear.c
utilities/dpctl.c

index 97aa44742211904793fa9e13147362af85c0a0b5..0c0ba345d77fb78ab17c9b22322f666a50c0c3a6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
-v0.2.2 - 13 Apr 2008
+v0.8.0 - 13 Apr 2008
 --------------------
+    - Added support for flow entry priorities
+    - Added support for all stats messages
+    - Added support for OFPP_TABLE virtual port
     - Removed MAC tables
     - Various bug fixes and tweaks
 
diff --git a/README b/README
index 3031bfe4416c0cf558bc4f33298ec21759096b61..49363229917c3ba5ea18a1ab5cce1b19f4980b38 100644 (file)
--- a/README
+++ b/README
@@ -90,17 +90,11 @@ GCC is the expected compiler.
 Bugs/Shortcomings
 -----------------
 
-- The current flowtable does not support all statistics messages
-  mentioned in the Type 0 OpenFlow spec.
-
 - The flowtable does not support the "normal processing" action.
 
 - Configure/build system does not support separate build directory for
   the datapath.  ./configure must be run from the source root.
 
-- dpctl dump-flows may freeze when large numbers of flows are in the
-  flow table.  This has no effect on the datapath.
-
 References
 ----------
 
index 5d0a23ac7a3f9a70979a1302e6e2f958698aba99..7b3ac1c3a922615cf235b4892c070f99d043db6d 100644 (file)
@@ -1,5 +1,5 @@
 AC_PREREQ(2.59)
-AC_INIT(openflow, v0.2.2a2, info@openflowswitch.org)
+AC_INIT(openflow, v0.2.2a5, info@openflowswitch.org)
 AM_INIT_AUTOMAKE
 
 AC_PROG_CC
index 8a399fbe5b5bc57c9f6e66684ca1d8f6f9703cab..a0395904c20dcdf0e28cd10f59cd746990283c42 100644 (file)
@@ -783,6 +783,7 @@ fill_flow_stats(struct ofp_flow_stats *ofs, struct sw_flow *flow,
        ofs->match.tp_src    = flow->key.tp_src;
        ofs->match.tp_dst    = flow->key.tp_dst;
        ofs->duration        = htonl((jiffies - flow->init_time) / HZ);
+       ofs->priority        = htons(flow->priority);
        ofs->table_id        = table_idx;
        ofs->packet_count    = cpu_to_be64(flow->packet_count);
        ofs->byte_count      = cpu_to_be64(flow->byte_count);
index 5faeaf9df949d681624e7d9bd32d7869ea701502..3a34a9e45ef67bc9a25a5cab2c3029396e2ef9aa 100644 (file)
@@ -67,6 +67,7 @@ struct sw_flow {
 
        uint32_t group_id;      /* Flow group ID (for QoS). */
        uint16_t max_idle;      /* Idle time before discarding (seconds). */
+       uint16_t priority;      /* Only used on entries with wildcards. */
        unsigned long timeout;  /* Expiration time (in jiffies). */
 
        /* FIXME?  Probably most flows have only a single action. */
index d3d27334a02c5b08f131547cfd37e1938dc99d61..aa4000026290787ce72d00db352103f4d85af1a8 100644 (file)
@@ -380,6 +380,7 @@ add_flow(struct sw_chain *chain, const struct ofp_flow_mod *ofm)
        flow_extract_match(&flow->key, &ofm->match);
        flow->group_id = ntohl(ofm->group_id);
        flow->max_idle = ntohs(ofm->max_idle);
+       flow->priority = ntohs(ofm->priority);
        flow->timeout = jiffies + flow->max_idle * HZ;
        flow->n_actions = n_acts;
        flow->init_time = jiffies;
index cf0e3f8a4ae0b83910bd84c4ad05a08df384d018..a82b63ebf6a4ee444374b364df0f344d66efba6f 100644 (file)
@@ -39,10 +39,15 @@ static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow)
        unsigned long int flags;
        struct sw_flow *f;
 
-       /* Replace flows that match exactly. */
+
+       /* Loop through the existing list of entries.  New entries will
+        * always be placed behind those with equal priority.  Just replace 
+        * any flows that match exactly.
+        */
        spin_lock_irqsave(&tl->lock, flags);
        list_for_each_entry_rcu (f, &tl->flows, u.node) {
-               if (f->key.wildcards == flow->key.wildcards
+               if (f->priority == flow->priority
+                               && f->key.wildcards == flow->key.wildcards
                                && flow_matches(&f->key, &flow->key)
                                && flow_del(f)) {
                        list_replace_rcu(&f->u.node, &flow->u.node);
@@ -50,17 +55,20 @@ static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow)
                        flow_deferred_free(f);
                        return 1;
                }
+
+               if (f->priority < flow->priority)
+                       break;
        }
 
-       /* Table overflow? */
+       /* Make sure there's room in the table. */
        if (atomic_read(&tl->n_flows) >= tl->max_flows) {
                spin_unlock_irqrestore(&tl->lock, flags);
                return 0;
        }
        atomic_inc(&tl->n_flows);
 
-       /* FIXME: need to order rules from most to least specific. */
-       list_add_rcu(&flow->u.node, &tl->flows);
+       /* Insert the entry immediately in front of where we're pointing. */
+       list_add_tail_rcu(&flow->u.node, &f->u.node);
        spin_unlock_irqrestore(&tl->lock, flags);
        return 1;
 }
index 81b94afec259d0c454f5aad702d82c3fe10d8ddc..836c03a43e620a8b793663baad3a9096ce5eca83 100644 (file)
@@ -50,7 +50,7 @@
 /* The most significant bit being set in the version field indicates an
  * experimental OpenFlow version.  
  */
-#define OFP_VERSION   0x80
+#define OFP_VERSION   0x81
 
 #define OFP_MAX_TABLE_NAME_LEN 32
 #define OFP_MAX_PORT_NAME_LEN  16
@@ -341,6 +341,7 @@ struct ofp_flow_mod {
     uint32_t group_id;            /* Flow group ID (for QoS). */
     uint16_t priority;            /* Priority level of flow entry. */
     uint8_t pad[2];               /* Align to 32-bits. */
+    uint32_t reserved;            /* Reserved for future use. */
     struct ofp_action actions[0]; /* The number of actions is inferred from
                                     the length field in the header. */
 };
@@ -362,8 +363,10 @@ struct ofp_flow_stats {
                                  used for non-aggregated results. */
     uint64_t packet_count;    /* Number of packets in flow. */
     uint64_t byte_count;      /* Number of bytes in flow. */
+    uint16_t priority;        /* Priority of the entry.  Only meaningful 
+                                 when this is not an exact-match entry. */
     uint8_t table_id;         /* ID of table flow came from. */
-    uint8_t pad[7];           /* Align to 64-bits. */
+    uint8_t pad[5];           /* Align to 64-bits. */
 };
 
 enum ofp_stats_type {
index 4983f84f7628bd2269858a36d71875fcd54a8486..92eb87d82fd8ed2f81f384e8909ca49665c76c20 100644 (file)
@@ -366,7 +366,7 @@ static void ofp_print_match(struct ds *f, const struct ofp_match *om)
 {
     uint16_t w = ntohs(om->wildcards);
 
-    print_wild(f, "inport", w & OFPFW_IN_PORT, "%04x", ntohs(om->in_port));
+    print_wild(f, "inport", w & OFPFW_IN_PORT, "%d", ntohs(om->in_port));
     print_wild(f, ":vlan", w & OFPFW_DL_VLAN, "%04x", ntohs(om->dl_vlan));
     print_wild(f, " mac[", w & OFPFW_DL_SRC,
                ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_src));
@@ -468,6 +468,7 @@ ofp_flow_stats_reply(struct ds *string, const void *oh, size_t len,
     for (fs = &fsr->flows[0]; fs < &fsr->flows[n]; fs++) {
         ds_put_format(string, "  duration=%"PRIu32" s, ", ntohs(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);
         ds_put_format(string, "n_packets=%"PRIu64", ",
                       ntohll(fs->packet_count));
         ds_put_format(string, "n_bytes=%"PRIu64", ", ntohll(fs->byte_count));
index 18435676f9a07679fcd474360f104b1aa9f40d94..c465b76a1c955e6d9e954bc00a58fda78772a4fc 100644 (file)
@@ -644,6 +644,7 @@ fill_flow_stats(struct ofp_flow_stats *ofs, struct sw_flow *flow,
        ofs->match.tp_src    = flow->key.flow.tp_src;
        ofs->match.tp_dst    = flow->key.flow.tp_dst;
        ofs->duration        = htonl(now - flow->created);
+       ofs->priority        = htons(flow->priority);
        ofs->table_id        = table_idx;
        ofs->packet_count    = htonll(flow->packet_count);
        ofs->byte_count      = htonll(flow->byte_count);
@@ -1061,6 +1062,7 @@ add_flow(struct datapath *dp, const struct ofp_flow_mod *ofm)
     flow_extract_match(&flow->key, &ofm->match);
     flow->group_id = ntohl(ofm->group_id);
     flow->max_idle = ntohs(ofm->max_idle);
+    flow->priority = ntohs(ofm->priority);
     flow->timeout = time(0) + flow->max_idle; /* FIXME */
     flow->n_actions = n_acts;
     flow->created = time(0);    /* FIXME */
index 1f31cd2f2de7dc2ca65c3a76ecbddc842b06d5c4..5a35c0d9c0787146588e40f7d0ac2c2982e3b9f9 100644 (file)
@@ -54,6 +54,7 @@ struct sw_flow {
 
     uint32_t group_id;          /* Flow group ID (for QoS). */
     uint16_t max_idle;          /* Idle time before discarding (seconds). */
+    uint16_t priority;          /* Only used on entries with wildcards. */
     time_t created;             /* When the flow was created. */
     time_t timeout;             /* When the flow expires (if idle). */
     uint64_t packet_count;      /* Number of packets seen. */
index 9e7cec3251e4c974e5a17af371fc866711e8162c..6da93a239152de960267e0bf918fe0eaac8b514a 100644 (file)
@@ -63,24 +63,34 @@ static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow)
     struct sw_table_linear *tl = (struct sw_table_linear *) swt;
     struct sw_flow *f;
 
-    /* Replace flows that match exactly. */
+    /* Loop through the existing list of entries.  New entries will
+     * always be placed behind those with equal priority.  Just replace 
+     * any flows that match exactly.
+     */
     LIST_FOR_EACH (f, struct sw_flow, node, &tl->flows) {
-        if (f->key.wildcards == flow->key.wildcards
-            && flow_matches(&f->key, &flow->key)) {
+        if (f->priority == flow->priority
+                && f->key.wildcards == flow->key.wildcards
+                && flow_matches(&f->key, &flow->key)) {
             list_replace(&flow->node, &f->node);
             flow_free(f);
             return 1;
         }
+
+        if (f->priority < flow->priority)
+            break;
     }
 
-    /* Table overflow? */
+    /* Make sure there's room in the table. */
     if (tl->n_flows >= tl->max_flows) {
         return 0;
     }
     tl->n_flows++;
 
-    /* FIXME: need to order rules from most to least specific. */
-    list_push_back(&tl->flows, &flow->node);
+    /* Insert the entry immediately in front of where we're pointing. */
+    if (f)
+        list_push_back(&f->node, &flow->node);
+    else
+        list_push_back(&tl->flows, &flow->node);
     return 1;
 }
 
index 8637202dc3e93881b605d7d8ccac4f798078b9a1..ac7701836f4dc8061a251aa5911c0333e91c9a47 100644 (file)
@@ -455,7 +455,7 @@ str_to_action(const char *str, struct ofp_action *action)
 
 static void
 str_to_flow(char *string, struct ofp_match *match, struct ofp_action *action,
-            uint8_t *table_idx)
+            uint8_t *table_idx, uint16_t *priority)
 {
     struct field {
         const char *name;
@@ -505,6 +505,11 @@ str_to_flow(char *string, struct ofp_match *match, struct ofp_action *action,
             continue;
         }
 
+        if (priority && !strcmp(name, "priority")) {
+            *priority = atoi(value);
+            continue;
+        }
+
         for (f = fields; f < &fields[ARRAY_SIZE(fields)]; f++) {
             if (!strcmp(f->name, name)) {
                 goto found;
@@ -557,7 +562,7 @@ static void do_dump_flows(int argc, char *argv[])
 
     run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
     fsr = alloc_openflow_buffer(sizeof *fsr, OFPT_FLOW_STATS_REQUEST, &request);
-    str_to_flow(argc > 2 ? argv[2] : "", &fsr->match, NULL, &fsr->table_id);
+    str_to_flow(argc > 2 ? argv[2] : "", &fsr->match, NULL, &fsr->table_id, NULL);
     fsr->type = OFPFS_INDIV;
     fsr->pad = 0;
     reply = transact_openflow(vconn, request);
@@ -581,6 +586,7 @@ static void do_add_flows(int argc, char *argv[])
     while (fgets(line, sizeof line, file)) {
         struct buffer *buffer;
         struct ofp_flow_mod *ofm;
+        uint16_t priority=0;
         size_t size;
 
         char *comment;
@@ -603,8 +609,10 @@ static void do_add_flows(int argc, char *argv[])
         ofm->max_idle = htons(50);
         ofm->buffer_id = htonl(UINT32_MAX);
         ofm->group_id = htonl(0);
-        str_to_flow(line, &ofm->match, &ofm->actions[0], NULL);
-        run(vconn_send_block(vconn, buffer), "send OpenFlow packet");
+        str_to_flow(line, &ofm->match, &ofm->actions[0], NULL, &priority);
+        ofm->priority = htons(priority);
+
+        send_openflow_buffer(vconn, buffer);
     }
     vconn_close(vconn);
     fclose(file);