Send actions as part of flow statistics messages.
authorBen Pfaff <blp@nicira.com>
Fri, 2 May 2008 17:52:53 +0000 (10:52 -0700)
committerBen Pfaff <blp@nicira.com>
Fri, 2 May 2008 17:58:53 +0000 (10:58 -0700)
datapath/datapath.c
include/openflow.h
lib/ofp-print.c
switch/datapath.c

index e75aaa5b919b81c180a8d0bb41307f8accac0f12..444b5e96aa01e73bebad5356664643b09cc61dbe 100644 (file)
@@ -838,10 +838,14 @@ dp_send_error_msg(struct datapath *dp, const struct sender *sender,
        return send_openflow_skb(skb, sender);
 }
 
-static void
+static int
 fill_flow_stats(struct ofp_flow_stats *ofs, struct sw_flow *flow,
                int table_idx)
 {
+       int length = sizeof *ofs + sizeof *ofs->actions * flow->n_actions;
+       ofs->length          = htons(length);
+       ofs->table_id        = table_idx;
+       ofs->pad             = 0;
        ofs->match.wildcards = htons(flow->key.wildcards);
        ofs->match.in_port   = flow->key.in_port;
        memcpy(ofs->match.dl_src, flow->key.dl_src, ETH_ALEN);
@@ -859,8 +863,9 @@ fill_flow_stats(struct ofp_flow_stats *ofs, struct sw_flow *flow,
        ofs->byte_count      = cpu_to_be64(flow->byte_count);
        ofs->priority        = htons(flow->priority);
        ofs->max_idle        = htons(flow->max_idle);
-       ofs->table_id        = table_idx;
-       memset(ofs->pad, 0, sizeof ofs->pad);
+       memcpy(ofs->actions, flow->actions,
+              sizeof *ofs->actions * flow->n_actions);
+       return length;
 }
 
 /* Generic Netlink interface.
@@ -1100,10 +1105,13 @@ struct flow_stats_state {
        struct sw_table_position position;
        const struct ofp_flow_stats_request *rq;
 
-       struct ofp_flow_stats *flows;
-       int n_flows, max_flows;
+       void *body;
+       int bytes_used, bytes_allocated;
 };
 
+#define MAX_FLOW_STATS_SIZE (sizeof(struct ofp_flow_stats) \
+                            + MAX_ACTIONS * sizeof(struct ofp_action))
+
 static int flow_stats_init(struct datapath *dp, const void *body, int body_len,
                           void **state)
 {
@@ -1121,25 +1129,24 @@ static int flow_stats_init(struct datapath *dp, const void *body, int body_len,
 static int flow_stats_dump_callback(struct sw_flow *flow, void *private)
 {
        struct flow_stats_state *s = private;
-
-       fill_flow_stats(&s->flows[s->n_flows], flow, s->table_idx);
-       return ++s->n_flows >= s->max_flows;
+       s->bytes_used += fill_flow_stats(s->body + s->bytes_used, flow,
+                                        s->table_idx);
+       return s->bytes_used + MAX_FLOW_STATS_SIZE > s->bytes_allocated;
 }
 
 static int flow_stats_dump(struct datapath *dp, void *state,
                           void *body, int *body_len)
 {
        struct flow_stats_state *s = state;
-       struct ofp_flow_stats *ofs;
        struct sw_flow_key match_key;
 
-       s->max_flows = *body_len / sizeof *ofs;
-       if (!s->max_flows)
+       s->bytes_used = 0;
+       s->bytes_allocated = *body_len;
+       if (s->bytes_allocated < MAX_FLOW_STATS_SIZE)
                return -ENOMEM;
-       s->flows = body;
+       s->body = body;
 
        flow_extract_match(&match_key, &s->rq->match);
-       s->n_flows = 0;
        while (s->table_idx < dp->chain->n_tables
               && (s->rq->table_id == 0xff || s->rq->table_id == s->table_idx))
        {
@@ -1152,8 +1159,8 @@ static int flow_stats_dump(struct datapath *dp, void *state,
                s->table_idx++;
                memset(&s->position, 0, sizeof s->position);
        }
-       *body_len = sizeof *ofs * s->n_flows;
-       return s->n_flows >= s->max_flows;
+       *body_len = s->bytes_used;
+       return s->bytes_used + MAX_FLOW_STATS_SIZE > s->bytes_allocated;
 }
 
 static void flow_stats_done(void *state)
index e1dd9f57bdcfcc536dcd38d582081565f9139821..3b5176a582f75f6aed57f4977c841487f241aed6 100644 (file)
@@ -419,16 +419,19 @@ struct ofp_flow_stats_request {
 
 /* Body of reply to OFPST_FLOW request. */
 struct ofp_flow_stats {
+    uint16_t length;          /* Length of this entry */
+    uint8_t table_id;         /* ID of table flow came from. 0nly used for
+                                 non-aggregated results */
+    uint8_t pad;
     struct ofp_match match;   /* Description of fields */
-    uint32_t duration;        /* Time flow has been alive in seconds.  Only 
+    uint32_t duration;        /* Time flow has been alive in seconds. Only
                                  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 
+    uint16_t priority;        /* Priority of the entry. Only meaningful
                                  when this is not an exact-match entry. */
     uint16_t max_idle;        /* Only used for non-aggregated results. */
-    uint8_t table_id;         /* ID of table flow came from. */
-    uint8_t pad[5];           /* Align to 64-bits. */
+    struct ofp_action actions[0]; /* Only used for non-aggregated results. */
 };
 
 /* Body of reply to OFPST_TABLE request. */
index ef4c1383dde6a3ffa8fb14e747afb2a9ada16d85..80d8ea68731e030983e1f3c0c50c86313337f0d0 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, "%d", 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));
@@ -378,7 +378,7 @@ static void ofp_print_match(struct ds *f, const struct ofp_match *om)
     print_wild(f, "] proto", w & OFPFW_NW_PROTO, "%u", om->nw_proto);
     print_wild(f, " tport[", w & OFPFW_TP_SRC, "%d", ntohs(om->tp_src));
     print_wild(f, "->", w & OFPFW_TP_DST, "%d", ntohs(om->tp_dst));
-    ds_put_cstr(f, "]\n");
+    ds_put_cstr(f, "]");
 }
 
 /* Pretty-print the OFPT_FLOW_MOD packet of 'len' bytes at 'oh' to 'string'
@@ -468,17 +468,44 @@ ofp_flow_stats_request(struct ds *string, const void *oh, size_t len,
 }
 
 static void
-ofp_flow_stats_reply(struct ds *string, const void *body, size_t len,
+ofp_flow_stats_reply(struct ds *string, const void *body_, size_t len,
                      int verbosity)
 {
-    const struct ofp_flow_stats *fs = body;
-    size_t n = len / sizeof *fs;
-    ds_put_format(string, " %zu flows\n", n);
-    if (verbosity < 1) {
-        return;
-    }
+    const char *body = body_;
+    const char *pos = body;
+    for (;;) {
+        const struct ofp_flow_stats *fs;
+        ptrdiff_t bytes_left = body + len - pos;
+        size_t length;
+
+        if (bytes_left < sizeof *fs) {
+            if (bytes_left != 0) {
+                ds_put_format(string, " ***%td leftover bytes at end***",
+                              bytes_left);
+            }
+            break;
+        }
+
+        fs = (const void *) pos;
+        length = ntohs(fs->length);
+        if (length < sizeof *fs) {
+            ds_put_format(string, " ***length=%zu shorter than minimum %zu***",
+                          length, sizeof *fs);
+            break;
+        } else if (length > bytes_left) {
+            ds_put_format(string,
+                          " ***length=%zu but only %td bytes left***",
+                          length, bytes_left);
+            break;
+        } else if ((length - sizeof *fs) % sizeof fs->actions[0]) {
+            ds_put_format(string,
+                          " ***length=%zu has %zu bytes leftover in "
+                          "final action***",
+                          length,
+                          (length - sizeof *fs) % sizeof fs->actions[0]);
+            break;
+        }
 
-    for (; n--; fs++) {
         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", ", 
@@ -488,6 +515,10 @@ ofp_flow_stats_reply(struct ds *string, const void *body, size_t len,
         ds_put_format(string, "n_bytes=%"PRIu64", ", ntohll(fs->byte_count));
         ds_put_format(string, "max_idle=%"PRIu16", ", ntohs(fs->max_idle));
         ofp_print_match(string, &fs->match);
+        ofp_print_actions(string, fs->actions, length - sizeof *fs);
+        ds_put_char(string, '\n');
+
+        pos += length;
      }
 }
 
index 8438b4738199b0c77b77fafe541c9e6d496da3d8..bef86fbd8dba4e4cbf921ba635991a60ecbe8773 100644 (file)
@@ -714,9 +714,15 @@ dp_send_error_msg(struct datapath *dp, const struct sender *sender,
 }
 
 static void
-fill_flow_stats(struct ofp_flow_stats *ofs, struct sw_flow *flow,
+fill_flow_stats(struct buffer *buffer, struct sw_flow *flow,
                 int table_idx, time_t now)
 {
+    struct ofp_flow_stats *ofs;
+    int length = sizeof *ofs + sizeof *ofs->actions * flow->n_actions;
+    ofs = buffer_put_uninit(buffer, length);
+    ofs->length          = htons(length);
+    ofs->table_id        = table_idx;
+    ofs->pad             = 0;
     ofs->match.wildcards = htons(flow->key.wildcards);
     ofs->match.in_port   = flow->key.flow.in_port;
     memcpy(ofs->match.dl_src, flow->key.flow.dl_src, ETH_ADDR_LEN);
@@ -734,8 +740,8 @@ fill_flow_stats(struct ofp_flow_stats *ofs, struct sw_flow *flow,
     ofs->byte_count      = htonll(flow->byte_count);
     ofs->priority        = htons(flow->priority);
     ofs->max_idle        = htons(flow->max_idle);
-    ofs->table_id        = table_idx;
-    memset(ofs->pad, 0, sizeof ofs->pad);
+    memcpy(ofs->actions, flow->actions,
+           sizeof *ofs->actions * flow->n_actions);
 }
 
 \f
@@ -1136,9 +1142,10 @@ struct flow_stats_state {
     time_t now;
 
     struct buffer *buffer;
-    int n_flows, max_flows;
 };
 
+#define MAX_FLOW_STATS_BYTES 4096
+
 static int flow_stats_init(struct datapath *dp, const void *body, int body_len,
                            void **state)
 {
@@ -1154,25 +1161,18 @@ static int flow_stats_init(struct datapath *dp, const void *body, int body_len,
 static int flow_stats_dump_callback(struct sw_flow *flow, void *private)
 {
     struct flow_stats_state *s = private;
-    struct ofp_flow_stats *ofs = buffer_put_uninit(s->buffer, sizeof *ofs);
-    fill_flow_stats(ofs, flow, s->table_idx, s->now);
-    return ++s->n_flows >= s->max_flows;
+    fill_flow_stats(s->buffer, flow, s->table_idx, s->now);
+    return s->buffer->size >= MAX_FLOW_STATS_BYTES;
 }
 
 static int flow_stats_dump(struct datapath *dp, void *state,
                            struct buffer *buffer)
 {
     struct flow_stats_state *s = state;
-    struct ofp_flow_stats *ofs;
     struct sw_flow_key match_key;
 
-    s->max_flows = 4096 / sizeof *ofs;
-    if (!s->max_flows)
-        return -ENOMEM;
-
     flow_extract_match(&match_key, &s->rq.match);
     s->buffer = buffer;
-    s->n_flows = 0;
     s->now = time(0);
     while (s->table_idx < dp->chain->n_tables
            && (s->rq.table_id == 0xff || s->rq.table_id == s->table_idx))
@@ -1186,7 +1186,7 @@ static int flow_stats_dump(struct datapath *dp, void *state,
         s->table_idx++;
         memset(&s->position, 0, sizeof s->position);
     }
-    return s->n_flows >= s->max_flows;
+    return s->buffer->size >= MAX_FLOW_STATS_BYTES;
 }
 
 static void flow_stats_done(void *state)