]>
git.proxmox.com Git - mirror_ovs.git/blob - lib/ox-stat.c
2 * Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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"
26 VLOG_DEFINE_THIS_MODULE(ox_stat
);
28 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
33 * The header is 32 bits long. It looks like this:
36 * +----------------------------------+---------------+-+------------------+
37 * | oxs_class | oxs_field |r| oxs_length |
38 * +----------------------------------+---------------+-+------------------+
40 * where r stands for oxs_reserved. It is followed by oxs_length bytes of
41 * payload (the statistic's value).
43 * Internally, we represent a standard OXS header as a 64-bit integer with the
44 * above information in the most-significant bits.
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.
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.)
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.
71 OFPXSC_OPENFLOW_BASIC
= 0x8002, /* Basic stats class for OpenFlow */
72 OFPXSC_EXPERIMENTER
= 0xFFFF, /* Experimenter class */
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; }
82 is_experimenter_oxs(uint64_t header
)
84 return oxs_class(header
) == OFPXSC_EXPERIMENTER
;
87 /* The OXS header "length" field is somewhat tricky:
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.
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.
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
101 oxs_experimenter_len(uint64_t header
)
103 return is_experimenter_oxs(header
) ? 4 : 0;
106 /* Returns the number of bytes that follow the header for an OXS entry with the
109 oxs_payload_len(uint64_t header
)
111 return oxs_length(header
) - oxs_experimenter_len(header
);
114 /* Returns the number of bytes in the header for an OXS entry with the given
117 oxs_header_len(uint64_t header
)
119 return 4 + oxs_experimenter_len(header
);
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) | \
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), \
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)
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 */
146 BUILD_ASSERT_DECL(sizeof(struct ofp_oxs_stat
) == 4);
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
);
153 oxs_pull_header__(struct ofpbuf
*b
, uint64_t *header
)
159 *header
= ((uint64_t) ntohl(get_unaligned_be32(b
->data
))) << 32;
160 if (is_experimenter_oxs(*header
)) {
164 *header
= ntohll(get_unaligned_be64(b
->data
));
166 if (oxs_length(*header
) < oxs_experimenter_len(*header
)) {
167 VLOG_WARN_RL(&rl
, "OXS header "OXS_HEADER_FMT
" has invalid length %d "
169 OXS_HEADER_ARGS(*header
), oxs_length(*header
),
170 oxs_header_len(*header
));
173 ofpbuf_pull(b
, oxs_header_len(*header
));
178 VLOG_DBG_RL(&rl
, "encountered partial (%"PRIu32
"-byte) OXS entry",
182 return OFPERR_OFPBMC_BAD_LEN
;
186 oxs_pull_entry__(struct ofpbuf
*b
, struct oxs_stats
*stats
,
187 uint8_t *oxs_field_set
)
190 enum ofperr error
= oxs_pull_header__(b
, &header
);
195 unsigned int payload_len
= oxs_payload_len(header
);
196 const void *payload
= ofpbuf_try_pull(b
, payload_len
);
198 return OFPERR_OFPBMC_BAD_LEN
;
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
;
208 case OXS_OF_IDLE_TIME
:
209 stats
->idle_age
= ntohll(get_unaligned_be64(payload
)) >> 32;
211 case OXS_OF_PACKET_COUNT
:
212 stats
->packet_count
= ntohll(get_unaligned_be64(payload
));
214 case OXS_OF_BYTE_COUNT
:
215 stats
->byte_count
= ntohll(get_unaligned_be64(payload
));
217 case OXS_OF_FLOW_COUNT
:
218 stats
->flow_count
= ntohl(get_unaligned_be32(payload
));
222 /* Unknown header. */
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
);
234 oxs_pull_raw(const uint8_t * p
, unsigned int stat_len
,
235 struct oxs_stats
*stats
, uint8_t *oxs_field_set
)
237 struct ofpbuf b
= ofpbuf_const_initializer(p
, stat_len
);
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
" "
244 pos
- p
, ofperr_to_string(error
));
251 /* Retrieve struct ofp_oxs_stat from 'b', followed by the flow entry
252 * statistics in OXS format.
254 * Returns error if message parsing fails, otherwise returns zero . */
256 oxs_pull_stat(struct ofpbuf
*b
, struct oxs_stats
*stats
,
257 uint16_t *statlen
, uint8_t *oxs_field_set
)
259 memset(stats
, 0xff, sizeof *stats
);
261 struct ofp_oxs_stat
*oxs
= b
->data
;
262 if (b
->size
< sizeof *oxs
) {
263 return OFPERR_OFPBMC_BAD_LEN
;
266 uint16_t stat_len
= ntohs(oxs
->length
);
267 if (stat_len
< sizeof *oxs
) {
268 return OFPERR_OFPBMC_BAD_LEN
;
271 uint8_t *p
= ofpbuf_try_pull(b
, ROUND_UP(stat_len
, 8));
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
;
278 *statlen
= ROUND_UP(stat_len
, 8);
279 return oxs_pull_raw(p
+ sizeof *oxs
, stat_len
- sizeof *oxs
, stats
,
284 oxs_put__(struct ofpbuf
*b
, uint64_t header
,
285 const void *value
, size_t value_size
)
287 if (is_experimenter_oxs(header
)) {
288 ovs_be64 be64
= htonll(header
);
289 ofpbuf_put(b
, &be64
, sizeof be64
);
291 ovs_be32 be32
= htonl(header
>> 32);
292 ofpbuf_put(b
, &be32
, sizeof be32
);
295 ovs_assert(oxs_payload_len(header
) == value_size
);
296 ofpbuf_put(b
, value
, value_size
);
300 oxs_put32(struct ofpbuf
*b
, uint64_t header
, uint32_t value_
)
302 ovs_be32 value
= htonl(value_
);
303 oxs_put__(b
, header
, &value
, sizeof value
);
307 oxs_put64(struct ofpbuf
*b
, uint64_t header
, uint64_t value_
)
309 ovs_be64 value
= htonll(value_
);
310 oxs_put__(b
, header
, &value
, sizeof value
);
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
317 * Specify the OpenFlow version in use as 'version'.
319 * This function can cause 'b''s data to be reallocated.
321 * Returns the number of bytes appended to 'b', excluding the padding.Never
324 oxs_put_stats(struct ofpbuf
*b
, const struct oxs_stats
*stats
)
326 size_t start
= b
->size
;
328 /* Put empty header. */
329 struct ofp_oxs_stat
*oxs
;
330 ofpbuf_put_zeros(b
, sizeof *oxs
);
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
));
338 if (stats
->idle_age
!= UINT32_MAX
) {
339 oxs_put64(b
, OXS_OF_IDLE_TIME
, (uint64_t) stats
->idle_age
<< 32);
341 if (stats
->packet_count
!= UINT64_MAX
) {
342 oxs_put64(b
, OXS_OF_PACKET_COUNT
, stats
->packet_count
);
344 if (stats
->byte_count
!= UINT64_MAX
) {
345 oxs_put64(b
, OXS_OF_BYTE_COUNT
, stats
->byte_count
);
347 if (stats
->flow_count
!= UINT32_MAX
) {
348 oxs_put32(b
, OXS_OF_FLOW_COUNT
, stats
->flow_count
);
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));