process_stats_reply(struct lswitch *sw, struct rconn *rconn, void *osr_)
{
struct ofp_stats_reply *osr = osr_;
- const uint8_t *body = osr->body;
- const uint8_t *pos = body;
- size_t body_len;
+ struct flow_stats_iterator i;
+ const struct ofp_flow_stats *fs;
if (sw->last_query == LLONG_MIN
|| osr->type != htons(OFPST_FLOW)
|| osr->header.xid != sw->query_xid) {
return;
}
- body_len = (ntohs(osr->header.length)
- - offsetof(struct ofp_stats_reply, body));
- for (;;) {
- const struct ofp_flow_stats *fs;
- ptrdiff_t bytes_left = body + body_len - pos;
- size_t length;
-
- if (bytes_left < sizeof *fs) {
- if (bytes_left != 0) {
- VLOG_WARN_RL(&rl, "%012llx: %td leftover bytes in flow "
- "stats reply", sw->datapath_id, bytes_left);
- }
- break;
- }
-
- fs = (const void *) pos;
- length = ntohs(fs->length);
- if (length < sizeof *fs) {
- VLOG_WARN_RL(&rl, "%012llx: flow stats length %zu is shorter than "
- "min %zu", sw->datapath_id, length, sizeof *fs);
- break;
- } else if (length > bytes_left) {
- VLOG_WARN_RL(&rl, "%012llx: flow stats length %zu but only %td "
- "bytes left", sw->datapath_id, length, bytes_left);
- break;
- } else if ((length - sizeof *fs) % sizeof fs->actions[0]) {
- VLOG_WARN_RL(&rl, "%012llx: flow stats length %zu has %zu bytes "
- "left over in final action", sw->datapath_id, length,
- (length - sizeof *fs) % sizeof fs->actions[0]);
- break;
- }
-
+ for (fs = flow_stats_first(&i, osr); fs; fs = flow_stats_next(&i)) {
sw->n_flows++;
process_flow_stats(sw, rconn, fs);
-
- pos += length;
- }
+ }
if (!(osr->flags & htons(OFPSF_REPLY_MORE))) {
VLOG_DBG("%012llx: Deleted %d of %d received flows to "
"implement STP, %d because of no-recv, %d because of "
return 0;
}
+const struct ofp_flow_stats *
+flow_stats_first(struct flow_stats_iterator *iter,
+ const struct ofp_stats_reply *osr)
+{
+ iter->pos = osr->body;
+ iter->end = osr->body + (ntohs(osr->header.length) + sizeof *osr);
+ return flow_stats_next(iter);
+}
+
+const struct ofp_flow_stats *
+flow_stats_next(struct flow_stats_iterator *iter)
+{
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+ ptrdiff_t bytes_left = iter->end - iter->pos;
+ const struct ofp_flow_stats *fs;
+ size_t length;
+
+ if (bytes_left < sizeof *fs) {
+ if (bytes_left != 0) {
+ VLOG_WARN_RL(&rl, "%td leftover bytes in flow stats reply",
+ bytes_left);
+ }
+ return NULL;
+ }
+
+ fs = (const void *) iter->pos;
+ length = ntohs(fs->length);
+ if (length < sizeof *fs) {
+ VLOG_WARN_RL(&rl, "flow stats length %zu is shorter than min %zu",
+ length, sizeof *fs);
+ return NULL;
+ } else if (length > bytes_left) {
+ VLOG_WARN_RL(&rl, "flow stats length %zu but only %td bytes left",
+ length, bytes_left);
+ return NULL;
+ } else if ((length - sizeof *fs) % sizeof fs->actions[0]) {
+ VLOG_WARN_RL(&rl, "flow stats length %zu has %zu bytes "
+ "left over in final action", length,
+ (length - sizeof *fs) % sizeof fs->actions[0]);
+ return NULL;
+ }
+ iter->pos += length;
+ return fs;
+}
+
void
vconn_init(struct vconn *vconn, struct vconn_class *class, int connect_status,
uint32_t ip, const char *name, bool reconnectable)
struct ofpbuf;
struct flow;
struct ofp_header;
+struct ofp_stats_reply;
struct pvconn;
struct vconn;
size_t size, size_t array_elt_size,
size_t *n_array_elts);
+struct flow_stats_iterator {
+ const uint8_t *pos, *end;
+};
+const struct ofp_flow_stats *flow_stats_first(struct flow_stats_iterator *,
+ const struct ofp_stats_reply *);
+const struct ofp_flow_stats *flow_stats_next(struct flow_stats_iterator *);
+
#endif /* vconn.h */