]>
Commit | Line | Data |
---|---|---|
064af421 | 1 | /* |
04f48a68 | 2 | * Copyright (c) 2008-2017 Nicira, Inc. |
064af421 | 3 | * |
a14bc59f BP |
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: | |
064af421 | 7 | * |
a14bc59f BP |
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. | |
064af421 BP |
15 | */ |
16 | ||
17 | #include <config.h> | |
064af421 | 18 | |
0c24b0ba BP |
19 | #include "openvswitch/ofp-print.h" |
20 | ||
064af421 BP |
21 | #include <errno.h> |
22 | #include <inttypes.h> | |
7f3adc00 | 23 | #include <sys/types.h> |
064af421 BP |
24 | #include <netinet/in.h> |
25 | #include <sys/wait.h> | |
26 | #include <stdarg.h> | |
27 | #include <stdlib.h> | |
28 | #include <ctype.h> | |
29 | ||
daff3353 | 30 | #include "bundle.h" |
10a24935 | 31 | #include "byte-order.h" |
ab8e7f7d | 32 | #include "colors.h" |
064af421 | 33 | #include "compiler.h" |
25d436fb | 34 | #include "dp-packet.h" |
064af421 | 35 | #include "flow.h" |
75a75043 | 36 | #include "learn.h" |
53ddd40a | 37 | #include "multipath.h" |
9e1fd49b | 38 | #include "netdev.h" |
7fa91113 | 39 | #include "nx-match.h" |
25d436fb | 40 | #include "odp-util.h" |
064af421 | 41 | #include "openflow/nicira-ext.h" |
b598f214 | 42 | #include "openflow/openflow.h" |
d271907f BW |
43 | #include "openvswitch/dynamic-string.h" |
44 | #include "openvswitch/meta-flow.h" | |
b598f214 | 45 | #include "openvswitch/ofp-actions.h" |
0d71302e BP |
46 | #include "openvswitch/ofp-bundle.h" |
47 | #include "openvswitch/ofp-connection.h" | |
e03c096d | 48 | #include "openvswitch/ofp-errors.h" |
0d71302e BP |
49 | #include "openvswitch/ofp-group.h" |
50 | #include "openvswitch/ofp-ipfix.h" | |
51 | #include "openvswitch/ofp-match.h" | |
52 | #include "openvswitch/ofp-meter.h" | |
53 | #include "openvswitch/ofp-monitor.h" | |
d271907f | 54 | #include "openvswitch/ofp-msgs.h" |
0d71302e BP |
55 | #include "openvswitch/ofp-port.h" |
56 | #include "openvswitch/ofp-queue.h" | |
57 | #include "openvswitch/ofp-switch.h" | |
58 | #include "openvswitch/ofp-table.h" | |
d271907f BW |
59 | #include "openvswitch/ofp-util.h" |
60 | #include "openvswitch/ofpbuf.h" | |
61 | #include "openvswitch/type-props.h" | |
064af421 | 62 | #include "packets.h" |
c4617b3c | 63 | #include "unaligned.h" |
064af421 | 64 | #include "util.h" |
d5dc60f0 | 65 | #include "uuid.h" |
064af421 | 66 | |
d2805da2 | 67 | static void ofp_print_queue_name(struct ds *string, uint32_t port); |
90bf1e07 | 68 | static void ofp_print_error(struct ds *, enum ofperr); |
064af421 BP |
69 | |
70 | /* Returns a string that represents the contents of the Ethernet frame in the | |
897a8e07 | 71 | * 'len' bytes starting at 'data'. The caller must free the returned string.*/ |
064af421 | 72 | char * |
2482b0b0 | 73 | ofp_packet_to_string(const void *data, size_t len, ovs_be32 packet_type) |
064af421 BP |
74 | { |
75 | struct ds ds = DS_EMPTY_INITIALIZER; | |
cf62fa4c | 76 | struct dp_packet buf; |
897a8e07 | 77 | struct flow flow; |
5a51b2cd | 78 | size_t l4_size; |
064af421 | 79 | |
cf62fa4c | 80 | dp_packet_use_const(&buf, data, len); |
2482b0b0 | 81 | buf.packet_type = packet_type; |
cf62fa4c | 82 | flow_extract(&buf, &flow); |
50f96b10 | 83 | flow_format(&ds, &flow, NULL); |
e50abca5 | 84 | |
cf62fa4c | 85 | l4_size = dp_packet_l4_size(&buf); |
5a51b2cd JR |
86 | |
87 | if (flow.nw_proto == IPPROTO_TCP && l4_size >= TCP_HEADER_LEN) { | |
cf62fa4c | 88 | struct tcp_header *th = dp_packet_l4(&buf); |
5a51b2cd JR |
89 | ds_put_format(&ds, " tcp_csum:%"PRIx16, ntohs(th->tcp_csum)); |
90 | } else if (flow.nw_proto == IPPROTO_UDP && l4_size >= UDP_HEADER_LEN) { | |
cf62fa4c | 91 | struct udp_header *uh = dp_packet_l4(&buf); |
5a51b2cd JR |
92 | ds_put_format(&ds, " udp_csum:%"PRIx16, ntohs(uh->udp_csum)); |
93 | } else if (flow.nw_proto == IPPROTO_SCTP && l4_size >= SCTP_HEADER_LEN) { | |
cf62fa4c | 94 | struct sctp_header *sh = dp_packet_l4(&buf); |
5fa008d4 BP |
95 | ds_put_format(&ds, " sctp_csum:%"PRIx32, |
96 | ntohl(get_16aligned_be32(&sh->sctp_csum))); | |
e60e935b | 97 | } else if (flow.nw_proto == IPPROTO_ICMP && l4_size >= ICMP_HEADER_LEN) { |
cf62fa4c | 98 | struct icmp_header *icmph = dp_packet_l4(&buf); |
e60e935b SRCSA |
99 | ds_put_format(&ds, " icmp_csum:%"PRIx16, |
100 | ntohs(icmph->icmp_csum)); | |
101 | } else if (flow.nw_proto == IPPROTO_ICMPV6 && l4_size >= ICMP6_HEADER_LEN) { | |
cf62fa4c | 102 | struct icmp6_header *icmp6h = dp_packet_l4(&buf); |
e60e935b SRCSA |
103 | ds_put_format(&ds, " icmp6_csum:%"PRIx16, |
104 | ntohs(icmp6h->icmp6_cksum)); | |
e50abca5 EJ |
105 | } |
106 | ||
897a8e07 | 107 | ds_put_char(&ds, '\n'); |
064af421 | 108 | |
064af421 BP |
109 | return ds_cstr(&ds); |
110 | } | |
111 | ||
2482b0b0 JS |
112 | char * |
113 | ofp_dp_packet_to_string(const struct dp_packet *packet) | |
114 | { | |
115 | return ofp_packet_to_string(dp_packet_data(packet), | |
116 | dp_packet_size(packet), | |
117 | packet->packet_type); | |
118 | } | |
119 | ||
2d071a32 | 120 | static enum ofperr |
65120a8a | 121 | ofp_print_packet_in(struct ds *string, const struct ofp_header *oh, |
4bc938cc BP |
122 | const struct ofputil_port_map *port_map, |
123 | const struct ofputil_table_map *table_map, int verbosity) | |
064af421 | 124 | { |
77ab5fd2 | 125 | struct ofputil_packet_in_private pin; |
9bfe9334 BP |
126 | uint32_t buffer_id; |
127 | size_t total_len; | |
dfc77282 BP |
128 | enum ofperr error = ofputil_decode_packet_in_private(oh, true, NULL, NULL, |
129 | &pin, &total_len, | |
130 | &buffer_id); | |
131 | if (!error) { | |
132 | ofputil_packet_in_private_format(string, &pin, total_len, buffer_id, | |
133 | port_map, table_map, verbosity); | |
134 | ofputil_packet_in_private_destroy(&pin); | |
b4ccee75 | 135 | } |
dfc77282 | 136 | return error; |
064af421 BP |
137 | } |
138 | ||
2d071a32 | 139 | static enum ofperr |
982697a4 | 140 | ofp_print_packet_out(struct ds *string, const struct ofp_header *oh, |
4bc938cc BP |
141 | const struct ofputil_port_map *port_map, |
142 | const struct ofputil_table_map *table_map, int verbosity) | |
064af421 | 143 | { |
c6a93eb7 | 144 | struct ofputil_packet_out po; |
f25d0cf3 | 145 | struct ofpbuf ofpacts; |
c6a93eb7 | 146 | enum ofperr error; |
064af421 | 147 | |
f25d0cf3 | 148 | ofpbuf_init(&ofpacts, 64); |
89d7927b | 149 | error = ofputil_decode_packet_out(&po, oh, NULL, &ofpacts); |
dfc77282 BP |
150 | if (!error) { |
151 | ofputil_packet_out_format(string, &po, port_map, table_map, verbosity); | |
064af421 | 152 | } |
f25d0cf3 | 153 | ofpbuf_uninit(&ofpacts); |
dfc77282 | 154 | return error; |
064af421 BP |
155 | } |
156 | ||
dfc77282 | 157 | void |
0ab14c8e | 158 | ofp_print_bit_names(struct ds *string, uint32_t bits, |
e8fa940e BP |
159 | const char *(*bit_to_name)(uint32_t bit), |
160 | char separator) | |
064af421 | 161 | { |
0ab14c8e | 162 | int n = 0; |
9e1fd49b | 163 | int i; |
0ab14c8e BP |
164 | |
165 | if (!bits) { | |
166 | ds_put_cstr(string, "0"); | |
064af421 BP |
167 | return; |
168 | } | |
0ab14c8e | 169 | |
9e1fd49b BP |
170 | for (i = 0; i < 32; i++) { |
171 | uint32_t bit = UINT32_C(1) << i; | |
172 | ||
173 | if (bits & bit) { | |
174 | const char *name = bit_to_name(bit); | |
175 | if (name) { | |
176 | if (n++) { | |
e8fa940e | 177 | ds_put_char(string, separator); |
9e1fd49b BP |
178 | } |
179 | ds_put_cstr(string, name); | |
180 | bits &= ~bit; | |
0ab14c8e | 181 | } |
0ab14c8e | 182 | } |
064af421 | 183 | } |
0ab14c8e BP |
184 | |
185 | if (bits) { | |
f5cd6874 | 186 | if (n) { |
e8fa940e | 187 | ds_put_char(string, separator); |
0ab14c8e BP |
188 | } |
189 | ds_put_format(string, "0x%"PRIx32, bits); | |
064af421 | 190 | } |
0ab14c8e BP |
191 | } |
192 | ||
2d071a32 | 193 | static enum ofperr |
982697a4 | 194 | ofp_print_switch_features(struct ds *string, const struct ofp_header *oh) |
064af421 | 195 | { |
9e1fd49b | 196 | struct ofputil_switch_features features; |
0a2869d5 BP |
197 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
198 | enum ofperr error = ofputil_pull_switch_features(&b, &features); | |
dfc77282 BP |
199 | if (!error) { |
200 | ofputil_switch_features_format(string, &features); | |
201 | error = ofputil_phy_ports_format(string, oh->version, &b); | |
f0fd1a17 | 202 | } |
dfc77282 | 203 | return error; |
ad99e2ed BP |
204 | } |
205 | ||
2d071a32 | 206 | static enum ofperr |
ad99e2ed BP |
207 | ofp_print_set_config(struct ds *string, const struct ofp_header *oh) |
208 | { | |
209 | struct ofputil_switch_config config; | |
210 | enum ofperr error; | |
211 | ||
212 | error = ofputil_decode_set_config(oh, &config); | |
213 | if (error) { | |
2d071a32 | 214 | return error; |
064af421 | 215 | } |
dfc77282 | 216 | ofputil_switch_config_format(string, &config); |
2d071a32 | 217 | return 0; |
ad99e2ed | 218 | } |
064af421 | 219 | |
2d071a32 | 220 | static enum ofperr |
ad99e2ed BP |
221 | ofp_print_get_config_reply(struct ds *string, const struct ofp_header *oh) |
222 | { | |
223 | struct ofputil_switch_config config; | |
224 | ofputil_decode_get_config_reply(oh, &config); | |
dfc77282 | 225 | ofputil_switch_config_format(string, &config); |
2d071a32 | 226 | return 0; |
064af421 BP |
227 | } |
228 | ||
2d071a32 | 229 | static enum ofperr |
dfc77282 BP |
230 | ofp_print_table_features_reply(struct ds *s, const struct ofp_header *oh, |
231 | const struct ofputil_table_map *table_map) | |
064af421 | 232 | { |
dfc77282 | 233 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
f904747b | 234 | |
dfc77282 BP |
235 | struct ofputil_table_features prev; |
236 | for (int i = 0; ; i++) { | |
237 | struct ofputil_table_features tf; | |
238 | int retval; | |
7fa91113 | 239 | |
dfc77282 BP |
240 | retval = ofputil_decode_table_features(&b, &tf, true); |
241 | if (retval) { | |
242 | return retval != EOF ? retval : 0; | |
243 | } | |
0fb88c18 | 244 | |
dfc77282 BP |
245 | ds_put_char(s, '\n'); |
246 | ofputil_table_features_format(s, &tf, i ? &prev : NULL, NULL, NULL, | |
247 | table_map); | |
248 | prev = tf; | |
7fa91113 | 249 | } |
064af421 BP |
250 | } |
251 | ||
dfc77282 | 252 | void |
09862ec6 BP |
253 | ofp_print_duration(struct ds *string, unsigned int sec, unsigned int nsec) |
254 | { | |
255 | ds_put_format(string, "%u", sec); | |
b1634591 BP |
256 | |
257 | /* If there are no fractional seconds, don't print any decimals. | |
258 | * | |
259 | * If the fractional seconds can be expressed exactly as milliseconds, | |
260 | * print 3 decimals. Open vSwitch provides millisecond precision for most | |
261 | * time measurements, so printing 3 decimals every time makes it easier to | |
dfc77282 BP |
262 | * spot real changes in flow dumps that refresh themselves quickly. |
263 | * | |
264 | * If the fractional seconds are more precise than milliseconds, print the | |
265 | * number of decimals needed to express them exactly. | |
266 | */ | |
267 | if (nsec > 0) { | |
268 | unsigned int msec = nsec / 1000000; | |
269 | if (msec * 1000000 == nsec) { | |
270 | ds_put_format(string, ".%03u", msec); | |
271 | } else { | |
272 | ds_put_format(string, ".%09u", nsec); | |
273 | while (string->string[string->length - 1] == '0') { | |
274 | string->length--; | |
275 | } | |
276 | } | |
82c22d34 | 277 | } |
dfc77282 | 278 | ds_put_char(string, 's'); |
82c22d34 BP |
279 | } |
280 | ||
dfc77282 BP |
281 | static enum ofperr |
282 | ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh, | |
283 | const struct ofputil_port_map *port_map, | |
284 | const struct ofputil_table_map *table_map) | |
82c22d34 | 285 | { |
dfc77282 BP |
286 | struct ofputil_flow_removed fr; |
287 | enum ofperr error = ofputil_decode_flow_removed(&fr, oh); | |
288 | if (!error) { | |
289 | ofputil_flow_removed_format(string, &fr, port_map, table_map); | |
918f2b82 | 290 | } |
dfc77282 | 291 | return error; |
918f2b82 AZ |
292 | } |
293 | ||
dfc77282 BP |
294 | static enum ofperr |
295 | ofp_print_port_mod(struct ds *string, const struct ofp_header *oh, | |
296 | const struct ofputil_port_map *port_map) | |
de7d3c07 | 297 | { |
dfc77282 BP |
298 | struct ofputil_port_mod pm; |
299 | enum ofperr error = ofputil_decode_port_mod(oh, &pm, true); | |
300 | if (!error) { | |
301 | ofputil_port_mod_format(string, &pm, port_map); | |
de7d3c07 | 302 | } |
dfc77282 | 303 | return error; |
de7d3c07 SJ |
304 | } |
305 | ||
2d071a32 | 306 | static enum ofperr |
4bc938cc BP |
307 | ofp_print_table_mod(struct ds *string, const struct ofp_header *oh, |
308 | const struct ofputil_table_map *table_map) | |
918f2b82 | 309 | { |
dfc77282 BP |
310 | struct ofputil_table_mod tm; |
311 | enum ofperr error = ofputil_decode_table_mod(oh, &tm); | |
312 | if (!error) { | |
313 | ofputil_table_mod_format(string, &tm, table_map); | |
bab86012 | 314 | } |
dfc77282 | 315 | return error; |
03c72922 BP |
316 | } |
317 | ||
2d071a32 | 318 | static enum ofperr |
4bc938cc BP |
319 | ofp_print_table_status_message(struct ds *string, const struct ofp_header *oh, |
320 | const struct ofputil_table_map *table_map) | |
6c6eedc5 SJ |
321 | { |
322 | struct ofputil_table_status ts; | |
323 | enum ofperr error; | |
324 | ||
325 | error = ofputil_decode_table_status(oh, &ts); | |
326 | if (error) { | |
2d071a32 | 327 | return error; |
6c6eedc5 SJ |
328 | } |
329 | ||
330 | if (ts.reason == OFPTR_VACANCY_DOWN) { | |
331 | ds_put_format(string, " reason=VACANCY_DOWN"); | |
332 | } else if (ts.reason == OFPTR_VACANCY_UP) { | |
333 | ds_put_format(string, " reason=VACANCY_UP"); | |
334 | } | |
335 | ||
336 | ds_put_format(string, "\ntable_desc:-"); | |
dfc77282 | 337 | ofputil_table_desc_format(string, &ts.desc, table_map); |
2d071a32 BP |
338 | |
339 | return 0; | |
6c6eedc5 SJ |
340 | } |
341 | ||
2d071a32 | 342 | static enum ofperr |
e8f9a7bb | 343 | ofp_print_queue_get_config_request(struct ds *string, |
50f96b10 BP |
344 | const struct ofp_header *oh, |
345 | const struct ofputil_port_map *port_map) | |
e8f9a7bb VG |
346 | { |
347 | enum ofperr error; | |
348 | ofp_port_t port; | |
e016fb63 | 349 | uint32_t queue; |
e8f9a7bb | 350 | |
e016fb63 | 351 | error = ofputil_decode_queue_get_config_request(oh, &port, &queue); |
e8f9a7bb | 352 | if (error) { |
2d071a32 | 353 | return error; |
e8f9a7bb VG |
354 | } |
355 | ||
356 | ds_put_cstr(string, " port="); | |
50f96b10 | 357 | ofputil_format_port(port, port_map, string); |
e016fb63 BP |
358 | |
359 | if (queue != OFPQ_ALL) { | |
360 | ds_put_cstr(string, " queue="); | |
361 | ofp_print_queue_name(string, queue); | |
362 | } | |
2d071a32 BP |
363 | |
364 | return 0; | |
e8f9a7bb VG |
365 | } |
366 | ||
367 | static void | |
368 | print_queue_rate(struct ds *string, const char *name, unsigned int rate) | |
369 | { | |
370 | if (rate <= 1000) { | |
371 | ds_put_format(string, " %s:%u.%u%%", name, rate / 10, rate % 10); | |
372 | } else if (rate < UINT16_MAX) { | |
373 | ds_put_format(string, " %s:(disabled)", name); | |
374 | } | |
375 | } | |
376 | ||
a28239c0 BP |
377 | /* qsort comparison function. */ |
378 | static int | |
379 | compare_queues(const void *a_, const void *b_) | |
380 | { | |
381 | const struct ofputil_queue_config *a = a_; | |
382 | const struct ofputil_queue_config *b = b_; | |
383 | ||
384 | uint16_t ap = ofp_to_u16(a->port); | |
385 | uint16_t bp = ofp_to_u16(b->port); | |
386 | if (ap != bp) { | |
387 | return ap < bp ? -1 : 1; | |
388 | } | |
389 | ||
390 | uint32_t aq = a->queue; | |
391 | uint32_t bq = b->queue; | |
392 | return aq < bq ? -1 : aq > bq; | |
393 | } | |
394 | ||
2d071a32 | 395 | static enum ofperr |
e8f9a7bb | 396 | ofp_print_queue_get_config_reply(struct ds *string, |
50f96b10 BP |
397 | const struct ofp_header *oh, |
398 | const struct ofputil_port_map *port_map) | |
e8f9a7bb | 399 | { |
0a2869d5 | 400 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
e8f9a7bb | 401 | |
a28239c0 BP |
402 | struct ofputil_queue_config *queues = NULL; |
403 | size_t allocated_queues = 0; | |
404 | size_t n = 0; | |
e8f9a7bb | 405 | |
a28239c0 BP |
406 | int retval = 0; |
407 | for (;;) { | |
408 | if (n >= allocated_queues) { | |
409 | queues = x2nrealloc(queues, &allocated_queues, sizeof *queues); | |
410 | } | |
411 | retval = ofputil_pull_queue_get_config_reply(&b, &queues[n]); | |
e8f9a7bb | 412 | if (retval) { |
e8f9a7bb VG |
413 | break; |
414 | } | |
a28239c0 BP |
415 | n++; |
416 | } | |
e8f9a7bb | 417 | |
a28239c0 BP |
418 | qsort(queues, n, sizeof *queues, compare_queues); |
419 | ||
420 | ds_put_char(string, ' '); | |
421 | ||
422 | ofp_port_t port = 0; | |
423 | for (const struct ofputil_queue_config *q = queues; q < &queues[n]; q++) { | |
424 | if (q->port != port) { | |
425 | port = q->port; | |
e016fb63 BP |
426 | |
427 | ds_put_cstr(string, "port="); | |
50f96b10 | 428 | ofputil_format_port(port, port_map, string); |
e016fb63 BP |
429 | ds_put_char(string, '\n'); |
430 | } | |
431 | ||
a28239c0 BP |
432 | ds_put_format(string, "queue %"PRIu32":", q->queue); |
433 | print_queue_rate(string, "min_rate", q->min_rate); | |
434 | print_queue_rate(string, "max_rate", q->max_rate); | |
e8f9a7bb VG |
435 | ds_put_char(string, '\n'); |
436 | } | |
a28239c0 | 437 | |
a28239c0 | 438 | ds_chomp(string, ' '); |
18dc96b0 | 439 | free(queues); |
2d071a32 BP |
440 | |
441 | return retval != EOF ? retval : 0; | |
e8f9a7bb VG |
442 | } |
443 | ||
638a19b0 JR |
444 | static void |
445 | ofp_print_meter_flags(struct ds *s, uint16_t flags) | |
446 | { | |
447 | if (flags & OFPMF13_KBPS) { | |
448 | ds_put_cstr(s, "kbps "); | |
449 | } | |
450 | if (flags & OFPMF13_PKTPS) { | |
451 | ds_put_cstr(s, "pktps "); | |
452 | } | |
453 | if (flags & OFPMF13_BURST) { | |
454 | ds_put_cstr(s, "burst "); | |
455 | } | |
456 | if (flags & OFPMF13_STATS) { | |
457 | ds_put_cstr(s, "stats "); | |
458 | } | |
459 | ||
460 | flags &= ~(OFPMF13_KBPS | OFPMF13_PKTPS | OFPMF13_BURST | OFPMF13_STATS); | |
461 | if (flags) { | |
462 | ds_put_format(s, "flags:0x%"PRIx16" ", flags); | |
463 | } | |
464 | } | |
465 | ||
466 | static void | |
467 | ofp_print_meter_band(struct ds *s, uint16_t flags, | |
468 | const struct ofputil_meter_band *mb) | |
469 | { | |
470 | ds_put_cstr(s, "\ntype="); | |
471 | switch (mb->type) { | |
472 | case OFPMBT13_DROP: | |
473 | ds_put_cstr(s, "drop"); | |
474 | break; | |
475 | case OFPMBT13_DSCP_REMARK: | |
476 | ds_put_cstr(s, "dscp_remark"); | |
477 | break; | |
478 | default: | |
479 | ds_put_format(s, "%u", mb->type); | |
480 | } | |
481 | ||
482 | ds_put_format(s, " rate=%"PRIu32, mb->rate); | |
483 | ||
484 | if (flags & OFPMF13_BURST) { | |
485 | ds_put_format(s, " burst_size=%"PRIu32, mb->burst_size); | |
486 | } | |
487 | if (mb->type == OFPMBT13_DSCP_REMARK) { | |
488 | ds_put_format(s, " prec_level=%"PRIu8, mb->prec_level); | |
489 | } | |
490 | } | |
491 | ||
9e638f22 AZ |
492 | static void |
493 | ofp_print_meter_id(struct ds *s, uint32_t meter_id, char seperator) | |
494 | { | |
495 | if (meter_id <= OFPM13_MAX) { | |
496 | ds_put_format(s, "meter%c%"PRIu32, seperator, meter_id); | |
497 | } else { | |
498 | const char *name; | |
499 | switch (meter_id) { | |
500 | case OFPM13_SLOWPATH: | |
501 | name = "slowpath"; | |
502 | break; | |
503 | case OFPM13_CONTROLLER: | |
504 | name = "controller"; | |
505 | break; | |
506 | case OFPM13_ALL: | |
507 | name = "all"; | |
508 | break; | |
509 | default: | |
510 | name = "unknown"; | |
511 | } | |
512 | ds_put_format(s, "meter%c%s", seperator, name); | |
513 | } | |
514 | } | |
515 | ||
638a19b0 JR |
516 | static void |
517 | ofp_print_meter_stats(struct ds *s, const struct ofputil_meter_stats *ms) | |
518 | { | |
519 | uint16_t i; | |
520 | ||
9e638f22 AZ |
521 | ofp_print_meter_id(s, ms->meter_id, ':'); |
522 | ds_put_char(s, ' '); | |
638a19b0 JR |
523 | ds_put_format(s, "flow_count:%"PRIu32" ", ms->flow_count); |
524 | ds_put_format(s, "packet_in_count:%"PRIu64" ", ms->packet_in_count); | |
525 | ds_put_format(s, "byte_in_count:%"PRIu64" ", ms->byte_in_count); | |
526 | ds_put_cstr(s, "duration:"); | |
527 | ofp_print_duration(s, ms->duration_sec, ms->duration_nsec); | |
528 | ds_put_char(s, ' '); | |
529 | ||
530 | ds_put_cstr(s, "bands:\n"); | |
531 | for (i = 0; i < ms->n_bands; ++i) { | |
532 | ds_put_format(s, "%d: ", i); | |
533 | ds_put_format(s, "packet_count:%"PRIu64" ", ms->bands[i].packet_count); | |
534 | ds_put_format(s, "byte_count:%"PRIu64"\n", ms->bands[i].byte_count); | |
535 | } | |
536 | } | |
537 | ||
538 | static void | |
539 | ofp_print_meter_config(struct ds *s, const struct ofputil_meter_config *mc) | |
540 | { | |
541 | uint16_t i; | |
542 | ||
9e638f22 AZ |
543 | ofp_print_meter_id(s, mc->meter_id, '='); |
544 | ds_put_char(s, ' '); | |
638a19b0 JR |
545 | |
546 | ofp_print_meter_flags(s, mc->flags); | |
547 | ||
548 | ds_put_cstr(s, "bands="); | |
549 | for (i = 0; i < mc->n_bands; ++i) { | |
550 | ofp_print_meter_band(s, mc->flags, &mc->bands[i]); | |
551 | } | |
552 | ds_put_char(s, '\n'); | |
553 | } | |
554 | ||
555 | static void | |
3c35db62 | 556 | ofp_print_meter_mod__(struct ds *s, const struct ofputil_meter_mod *mm) |
638a19b0 | 557 | { |
3c35db62 | 558 | switch (mm->command) { |
638a19b0 JR |
559 | case OFPMC13_ADD: |
560 | ds_put_cstr(s, " ADD "); | |
561 | break; | |
562 | case OFPMC13_MODIFY: | |
563 | ds_put_cstr(s, " MOD "); | |
564 | break; | |
565 | case OFPMC13_DELETE: | |
566 | ds_put_cstr(s, " DEL "); | |
567 | break; | |
568 | default: | |
3c35db62 | 569 | ds_put_format(s, " cmd:%d ", mm->command); |
638a19b0 JR |
570 | } |
571 | ||
3c35db62 NR |
572 | ofp_print_meter_config(s, &mm->meter); |
573 | } | |
574 | ||
2d071a32 | 575 | static enum ofperr |
3c35db62 NR |
576 | ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh) |
577 | { | |
578 | struct ofputil_meter_mod mm; | |
579 | struct ofpbuf bands; | |
580 | enum ofperr error; | |
581 | ||
582 | ofpbuf_init(&bands, 64); | |
583 | error = ofputil_decode_meter_mod(oh, &mm, &bands); | |
2d071a32 | 584 | if (!error) { |
3c35db62 NR |
585 | ofp_print_meter_mod__(s, &mm); |
586 | } | |
638a19b0 | 587 | ofpbuf_uninit(&bands); |
2d071a32 BP |
588 | |
589 | return error; | |
638a19b0 JR |
590 | } |
591 | ||
2d071a32 | 592 | static enum ofperr |
638a19b0 JR |
593 | ofp_print_meter_stats_request(struct ds *s, const struct ofp_header *oh) |
594 | { | |
595 | uint32_t meter_id; | |
596 | ||
597 | ofputil_decode_meter_request(oh, &meter_id); | |
9e638f22 | 598 | ds_put_char(s, ' '); |
638a19b0 | 599 | |
9e638f22 | 600 | ofp_print_meter_id(s, meter_id, '='); |
2d071a32 BP |
601 | |
602 | return 0; | |
638a19b0 JR |
603 | } |
604 | ||
605 | static const char * | |
606 | ofputil_meter_capabilities_to_name(uint32_t bit) | |
607 | { | |
608 | enum ofp13_meter_flags flag = bit; | |
609 | ||
610 | switch (flag) { | |
611 | case OFPMF13_KBPS: return "kbps"; | |
612 | case OFPMF13_PKTPS: return "pktps"; | |
613 | case OFPMF13_BURST: return "burst"; | |
614 | case OFPMF13_STATS: return "stats"; | |
615 | } | |
616 | ||
617 | return NULL; | |
618 | } | |
619 | ||
620 | static const char * | |
621 | ofputil_meter_band_types_to_name(uint32_t bit) | |
622 | { | |
638a19b0 | 623 | switch (bit) { |
6e055a6c BP |
624 | case 1 << OFPMBT13_DROP: return "drop"; |
625 | case 1 << OFPMBT13_DSCP_REMARK: return "dscp_remark"; | |
638a19b0 JR |
626 | } |
627 | ||
628 | return NULL; | |
629 | } | |
630 | ||
2d071a32 | 631 | static enum ofperr |
638a19b0 JR |
632 | ofp_print_meter_features_reply(struct ds *s, const struct ofp_header *oh) |
633 | { | |
634 | struct ofputil_meter_features mf; | |
635 | ||
636 | ofputil_decode_meter_features(oh, &mf); | |
637 | ||
638 | ds_put_format(s, "\nmax_meter:%"PRIu32, mf.max_meters); | |
639 | ds_put_format(s, " max_bands:%"PRIu8, mf.max_bands); | |
640 | ds_put_format(s, " max_color:%"PRIu8"\n", mf.max_color); | |
641 | ||
642 | ds_put_cstr(s, "band_types: "); | |
643 | ofp_print_bit_names(s, mf.band_types, | |
644 | ofputil_meter_band_types_to_name, ' '); | |
645 | ds_put_char(s, '\n'); | |
646 | ||
647 | ds_put_cstr(s, "capabilities: "); | |
648 | ofp_print_bit_names(s, mf.capabilities, | |
649 | ofputil_meter_capabilities_to_name, ' '); | |
650 | ds_put_char(s, '\n'); | |
2d071a32 BP |
651 | |
652 | return 0; | |
638a19b0 JR |
653 | } |
654 | ||
2d071a32 | 655 | static enum ofperr |
638a19b0 JR |
656 | ofp_print_meter_config_reply(struct ds *s, const struct ofp_header *oh) |
657 | { | |
0a2869d5 | 658 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
638a19b0 | 659 | struct ofpbuf bands; |
2d071a32 | 660 | int retval; |
638a19b0 | 661 | |
638a19b0 JR |
662 | ofpbuf_init(&bands, 64); |
663 | for (;;) { | |
664 | struct ofputil_meter_config mc; | |
638a19b0 JR |
665 | |
666 | retval = ofputil_decode_meter_config(&b, &mc, &bands); | |
667 | if (retval) { | |
638a19b0 JR |
668 | break; |
669 | } | |
670 | ds_put_char(s, '\n'); | |
671 | ofp_print_meter_config(s, &mc); | |
672 | } | |
673 | ofpbuf_uninit(&bands); | |
2d071a32 BP |
674 | |
675 | return retval != EOF ? retval : 0; | |
638a19b0 JR |
676 | } |
677 | ||
2d071a32 | 678 | static enum ofperr |
638a19b0 JR |
679 | ofp_print_meter_stats_reply(struct ds *s, const struct ofp_header *oh) |
680 | { | |
0a2869d5 | 681 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
638a19b0 | 682 | struct ofpbuf bands; |
2d071a32 | 683 | int retval; |
638a19b0 | 684 | |
638a19b0 JR |
685 | ofpbuf_init(&bands, 64); |
686 | for (;;) { | |
687 | struct ofputil_meter_stats ms; | |
638a19b0 JR |
688 | |
689 | retval = ofputil_decode_meter_stats(&b, &ms, &bands); | |
690 | if (retval) { | |
638a19b0 JR |
691 | break; |
692 | } | |
693 | ds_put_char(s, '\n'); | |
694 | ofp_print_meter_stats(s, &ms); | |
695 | } | |
696 | ofpbuf_uninit(&bands); | |
2d071a32 BP |
697 | |
698 | return retval != EOF ? retval : 0; | |
638a19b0 JR |
699 | } |
700 | ||
7fa91113 | 701 | static void |
90bf1e07 | 702 | ofp_print_error(struct ds *string, enum ofperr error) |
7fa91113 | 703 | { |
90bf1e07 | 704 | ds_put_format(string, "***decode error: %s***\n", ofperr_get_name(error)); |
f74be05a JP |
705 | } |
706 | ||
2d071a32 | 707 | static enum ofperr |
de6c85b0 SH |
708 | ofp_print_hello(struct ds *string, const struct ofp_header *oh) |
709 | { | |
dfc77282 | 710 | ofputil_hello_format(string, oh); |
2d071a32 | 711 | return 0; |
de6c85b0 SH |
712 | } |
713 | ||
2d071a32 | 714 | static enum ofperr |
50f96b10 | 715 | ofp_print_error_msg(struct ds *string, const struct ofp_header *oh, |
4bc938cc BP |
716 | const struct ofputil_port_map *port_map, |
717 | const struct ofputil_table_map *table_map) | |
064af421 | 718 | { |
982697a4 | 719 | struct ofpbuf payload; |
dfc77282 | 720 | enum ofperr error = ofperr_decode_msg(oh, &payload); |
90bf1e07 | 721 | if (!error) { |
2d071a32 | 722 | return OFPERR_OFPBRC_BAD_LEN; |
f74be05a | 723 | } |
dfc77282 | 724 | ofperr_msg_format(string, error, &payload, port_map, table_map); |
dea241f1 | 725 | ofpbuf_uninit(&payload); |
2d071a32 BP |
726 | |
727 | return 0; | |
064af421 BP |
728 | } |
729 | ||
2d071a32 | 730 | static enum ofperr |
982697a4 | 731 | ofp_print_port_status(struct ds *string, const struct ofp_header *oh) |
064af421 | 732 | { |
9e1fd49b | 733 | struct ofputil_port_status ps; |
dfc77282 BP |
734 | enum ofperr error = ofputil_decode_port_status(oh, &ps); |
735 | if (!error) { | |
736 | ofputil_port_status_format(string, &ps); | |
064af421 | 737 | } |
dfc77282 | 738 | return error; |
064af421 BP |
739 | } |
740 | ||
2d071a32 | 741 | static enum ofperr |
982697a4 | 742 | ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_header *oh) |
064af421 | 743 | { |
982697a4 BP |
744 | const struct ofp_desc_stats *ods = ofpmsg_body(oh); |
745 | ||
fbd76b2e | 746 | ds_put_char(string, '\n'); |
d295e8e9 | 747 | ds_put_format(string, "Manufacturer: %.*s\n", |
dd70b475 JP |
748 | (int) sizeof ods->mfr_desc, ods->mfr_desc); |
749 | ds_put_format(string, "Hardware: %.*s\n", | |
750 | (int) sizeof ods->hw_desc, ods->hw_desc); | |
751 | ds_put_format(string, "Software: %.*s\n", | |
752 | (int) sizeof ods->sw_desc, ods->sw_desc); | |
753 | ds_put_format(string, "Serial Num: %.*s\n", | |
754 | (int) sizeof ods->serial_num, ods->serial_num); | |
755 | ds_put_format(string, "DP Description: %.*s\n", | |
756 | (int) sizeof ods->dp_desc, ods->dp_desc); | |
2d071a32 BP |
757 | |
758 | return 0; | |
064af421 BP |
759 | } |
760 | ||
2d071a32 | 761 | static enum ofperr |
50f96b10 | 762 | ofp_print_flow_stats_request(struct ds *string, const struct ofp_header *oh, |
4bc938cc BP |
763 | const struct ofputil_port_map *port_map, |
764 | const struct ofputil_table_map *table_map) | |
064af421 | 765 | { |
81d1ea94 | 766 | struct ofputil_flow_stats_request fsr; |
dfc77282 BP |
767 | enum ofperr error = ofputil_decode_flow_stats_request(&fsr, oh, NULL, |
768 | NULL); | |
769 | if (!error) { | |
770 | ofputil_flow_stats_request_format(string, &fsr, port_map, table_map); | |
bdcc5925 | 771 | } |
dfc77282 | 772 | return error; |
bdcc5925 BP |
773 | } |
774 | ||
2d071a32 | 775 | static enum ofperr |
50f96b10 | 776 | ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh, |
4bc938cc BP |
777 | const struct ofputil_port_map *port_map, |
778 | const struct ofputil_table_map *table_map) | |
064af421 | 779 | { |
0a2869d5 | 780 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
f25d0cf3 | 781 | struct ofpbuf ofpacts; |
2d071a32 | 782 | int retval; |
064af421 | 783 | |
f25d0cf3 | 784 | ofpbuf_init(&ofpacts, 64); |
4ffd1b43 BP |
785 | for (;;) { |
786 | struct ofputil_flow_stats fs; | |
fab8fadb | 787 | |
f25d0cf3 | 788 | retval = ofputil_decode_flow_stats_reply(&fs, &b, true, &ofpacts); |
4ffd1b43 | 789 | if (retval) { |
064af421 BP |
790 | break; |
791 | } | |
1b3758c3 | 792 | ds_put_cstr(string, "\n "); |
dfc77282 | 793 | ofputil_flow_stats_format(string, &fs, port_map, table_map, true); |
bdcc5925 | 794 | } |
cb80d803 | 795 | ofpbuf_uninit(&ofpacts); |
2d071a32 BP |
796 | |
797 | return retval != EOF ? retval : 0; | |
c6430da5 BP |
798 | } |
799 | ||
2d071a32 | 800 | static enum ofperr |
982697a4 | 801 | ofp_print_aggregate_stats_reply(struct ds *string, const struct ofp_header *oh) |
064af421 | 802 | { |
982697a4 BP |
803 | struct ofputil_aggregate_stats as; |
804 | enum ofperr error; | |
064af421 | 805 | |
982697a4 | 806 | error = ofputil_decode_aggregate_stats_reply(&as, oh); |
dfc77282 BP |
807 | if (!error) { |
808 | ofputil_aggregate_stats_format(string, &as); | |
982697a4 | 809 | } |
dfc77282 | 810 | return error; |
a2ad9ecd BP |
811 | } |
812 | ||
f8e4867e SH |
813 | static void |
814 | print_port_stat(struct ds *string, const char *leader, uint64_t stat, int more) | |
064af421 BP |
815 | { |
816 | ds_put_cstr(string, leader); | |
c4617b3c | 817 | if (stat != UINT64_MAX) { |
064af421 BP |
818 | ds_put_format(string, "%"PRIu64, stat); |
819 | } else { | |
820 | ds_put_char(string, '?'); | |
821 | } | |
822 | if (more) { | |
823 | ds_put_cstr(string, ", "); | |
824 | } else { | |
825 | ds_put_cstr(string, "\n"); | |
826 | } | |
827 | } | |
828 | ||
d6e3feb5 | 829 | static void |
830 | print_port_stat_cond(struct ds *string, const char *leader, uint64_t stat) | |
831 | { | |
832 | if (stat != UINT64_MAX) { | |
833 | ds_put_format(string, "%s%"PRIu64", ", leader, stat); | |
834 | } | |
835 | } | |
836 | ||
2d071a32 | 837 | static enum ofperr |
50f96b10 BP |
838 | ofp_print_ofpst_port_request(struct ds *string, const struct ofp_header *oh, |
839 | const struct ofputil_port_map *port_map) | |
abaad8cf | 840 | { |
4e022ec0 | 841 | ofp_port_t ofp10_port; |
f8e4867e SH |
842 | enum ofperr error; |
843 | ||
844 | error = ofputil_decode_port_stats_request(oh, &ofp10_port); | |
845 | if (error) { | |
2d071a32 | 846 | return error; |
f8e4867e SH |
847 | } |
848 | ||
e1db42d6 | 849 | ds_put_cstr(string, " port_no="); |
50f96b10 | 850 | ofputil_format_port(ofp10_port, port_map, string); |
2d071a32 BP |
851 | |
852 | return 0; | |
abaad8cf JP |
853 | } |
854 | ||
2d071a32 | 855 | static enum ofperr |
d1e2cf21 | 856 | ofp_print_ofpst_port_reply(struct ds *string, const struct ofp_header *oh, |
50f96b10 | 857 | const struct ofputil_port_map *port_map, |
d1e2cf21 | 858 | int verbosity) |
064af421 | 859 | { |
971f4b39 | 860 | uint32_t i; |
34582733 | 861 | ds_put_format(string, " %"PRIuSIZE" ports\n", ofputil_count_port_stats(oh)); |
064af421 | 862 | if (verbosity < 1) { |
2d071a32 | 863 | return 0; |
064af421 BP |
864 | } |
865 | ||
0a2869d5 | 866 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
982697a4 | 867 | for (;;) { |
f8e4867e SH |
868 | struct ofputil_port_stats ps; |
869 | int retval; | |
870 | ||
871 | retval = ofputil_decode_port_stats(&ps, &b); | |
872 | if (retval) { | |
2d071a32 | 873 | return retval != EOF ? retval : 0; |
982697a4 BP |
874 | } |
875 | ||
e1db42d6 | 876 | ds_put_cstr(string, " port "); |
4e022ec0 | 877 | if (ofp_to_u16(ps.port_no) < 10) { |
e1db42d6 JR |
878 | ds_put_char(string, ' '); |
879 | } | |
50f96b10 | 880 | ofputil_format_port(ps.port_no, port_map, string); |
064af421 | 881 | |
f8e4867e SH |
882 | ds_put_cstr(string, ": rx "); |
883 | print_port_stat(string, "pkts=", ps.stats.rx_packets, 1); | |
884 | print_port_stat(string, "bytes=", ps.stats.rx_bytes, 1); | |
885 | print_port_stat(string, "drop=", ps.stats.rx_dropped, 1); | |
886 | print_port_stat(string, "errs=", ps.stats.rx_errors, 1); | |
887 | print_port_stat(string, "frame=", ps.stats.rx_frame_errors, 1); | |
888 | print_port_stat(string, "over=", ps.stats.rx_over_errors, 1); | |
889 | print_port_stat(string, "crc=", ps.stats.rx_crc_errors, 0); | |
064af421 BP |
890 | |
891 | ds_put_cstr(string, " tx "); | |
f8e4867e SH |
892 | print_port_stat(string, "pkts=", ps.stats.tx_packets, 1); |
893 | print_port_stat(string, "bytes=", ps.stats.tx_bytes, 1); | |
894 | print_port_stat(string, "drop=", ps.stats.tx_dropped, 1); | |
895 | print_port_stat(string, "errs=", ps.stats.tx_errors, 1); | |
896 | print_port_stat(string, "coll=", ps.stats.collisions, 0); | |
65e0be10 BP |
897 | |
898 | if (ps.duration_sec != UINT32_MAX) { | |
899 | ds_put_cstr(string, " duration="); | |
900 | ofp_print_duration(string, ps.duration_sec, ps.duration_nsec); | |
901 | ds_put_char(string, '\n'); | |
902 | } | |
d6e3feb5 | 903 | struct ds string_ext_stats = DS_EMPTY_INITIALIZER; |
904 | ||
905 | ds_init(&string_ext_stats); | |
906 | ||
907 | print_port_stat_cond(&string_ext_stats, "1_to_64_packets=", | |
908 | ps.stats.rx_1_to_64_packets); | |
909 | print_port_stat_cond(&string_ext_stats, "65_to_127_packets=", | |
910 | ps.stats.rx_65_to_127_packets); | |
911 | print_port_stat_cond(&string_ext_stats, "128_to_255_packets=", | |
912 | ps.stats.rx_128_to_255_packets); | |
913 | print_port_stat_cond(&string_ext_stats, "256_to_511_packets=", | |
914 | ps.stats.rx_256_to_511_packets); | |
915 | print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=", | |
916 | ps.stats.rx_512_to_1023_packets); | |
917 | print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=", | |
918 | ps.stats.rx_1024_to_1522_packets); | |
919 | print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=", | |
920 | ps.stats.rx_1523_to_max_packets); | |
921 | print_port_stat_cond(&string_ext_stats, "broadcast_packets=", | |
922 | ps.stats.rx_broadcast_packets); | |
923 | print_port_stat_cond(&string_ext_stats, "undersized_errors=", | |
924 | ps.stats.rx_undersized_errors); | |
925 | print_port_stat_cond(&string_ext_stats, "oversize_errors=", | |
926 | ps.stats.rx_oversize_errors); | |
927 | print_port_stat_cond(&string_ext_stats, "rx_fragmented_errors=", | |
928 | ps.stats.rx_fragmented_errors); | |
929 | print_port_stat_cond(&string_ext_stats, "rx_jabber_errors=", | |
930 | ps.stats.rx_jabber_errors); | |
931 | ||
932 | if (string_ext_stats.length != 0) { | |
933 | /* If at least one statistics counter is reported: */ | |
934 | ds_put_cstr(string, " rx rfc2819 "); | |
935 | ds_put_buffer(string, string_ext_stats.string, | |
936 | string_ext_stats.length); | |
937 | ds_put_cstr(string, "\n"); | |
938 | ds_destroy(&string_ext_stats); | |
939 | } | |
940 | ||
941 | ds_init(&string_ext_stats); | |
942 | ||
943 | print_port_stat_cond(&string_ext_stats, "1_to_64_packets=", | |
944 | ps.stats.tx_1_to_64_packets); | |
945 | print_port_stat_cond(&string_ext_stats, "65_to_127_packets=", | |
946 | ps.stats.tx_65_to_127_packets); | |
947 | print_port_stat_cond(&string_ext_stats, "128_to_255_packets=", | |
948 | ps.stats.tx_128_to_255_packets); | |
949 | print_port_stat_cond(&string_ext_stats, "256_to_511_packets=", | |
950 | ps.stats.tx_256_to_511_packets); | |
951 | print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=", | |
952 | ps.stats.tx_512_to_1023_packets); | |
953 | print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=", | |
954 | ps.stats.tx_1024_to_1522_packets); | |
955 | print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=", | |
956 | ps.stats.tx_1523_to_max_packets); | |
957 | print_port_stat_cond(&string_ext_stats, "multicast_packets=", | |
958 | ps.stats.tx_multicast_packets); | |
959 | print_port_stat_cond(&string_ext_stats, "broadcast_packets=", | |
960 | ps.stats.tx_broadcast_packets); | |
961 | ||
962 | if (string_ext_stats.length != 0) { | |
963 | /* If at least one statistics counter is reported: */ | |
964 | ds_put_cstr(string, " tx rfc2819 "); | |
965 | ds_put_buffer(string, string_ext_stats.string, | |
966 | string_ext_stats.length); | |
967 | ds_put_cstr(string, "\n"); | |
968 | ds_destroy(&string_ext_stats); | |
969 | } | |
971f4b39 MW |
970 | |
971 | if (ps.custom_stats.size) { | |
972 | ds_put_cstr(string, " CUSTOM Statistics"); | |
973 | for (i = 0; i < ps.custom_stats.size; i++) { | |
974 | /* 3 counters in the row */ | |
975 | if (ps.custom_stats.counters[i].name[0]) { | |
976 | if (i % 3 == 0) { | |
977 | ds_put_cstr(string, "\n"); | |
978 | ds_put_cstr(string, " "); | |
979 | } else { | |
980 | ds_put_char(string, ' '); | |
981 | } | |
982 | ds_put_format(string, "%s=%"PRIu64",", | |
983 | ps.custom_stats.counters[i].name, | |
984 | ps.custom_stats.counters[i].value); | |
985 | } | |
986 | } | |
987 | ds_put_cstr(string, "\n"); | |
988 | } | |
064af421 BP |
989 | } |
990 | } | |
991 | ||
2d071a32 | 992 | static enum ofperr |
4bc938cc BP |
993 | ofp_print_table_stats_reply(struct ds *string, const struct ofp_header *oh, |
994 | const struct ofputil_table_map *table_map) | |
26df8b3e | 995 | { |
0a2869d5 | 996 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
26df8b3e SH |
997 | ofpraw_pull_assert(&b); |
998 | ||
8811fc0a BP |
999 | struct ofputil_table_features prev_features; |
1000 | struct ofputil_table_stats prev_stats; | |
1001 | for (int i = 0;; i++) { | |
3c1bb396 BP |
1002 | struct ofputil_table_features features; |
1003 | struct ofputil_table_stats stats; | |
1004 | int retval; | |
982697a4 | 1005 | |
3c1bb396 BP |
1006 | retval = ofputil_decode_table_stats_reply(&b, &stats, &features); |
1007 | if (retval) { | |
2d071a32 | 1008 | return retval != EOF ? retval : 0; |
982697a4 BP |
1009 | } |
1010 | ||
8811fc0a | 1011 | ds_put_char(string, '\n'); |
dfc77282 BP |
1012 | ofputil_table_features_format(string, |
1013 | &features, i ? &prev_features : NULL, | |
1014 | &stats, i ? &prev_stats : NULL, | |
1015 | table_map); | |
8811fc0a BP |
1016 | prev_features = features; |
1017 | prev_stats = stats; | |
26df8b3e SH |
1018 | } |
1019 | } | |
1020 | ||
d2805da2 BP |
1021 | static void |
1022 | ofp_print_queue_name(struct ds *string, uint32_t queue_id) | |
1023 | { | |
1024 | if (queue_id == OFPQ_ALL) { | |
1025 | ds_put_cstr(string, "ALL"); | |
1026 | } else { | |
1027 | ds_put_format(string, "%"PRIu32, queue_id); | |
1028 | } | |
1029 | } | |
1030 | ||
2d071a32 | 1031 | static enum ofperr |
50f96b10 BP |
1032 | ofp_print_ofpst_queue_request(struct ds *string, const struct ofp_header *oh, |
1033 | const struct ofputil_port_map *port_map) | |
d2805da2 | 1034 | { |
64626975 SH |
1035 | struct ofputil_queue_stats_request oqsr; |
1036 | enum ofperr error; | |
1037 | ||
1038 | error = ofputil_decode_queue_stats_request(oh, &oqsr); | |
1039 | if (error) { | |
2d071a32 | 1040 | return error; |
64626975 | 1041 | } |
982697a4 | 1042 | |
3e461c2c | 1043 | ds_put_cstr(string, " port="); |
50f96b10 | 1044 | ofputil_format_port(oqsr.port_no, port_map, string); |
d2805da2 BP |
1045 | |
1046 | ds_put_cstr(string, " queue="); | |
64626975 | 1047 | ofp_print_queue_name(string, oqsr.queue_id); |
2d071a32 BP |
1048 | |
1049 | return 0; | |
f8e4867e SH |
1050 | } |
1051 | ||
2d071a32 | 1052 | static enum ofperr |
d1e2cf21 | 1053 | ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh, |
50f96b10 | 1054 | const struct ofputil_port_map *port_map, |
d1e2cf21 | 1055 | int verbosity) |
d2805da2 | 1056 | { |
34582733 | 1057 | ds_put_format(string, " %"PRIuSIZE" queues\n", ofputil_count_queue_stats(oh)); |
d2805da2 | 1058 | if (verbosity < 1) { |
2d071a32 | 1059 | return 0; |
d2805da2 BP |
1060 | } |
1061 | ||
0a2869d5 | 1062 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
982697a4 | 1063 | for (;;) { |
64626975 SH |
1064 | struct ofputil_queue_stats qs; |
1065 | int retval; | |
1066 | ||
1067 | retval = ofputil_decode_queue_stats(&qs, &b); | |
1068 | if (retval) { | |
2d071a32 | 1069 | return retval != EOF ? retval : 0; |
982697a4 BP |
1070 | } |
1071 | ||
d2805da2 | 1072 | ds_put_cstr(string, " port "); |
50f96b10 | 1073 | ofputil_format_port(qs.port_no, port_map, string); |
d2805da2 | 1074 | ds_put_cstr(string, " queue "); |
64626975 | 1075 | ofp_print_queue_name(string, qs.queue_id); |
d2805da2 BP |
1076 | ds_put_cstr(string, ": "); |
1077 | ||
6dc34a0d BP |
1078 | print_port_stat(string, "bytes=", qs.tx_bytes, 1); |
1079 | print_port_stat(string, "pkts=", qs.tx_packets, 1); | |
1080 | print_port_stat(string, "errors=", qs.tx_errors, 1); | |
1081 | ||
1082 | ds_put_cstr(string, "duration="); | |
1083 | if (qs.duration_sec != UINT32_MAX) { | |
1084 | ofp_print_duration(string, qs.duration_sec, qs.duration_nsec); | |
1085 | } else { | |
1086 | ds_put_char(string, '?'); | |
1087 | } | |
1088 | ds_put_char(string, '\n'); | |
d2805da2 BP |
1089 | } |
1090 | } | |
1091 | ||
2d071a32 | 1092 | static enum ofperr |
70ae4f93 | 1093 | ofp_print_ofpst_port_desc_request(struct ds *string, |
50f96b10 BP |
1094 | const struct ofp_header *oh, |
1095 | const struct ofputil_port_map *port_map) | |
70ae4f93 BP |
1096 | { |
1097 | enum ofperr error; | |
1098 | ofp_port_t port; | |
1099 | ||
1100 | error = ofputil_decode_port_desc_stats_request(oh, &port); | |
1101 | if (error) { | |
2d071a32 | 1102 | return error; |
70ae4f93 BP |
1103 | } |
1104 | ||
1105 | ds_put_cstr(string, " port="); | |
50f96b10 | 1106 | ofputil_format_port(port, port_map, string); |
2d071a32 BP |
1107 | |
1108 | return 0; | |
70ae4f93 BP |
1109 | } |
1110 | ||
2d071a32 | 1111 | static enum ofperr |
2be393ed JP |
1112 | ofp_print_ofpst_port_desc_reply(struct ds *string, |
1113 | const struct ofp_header *oh) | |
1114 | { | |
0a2869d5 | 1115 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
982697a4 | 1116 | ofpraw_pull_assert(&b); |
2be393ed | 1117 | ds_put_char(string, '\n'); |
dfc77282 | 1118 | return ofputil_phy_ports_format(string, oh->version, &b); |
2be393ed JP |
1119 | } |
1120 | ||
064af421 | 1121 | static void |
5d40fc57 | 1122 | ofp_print_stats(struct ds *string, const struct ofp_header *oh) |
064af421 | 1123 | { |
982697a4 | 1124 | uint16_t flags = ofpmp_flags(oh); |
d1e2cf21 | 1125 | |
982697a4 | 1126 | if (flags) { |
d1e2cf21 | 1127 | ds_put_cstr(string, " flags="); |
5d40fc57 SH |
1128 | if ((!ofpmsg_is_stat_request(oh) || oh->version >= OFP13_VERSION) |
1129 | && (flags & OFPSF_REPLY_MORE)) { | |
064af421 BP |
1130 | ds_put_cstr(string, "[more]"); |
1131 | flags &= ~OFPSF_REPLY_MORE; | |
1132 | } | |
1133 | if (flags) { | |
d1e2cf21 BP |
1134 | ds_put_format(string, "[***unknown flags 0x%04"PRIx16"***]", |
1135 | flags); | |
064af421 BP |
1136 | } |
1137 | } | |
064af421 BP |
1138 | } |
1139 | ||
2d071a32 | 1140 | static enum ofperr |
d1e2cf21 | 1141 | ofp_print_echo(struct ds *string, const struct ofp_header *oh, int verbosity) |
064af421 | 1142 | { |
d1e2cf21 | 1143 | size_t len = ntohs(oh->length); |
064af421 | 1144 | |
34582733 | 1145 | ds_put_format(string, " %"PRIuSIZE" bytes of payload\n", len - sizeof *oh); |
064af421 | 1146 | if (verbosity > 1) { |
d1e2cf21 | 1147 | ds_put_hex_dump(string, oh + 1, len - sizeof *oh, 0, true); |
064af421 | 1148 | } |
2d071a32 BP |
1149 | |
1150 | return 0; | |
064af421 BP |
1151 | } |
1152 | ||
61fe3a7b | 1153 | static void |
00467f73 AC |
1154 | ofp_print_role_generic(struct ds *string, enum ofp12_controller_role role, |
1155 | uint64_t generation_id) | |
61fe3a7b | 1156 | { |
61fe3a7b | 1157 | ds_put_cstr(string, " role="); |
6ea4776b | 1158 | |
00467f73 | 1159 | switch (role) { |
f4f1ea7e BP |
1160 | case OFPCR12_ROLE_NOCHANGE: |
1161 | ds_put_cstr(string, "nochange"); | |
1162 | break; | |
1163 | case OFPCR12_ROLE_EQUAL: | |
6ea4776b JR |
1164 | ds_put_cstr(string, "equal"); /* OF 1.2 wording */ |
1165 | break; | |
f4f1ea7e | 1166 | case OFPCR12_ROLE_MASTER: |
61fe3a7b | 1167 | ds_put_cstr(string, "master"); |
6ea4776b | 1168 | break; |
f4f1ea7e | 1169 | case OFPCR12_ROLE_SLAVE: |
61fe3a7b | 1170 | ds_put_cstr(string, "slave"); |
6ea4776b JR |
1171 | break; |
1172 | default: | |
428b2edd | 1173 | OVS_NOT_REACHED(); |
6ea4776b JR |
1174 | } |
1175 | ||
00467f73 AC |
1176 | if (generation_id != UINT64_MAX) { |
1177 | ds_put_format(string, " generation_id=%"PRIu64, generation_id); | |
1178 | } | |
1179 | } | |
1180 | ||
2d071a32 | 1181 | static enum ofperr |
00467f73 AC |
1182 | ofp_print_role_message(struct ds *string, const struct ofp_header *oh) |
1183 | { | |
1184 | struct ofputil_role_request rr; | |
1185 | enum ofperr error; | |
1186 | ||
1187 | error = ofputil_decode_role_message(oh, &rr); | |
1188 | if (error) { | |
2d071a32 | 1189 | return error; |
00467f73 AC |
1190 | } |
1191 | ||
1192 | ofp_print_role_generic(string, rr.role, rr.have_generation_id ? rr.generation_id : UINT64_MAX); | |
2d071a32 BP |
1193 | |
1194 | return 0; | |
00467f73 AC |
1195 | } |
1196 | ||
2d071a32 | 1197 | static enum ofperr |
00467f73 AC |
1198 | ofp_print_role_status_message(struct ds *string, const struct ofp_header *oh) |
1199 | { | |
1200 | struct ofputil_role_status rs; | |
1201 | enum ofperr error; | |
1202 | ||
1203 | error = ofputil_decode_role_status(oh, &rs); | |
1204 | if (error) { | |
2d071a32 | 1205 | return error; |
00467f73 AC |
1206 | } |
1207 | ||
1208 | ofp_print_role_generic(string, rs.role, rs.generation_id); | |
1209 | ||
1210 | ds_put_cstr(string, " reason="); | |
1211 | ||
1212 | switch (rs.reason) { | |
1213 | case OFPCRR_MASTER_REQUEST: | |
1214 | ds_put_cstr(string, "master_request"); | |
1215 | break; | |
1216 | case OFPCRR_CONFIG: | |
1217 | ds_put_cstr(string, "configuration_changed"); | |
1218 | break; | |
1219 | case OFPCRR_EXPERIMENTER: | |
1220 | ds_put_cstr(string, "experimenter_data_changed"); | |
1221 | break; | |
d18cc1ee | 1222 | case OFPCRR_N_REASONS: |
00467f73 | 1223 | default: |
b76d4a81 BP |
1224 | ds_put_cstr(string, "(unknown)"); |
1225 | break; | |
61fe3a7b | 1226 | } |
2d071a32 BP |
1227 | |
1228 | return 0; | |
61fe3a7b BP |
1229 | } |
1230 | ||
2d071a32 | 1231 | static enum ofperr |
225c33ba | 1232 | ofp_print_nxt_flow_mod_table_id(struct ds *string, const struct ofp_header *oh) |
6c1491fb | 1233 | { |
225c33ba BP |
1234 | bool enable = ofputil_decode_nx_flow_mod_table_id(oh); |
1235 | ds_put_format(string, " %s", enable ? "enable" : "disable"); | |
2d071a32 | 1236 | return 0; |
6c1491fb BP |
1237 | } |
1238 | ||
2d071a32 | 1239 | static enum ofperr |
225c33ba | 1240 | ofp_print_nxt_set_flow_format(struct ds *string, const struct ofp_header *oh) |
7fa91113 | 1241 | { |
225c33ba BP |
1242 | enum ofputil_protocol p = ofputil_decode_nx_set_flow_format(oh); |
1243 | ds_put_format(string, " format=%s", | |
1244 | p == OFPUTIL_P_OF10_STD ? "openflow10" | |
1245 | : p == OFPUTIL_P_OF10_NXM ? "nxm" | |
1246 | : "(unknown)"); | |
2d071a32 | 1247 | return 0; |
7fa91113 BP |
1248 | } |
1249 | ||
2d071a32 | 1250 | static enum ofperr |
54834960 | 1251 | ofp_print_nxt_set_packet_in_format(struct ds *string, |
d8790c08 | 1252 | const struct ofp_header *oh) |
54834960 | 1253 | { |
d8790c08 BP |
1254 | enum ofputil_packet_in_format format; |
1255 | enum ofperr error = ofputil_decode_set_packet_in_format(oh, &format); | |
1256 | if (!error) { | |
1257 | ds_put_format(string, " format=%s", | |
1258 | ofputil_packet_in_format_to_string(format)); | |
54834960 | 1259 | } |
d8790c08 | 1260 | return error; |
54834960 EJ |
1261 | } |
1262 | ||
8961699e BP |
1263 | /* Returns a string form of 'reason'. The return value is either a statically |
1264 | * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'. | |
1265 | * 'bufsize' should be at least OFP_PORT_REASON_BUFSIZE. */ | |
1266 | #define OFP_PORT_REASON_BUFSIZE (INT_STRLEN(int) + 1) | |
80d5aefd | 1267 | static const char * |
8961699e BP |
1268 | ofp_port_reason_to_string(enum ofp_port_reason reason, |
1269 | char *reasonbuf, size_t bufsize) | |
80d5aefd | 1270 | { |
80d5aefd BP |
1271 | switch (reason) { |
1272 | case OFPPR_ADD: | |
1273 | return "add"; | |
1274 | ||
1275 | case OFPPR_DELETE: | |
1276 | return "delete"; | |
1277 | ||
1278 | case OFPPR_MODIFY: | |
1279 | return "modify"; | |
1280 | ||
d18cc1ee | 1281 | case OFPPR_N_REASONS: |
80d5aefd | 1282 | default: |
8961699e BP |
1283 | snprintf(reasonbuf, bufsize, "%d", (int) reason); |
1284 | return reasonbuf; | |
80d5aefd BP |
1285 | } |
1286 | } | |
1287 | ||
98090482 NR |
1288 | /* Returns a string form of 'reason'. The return value is either a statically |
1289 | * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'. | |
1290 | * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */ | |
1291 | static const char* | |
1292 | ofp_role_reason_to_string(enum ofp14_controller_role_reason reason, | |
1293 | char *reasonbuf, size_t bufsize) | |
1294 | { | |
1295 | switch (reason) { | |
1296 | case OFPCRR_MASTER_REQUEST: | |
1297 | return "master_request"; | |
1298 | ||
1299 | case OFPCRR_CONFIG: | |
1300 | return "configuration_changed"; | |
1301 | ||
1302 | case OFPCRR_EXPERIMENTER: | |
1303 | return "experimenter_data_changed"; | |
1304 | ||
d18cc1ee | 1305 | case OFPCRR_N_REASONS: |
98090482 NR |
1306 | default: |
1307 | snprintf(reasonbuf, bufsize, "%d", (int) reason); | |
1308 | return reasonbuf; | |
1309 | } | |
1310 | } | |
1311 | ||
1312 | /* Returns a string form of 'reason'. The return value is either a statically | |
1313 | * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'. | |
1314 | * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */ | |
1315 | static const char* | |
1316 | ofp_table_reason_to_string(enum ofp14_table_reason reason, | |
1317 | char *reasonbuf, size_t bufsize) | |
1318 | { | |
1319 | switch (reason) { | |
1320 | case OFPTR_VACANCY_DOWN: | |
1321 | return "vacancy_down"; | |
1322 | ||
1323 | case OFPTR_VACANCY_UP: | |
1324 | return "vacancy_up"; | |
1325 | ||
1326 | default: | |
1327 | snprintf(reasonbuf, bufsize, "%d", (int) reason); | |
1328 | return reasonbuf; | |
1329 | } | |
1330 | } | |
1331 | ||
1332 | /* Returns a string form of 'reason'. The return value is either a statically | |
1333 | * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'. | |
1334 | * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */ | |
1335 | static const char* | |
1336 | ofp_requestforward_reason_to_string(enum ofp14_requestforward_reason reason, | |
1337 | char *reasonbuf, size_t bufsize) | |
1338 | { | |
1339 | switch (reason) { | |
1340 | case OFPRFR_GROUP_MOD: | |
1341 | return "group_mod_request"; | |
1342 | ||
1343 | case OFPRFR_METER_MOD: | |
1344 | return "meter_mod_request"; | |
1345 | ||
d18cc1ee | 1346 | case OFPRFR_N_REASONS: |
98090482 NR |
1347 | default: |
1348 | snprintf(reasonbuf, bufsize, "%d", (int) reason); | |
1349 | return reasonbuf; | |
1350 | } | |
1351 | } | |
1352 | ||
1353 | static const char * | |
1354 | ofp_async_config_reason_to_string(uint32_t reason, | |
1355 | enum ofputil_async_msg_type type, | |
1356 | char *reasonbuf, size_t bufsize) | |
1357 | { | |
1358 | switch (type) { | |
1359 | case OAM_PACKET_IN: | |
1360 | return ofputil_packet_in_reason_to_string(reason, reasonbuf, bufsize); | |
1361 | ||
1362 | case OAM_PORT_STATUS: | |
1363 | return ofp_port_reason_to_string(reason, reasonbuf, bufsize); | |
1364 | ||
1365 | case OAM_FLOW_REMOVED: | |
1366 | return ofp_flow_removed_reason_to_string(reason, reasonbuf, bufsize); | |
1367 | ||
1368 | case OAM_ROLE_STATUS: | |
1369 | return ofp_role_reason_to_string(reason, reasonbuf, bufsize); | |
1370 | ||
1371 | case OAM_TABLE_STATUS: | |
1372 | return ofp_table_reason_to_string(reason, reasonbuf, bufsize); | |
1373 | ||
1374 | case OAM_REQUESTFORWARD: | |
1375 | return ofp_requestforward_reason_to_string(reason, reasonbuf, bufsize); | |
1376 | ||
1377 | case OAM_N_TYPES: | |
1378 | default: | |
1379 | return "Unknown asynchronous configuration message type"; | |
1380 | } | |
1381 | } | |
1382 | ||
1383 | ||
1384 | #define OFP_ASYNC_CONFIG_REASON_BUFSIZE (INT_STRLEN(int) + 1) | |
2d071a32 | 1385 | static enum ofperr |
904e5202 | 1386 | ofp_print_set_async_config(struct ds *string, const struct ofp_header *oh, |
71f21279 | 1387 | enum ofptype ofptype) |
80d5aefd | 1388 | { |
904e5202 BP |
1389 | struct ofputil_async_cfg basis = OFPUTIL_ASYNC_CFG_INIT; |
1390 | struct ofputil_async_cfg ac; | |
80d5aefd | 1391 | |
71f21279 | 1392 | bool is_reply = ofptype == OFPTYPE_GET_ASYNC_REPLY; |
904e5202 BP |
1393 | enum ofperr error = ofputil_decode_set_async_config(oh, is_reply, |
1394 | &basis, &ac); | |
1395 | if (error) { | |
2d071a32 | 1396 | return error; |
904e5202 | 1397 | } |
8961699e | 1398 | |
904e5202 BP |
1399 | for (int i = 0; i < 2; i++) { |
1400 | ds_put_format(string, "\n %s:\n", i == 0 ? "master" : "slave"); | |
1401 | for (uint32_t type = 0; type < OAM_N_TYPES; type++) { | |
1402 | ds_put_format(string, "%16s:", | |
1403 | ofputil_async_msg_type_to_string(type)); | |
80d5aefd | 1404 | |
904e5202 BP |
1405 | uint32_t role = i == 0 ? ac.master[type] : ac.slave[type]; |
1406 | for (int j = 0; j < 32; j++) { | |
1407 | if (role & (1u << j)) { | |
1408 | char reasonbuf[OFP_ASYNC_CONFIG_REASON_BUFSIZE]; | |
98090482 | 1409 | const char *reason; |
8961699e | 1410 | |
904e5202 BP |
1411 | reason = ofp_async_config_reason_to_string( |
1412 | j, type, reasonbuf, sizeof reasonbuf); | |
9bfe9334 BP |
1413 | if (reason[0]) { |
1414 | ds_put_format(string, " %s", reason); | |
1415 | } | |
98090482 | 1416 | } |
80d5aefd | 1417 | } |
904e5202 | 1418 | if (!role) { |
98090482 NR |
1419 | ds_put_cstr(string, " (off)"); |
1420 | } | |
1421 | ds_put_char(string, '\n'); | |
80d5aefd | 1422 | } |
80d5aefd | 1423 | } |
2d071a32 BP |
1424 | |
1425 | return 0; | |
80d5aefd BP |
1426 | } |
1427 | ||
2d071a32 | 1428 | static enum ofperr |
a7349929 BP |
1429 | ofp_print_nxt_set_controller_id(struct ds *string, |
1430 | const struct nx_controller_id *nci) | |
1431 | { | |
1432 | ds_put_format(string, " id=%"PRIu16, ntohs(nci->controller_id)); | |
2d071a32 | 1433 | return 0; |
a7349929 BP |
1434 | } |
1435 | ||
2d071a32 | 1436 | static enum ofperr |
2b07c8b1 BP |
1437 | ofp_print_nxt_flow_monitor_cancel(struct ds *string, |
1438 | const struct ofp_header *oh) | |
1439 | { | |
1440 | ds_put_format(string, " id=%"PRIu32, | |
1441 | ofputil_decode_flow_monitor_cancel(oh)); | |
2d071a32 | 1442 | return 0; |
2b07c8b1 BP |
1443 | } |
1444 | ||
2d071a32 | 1445 | static enum ofperr |
2b07c8b1 | 1446 | ofp_print_nxst_flow_monitor_request(struct ds *string, |
50f96b10 | 1447 | const struct ofp_header *oh, |
4bc938cc BP |
1448 | const struct ofputil_port_map *port_map, |
1449 | const struct ofputil_table_map *table_map) | |
2b07c8b1 | 1450 | { |
0a2869d5 | 1451 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
2b07c8b1 BP |
1452 | for (;;) { |
1453 | struct ofputil_flow_monitor_request request; | |
1454 | int retval; | |
1455 | ||
1456 | retval = ofputil_decode_flow_monitor_request(&request, &b); | |
1457 | if (retval) { | |
2d071a32 | 1458 | return retval != EOF ? retval : 0; |
2b07c8b1 BP |
1459 | } |
1460 | ||
dfc77282 BP |
1461 | ofputil_flow_monitor_request_format(string, &request, |
1462 | port_map, table_map); | |
2b07c8b1 BP |
1463 | } |
1464 | } | |
1465 | ||
2d071a32 | 1466 | static enum ofperr |
2b07c8b1 | 1467 | ofp_print_nxst_flow_monitor_reply(struct ds *string, |
50f96b10 | 1468 | const struct ofp_header *oh, |
4bc938cc BP |
1469 | const struct ofputil_port_map *port_map, |
1470 | const struct ofputil_table_map *table_map) | |
2b07c8b1 BP |
1471 | { |
1472 | uint64_t ofpacts_stub[1024 / 8]; | |
0a2869d5 BP |
1473 | struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub); |
1474 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); | |
2b07c8b1 | 1475 | |
2b07c8b1 BP |
1476 | for (;;) { |
1477 | struct ofputil_flow_update update; | |
dfc77282 | 1478 | int retval = ofputil_decode_flow_update(&update, &b, &ofpacts); |
2b07c8b1 | 1479 | if (retval) { |
2b07c8b1 | 1480 | ofpbuf_uninit(&ofpacts); |
2d071a32 | 1481 | return retval != EOF ? retval : 0; |
2b07c8b1 | 1482 | } |
dfc77282 | 1483 | ofputil_flow_update_format(string, &update, port_map, table_map); |
2b07c8b1 BP |
1484 | } |
1485 | } | |
1486 | ||
bdcc5925 BP |
1487 | void |
1488 | ofp_print_version(const struct ofp_header *oh, | |
1489 | struct ds *string) | |
d1e2cf21 | 1490 | { |
3811e66b BP |
1491 | switch (oh->version) { |
1492 | case OFP10_VERSION: | |
1493 | break; | |
1494 | case OFP11_VERSION: | |
1495 | ds_put_cstr(string, " (OF1.1)"); | |
4232ef77 SH |
1496 | break; |
1497 | case OFP12_VERSION: | |
1498 | ds_put_cstr(string, " (OF1.2)"); | |
3811e66b | 1499 | break; |
2e1ae200 JR |
1500 | case OFP13_VERSION: |
1501 | ds_put_cstr(string, " (OF1.3)"); | |
1502 | break; | |
9620f50c AC |
1503 | case OFP14_VERSION: |
1504 | ds_put_cstr(string, " (OF1.4)"); | |
1505 | break; | |
42dccab5 BP |
1506 | case OFP15_VERSION: |
1507 | ds_put_cstr(string, " (OF1.5)"); | |
1508 | break; | |
b79d45a1 BP |
1509 | case OFP16_VERSION: |
1510 | ds_put_cstr(string, " (OF1.6)"); | |
1511 | break; | |
3811e66b BP |
1512 | default: |
1513 | ds_put_format(string, " (OF 0x%02"PRIx8")", oh->version); | |
1514 | break; | |
1515 | } | |
1516 | ds_put_format(string, " (xid=0x%"PRIx32"):", ntohl(oh->xid)); | |
bdcc5925 | 1517 | } |
d1e2cf21 | 1518 | |
f25b4a81 | 1519 | static void |
982697a4 BP |
1520 | ofp_header_to_string__(const struct ofp_header *oh, enum ofpraw raw, |
1521 | struct ds *string) | |
f25b4a81 | 1522 | { |
982697a4 | 1523 | ds_put_cstr(string, ofpraw_get_name(raw)); |
f25b4a81 BP |
1524 | ofp_print_version(oh, string); |
1525 | } | |
1526 | ||
2d071a32 | 1527 | static enum ofperr |
4bc938cc BP |
1528 | ofp_print_table_desc_reply(struct ds *s, const struct ofp_header *oh, |
1529 | const struct ofputil_table_map *table_map) | |
03c72922 | 1530 | { |
0a2869d5 | 1531 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
03c72922 BP |
1532 | for (;;) { |
1533 | struct ofputil_table_desc td; | |
1534 | int retval; | |
1535 | ||
1536 | retval = ofputil_decode_table_desc(&b, &td, oh->version); | |
1537 | if (retval) { | |
2d071a32 | 1538 | return retval != EOF ? retval : 0; |
03c72922 | 1539 | } |
dfc77282 | 1540 | ofputil_table_desc_format(s, &td, table_map); |
03c72922 BP |
1541 | } |
1542 | } | |
1543 | ||
777af88d AC |
1544 | static const char * |
1545 | bundle_flags_to_name(uint32_t bit) | |
1546 | { | |
1547 | switch (bit) { | |
1548 | case OFPBF_ATOMIC: | |
1549 | return "atomic"; | |
1550 | case OFPBF_ORDERED: | |
1551 | return "ordered"; | |
1552 | default: | |
1553 | return NULL; | |
1554 | } | |
1555 | } | |
1556 | ||
2d071a32 | 1557 | static enum ofperr |
777af88d AC |
1558 | ofp_print_bundle_ctrl(struct ds *s, const struct ofp_header *oh) |
1559 | { | |
1560 | int error; | |
1561 | struct ofputil_bundle_ctrl_msg bctrl; | |
1562 | ||
1563 | error = ofputil_decode_bundle_ctrl(oh, &bctrl); | |
1564 | if (error) { | |
2d071a32 | 1565 | return error; |
777af88d AC |
1566 | } |
1567 | ||
1568 | ds_put_char(s, '\n'); | |
1569 | ||
1570 | ds_put_format(s, " bundle_id=%#"PRIx32" type=", bctrl.bundle_id); | |
1571 | switch (bctrl.type) { | |
1572 | case OFPBCT_OPEN_REQUEST: | |
1573 | ds_put_cstr(s, "OPEN_REQUEST"); | |
1574 | break; | |
1575 | case OFPBCT_OPEN_REPLY: | |
1576 | ds_put_cstr(s, "OPEN_REPLY"); | |
1577 | break; | |
1578 | case OFPBCT_CLOSE_REQUEST: | |
1579 | ds_put_cstr(s, "CLOSE_REQUEST"); | |
1580 | break; | |
1581 | case OFPBCT_CLOSE_REPLY: | |
1582 | ds_put_cstr(s, "CLOSE_REPLY"); | |
1583 | break; | |
1584 | case OFPBCT_COMMIT_REQUEST: | |
1585 | ds_put_cstr(s, "COMMIT_REQUEST"); | |
1586 | break; | |
1587 | case OFPBCT_COMMIT_REPLY: | |
1588 | ds_put_cstr(s, "COMMIT_REPLY"); | |
1589 | break; | |
1590 | case OFPBCT_DISCARD_REQUEST: | |
1591 | ds_put_cstr(s, "DISCARD_REQUEST"); | |
1592 | break; | |
1593 | case OFPBCT_DISCARD_REPLY: | |
1594 | ds_put_cstr(s, "DISCARD_REPLY"); | |
1595 | break; | |
1596 | } | |
1597 | ||
1598 | ds_put_cstr(s, " flags="); | |
1599 | ofp_print_bit_names(s, bctrl.flags, bundle_flags_to_name, ' '); | |
2d071a32 BP |
1600 | |
1601 | return 0; | |
777af88d AC |
1602 | } |
1603 | ||
2d071a32 | 1604 | static enum ofperr |
50f96b10 | 1605 | ofp_print_bundle_add(struct ds *s, const struct ofp_header *oh, |
4bc938cc BP |
1606 | const struct ofputil_port_map *port_map, |
1607 | const struct ofputil_table_map *table_map, | |
1608 | int verbosity) | |
777af88d AC |
1609 | { |
1610 | int error; | |
1611 | struct ofputil_bundle_add_msg badd; | |
777af88d | 1612 | |
7ac27a04 | 1613 | error = ofputil_decode_bundle_add(oh, &badd, NULL); |
777af88d | 1614 | if (error) { |
2d071a32 | 1615 | return error; |
777af88d AC |
1616 | } |
1617 | ||
1618 | ds_put_char(s, '\n'); | |
1619 | ds_put_format(s, " bundle_id=%#"PRIx32, badd.bundle_id); | |
1620 | ds_put_cstr(s, " flags="); | |
1621 | ofp_print_bit_names(s, badd.flags, bundle_flags_to_name, ' '); | |
1622 | ||
1623 | ds_put_char(s, '\n'); | |
50f96b10 | 1624 | char *msg = ofp_to_string(badd.msg, ntohs(badd.msg->length), port_map, |
4bc938cc | 1625 | table_map, verbosity); |
cf8fbeaa | 1626 | ds_put_and_free_cstr(s, msg); |
2d071a32 BP |
1627 | |
1628 | return 0; | |
777af88d AC |
1629 | } |
1630 | ||
6159c531 | 1631 | static void |
4e548ad9 | 1632 | print_tlv_table(struct ds *s, struct ovs_list *mappings) |
6159c531 | 1633 | { |
4e548ad9 | 1634 | struct ofputil_tlv_map *map; |
6159c531 JG |
1635 | |
1636 | ds_put_cstr(s, " mapping table:\n"); | |
5a0e4aec BP |
1637 | ds_put_cstr(s, " class type length match field\n"); |
1638 | ds_put_cstr(s, " ------ ---- ------ --------------"); | |
6159c531 JG |
1639 | |
1640 | LIST_FOR_EACH (map, list_node, mappings) { | |
5a0e4aec BP |
1641 | ds_put_format(s, "\n %#6"PRIx16" %#4"PRIx8" %6"PRIu8" " |
1642 | "tun_metadata%"PRIu16, | |
6159c531 JG |
1643 | map->option_class, map->option_type, map->option_len, |
1644 | map->index); | |
1645 | } | |
1646 | } | |
1647 | ||
2d071a32 | 1648 | static enum ofperr |
4e548ad9 | 1649 | ofp_print_tlv_table_mod(struct ds *s, const struct ofp_header *oh) |
6159c531 JG |
1650 | { |
1651 | int error; | |
4e548ad9 | 1652 | struct ofputil_tlv_table_mod ttm; |
6159c531 | 1653 | |
4e548ad9 | 1654 | error = ofputil_decode_tlv_table_mod(oh, &ttm); |
6159c531 | 1655 | if (error) { |
2d071a32 | 1656 | return error; |
6159c531 JG |
1657 | } |
1658 | ||
1659 | ds_put_cstr(s, "\n "); | |
1660 | ||
4e548ad9 ML |
1661 | switch (ttm.command) { |
1662 | case NXTTMC_ADD: | |
6159c531 JG |
1663 | ds_put_cstr(s, "ADD"); |
1664 | break; | |
4e548ad9 | 1665 | case NXTTMC_DELETE: |
6159c531 JG |
1666 | ds_put_cstr(s, "DEL"); |
1667 | break; | |
4e548ad9 | 1668 | case NXTTMC_CLEAR: |
6159c531 JG |
1669 | ds_put_cstr(s, "CLEAR"); |
1670 | break; | |
1671 | } | |
1672 | ||
4e548ad9 ML |
1673 | if (ttm.command != NXTTMC_CLEAR) { |
1674 | print_tlv_table(s, &ttm.mappings); | |
6159c531 JG |
1675 | } |
1676 | ||
4e548ad9 | 1677 | ofputil_uninit_tlv_table(&ttm.mappings); |
2d071a32 BP |
1678 | |
1679 | return 0; | |
6159c531 JG |
1680 | } |
1681 | ||
2d071a32 | 1682 | static enum ofperr |
4e548ad9 | 1683 | ofp_print_tlv_table_reply(struct ds *s, const struct ofp_header *oh) |
6159c531 JG |
1684 | { |
1685 | int error; | |
4e548ad9 ML |
1686 | struct ofputil_tlv_table_reply ttr; |
1687 | struct ofputil_tlv_map *map; | |
6159c531 JG |
1688 | int allocated_space = 0; |
1689 | ||
4e548ad9 | 1690 | error = ofputil_decode_tlv_table_reply(oh, &ttr); |
6159c531 | 1691 | if (error) { |
2d071a32 | 1692 | return error; |
6159c531 JG |
1693 | } |
1694 | ||
1695 | ds_put_char(s, '\n'); | |
1696 | ||
4e548ad9 | 1697 | LIST_FOR_EACH (map, list_node, &ttr.mappings) { |
6159c531 JG |
1698 | allocated_space += map->option_len; |
1699 | } | |
1700 | ||
1701 | ds_put_format(s, " max option space=%"PRIu32" max fields=%"PRIu16"\n", | |
4e548ad9 | 1702 | ttr.max_option_space, ttr.max_fields); |
6159c531 JG |
1703 | ds_put_format(s, " allocated option space=%d\n", allocated_space); |
1704 | ds_put_char(s, '\n'); | |
4e548ad9 | 1705 | print_tlv_table(s, &ttr.mappings); |
6159c531 | 1706 | |
4e548ad9 | 1707 | ofputil_uninit_tlv_table(&ttr.mappings); |
2d071a32 BP |
1708 | |
1709 | return 0; | |
6159c531 JG |
1710 | } |
1711 | ||
3c35db62 NR |
1712 | /* This function will print the request forward message. The reason for |
1713 | * request forward is taken from rf.request.type */ | |
2d071a32 | 1714 | static enum ofperr |
50f96b10 | 1715 | ofp_print_requestforward(struct ds *string, const struct ofp_header *oh, |
4bc938cc BP |
1716 | const struct ofputil_port_map *port_map, |
1717 | const struct ofputil_table_map *table_map) | |
3c35db62 NR |
1718 | { |
1719 | struct ofputil_requestforward rf; | |
1720 | enum ofperr error; | |
1721 | ||
1722 | error = ofputil_decode_requestforward(oh, &rf); | |
1723 | if (error) { | |
2d071a32 | 1724 | return error; |
3c35db62 NR |
1725 | } |
1726 | ||
1727 | ds_put_cstr(string, " reason="); | |
1728 | ||
1729 | switch (rf.reason) { | |
1730 | case OFPRFR_GROUP_MOD: | |
1731 | ds_put_cstr(string, "group_mod"); | |
e9c9481f BP |
1732 | ofputil_group_mod_format__(string, oh->version, rf.group_mod, port_map, |
1733 | table_map); | |
3c35db62 NR |
1734 | break; |
1735 | ||
1736 | case OFPRFR_METER_MOD: | |
1737 | ds_put_cstr(string, "meter_mod"); | |
1738 | ofp_print_meter_mod__(string, rf.meter_mod); | |
1739 | break; | |
d18cc1ee AA |
1740 | |
1741 | case OFPRFR_N_REASONS: | |
1742 | OVS_NOT_REACHED(); | |
3c35db62 NR |
1743 | } |
1744 | ofputil_destroy_requestforward(&rf); | |
2d071a32 BP |
1745 | |
1746 | return 0; | |
3c35db62 NR |
1747 | } |
1748 | ||
fb8f22c1 BY |
1749 | static void |
1750 | print_ipfix_stat(struct ds *string, const char *leader, uint64_t stat, int more) | |
1751 | { | |
1752 | ds_put_cstr(string, leader); | |
1753 | if (stat != UINT64_MAX) { | |
1754 | ds_put_format(string, "%"PRIu64, stat); | |
1755 | } else { | |
1756 | ds_put_char(string, '?'); | |
1757 | } | |
1758 | if (more) { | |
1759 | ds_put_cstr(string, ", "); | |
1760 | } else { | |
1761 | ds_put_cstr(string, "\n"); | |
1762 | } | |
1763 | } | |
1764 | ||
2d071a32 | 1765 | static enum ofperr |
fb8f22c1 BY |
1766 | ofp_print_nxst_ipfix_bridge_reply(struct ds *string, const struct ofp_header *oh) |
1767 | { | |
1768 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); | |
1769 | for (;;) { | |
1770 | struct ofputil_ipfix_stats is; | |
1771 | int retval; | |
1772 | ||
1773 | retval = ofputil_pull_ipfix_stats(&is, &b); | |
1774 | if (retval) { | |
2d071a32 | 1775 | return retval != EOF ? retval : 0; |
fb8f22c1 BY |
1776 | } |
1777 | ||
1778 | ds_put_cstr(string, "\n bridge ipfix: "); | |
1779 | print_ipfix_stat(string, "flows=", is.total_flows, 1); | |
1780 | print_ipfix_stat(string, "current flows=", is.current_flows, 1); | |
1781 | print_ipfix_stat(string, "sampled pkts=", is.pkts, 1); | |
1782 | print_ipfix_stat(string, "ipv4 ok=", is.ipv4_pkts, 1); | |
1783 | print_ipfix_stat(string, "ipv6 ok=", is.ipv6_pkts, 1); | |
1784 | print_ipfix_stat(string, "tx pkts=", is.tx_pkts, 0); | |
1785 | ds_put_cstr(string, " "); | |
1786 | print_ipfix_stat(string, "pkts errs=", is.error_pkts, 1); | |
1787 | print_ipfix_stat(string, "ipv4 errs=", is.ipv4_error_pkts, 1); | |
1788 | print_ipfix_stat(string, "ipv6 errs=", is.ipv6_error_pkts, 1); | |
1789 | print_ipfix_stat(string, "tx errs=", is.tx_errors, 0); | |
1790 | } | |
1791 | } | |
1792 | ||
2d071a32 | 1793 | static enum ofperr |
fb8f22c1 BY |
1794 | ofp_print_nxst_ipfix_flow_reply(struct ds *string, const struct ofp_header *oh) |
1795 | { | |
1796 | ds_put_format(string, " %"PRIuSIZE" ids\n", ofputil_count_ipfix_stats(oh)); | |
1797 | ||
1798 | struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); | |
1799 | for (;;) { | |
1800 | struct ofputil_ipfix_stats is; | |
1801 | int retval; | |
1802 | ||
1803 | retval = ofputil_pull_ipfix_stats(&is, &b); | |
1804 | if (retval) { | |
2d071a32 | 1805 | return retval != EOF ? retval : 0; |
fb8f22c1 BY |
1806 | } |
1807 | ||
1808 | ds_put_cstr(string, " id"); | |
1809 | ds_put_format(string, " %3"PRIuSIZE": ", (size_t) is.collector_set_id); | |
1810 | print_ipfix_stat(string, "flows=", is.total_flows, 1); | |
1811 | print_ipfix_stat(string, "current flows=", is.current_flows, 1); | |
1812 | print_ipfix_stat(string, "sampled pkts=", is.pkts, 1); | |
1813 | print_ipfix_stat(string, "ipv4 ok=", is.ipv4_pkts, 1); | |
1814 | print_ipfix_stat(string, "ipv6 ok=", is.ipv6_pkts, 1); | |
1815 | print_ipfix_stat(string, "tx pkts=", is.tx_pkts, 0); | |
1816 | ds_put_cstr(string, " "); | |
1817 | print_ipfix_stat(string, "pkts errs=", is.error_pkts, 1); | |
1818 | print_ipfix_stat(string, "ipv4 errs=", is.ipv4_error_pkts, 1); | |
1819 | print_ipfix_stat(string, "ipv6 errs=", is.ipv6_error_pkts, 1); | |
1820 | print_ipfix_stat(string, "tx errs=", is.tx_errors, 0); | |
1821 | } | |
1822 | } | |
1823 | ||
2d071a32 | 1824 | static enum ofperr |
2a7c4805 JP |
1825 | ofp_print_nxt_ct_flush_zone(struct ds *string, const struct nx_zone_id *nzi) |
1826 | { | |
1827 | ds_put_format(string, " zone_id=%"PRIu16, ntohs(nzi->zone_id)); | |
2d071a32 | 1828 | return 0; |
2a7c4805 JP |
1829 | } |
1830 | ||
2d071a32 | 1831 | static enum ofperr |
50f96b10 | 1832 | ofp_to_string__(const struct ofp_header *oh, |
4bc938cc BP |
1833 | const struct ofputil_port_map *port_map, |
1834 | const struct ofputil_table_map *table_map, enum ofpraw raw, | |
982697a4 | 1835 | struct ds *string, int verbosity) |
bdcc5925 | 1836 | { |
e428148a BP |
1837 | if (ofpmsg_is_stat(oh)) { |
1838 | ofp_print_stats(string, oh); | |
1839 | } | |
1840 | ||
bdcc5925 | 1841 | const void *msg = oh; |
904e5202 BP |
1842 | enum ofptype type = ofptype_from_ofpraw(raw); |
1843 | switch (type) { | |
261bd854 | 1844 | case OFPTYPE_GROUP_STATS_REQUEST: |
e9c9481f | 1845 | return ofputil_group_stats_request_format(string, oh); |
7395c052 | 1846 | |
261bd854 | 1847 | case OFPTYPE_GROUP_STATS_REPLY: |
e9c9481f | 1848 | return ofputil_group_stats_format(string, oh); |
7395c052 | 1849 | |
261bd854 | 1850 | case OFPTYPE_GROUP_DESC_STATS_REQUEST: |
e9c9481f | 1851 | return ofputil_group_desc_request_format(string, oh); |
7395c052 | 1852 | |
261bd854 | 1853 | case OFPTYPE_GROUP_DESC_STATS_REPLY: |
e9c9481f | 1854 | return ofputil_group_desc_format(string, oh, port_map, table_map); |
7395c052 | 1855 | |
261bd854 | 1856 | case OFPTYPE_GROUP_FEATURES_STATS_REQUEST: |
7395c052 NZ |
1857 | break; |
1858 | ||
261bd854 | 1859 | case OFPTYPE_GROUP_FEATURES_STATS_REPLY: |
e9c9481f | 1860 | return ofputil_group_features_format(string, oh); |
7395c052 NZ |
1861 | |
1862 | case OFPTYPE_GROUP_MOD: | |
e9c9481f | 1863 | return ofputil_group_mod_format(string, oh, port_map, table_map); |
7395c052 | 1864 | |
261bd854 BP |
1865 | case OFPTYPE_TABLE_FEATURES_STATS_REQUEST: |
1866 | case OFPTYPE_TABLE_FEATURES_STATS_REPLY: | |
4bc938cc | 1867 | return ofp_print_table_features_reply(string, oh, table_map); |
2e1ae200 | 1868 | |
03c72922 BP |
1869 | case OFPTYPE_TABLE_DESC_REQUEST: |
1870 | case OFPTYPE_TABLE_DESC_REPLY: | |
4bc938cc | 1871 | return ofp_print_table_desc_reply(string, oh, table_map); |
03c72922 | 1872 | |
982697a4 | 1873 | case OFPTYPE_HELLO: |
2d071a32 | 1874 | return ofp_print_hello(string, oh); |
d1e2cf21 | 1875 | |
982697a4 | 1876 | case OFPTYPE_ERROR: |
4bc938cc | 1877 | return ofp_print_error_msg(string, oh, port_map, table_map); |
d1e2cf21 | 1878 | |
982697a4 BP |
1879 | case OFPTYPE_ECHO_REQUEST: |
1880 | case OFPTYPE_ECHO_REPLY: | |
2d071a32 | 1881 | return ofp_print_echo(string, oh, verbosity); |
d1e2cf21 | 1882 | |
982697a4 | 1883 | case OFPTYPE_FEATURES_REQUEST: |
d1e2cf21 BP |
1884 | break; |
1885 | ||
982697a4 | 1886 | case OFPTYPE_FEATURES_REPLY: |
2d071a32 | 1887 | return ofp_print_switch_features(string, oh); |
d1e2cf21 | 1888 | |
982697a4 | 1889 | case OFPTYPE_GET_CONFIG_REQUEST: |
d1e2cf21 BP |
1890 | break; |
1891 | ||
982697a4 | 1892 | case OFPTYPE_GET_CONFIG_REPLY: |
2d071a32 | 1893 | return ofp_print_get_config_reply(string, oh); |
ad99e2ed | 1894 | |
982697a4 | 1895 | case OFPTYPE_SET_CONFIG: |
2d071a32 | 1896 | return ofp_print_set_config(string, oh); |
d1e2cf21 | 1897 | |
982697a4 | 1898 | case OFPTYPE_PACKET_IN: |
4bc938cc | 1899 | return ofp_print_packet_in(string, oh, port_map, table_map, verbosity); |
d1e2cf21 | 1900 | |
982697a4 | 1901 | case OFPTYPE_FLOW_REMOVED: |
4bc938cc | 1902 | return ofp_print_flow_removed(string, oh, port_map, table_map); |
d1e2cf21 | 1903 | |
982697a4 | 1904 | case OFPTYPE_PORT_STATUS: |
2d071a32 | 1905 | return ofp_print_port_status(string, oh); |
d1e2cf21 | 1906 | |
982697a4 | 1907 | case OFPTYPE_PACKET_OUT: |
4bc938cc BP |
1908 | return ofp_print_packet_out(string, oh, port_map, table_map, |
1909 | verbosity); | |
d1e2cf21 | 1910 | |
982697a4 | 1911 | case OFPTYPE_FLOW_MOD: |
dfc77282 BP |
1912 | return ofputil_flow_mod_format(string, oh, port_map, table_map, |
1913 | verbosity); | |
d1e2cf21 | 1914 | |
982697a4 | 1915 | case OFPTYPE_PORT_MOD: |
2d071a32 | 1916 | return ofp_print_port_mod(string, oh, port_map); |
d1e2cf21 | 1917 | |
918f2b82 | 1918 | case OFPTYPE_TABLE_MOD: |
4bc938cc | 1919 | return ofp_print_table_mod(string, oh, table_map); |
918f2b82 | 1920 | |
638a19b0 | 1921 | case OFPTYPE_METER_MOD: |
2d071a32 | 1922 | return ofp_print_meter_mod(string, oh); |
638a19b0 | 1923 | |
982697a4 BP |
1924 | case OFPTYPE_BARRIER_REQUEST: |
1925 | case OFPTYPE_BARRIER_REPLY: | |
d1e2cf21 BP |
1926 | break; |
1927 | ||
e8f9a7bb | 1928 | case OFPTYPE_QUEUE_GET_CONFIG_REQUEST: |
2d071a32 | 1929 | return ofp_print_queue_get_config_request(string, oh, port_map); |
e8f9a7bb VG |
1930 | |
1931 | case OFPTYPE_QUEUE_GET_CONFIG_REPLY: | |
2d071a32 | 1932 | return ofp_print_queue_get_config_reply(string, oh, port_map); |
e8f9a7bb | 1933 | |
6ea4776b JR |
1934 | case OFPTYPE_ROLE_REQUEST: |
1935 | case OFPTYPE_ROLE_REPLY: | |
2d071a32 | 1936 | return ofp_print_role_message(string, oh); |
252f3411 | 1937 | case OFPTYPE_ROLE_STATUS: |
2d071a32 | 1938 | return ofp_print_role_status_message(string, oh); |
6ea4776b | 1939 | |
3c35db62 | 1940 | case OFPTYPE_REQUESTFORWARD: |
4bc938cc | 1941 | return ofp_print_requestforward(string, oh, port_map, table_map); |
3c35db62 | 1942 | |
6c6eedc5 | 1943 | case OFPTYPE_TABLE_STATUS: |
4bc938cc | 1944 | return ofp_print_table_status_message(string, oh, table_map); |
6c6eedc5 | 1945 | |
261bd854 BP |
1946 | case OFPTYPE_METER_STATS_REQUEST: |
1947 | case OFPTYPE_METER_CONFIG_STATS_REQUEST: | |
2d071a32 | 1948 | return ofp_print_meter_stats_request(string, oh); |
638a19b0 | 1949 | |
261bd854 | 1950 | case OFPTYPE_METER_STATS_REPLY: |
2d071a32 | 1951 | return ofp_print_meter_stats_reply(string, oh); |
638a19b0 | 1952 | |
261bd854 | 1953 | case OFPTYPE_METER_CONFIG_STATS_REPLY: |
2d071a32 | 1954 | return ofp_print_meter_config_reply(string, oh); |
638a19b0 | 1955 | |
261bd854 | 1956 | case OFPTYPE_METER_FEATURES_STATS_REPLY: |
2d071a32 | 1957 | return ofp_print_meter_features_reply(string, oh); |
638a19b0 | 1958 | |
982697a4 | 1959 | case OFPTYPE_DESC_STATS_REQUEST: |
261bd854 | 1960 | case OFPTYPE_METER_FEATURES_STATS_REQUEST: |
d1e2cf21 BP |
1961 | break; |
1962 | ||
982697a4 BP |
1963 | case OFPTYPE_FLOW_STATS_REQUEST: |
1964 | case OFPTYPE_AGGREGATE_STATS_REQUEST: | |
4bc938cc | 1965 | return ofp_print_flow_stats_request(string, oh, port_map, table_map); |
d1e2cf21 | 1966 | |
982697a4 | 1967 | case OFPTYPE_TABLE_STATS_REQUEST: |
d1e2cf21 BP |
1968 | break; |
1969 | ||
982697a4 | 1970 | case OFPTYPE_PORT_STATS_REQUEST: |
2d071a32 | 1971 | return ofp_print_ofpst_port_request(string, oh, port_map); |
d1e2cf21 | 1972 | |
982697a4 | 1973 | case OFPTYPE_QUEUE_STATS_REQUEST: |
2d071a32 | 1974 | return ofp_print_ofpst_queue_request(string, oh, port_map); |
d1e2cf21 | 1975 | |
982697a4 | 1976 | case OFPTYPE_DESC_STATS_REPLY: |
2d071a32 | 1977 | return ofp_print_ofpst_desc_reply(string, oh); |
d1e2cf21 | 1978 | |
982697a4 | 1979 | case OFPTYPE_FLOW_STATS_REPLY: |
4bc938cc | 1980 | return ofp_print_flow_stats_reply(string, oh, port_map, table_map); |
d1e2cf21 | 1981 | |
982697a4 | 1982 | case OFPTYPE_QUEUE_STATS_REPLY: |
2d071a32 | 1983 | return ofp_print_ofpst_queue_reply(string, oh, port_map, verbosity); |
d1e2cf21 | 1984 | |
982697a4 | 1985 | case OFPTYPE_PORT_STATS_REPLY: |
2d071a32 | 1986 | return ofp_print_ofpst_port_reply(string, oh, port_map, verbosity); |
d1e2cf21 | 1987 | |
982697a4 | 1988 | case OFPTYPE_TABLE_STATS_REPLY: |
4bc938cc | 1989 | return ofp_print_table_stats_reply(string, oh, table_map); |
d1e2cf21 | 1990 | |
982697a4 | 1991 | case OFPTYPE_AGGREGATE_STATS_REPLY: |
2d071a32 | 1992 | return ofp_print_aggregate_stats_reply(string, oh); |
064af421 | 1993 | |
70ae4f93 | 1994 | case OFPTYPE_PORT_DESC_STATS_REQUEST: |
2d071a32 | 1995 | return ofp_print_ofpst_port_desc_request(string, oh, port_map); |
70ae4f93 | 1996 | |
982697a4 | 1997 | case OFPTYPE_PORT_DESC_STATS_REPLY: |
2d071a32 | 1998 | return ofp_print_ofpst_port_desc_reply(string, oh); |
2be393ed | 1999 | |
982697a4 | 2000 | case OFPTYPE_FLOW_MOD_TABLE_ID: |
225c33ba | 2001 | return ofp_print_nxt_flow_mod_table_id(string, oh); |
6c1491fb | 2002 | |
982697a4 | 2003 | case OFPTYPE_SET_FLOW_FORMAT: |
225c33ba | 2004 | return ofp_print_nxt_set_flow_format(string, oh); |
7fa91113 | 2005 | |
982697a4 | 2006 | case OFPTYPE_SET_PACKET_IN_FORMAT: |
d8790c08 | 2007 | return ofp_print_nxt_set_packet_in_format(string, oh); |
54834960 | 2008 | |
982697a4 | 2009 | case OFPTYPE_FLOW_AGE: |
f27f2134 BP |
2010 | break; |
2011 | ||
982697a4 | 2012 | case OFPTYPE_SET_CONTROLLER_ID: |
2d071a32 | 2013 | return ofp_print_nxt_set_controller_id(string, ofpmsg_body(oh)); |
a7349929 | 2014 | |
db09e430 | 2015 | case OFPTYPE_GET_ASYNC_REPLY: |
982697a4 | 2016 | case OFPTYPE_SET_ASYNC_CONFIG: |
2d071a32 | 2017 | return ofp_print_set_async_config(string, oh, type); |
db09e430 AC |
2018 | case OFPTYPE_GET_ASYNC_REQUEST: |
2019 | break; | |
982697a4 | 2020 | case OFPTYPE_FLOW_MONITOR_CANCEL: |
2d071a32 | 2021 | return ofp_print_nxt_flow_monitor_cancel(string, msg); |
2b07c8b1 | 2022 | |
982697a4 BP |
2023 | case OFPTYPE_FLOW_MONITOR_PAUSED: |
2024 | case OFPTYPE_FLOW_MONITOR_RESUMED: | |
2b07c8b1 BP |
2025 | break; |
2026 | ||
982697a4 | 2027 | case OFPTYPE_FLOW_MONITOR_STATS_REQUEST: |
4bc938cc BP |
2028 | return ofp_print_nxst_flow_monitor_request(string, msg, port_map, |
2029 | table_map); | |
2b07c8b1 | 2030 | |
982697a4 | 2031 | case OFPTYPE_FLOW_MONITOR_STATS_REPLY: |
4bc938cc BP |
2032 | return ofp_print_nxst_flow_monitor_reply(string, msg, port_map, |
2033 | table_map); | |
777af88d AC |
2034 | |
2035 | case OFPTYPE_BUNDLE_CONTROL: | |
2d071a32 | 2036 | return ofp_print_bundle_ctrl(string, msg); |
777af88d AC |
2037 | |
2038 | case OFPTYPE_BUNDLE_ADD_MESSAGE: | |
4bc938cc BP |
2039 | return ofp_print_bundle_add(string, msg, port_map, table_map, |
2040 | verbosity); | |
6159c531 | 2041 | |
4e548ad9 | 2042 | case OFPTYPE_NXT_TLV_TABLE_MOD: |
2d071a32 | 2043 | return ofp_print_tlv_table_mod(string, msg); |
6159c531 | 2044 | |
4e548ad9 | 2045 | case OFPTYPE_NXT_TLV_TABLE_REQUEST: |
6159c531 JG |
2046 | break; |
2047 | ||
4e548ad9 | 2048 | case OFPTYPE_NXT_TLV_TABLE_REPLY: |
2d071a32 | 2049 | return ofp_print_tlv_table_reply(string, msg); |
6159c531 | 2050 | |
77ab5fd2 | 2051 | case OFPTYPE_NXT_RESUME: |
4bc938cc BP |
2052 | return ofp_print_packet_in(string, msg, port_map, table_map, |
2053 | verbosity); | |
fb8f22c1 BY |
2054 | case OFPTYPE_IPFIX_BRIDGE_STATS_REQUEST: |
2055 | break; | |
2056 | case OFPTYPE_IPFIX_BRIDGE_STATS_REPLY: | |
2d071a32 | 2057 | return ofp_print_nxst_ipfix_bridge_reply(string, oh); |
fb8f22c1 BY |
2058 | case OFPTYPE_IPFIX_FLOW_STATS_REQUEST: |
2059 | break; | |
2060 | case OFPTYPE_IPFIX_FLOW_STATS_REPLY: | |
2d071a32 | 2061 | return ofp_print_nxst_ipfix_flow_reply(string, oh); |
2a7c4805 JP |
2062 | |
2063 | case OFPTYPE_CT_FLUSH_ZONE: | |
2d071a32 BP |
2064 | return ofp_print_nxt_ct_flush_zone(string, ofpmsg_body(oh)); |
2065 | } | |
2066 | ||
2067 | return 0; | |
2068 | } | |
2069 | ||
2070 | static void | |
2071 | add_newline(struct ds *s) | |
2072 | { | |
2073 | if (s->length && s->string[s->length - 1] != '\n') { | |
2074 | ds_put_char(s, '\n'); | |
246e61ea | 2075 | } |
d1e2cf21 | 2076 | } |
064af421 BP |
2077 | |
2078 | /* Composes and returns a string representing the OpenFlow packet of 'len' | |
2079 | * bytes at 'oh' at the given 'verbosity' level. 0 is a minimal amount of | |
2080 | * verbosity and higher numbers increase verbosity. The caller is responsible | |
2081 | * for freeing the string. */ | |
2082 | char * | |
50f96b10 | 2083 | ofp_to_string(const void *oh_, size_t len, |
4bc938cc BP |
2084 | const struct ofputil_port_map *port_map, |
2085 | const struct ofputil_table_map *table_map, | |
2086 | int verbosity) | |
064af421 BP |
2087 | { |
2088 | struct ds string = DS_EMPTY_INITIALIZER; | |
2089 | const struct ofp_header *oh = oh_; | |
064af421 | 2090 | |
49ad0403 BP |
2091 | if (!len) { |
2092 | ds_put_cstr(&string, "OpenFlow message is empty\n"); | |
2093 | } else if (len < sizeof(struct ofp_header)) { | |
34582733 | 2094 | ds_put_format(&string, "OpenFlow packet too short (only %"PRIuSIZE" bytes):\n", |
49ad0403 | 2095 | len); |
d1e2cf21 | 2096 | } else if (ntohs(oh->length) > len) { |
f25b4a81 | 2097 | enum ofperr error; |
982697a4 | 2098 | enum ofpraw raw; |
f25b4a81 | 2099 | |
982697a4 | 2100 | error = ofpraw_decode_partial(&raw, oh, len); |
f25b4a81 | 2101 | if (!error) { |
982697a4 | 2102 | ofp_header_to_string__(oh, raw, &string); |
f25b4a81 BP |
2103 | ds_put_char(&string, '\n'); |
2104 | } | |
2105 | ||
d1e2cf21 | 2106 | ds_put_format(&string, |
34582733 | 2107 | "(***truncated to %"PRIuSIZE" bytes from %"PRIu16"***)\n", |
d1e2cf21 BP |
2108 | len, ntohs(oh->length)); |
2109 | } else if (ntohs(oh->length) < len) { | |
2110 | ds_put_format(&string, | |
34582733 | 2111 | "(***only uses %"PRIu16" bytes out of %"PRIuSIZE"***)\n", |
d1e2cf21 BP |
2112 | ntohs(oh->length), len); |
2113 | } else { | |
90bf1e07 | 2114 | enum ofperr error; |
982697a4 | 2115 | enum ofpraw raw; |
d1e2cf21 | 2116 | |
982697a4 | 2117 | error = ofpraw_decode(&raw, oh); |
d1e2cf21 | 2118 | if (!error) { |
2d071a32 BP |
2119 | ofp_header_to_string__(oh, raw, &string); |
2120 | size_t header_len = string.length; | |
2121 | ||
4bc938cc BP |
2122 | error = ofp_to_string__(oh, port_map, table_map, |
2123 | raw, &string, verbosity); | |
2d071a32 BP |
2124 | if (error) { |
2125 | if (string.length > header_len) { | |
2126 | ds_chomp(&string, ' '); | |
2127 | add_newline(&string); | |
2128 | } else { | |
2129 | ds_put_char(&string, ' '); | |
7fa91113 | 2130 | } |
2d071a32 BP |
2131 | ofp_print_error(&string, error); |
2132 | } else { | |
2133 | ds_chomp(&string, ' '); | |
d1e2cf21 | 2134 | } |
2d071a32 BP |
2135 | } else { |
2136 | ofp_print_error(&string, error); | |
2137 | } | |
2138 | ||
2139 | if (verbosity >= 5 || error) { | |
2140 | add_newline(&string); | |
2141 | ds_put_hex_dump(&string, oh, len, 0, true); | |
064af421 | 2142 | } |
064af421 | 2143 | |
2d071a32 BP |
2144 | add_newline(&string); |
2145 | return ds_steal_cstr(&string); | |
064af421 | 2146 | } |
d1e2cf21 BP |
2147 | ds_put_hex_dump(&string, oh, len, 0, true); |
2148 | return ds_steal_cstr(&string); | |
064af421 | 2149 | } |
064af421 BP |
2150 | \f |
2151 | static void | |
d295e8e9 | 2152 | print_and_free(FILE *stream, char *string) |
064af421 BP |
2153 | { |
2154 | fputs(string, stream); | |
2155 | free(string); | |
2156 | } | |
2157 | ||
2158 | /* Pretty-print the OpenFlow packet of 'len' bytes at 'oh' to 'stream' at the | |
2159 | * given 'verbosity' level. 0 is a minimal amount of verbosity and higher | |
2160 | * numbers increase verbosity. */ | |
2161 | void | |
50f96b10 | 2162 | ofp_print(FILE *stream, const void *oh, size_t len, |
4bc938cc BP |
2163 | const struct ofputil_port_map *port_map, |
2164 | const struct ofputil_table_map *table_map, int verbosity) | |
064af421 | 2165 | { |
4bc938cc BP |
2166 | print_and_free(stream, ofp_to_string(oh, len, port_map, table_map, |
2167 | verbosity)); | |
064af421 BP |
2168 | } |
2169 | ||
2170 | /* Dumps the contents of the Ethernet frame in the 'len' bytes starting at | |
897a8e07 | 2171 | * 'data' to 'stream'. */ |
064af421 | 2172 | void |
2482b0b0 JS |
2173 | ofp_print_packet(FILE *stream, const void *data, size_t len, |
2174 | ovs_be32 packet_type) | |
2175 | { | |
2176 | print_and_free(stream, ofp_packet_to_string(data, len, packet_type)); | |
2177 | } | |
2178 | ||
2179 | void | |
2180 | ofp_print_dp_packet(FILE *stream, const struct dp_packet *packet) | |
064af421 | 2181 | { |
2482b0b0 | 2182 | print_and_free(stream, ofp_dp_packet_to_string(packet)); |
064af421 | 2183 | } |