ofproto: Add support for flow cookies (OpenFlow 1.0)
authorJustin Pettit <jpettit@nicira.com>
Wed, 13 Jan 2010 07:22:22 +0000 (23:22 -0800)
committerJustin Pettit <jpettit@nicira.com>
Sat, 20 Feb 2010 10:22:28 +0000 (02:22 -0800)
In OpenFlow 1.0, flows have been extended to include an opaque
identifier, referred to as a cookie. The cookie is specified by the
controller when the flow is installed; the cookie will be returned as
part of each flow stats and flow removed message.

NOTE: OVS at this point is not wire-compatible with OpenFlow 1.0 until
the final commit in this Openflow 1.0 set.

include/openflow/openflow.h
lib/ofp-print.c
lib/vconn.c
ofproto/ofproto.c
utilities/ovs-ofctl.c

index 4835b8a9968fba093fe63010abe0b45b0dcf0f6a..2847aedd8065f477af00c978fd577f90b4410051 100644 (file)
@@ -543,6 +543,7 @@ enum ofp_flow_mod_flags {
 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_*. */
@@ -556,12 +557,11 @@ struct ofp_flow_mod {
                                      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 {
@@ -574,6 +574,7 @@ 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_*. */
@@ -585,7 +586,7 @@ struct ofp_flow_removed {
     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
@@ -753,12 +754,13 @@ struct ofp_flow_stats {
                                  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 {
index 19058b45b21061af1f612efff2ab1d39e58ff160..700f3c4f54724f36afa3e6d28a64267fbfac9233 100644 (file)
@@ -735,7 +735,8 @@ ofp_print_flow_mod(struct ds *string, const void *oh, size_t len,
     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));
@@ -769,8 +770,8 @@ ofp_print_flow_removed(struct ds *string, const void *oh,
         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));
@@ -984,7 +985,8 @@ ofp_flow_stats_reply(struct ds *string, const void *body_, size_t len,
             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);
index 19a19786f1ed342c7ff301cdb1e7ba50bfc2a096..de40744875d191cb4913b7c9f3cac946d8527624 100644 (file)
@@ -886,6 +886,7 @@ make_flow_mod(uint16_t command, const flow_t *flow, size_t actions_len)
     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);
index 14a425db2999b056f5a2dc291aadea41699bc5c4..18d3e029edbfa57a511440e6b8c85af8f0530f10 100644 (file)
@@ -83,6 +83,8 @@ static int xlate_actions(const union ofp_action *in, size_t n_in,
 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? */
@@ -144,7 +146,7 @@ rule_is_hidden(const struct rule *rule)
 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 *);
@@ -992,7 +994,7 @@ ofproto_add_flow(struct ofproto *p,
     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);
 }
@@ -1404,11 +1406,12 @@ static struct rule *
 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;
@@ -1571,7 +1574,7 @@ rule_create_subrule(struct ofproto *ofproto, struct rule *rule,
 {
     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
@@ -2565,10 +2568,11 @@ flow_stats_cb(struct cls_rule *rule_, void *cbdata_)
     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);
@@ -2819,7 +2823,7 @@ add_flow(struct ofproto *p, struct ofconn *ofconn,
 
     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));
 
@@ -2861,6 +2865,7 @@ modify_flow(struct ofproto *p, const struct ofp_flow_mod *ofm,
         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);
@@ -3260,6 +3265,7 @@ compose_flow_removed(const struct rule *rule, long long int now, uint8_t reason)
 
     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);
index 9dd80b1165a154be75cf4b4f255aff00eaa6019d..1a4700cd7bbf7a5f24eaa7dd36ace9a16f6dbd6b 100644 (file)
@@ -48,6 +48,7 @@
 #include "timeval.h"
 #include "util.h"
 #include "vconn.h"
+#include "xtoxll.h"
 
 #include "vlog.h"
 #define THIS_MODULE VLM_ofctl
@@ -686,7 +687,8 @@ parse_field(const char *name, const struct field **f_out)
 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;
@@ -707,6 +709,9 @@ str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions,
     if (hard_timeout) {
         *hard_timeout = OFP_FLOW_PERMANENT;
     }
+    if (cookie) {
+        *cookie = 0;
+    }
     if (actions) {
         char *act_str = strstr(string, "action");
         if (!act_str) {
@@ -755,6 +760,8 @@ str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions,
                 *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")) {
@@ -793,7 +800,7 @@ do_dump_flows(int argc, char *argv[])
 
     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);
 
@@ -809,7 +816,7 @@ do_dump_aggregate(int argc, char *argv[])
 
     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);
 
@@ -823,21 +830,23 @@ do_add_flow(int argc OVS_UNUSED, char *argv[])
     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);
@@ -861,6 +870,7 @@ do_add_flows(int argc OVS_UNUSED, char *argv[])
         struct ofpbuf *buffer;
         struct ofp_flow_mod *ofm;
         uint16_t priority, idle_timeout, hard_timeout;
+        uint64_t cookie;
         struct ofp_match match;
 
         char *comment;
@@ -881,15 +891,16 @@ do_add_flows(int argc OVS_UNUSED, char *argv[])
          * 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);
     }
@@ -901,6 +912,7 @@ static void
 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;
@@ -910,7 +922,8 @@ do_mod_flows(int argc OVS_UNUSED, char *argv[])
      * '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) {
@@ -920,9 +933,9 @@ do_mod_flows(int argc OVS_UNUSED, char *argv[])
     }
     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);
@@ -940,7 +953,7 @@ static void do_del_flows(int argc, char *argv[])
     /* 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 {
@@ -951,7 +964,6 @@ static void do_del_flows(int argc, char *argv[])
     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);