From: Ben Pfaff Date: Fri, 2 May 2008 17:52:53 +0000 (-0700) Subject: Send actions as part of flow statistics messages. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4f5b4efc54f3880ca5f5b5c292675aea8596a311;p=openvswitch Send actions as part of flow statistics messages. --- diff --git a/datapath/datapath.c b/datapath/datapath.c index e75aaa5b..444b5e96 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -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) diff --git a/include/openflow.h b/include/openflow.h index e1dd9f57..3b5176a5 100644 --- a/include/openflow.h +++ b/include/openflow.h @@ -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. */ diff --git a/lib/ofp-print.c b/lib/ofp-print.c index ef4c1383..80d8ea68 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -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; } } diff --git a/switch/datapath.c b/switch/datapath.c index 8438b473..bef86fbd 100644 --- a/switch/datapath.c +++ b/switch/datapath.c @@ -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); } @@ -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)