[ovs-dev] [PATCH 2/8] ofproto: Add support for flow cookies (OpenFlow 1.0)

Justin Pettit jpettit at nicira.com
Fri Jan 22 09:09:07 UTC 2010


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 |   12 +++++++-----
 lib/ofp-print.c             |   10 ++++++----
 lib/vconn.c                 |    3 ++-
 ofproto/ofproto.c           |   17 +++++++++++------
 utilities/ovs-ofctl.c       |   36 ++++++++++++++++++++++++------------
 5 files changed, 50 insertions(+), 28 deletions(-)

diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h
index 4835b8a..2847aed 100644
--- a/include/openflow/openflow.h
+++ b/include/openflow/openflow.h
@@ -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 {
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 1443842..25317f5 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -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, size_t len UNUSED,
         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);
diff --git a/lib/vconn.c b/lib/vconn.c
index 533278b..15ccfea 100644
--- a/lib/vconn.c
+++ b/lib/vconn.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -859,6 +859,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);
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 335e6c0..8fbef48 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -89,6 +89,7 @@ struct rule {
 
     uint16_t idle_timeout;      /* In seconds from time of last use. */
     uint16_t hard_timeout;      /* In seconds from time of creation. */
+    uint64_t flow_cookie;       /* Controller-issued identifier. */
     bool send_flow_removed;     /* Send a flow removed message? */
     long long int used;         /* Last-used time (0 if never used). */
     long long int created;      /* Creation time. */
@@ -148,7 +149,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 *);
@@ -1002,7 +1003,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);
 }
@@ -1397,11 +1398,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 = xcalloc(1, 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;
@@ -1564,7 +1566,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
@@ -2558,10 +2560,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 = htonll(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);
@@ -2812,7 +2815,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),  ntohll(ofm->cookie),
                        ofm->flags & htons(OFPFF_SEND_FLOW_REM));
     cls_rule_from_match(&rule->cr, &ofm->match, ntohs(ofm->priority));
 
@@ -2852,6 +2855,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 = ntohll(ofm->cookie);
 
         if (rule->cr.wc.wildcards) {
             COVERAGE_INC(ofproto_mod_wc_flow);
@@ -3297,6 +3301,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 = htonll(rule->flow_cookie);
     ofr->priority = htons(rule->cr.priority);
     ofr->reason = reason;
     ofr->duration = htonl((now - rule->created - last_used) / 1000);
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 7d6a600..712ac6c 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -48,6 +48,7 @@
 #include "util.h"
 #include "vconn-ssl.h"
 #include "vconn.h"
+#include "xtoxll.h"
 
 #include "vlog.h"
 #define THIS_MODULE VLM_ofctl
@@ -719,7 +720,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;
@@ -740,6 +742,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) {
@@ -788,6 +793,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")) {
@@ -826,7 +833,7 @@ do_dump_flows(const struct settings *s UNUSED, 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);
 
@@ -842,7 +849,7 @@ do_dump_aggregate(const struct settings *s UNUSED, 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);
 
@@ -856,21 +863,23 @@ do_add_flow(const struct settings *s UNUSED, int argc 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);
@@ -894,6 +903,7 @@ do_add_flows(const struct settings *s UNUSED, int argc 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;
@@ -914,15 +924,16 @@ do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
          * call. */
         ofm = 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);
     }
@@ -934,6 +945,7 @@ static void
 do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[])
 {
     uint16_t priority, idle_timeout, hard_timeout;
+    uint64_t cookie;
     struct vconn *vconn;
     struct ofpbuf *buffer;
     struct ofp_flow_mod *ofm;
@@ -943,7 +955,8 @@ do_mod_flows(const struct settings *s, int argc 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 (s->strict) {
@@ -953,9 +966,9 @@ do_mod_flows(const struct settings *s, int argc 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);
@@ -973,7 +986,7 @@ static void do_del_flows(const struct settings *s, 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 (s->strict) {
         ofm->command = htons(OFPFC_DELETE_STRICT);
     } else {
@@ -984,7 +997,6 @@ static void do_del_flows(const struct settings *s, 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);
-- 
1.5.5





More information about the dev mailing list