]> git.proxmox.com Git - mirror_ovs.git/blob - lib/ox-stat.c
ovsdb-idl: Fix iteration over tracked rows with no actual data.
[mirror_ovs.git] / lib / ox-stat.c
1 /*
2 * Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <config.h>
18 #include "ox-stat.h"
19 #include "byte-order.h"
20 #include "openvswitch/ofp-errors.h"
21 #include "openvswitch/compiler.h"
22 #include "openvswitch/ofpbuf.h"
23 #include "openvswitch/vlog.h"
24 #include "unaligned.h"
25
26 VLOG_DEFINE_THIS_MODULE(ox_stat);
27
28 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
29
30 /* OXS header
31 * ==========
32 *
33 * The header is 32 bits long. It looks like this:
34 *
35 * |31 16 15 9 8 7 0
36 * +----------------------------------+---------------+-+------------------+
37 * | oxs_class | oxs_field |r| oxs_length |
38 * +----------------------------------+---------------+-+------------------+
39 *
40 * where r stands for oxs_reserved. It is followed by oxs_length bytes of
41 * payload (the statistic's value).
42 *
43 * Internally, we represent a standard OXS header as a 64-bit integer with the
44 * above information in the most-significant bits.
45 *
46 *
47 * Experimenter OXS
48 * ================
49 *
50 * The header is 64 bits long. It looks like the diagram above except that a
51 * 32-bit experimenter ID, which we call oxs_experimenter and which identifies
52 * a vendor, is inserted just before the payload. Experimenter OXSs are
53 * identified by an all-1-bits oxs_class (OFPXSC_EXPERIMENTER). The oxs_length
54 * value *includes* the experimenter ID, so that the real payload is only
55 * oxs_length - 4 bytes long.
56 *
57 * Internally, we represent an experimenter OXS header as a 64-bit integer with
58 * the standard header in the upper 32 bits and the experimenter ID in the
59 * lower 32 bits. (It would be more convenient to swap the positions of the
60 * two 32-bit words, but this would be more error-prone because experimenter
61 * OXSs are very rarely used, so accidentally passing one through a 32-bit type
62 * somewhere in the OVS code would be hard to find.)
63 */
64
65 /* OXS Class IDs.
66 * The high order bit differentiate reserved classes from member classes.
67 * Classes 0x0000 to 0x7FFF are member classes, allocated by ONF.
68 * Classes 0x8000 to 0xFFFE are reserved classes, reserved for standardisation.
69 */
70 enum ofp_oxs_class {
71 OFPXSC_OPENFLOW_BASIC = 0x8002, /* Basic stats class for OpenFlow */
72 OFPXSC_EXPERIMENTER = 0xFFFF, /* Experimenter class */
73 };
74
75 /* Functions for extracting raw field values from OXS headers. */
76 static uint32_t oxs_experimenter(uint64_t header) { return header; }
77 static int oxs_class(uint64_t header) { return header >> 48; }
78 static int oxs_field(uint64_t header) { return (header >> 41) & 0x7f; }
79 static int oxs_length(uint64_t header) { return (header >> 32) & 0xff; }
80
81 static bool
82 is_experimenter_oxs(uint64_t header)
83 {
84 return oxs_class(header) == OFPXSC_EXPERIMENTER;
85 }
86
87 /* The OXS header "length" field is somewhat tricky:
88 *
89 * - For a standard OXS header, the length is the number of bytes of the
90 * payload, and the payload consists of just the value.
91 *
92 * - For an experimenter OXS header, the length is the number of bytes in
93 * the payload plus 4 (the length of the experimenter ID). That is, the
94 * experimenter ID is included in oxs_length.
95 *
96 * This function returns the length of the experimenter ID field in 'header'.
97 * That is, for an experimenter OXS (when an experimenter ID is present), it
98 * returns 4, and for a standard OXS (when no experimenter ID is present), it
99 * returns 0. */
100 static int
101 oxs_experimenter_len(uint64_t header)
102 {
103 return is_experimenter_oxs(header) ? 4 : 0;
104 }
105
106 /* Returns the number of bytes that follow the header for an OXS entry with the
107 * given 'header'. */
108 static int
109 oxs_payload_len(uint64_t header)
110 {
111 return oxs_length(header) - oxs_experimenter_len(header);
112 }
113
114 /* Returns the number of bytes in the header for an OXS entry with the given
115 * 'header'. */
116 static int
117 oxs_header_len(uint64_t header)
118 {
119 return 4 + oxs_experimenter_len(header);
120 }
121
122 /* Assembles an OXS header from its components. */
123 #define OXS_HEADER(EXPERIMENTER, CLASS, FIELD, LENGTH) \
124 (((uint64_t) (CLASS) << 48) | \
125 ((uint64_t) (FIELD) << 41) | \
126 ((uint64_t) (LENGTH) << 32) | \
127 (EXPERIMENTER))
128
129 #define OXS_HEADER_FMT "%#"PRIx32":%d:%d:%d"
130 #define OXS_HEADER_ARGS(HEADER) \
131 oxs_experimenter(HEADER), oxs_class(HEADER), oxs_field(HEADER), \
132 oxs_length(HEADER)
133
134 /* Currently defined OXS. */
135 #define OXS_OF_DURATION OXS_HEADER (0, 0x8002, OFPXST_OFB_DURATION, 8)
136 #define OXS_OF_IDLE_TIME OXS_HEADER (0, 0x8002, OFPXST_OFB_IDLE_TIME, 8)
137 #define OXS_OF_FLOW_COUNT OXS_HEADER (0, 0x8002, OFPXST_OFB_FLOW_COUNT, 4)
138 #define OXS_OF_PACKET_COUNT OXS_HEADER (0, 0x8002, OFPXST_OFB_PACKET_COUNT, 8)
139 #define OXS_OF_BYTE_COUNT OXS_HEADER (0, 0x8002, OFPXST_OFB_BYTE_COUNT, 8)
140
141 /* Header for a group of OXS statistics. */
142 struct ofp_oxs_stat {
143 ovs_be16 reserved; /* Must be zero. */
144 ovs_be16 length; /* Stats Length */
145 };
146 BUILD_ASSERT_DECL(sizeof(struct ofp_oxs_stat) == 4);
147
148 static int oxs_pull_header__(struct ofpbuf *b, uint64_t *header);
149 static enum ofperr oxs_pull_raw(const uint8_t *, unsigned int stat_len,
150 struct oxs_stats *, uint8_t *oxs_field_set);
151
152 static int
153 oxs_pull_header__(struct ofpbuf *b, uint64_t *header)
154 {
155 if (b->size < 4) {
156 goto bad_len;
157 }
158
159 *header = ((uint64_t) ntohl(get_unaligned_be32(b->data))) << 32;
160 if (is_experimenter_oxs(*header)) {
161 if (b->size < 8) {
162 goto bad_len;
163 }
164 *header = ntohll(get_unaligned_be64(b->data));
165 }
166 if (oxs_length(*header) < oxs_experimenter_len(*header)) {
167 VLOG_WARN_RL(&rl, "OXS header "OXS_HEADER_FMT" has invalid length %d "
168 "(minimum is %d)",
169 OXS_HEADER_ARGS(*header), oxs_length(*header),
170 oxs_header_len(*header));
171 goto error;
172 }
173 ofpbuf_pull(b, oxs_header_len(*header));
174
175 return 0;
176
177 bad_len:
178 VLOG_DBG_RL(&rl, "encountered partial (%"PRIu32"-byte) OXS entry",
179 b->size);
180 error:
181 *header = 0;
182 return OFPERR_OFPBMC_BAD_LEN;
183 }
184
185 static enum ofperr
186 oxs_pull_entry__(struct ofpbuf *b, struct oxs_stats *stats,
187 uint8_t *oxs_field_set)
188 {
189 uint64_t header;
190 enum ofperr error = oxs_pull_header__(b, &header);
191 if (error) {
192 return error;
193 }
194
195 unsigned int payload_len = oxs_payload_len(header);
196 const void *payload = ofpbuf_try_pull(b, payload_len);
197 if (!payload) {
198 return OFPERR_OFPBMC_BAD_LEN;
199 }
200
201 switch (header) {
202 case OXS_OF_DURATION: {
203 uint64_t duration = ntohll(get_unaligned_be64(payload));
204 stats->duration_sec = duration >> 32;
205 stats->duration_nsec = duration;
206 }
207 break;
208 case OXS_OF_IDLE_TIME:
209 stats->idle_age = ntohll(get_unaligned_be64(payload)) >> 32;
210 break;
211 case OXS_OF_PACKET_COUNT:
212 stats->packet_count = ntohll(get_unaligned_be64(payload));
213 break;
214 case OXS_OF_BYTE_COUNT:
215 stats->byte_count = ntohll(get_unaligned_be64(payload));
216 break;
217 case OXS_OF_FLOW_COUNT:
218 stats->flow_count = ntohl(get_unaligned_be32(payload));
219 break;
220
221 default:
222 /* Unknown header. */
223 return 0;
224 }
225 if (oxs_field_set
226 && oxs_class(header) == OFPXSC_OPENFLOW_BASIC
227 && oxs_field(header) < CHAR_BIT * sizeof *oxs_field_set) {
228 *oxs_field_set |= 1 << oxs_field(header);
229 }
230 return error;
231 }
232
233 static enum ofperr
234 oxs_pull_raw(const uint8_t * p, unsigned int stat_len,
235 struct oxs_stats *stats, uint8_t *oxs_field_set)
236 {
237 struct ofpbuf b = ofpbuf_const_initializer(p, stat_len);
238 while (b.size) {
239 const uint8_t *pos = b.data;
240 enum ofperr error = oxs_pull_entry__(&b, stats, oxs_field_set);
241 if (error && error != OFPERR_OFPBMC_BAD_FIELD) {
242 VLOG_DBG_RL(&rl, "error parsing OXS at offset %"PRIdPTR" "
243 "within match (%s)",
244 pos - p, ofperr_to_string(error));
245 return error;
246 }
247 }
248 return 0;
249 }
250
251 /* Retrieve struct ofp_oxs_stat from 'b', followed by the flow entry
252 * statistics in OXS format.
253 *
254 * Returns error if message parsing fails, otherwise returns zero . */
255 enum ofperr
256 oxs_pull_stat(struct ofpbuf *b, struct oxs_stats *stats,
257 uint16_t *statlen, uint8_t *oxs_field_set)
258 {
259 memset(stats, 0xff, sizeof *stats);
260
261 struct ofp_oxs_stat *oxs = b->data;
262 if (b->size < sizeof *oxs) {
263 return OFPERR_OFPBMC_BAD_LEN;
264 }
265
266 uint16_t stat_len = ntohs(oxs->length);
267 if (stat_len < sizeof *oxs) {
268 return OFPERR_OFPBMC_BAD_LEN;
269 }
270
271 uint8_t *p = ofpbuf_try_pull(b, ROUND_UP(stat_len, 8));
272 if (!p) {
273 VLOG_DBG_RL(&rl, "oxs length %u, rounded up to a "
274 "multiple of 8, is longer than space in message (max "
275 "length %" PRIu32 ")", stat_len, b->size);
276 return OFPERR_OFPBMC_BAD_LEN;
277 }
278 *statlen = ROUND_UP(stat_len, 8);
279 return oxs_pull_raw(p + sizeof *oxs, stat_len - sizeof *oxs, stats,
280 oxs_field_set);
281 }
282
283 static void
284 oxs_put__(struct ofpbuf *b, uint64_t header,
285 const void *value, size_t value_size)
286 {
287 if (is_experimenter_oxs(header)) {
288 ovs_be64 be64 = htonll(header);
289 ofpbuf_put(b, &be64, sizeof be64);
290 } else {
291 ovs_be32 be32 = htonl(header >> 32);
292 ofpbuf_put(b, &be32, sizeof be32);
293 }
294
295 ovs_assert(oxs_payload_len(header) == value_size);
296 ofpbuf_put(b, value, value_size);
297 }
298
299 static void
300 oxs_put32(struct ofpbuf *b, uint64_t header, uint32_t value_)
301 {
302 ovs_be32 value = htonl(value_);
303 oxs_put__(b, header, &value, sizeof value);
304 }
305
306 static void
307 oxs_put64(struct ofpbuf *b, uint64_t header, uint64_t value_)
308 {
309 ovs_be64 value = htonll(value_);
310 oxs_put__(b, header, &value, sizeof value);
311 }
312
313 /* Appends to 'b' an struct ofp_oxs_stat followed by the flow entry statistics
314 * in OXS format , plus enough zero bytes to pad the data appended out to a
315 * multiple of 8.
316 *
317 * Specify the OpenFlow version in use as 'version'.
318 *
319 * This function can cause 'b''s data to be reallocated.
320 *
321 * Returns the number of bytes appended to 'b', excluding the padding.Never
322 * returns zero. */
323 void
324 oxs_put_stats(struct ofpbuf *b, const struct oxs_stats *stats)
325 {
326 size_t start = b->size;
327
328 /* Put empty header. */
329 struct ofp_oxs_stat *oxs;
330 ofpbuf_put_zeros(b, sizeof *oxs);
331
332 /* Put stats. */
333 if (stats->duration_sec != UINT32_MAX) {
334 oxs_put64(b, OXS_OF_DURATION,
335 (((uint64_t) stats->duration_sec << 32)
336 | stats->duration_nsec));
337 }
338 if (stats->idle_age != UINT32_MAX) {
339 oxs_put64(b, OXS_OF_IDLE_TIME, (uint64_t) stats->idle_age << 32);
340 }
341 if (stats->packet_count != UINT64_MAX) {
342 oxs_put64(b, OXS_OF_PACKET_COUNT, stats->packet_count);
343 }
344 if (stats->byte_count != UINT64_MAX) {
345 oxs_put64(b, OXS_OF_BYTE_COUNT, stats->byte_count);
346 }
347 if (stats->flow_count != UINT32_MAX) {
348 oxs_put32(b, OXS_OF_FLOW_COUNT, stats->flow_count);
349 }
350
351 /* Fill in size in header, then pad to multiple of 8 bytes. */
352 oxs = ofpbuf_at(b, start, sizeof *oxs);
353 oxs->length = htons(b->size - start);
354 ofpbuf_put_zeros(b, PAD_SIZE(b->size - start, 8));
355 }