]> git.proxmox.com Git - ovs.git/blob - lib/ofp-monitor.c
compat: Add ipv6 GRE and IPV6 Tunneling
[ovs.git] / lib / ofp-monitor.c
1 /*
2 * Copyright (c) 2008-2017 Nicira, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <config.h>
18 #include "openvswitch/ofp-monitor.h"
19 #include "byte-order.h"
20 #include "nx-match.h"
21 #include "ovs-atomic.h"
22 #include "openvswitch/ofp-actions.h"
23 #include "openvswitch/ofp-errors.h"
24 #include "openvswitch/ofp-group.h"
25 #include "openvswitch/ofp-match.h"
26 #include "openvswitch/ofp-meter.h"
27 #include "openvswitch/ofp-msgs.h"
28 #include "openvswitch/ofp-parse.h"
29 #include "openvswitch/ofp-print.h"
30 #include "openvswitch/ofp-table.h"
31 #include "openvswitch/vlog.h"
32 #include "ox-stat.h"
33
34 VLOG_DEFINE_THIS_MODULE(ofp_monitor);
35
36 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
37
38 /* Returns a string form of 'reason'. The return value is either a statically
39 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
40 * 'bufsize' should be at least OFP_FLOW_REMOVED_REASON_BUFSIZE. */
41 #define OFP_FLOW_REMOVED_REASON_BUFSIZE (INT_STRLEN(int) + 1)
42 const char *
43 ofp_flow_removed_reason_to_string(enum ofp_flow_removed_reason reason,
44 char *reasonbuf, size_t bufsize)
45 {
46 switch (reason) {
47 case OFPRR_IDLE_TIMEOUT:
48 return "idle";
49 case OFPRR_HARD_TIMEOUT:
50 return "hard";
51 case OFPRR_DELETE:
52 return "delete";
53 case OFPRR_GROUP_DELETE:
54 return "group_delete";
55 case OFPRR_EVICTION:
56 return "eviction";
57 case OFPRR_METER_DELETE:
58 return "meter_delete";
59 case OVS_OFPRR_NONE:
60 default:
61 snprintf(reasonbuf, bufsize, "%d", (int) reason);
62 return reasonbuf;
63 }
64 }
65
66 /* Converts an OFPT_FLOW_REMOVED or NXT_FLOW_REMOVED message 'oh' into an
67 * abstract ofputil_flow_removed in 'fr'. Returns 0 if successful, otherwise
68 * an OpenFlow error code. */
69 enum ofperr
70 ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
71 const struct ofp_header *oh)
72 {
73 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
74 enum ofpraw raw = ofpraw_pull_assert(&b);
75 if (raw == OFPRAW_OFPT15_FLOW_REMOVED) {
76 const struct ofp15_flow_removed *ofr;
77 enum ofperr error;
78
79 ofr = ofpbuf_pull(&b, sizeof *ofr);
80
81 error = ofputil_pull_ofp11_match(&b, NULL, NULL, &fr->match, NULL);
82 if (error) {
83 return error;
84 }
85
86 struct oxs_stats stats;
87 uint16_t statlen;
88 uint8_t oxs_field_set;
89 error = oxs_pull_stat(&b, &stats, &statlen, &oxs_field_set);
90 if (error) {
91 return error;
92 }
93
94 fr->cookie = ofr->cookie;
95 fr->priority = ntohs(ofr->priority);
96 fr->reason = ofr->reason;
97 fr->table_id = ofr->table_id;
98 fr->duration_sec = stats.duration_sec;
99 fr->duration_nsec = stats.duration_nsec;
100 fr->idle_timeout = ntohs(ofr->idle_timeout);
101 fr->hard_timeout = ntohs(ofr->hard_timeout);
102 fr->packet_count = stats.packet_count;
103 fr->byte_count = stats.byte_count;
104 } else if (raw == OFPRAW_OFPT11_FLOW_REMOVED) {
105 const struct ofp12_flow_removed *ofr;
106 enum ofperr error;
107
108 ofr = ofpbuf_pull(&b, sizeof *ofr);
109
110 error = ofputil_pull_ofp11_match(&b, NULL, NULL, &fr->match, NULL);
111 if (error) {
112 return error;
113 }
114
115 fr->priority = ntohs(ofr->priority);
116 fr->cookie = ofr->cookie;
117 fr->reason = ofr->reason;
118 fr->table_id = ofr->table_id;
119 fr->duration_sec = ntohl(ofr->duration_sec);
120 fr->duration_nsec = ntohl(ofr->duration_nsec);
121 fr->idle_timeout = ntohs(ofr->idle_timeout);
122 fr->hard_timeout = ntohs(ofr->hard_timeout);
123 fr->packet_count = ntohll(ofr->packet_count);
124 fr->byte_count = ntohll(ofr->byte_count);
125 } else if (raw == OFPRAW_OFPT10_FLOW_REMOVED) {
126 const struct ofp10_flow_removed *ofr;
127
128 ofr = ofpbuf_pull(&b, sizeof *ofr);
129
130 ofputil_match_from_ofp10_match(&ofr->match, &fr->match);
131 fr->priority = ntohs(ofr->priority);
132 fr->cookie = ofr->cookie;
133 fr->reason = ofr->reason;
134 fr->table_id = 255;
135 fr->duration_sec = ntohl(ofr->duration_sec);
136 fr->duration_nsec = ntohl(ofr->duration_nsec);
137 fr->idle_timeout = ntohs(ofr->idle_timeout);
138 fr->hard_timeout = 0;
139 fr->packet_count = ntohll(ofr->packet_count);
140 fr->byte_count = ntohll(ofr->byte_count);
141 } else if (raw == OFPRAW_NXT_FLOW_REMOVED) {
142 struct nx_flow_removed *nfr;
143 enum ofperr error;
144
145 nfr = ofpbuf_pull(&b, sizeof *nfr);
146 error = nx_pull_match(&b, ntohs(nfr->match_len), &fr->match, NULL,
147 NULL, false, NULL, NULL);
148 if (error) {
149 return error;
150 }
151 if (b.size) {
152 return OFPERR_OFPBRC_BAD_LEN;
153 }
154
155 fr->priority = ntohs(nfr->priority);
156 fr->cookie = nfr->cookie;
157 fr->reason = nfr->reason;
158 fr->table_id = nfr->table_id ? nfr->table_id - 1 : 255;
159 fr->duration_sec = ntohl(nfr->duration_sec);
160 fr->duration_nsec = ntohl(nfr->duration_nsec);
161 fr->idle_timeout = ntohs(nfr->idle_timeout);
162 fr->hard_timeout = 0;
163 fr->packet_count = ntohll(nfr->packet_count);
164 fr->byte_count = ntohll(nfr->byte_count);
165 } else {
166 OVS_NOT_REACHED();
167 }
168
169 return 0;
170 }
171
172 /* Returns 'count' unchanged except that UINT64_MAX becomes 0.
173 *
174 * We use this in situations where OVS internally uses UINT64_MAX to mean
175 * "value unknown" but OpenFlow 1.0 does not define any unknown value. */
176 static uint64_t
177 unknown_to_zero(uint64_t count)
178 {
179 return count != UINT64_MAX ? count : 0;
180 }
181
182 /* Converts abstract ofputil_flow_removed 'fr' into an OFPT_FLOW_REMOVED or
183 * NXT_FLOW_REMOVED message 'oh' according to 'protocol', and returns the
184 * message. */
185 struct ofpbuf *
186 ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
187 enum ofputil_protocol protocol)
188 {
189 struct ofpbuf *msg;
190 enum ofp_flow_removed_reason reason = fr->reason;
191
192 if (reason == OFPRR_METER_DELETE && !(protocol & OFPUTIL_P_OF14_UP)) {
193 reason = OFPRR_DELETE;
194 }
195
196 switch (protocol) {
197 case OFPUTIL_P_OF11_STD:
198 case OFPUTIL_P_OF12_OXM:
199 case OFPUTIL_P_OF13_OXM:
200 case OFPUTIL_P_OF14_OXM: {
201 struct ofp12_flow_removed *ofr;
202
203 msg = ofpraw_alloc_xid(OFPRAW_OFPT11_FLOW_REMOVED,
204 ofputil_protocol_to_ofp_version(protocol),
205 htonl(0),
206 ofputil_match_typical_len(protocol));
207 ofr = ofpbuf_put_zeros(msg, sizeof *ofr);
208 ofr->cookie = fr->cookie;
209 ofr->priority = htons(fr->priority);
210 ofr->reason = reason;
211 ofr->table_id = fr->table_id;
212 ofr->duration_sec = htonl(fr->duration_sec);
213 ofr->duration_nsec = htonl(fr->duration_nsec);
214 ofr->idle_timeout = htons(fr->idle_timeout);
215 ofr->hard_timeout = htons(fr->hard_timeout);
216 ofr->packet_count = htonll(fr->packet_count);
217 ofr->byte_count = htonll(fr->byte_count);
218 ofputil_put_ofp11_match(msg, &fr->match, protocol);
219 break;
220 }
221 case OFPUTIL_P_OF15_OXM:
222 case OFPUTIL_P_OF16_OXM: {
223 struct ofp15_flow_removed *ofr;
224
225 msg = ofpraw_alloc_xid(OFPRAW_OFPT15_FLOW_REMOVED,
226 ofputil_protocol_to_ofp_version(protocol),
227 htonl(0),
228 ofputil_match_typical_len(protocol));
229 ofr = ofpbuf_put_zeros(msg, sizeof *ofr);
230 ofr->cookie = fr->cookie;
231 ofr->priority = htons(fr->priority);
232 ofr->reason = reason;
233 ofr->table_id = fr->table_id;
234 ofr->idle_timeout = htons(fr->idle_timeout);
235 ofr->hard_timeout = htons(fr->hard_timeout);
236 ofputil_put_ofp11_match(msg, &fr->match, protocol);
237
238 const struct oxs_stats oxs = {
239 .duration_sec = fr->duration_sec,
240 .duration_nsec = fr->duration_nsec,
241 .idle_age = UINT32_MAX,
242 .packet_count = fr->packet_count,
243 .byte_count = fr->byte_count,
244 .flow_count = UINT32_MAX,
245 };
246 oxs_put_stats(msg, &oxs);
247 break;
248 }
249 case OFPUTIL_P_OF10_STD:
250 case OFPUTIL_P_OF10_STD_TID: {
251 struct ofp10_flow_removed *ofr;
252
253 msg = ofpraw_alloc_xid(OFPRAW_OFPT10_FLOW_REMOVED, OFP10_VERSION,
254 htonl(0), 0);
255 ofr = ofpbuf_put_zeros(msg, sizeof *ofr);
256 ofputil_match_to_ofp10_match(&fr->match, &ofr->match);
257 ofr->cookie = fr->cookie;
258 ofr->priority = htons(fr->priority);
259 ofr->reason = reason;
260 ofr->duration_sec = htonl(fr->duration_sec);
261 ofr->duration_nsec = htonl(fr->duration_nsec);
262 ofr->idle_timeout = htons(fr->idle_timeout);
263 ofr->packet_count = htonll(unknown_to_zero(fr->packet_count));
264 ofr->byte_count = htonll(unknown_to_zero(fr->byte_count));
265 break;
266 }
267
268 case OFPUTIL_P_OF10_NXM:
269 case OFPUTIL_P_OF10_NXM_TID: {
270 struct nx_flow_removed *nfr;
271 int match_len;
272
273 msg = ofpraw_alloc_xid(OFPRAW_NXT_FLOW_REMOVED, OFP10_VERSION,
274 htonl(0), NXM_TYPICAL_LEN);
275 ofpbuf_put_zeros(msg, sizeof *nfr);
276 match_len = nx_put_match(msg, &fr->match, 0, 0);
277
278 nfr = msg->msg;
279 nfr->cookie = fr->cookie;
280 nfr->priority = htons(fr->priority);
281 nfr->reason = reason;
282 nfr->table_id = fr->table_id + 1;
283 nfr->duration_sec = htonl(fr->duration_sec);
284 nfr->duration_nsec = htonl(fr->duration_nsec);
285 nfr->idle_timeout = htons(fr->idle_timeout);
286 nfr->match_len = htons(match_len);
287 nfr->packet_count = htonll(fr->packet_count);
288 nfr->byte_count = htonll(fr->byte_count);
289 break;
290 }
291
292 default:
293 OVS_NOT_REACHED();
294 }
295
296 return msg;
297 }
298
299 void
300 ofputil_flow_removed_format(struct ds *s,
301 const struct ofputil_flow_removed *fr,
302 const struct ofputil_port_map *port_map,
303 const struct ofputil_table_map *table_map)
304 {
305 char reasonbuf[OFP_FLOW_REMOVED_REASON_BUFSIZE];
306
307 ds_put_char(s, ' ');
308 match_format(&fr->match, port_map, s, fr->priority);
309
310 ds_put_format(s, " reason=%s",
311 ofp_flow_removed_reason_to_string(fr->reason, reasonbuf,
312 sizeof reasonbuf));
313
314 if (fr->table_id != 255) {
315 ds_put_format(s, " table_id=");
316 ofputil_format_table(fr->table_id, table_map, s);
317 }
318
319 if (fr->cookie != htonll(0)) {
320 ds_put_format(s, " cookie:0x%"PRIx64, ntohll(fr->cookie));
321 }
322 ds_put_cstr(s, " duration");
323 ofp_print_duration(s, fr->duration_sec, fr->duration_nsec);
324 ds_put_format(s, " idle%"PRIu16, fr->idle_timeout);
325 if (fr->hard_timeout) {
326 /* The hard timeout was only added in OF1.2, so only print it if it is
327 * actually in use to avoid gratuitous change to the formatting. */
328 ds_put_format(s, " hard%"PRIu16, fr->hard_timeout);
329 }
330 ds_put_format(s, " pkts%"PRIu64" bytes%"PRIu64"\n",
331 fr->packet_count, fr->byte_count);
332 }
333 \f
334 /* ofputil_flow_monitor_request */
335
336 /* Converts an NXST_FLOW_MONITOR request in 'msg' into an abstract
337 * ofputil_flow_monitor_request in 'rq'.
338 *
339 * Multiple NXST_FLOW_MONITOR requests can be packed into a single OpenFlow
340 * message. Calling this function multiple times for a single 'msg' iterates
341 * through the requests. The caller must initially leave 'msg''s layer
342 * pointers null and not modify them between calls.
343 *
344 * Returns 0 if successful, EOF if no requests were left in this 'msg',
345 * otherwise an OFPERR_* value. */
346 int
347 ofputil_decode_flow_monitor_request(struct ofputil_flow_monitor_request *rq,
348 struct ofpbuf *msg)
349 {
350 struct nx_flow_monitor_request *nfmr;
351 uint16_t flags;
352
353 if (!msg->header) {
354 ofpraw_pull_assert(msg);
355 }
356
357 if (!msg->size) {
358 return EOF;
359 }
360
361 nfmr = ofpbuf_try_pull(msg, sizeof *nfmr);
362 if (!nfmr) {
363 VLOG_WARN_RL(&rl, "NXST_FLOW_MONITOR request has %"PRIu32" "
364 "leftover bytes at end", msg->size);
365 return OFPERR_OFPBRC_BAD_LEN;
366 }
367
368 flags = ntohs(nfmr->flags);
369 if (!(flags & (NXFMF_ADD | NXFMF_DELETE | NXFMF_MODIFY))
370 || flags & ~(NXFMF_INITIAL | NXFMF_ADD | NXFMF_DELETE
371 | NXFMF_MODIFY | NXFMF_ACTIONS | NXFMF_OWN)) {
372 VLOG_WARN_RL(&rl, "NXST_FLOW_MONITOR has bad flags %#"PRIx16, flags);
373 return OFPERR_OFPMOFC_BAD_FLAGS;
374 }
375
376 if (!is_all_zeros(nfmr->zeros, sizeof nfmr->zeros)) {
377 return OFPERR_NXBRC_MUST_BE_ZERO;
378 }
379
380 rq->id = ntohl(nfmr->id);
381 rq->flags = flags;
382 rq->out_port = u16_to_ofp(ntohs(nfmr->out_port));
383 rq->table_id = nfmr->table_id;
384
385 return nx_pull_match(msg, ntohs(nfmr->match_len), &rq->match, NULL,
386 NULL, false, NULL, NULL);
387 }
388
389 void
390 ofputil_append_flow_monitor_request(
391 const struct ofputil_flow_monitor_request *rq, struct ofpbuf *msg)
392 {
393 struct nx_flow_monitor_request *nfmr;
394 size_t start_ofs;
395 int match_len;
396
397 if (!msg->size) {
398 ofpraw_put(OFPRAW_NXST_FLOW_MONITOR_REQUEST, OFP10_VERSION, msg);
399 }
400
401 start_ofs = msg->size;
402 ofpbuf_put_zeros(msg, sizeof *nfmr);
403 match_len = nx_put_match(msg, &rq->match, htonll(0), htonll(0));
404
405 nfmr = ofpbuf_at_assert(msg, start_ofs, sizeof *nfmr);
406 nfmr->id = htonl(rq->id);
407 nfmr->flags = htons(rq->flags);
408 nfmr->out_port = htons(ofp_to_u16(rq->out_port));
409 nfmr->match_len = htons(match_len);
410 nfmr->table_id = rq->table_id;
411 }
412
413 static const char *
414 nx_flow_monitor_flags_to_name(uint32_t bit)
415 {
416 enum nx_flow_monitor_flags fmf = bit;
417
418 switch (fmf) {
419 case NXFMF_INITIAL: return "initial";
420 case NXFMF_ADD: return "add";
421 case NXFMF_DELETE: return "delete";
422 case NXFMF_MODIFY: return "modify";
423 case NXFMF_ACTIONS: return "actions";
424 case NXFMF_OWN: return "own";
425 }
426
427 return NULL;
428 }
429
430 void
431 ofputil_flow_monitor_request_format(
432 struct ds *s, const struct ofputil_flow_monitor_request *request,
433 const struct ofputil_port_map *port_map,
434 const struct ofputil_table_map *table_map)
435 {
436 ds_put_format(s, "\n id=%"PRIu32" flags=", request->id);
437 ofp_print_bit_names(s, request->flags, nx_flow_monitor_flags_to_name, ',');
438
439 if (request->out_port != OFPP_NONE) {
440 ds_put_cstr(s, " out_port=");
441 ofputil_format_port(request->out_port, port_map, s);
442 }
443
444 if (request->table_id != 0xff) {
445 ds_put_format(s, " table=");
446 ofputil_format_table(request->table_id, table_map, s);
447 }
448
449 ds_put_char(s, ' ');
450 match_format(&request->match, port_map, s, OFP_DEFAULT_PRIORITY);
451 ds_chomp(s, ' ');
452 }
453
454 static char * OVS_WARN_UNUSED_RESULT
455 parse_flow_monitor_request__(struct ofputil_flow_monitor_request *fmr,
456 const char *str_,
457 const struct ofputil_port_map *port_map,
458 const struct ofputil_table_map *table_map,
459 char *string,
460 enum ofputil_protocol *usable_protocols)
461 {
462 static atomic_count id = ATOMIC_COUNT_INIT(0);
463 char *name, *value;
464
465 fmr->id = atomic_count_inc(&id);
466
467 fmr->flags = (NXFMF_INITIAL | NXFMF_ADD | NXFMF_DELETE | NXFMF_MODIFY
468 | NXFMF_OWN | NXFMF_ACTIONS);
469 fmr->out_port = OFPP_NONE;
470 fmr->table_id = 0xff;
471 match_init_catchall(&fmr->match);
472
473 while (ofputil_parse_key_value(&string, &name, &value)) {
474 const struct ofp_protocol *p;
475 char *error = NULL;
476
477 if (!strcmp(name, "!initial")) {
478 fmr->flags &= ~NXFMF_INITIAL;
479 } else if (!strcmp(name, "!add")) {
480 fmr->flags &= ~NXFMF_ADD;
481 } else if (!strcmp(name, "!delete")) {
482 fmr->flags &= ~NXFMF_DELETE;
483 } else if (!strcmp(name, "!modify")) {
484 fmr->flags &= ~NXFMF_MODIFY;
485 } else if (!strcmp(name, "!actions")) {
486 fmr->flags &= ~NXFMF_ACTIONS;
487 } else if (!strcmp(name, "!own")) {
488 fmr->flags &= ~NXFMF_OWN;
489 } else if (ofp_parse_protocol(name, &p)) {
490 match_set_dl_type(&fmr->match, htons(p->dl_type));
491 if (p->nw_proto) {
492 match_set_nw_proto(&fmr->match, p->nw_proto);
493 }
494 } else if (mf_from_name(name)) {
495 error = ofp_parse_field(mf_from_name(name), value, port_map,
496 &fmr->match, usable_protocols);
497 } else {
498 if (!*value) {
499 return xasprintf("%s: field %s missing value", str_, name);
500 }
501
502 if (!strcmp(name, "table")) {
503 if (!ofputil_table_from_string(value, table_map,
504 &fmr->table_id)) {
505 error = xasprintf("unknown table \"%s\"", value);
506 }
507 } else if (!strcmp(name, "out_port")) {
508 fmr->out_port = u16_to_ofp(atoi(value));
509 } else {
510 return xasprintf("%s: unknown keyword %s", str_, name);
511 }
512 }
513
514 if (error) {
515 return error;
516 }
517 }
518 return NULL;
519 }
520
521 /* Convert 'str_' (as described in the documentation for the "monitor" command
522 * in the ovs-ofctl man page) into 'fmr'.
523 *
524 * Returns NULL if successful, otherwise a malloc()'d string describing the
525 * error. The caller is responsible for freeing the returned string. */
526 char * OVS_WARN_UNUSED_RESULT
527 parse_flow_monitor_request(struct ofputil_flow_monitor_request *fmr,
528 const char *str_,
529 const struct ofputil_port_map *port_map,
530 const struct ofputil_table_map *table_map,
531 enum ofputil_protocol *usable_protocols)
532 {
533 char *string = xstrdup(str_);
534 char *error = parse_flow_monitor_request__(fmr, str_, port_map, table_map,
535 string, usable_protocols);
536 free(string);
537 return error;
538 }
539
540 /* Converts an NXST_FLOW_MONITOR reply (also known as a flow update) in 'msg'
541 * into an abstract ofputil_flow_update in 'update'. The caller must have
542 * initialized update->match to point to space allocated for a match.
543 *
544 * Uses 'ofpacts' to store the abstract OFPACT_* version of the update's
545 * actions (except for NXFME_ABBREV, which never includes actions). The caller
546 * must initialize 'ofpacts' and retains ownership of it. 'update->ofpacts'
547 * will point into the 'ofpacts' buffer.
548 *
549 * Multiple flow updates can be packed into a single OpenFlow message. Calling
550 * this function multiple times for a single 'msg' iterates through the
551 * updates. The caller must initially leave 'msg''s layer pointers null and
552 * not modify them between calls.
553 *
554 * Returns 0 if successful, EOF if no updates were left in this 'msg',
555 * otherwise an OFPERR_* value. */
556 int
557 ofputil_decode_flow_update(struct ofputil_flow_update *update,
558 struct ofpbuf *msg, struct ofpbuf *ofpacts)
559 {
560 struct nx_flow_update_header *nfuh;
561 unsigned int length;
562 struct ofp_header *oh;
563
564 if (!msg->header) {
565 ofpraw_pull_assert(msg);
566 }
567
568 ofpbuf_clear(ofpacts);
569 if (!msg->size) {
570 return EOF;
571 }
572
573 if (msg->size < sizeof(struct nx_flow_update_header)) {
574 goto bad_len;
575 }
576
577 oh = msg->header;
578
579 nfuh = msg->data;
580 update->event = ntohs(nfuh->event);
581 length = ntohs(nfuh->length);
582 if (length > msg->size || length % 8) {
583 goto bad_len;
584 }
585
586 if (update->event == NXFME_ABBREV) {
587 struct nx_flow_update_abbrev *nfua;
588
589 if (length != sizeof *nfua) {
590 goto bad_len;
591 }
592
593 nfua = ofpbuf_pull(msg, sizeof *nfua);
594 update->xid = nfua->xid;
595 return 0;
596 } else if (update->event == NXFME_ADDED
597 || update->event == NXFME_DELETED
598 || update->event == NXFME_MODIFIED) {
599 struct nx_flow_update_full *nfuf;
600 unsigned int actions_len;
601 unsigned int match_len;
602 enum ofperr error;
603
604 if (length < sizeof *nfuf) {
605 goto bad_len;
606 }
607
608 nfuf = ofpbuf_pull(msg, sizeof *nfuf);
609 match_len = ntohs(nfuf->match_len);
610 if (sizeof *nfuf + match_len > length) {
611 goto bad_len;
612 }
613
614 update->reason = ntohs(nfuf->reason);
615 update->idle_timeout = ntohs(nfuf->idle_timeout);
616 update->hard_timeout = ntohs(nfuf->hard_timeout);
617 update->table_id = nfuf->table_id;
618 update->cookie = nfuf->cookie;
619 update->priority = ntohs(nfuf->priority);
620
621 error = nx_pull_match(msg, match_len, &update->match, NULL, NULL,
622 false, NULL, NULL);
623 if (error) {
624 return error;
625 }
626
627 actions_len = length - sizeof *nfuf - ROUND_UP(match_len, 8);
628 error = ofpacts_pull_openflow_actions(msg, actions_len, oh->version,
629 NULL, NULL, ofpacts);
630 if (error) {
631 return error;
632 }
633
634 update->ofpacts = ofpacts->data;
635 update->ofpacts_len = ofpacts->size;
636 return 0;
637 } else {
638 VLOG_WARN_RL(&rl, "NXST_FLOW_MONITOR reply has bad event %"PRIu16,
639 ntohs(nfuh->event));
640 return OFPERR_NXBRC_FM_BAD_EVENT;
641 }
642
643 bad_len:
644 VLOG_WARN_RL(&rl, "NXST_FLOW_MONITOR reply has %"PRIu32" "
645 "leftover bytes at end", msg->size);
646 return OFPERR_OFPBRC_BAD_LEN;
647 }
648
649 uint32_t
650 ofputil_decode_flow_monitor_cancel(const struct ofp_header *oh)
651 {
652 const struct nx_flow_monitor_cancel *cancel = ofpmsg_body(oh);
653
654 return ntohl(cancel->id);
655 }
656
657 struct ofpbuf *
658 ofputil_encode_flow_monitor_cancel(uint32_t id)
659 {
660 struct nx_flow_monitor_cancel *nfmc;
661 struct ofpbuf *msg;
662
663 msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MONITOR_CANCEL, OFP10_VERSION, 0);
664 nfmc = ofpbuf_put_uninit(msg, sizeof *nfmc);
665 nfmc->id = htonl(id);
666 return msg;
667 }
668
669 void
670 ofputil_start_flow_update(struct ovs_list *replies)
671 {
672 struct ofpbuf *msg;
673
674 msg = ofpraw_alloc_xid(OFPRAW_NXST_FLOW_MONITOR_REPLY, OFP10_VERSION,
675 htonl(0), 1024);
676
677 ovs_list_init(replies);
678 ovs_list_push_back(replies, &msg->list_node);
679 }
680
681 void
682 ofputil_append_flow_update(const struct ofputil_flow_update *update,
683 struct ovs_list *replies,
684 const struct tun_table *tun_table)
685 {
686 struct ofputil_flow_update *update_ =
687 CONST_CAST(struct ofputil_flow_update *, update);
688 const struct tun_table *orig_tun_table;
689 enum ofp_version version = ofpmp_version(replies);
690 struct nx_flow_update_header *nfuh;
691 struct ofpbuf *msg;
692 size_t start_ofs;
693
694 orig_tun_table = update->match.flow.tunnel.metadata.tab;
695 update_->match.flow.tunnel.metadata.tab = tun_table;
696
697 msg = ofpbuf_from_list(ovs_list_back(replies));
698 start_ofs = msg->size;
699
700 if (update->event == NXFME_ABBREV) {
701 struct nx_flow_update_abbrev *nfua;
702
703 nfua = ofpbuf_put_zeros(msg, sizeof *nfua);
704 nfua->xid = update->xid;
705 } else {
706 struct nx_flow_update_full *nfuf;
707 int match_len;
708
709 ofpbuf_put_zeros(msg, sizeof *nfuf);
710 match_len = nx_put_match(msg, &update->match, htonll(0), htonll(0));
711 ofpacts_put_openflow_actions(update->ofpacts, update->ofpacts_len, msg,
712 version);
713 nfuf = ofpbuf_at_assert(msg, start_ofs, sizeof *nfuf);
714 nfuf->reason = htons(update->reason);
715 nfuf->priority = htons(update->priority);
716 nfuf->idle_timeout = htons(update->idle_timeout);
717 nfuf->hard_timeout = htons(update->hard_timeout);
718 nfuf->match_len = htons(match_len);
719 nfuf->table_id = update->table_id;
720 nfuf->cookie = update->cookie;
721 }
722
723 nfuh = ofpbuf_at_assert(msg, start_ofs, sizeof *nfuh);
724 nfuh->length = htons(msg->size - start_ofs);
725 nfuh->event = htons(update->event);
726
727 ofpmp_postappend(replies, start_ofs);
728 update_->match.flow.tunnel.metadata.tab = orig_tun_table;
729 }
730
731 void
732 ofputil_flow_update_format(struct ds *s,
733 const struct ofputil_flow_update *update,
734 const struct ofputil_port_map *port_map,
735 const struct ofputil_table_map *table_map)
736 {
737 char reasonbuf[OFP_FLOW_REMOVED_REASON_BUFSIZE];
738
739 ds_put_cstr(s, "\n event=");
740 switch (update->event) {
741 case NXFME_ADDED:
742 ds_put_cstr(s, "ADDED");
743 break;
744
745 case NXFME_DELETED:
746 ds_put_format(s, "DELETED reason=%s",
747 ofp_flow_removed_reason_to_string(update->reason,
748 reasonbuf,
749 sizeof reasonbuf));
750 break;
751
752 case NXFME_MODIFIED:
753 ds_put_cstr(s, "MODIFIED");
754 break;
755
756 case NXFME_ABBREV:
757 ds_put_format(s, "ABBREV xid=0x%"PRIx32, ntohl(update->xid));
758 return;
759 }
760
761 ds_put_format(s, " table=");
762 ofputil_format_table(update->table_id, table_map, s);
763 if (update->idle_timeout != OFP_FLOW_PERMANENT) {
764 ds_put_format(s, " idle_timeout=%"PRIu16, update->idle_timeout);
765 }
766 if (update->hard_timeout != OFP_FLOW_PERMANENT) {
767 ds_put_format(s, " hard_timeout=%"PRIu16, update->hard_timeout);
768 }
769 ds_put_format(s, " cookie=%#"PRIx64, ntohll(update->cookie));
770
771 ds_put_char(s, ' ');
772 match_format(&update->match, port_map, s, OFP_DEFAULT_PRIORITY);
773
774 if (update->ofpacts_len) {
775 if (s->string[s->length - 1] != ' ') {
776 ds_put_char(s, ' ');
777 }
778 ds_put_cstr(s, "actions=");
779 struct ofpact_format_params fp = {
780 .port_map = port_map,
781 .table_map = table_map,
782 .s = s,
783 };
784 ofpacts_format(update->ofpacts, update->ofpacts_len, &fp);
785 }
786 }
787 \f
788 /* Encodes 'rf' according to 'protocol', and returns the encoded message.
789 * 'protocol' must be for OpenFlow 1.4 or later. */
790 struct ofpbuf *
791 ofputil_encode_requestforward(const struct ofputil_requestforward *rf,
792 enum ofputil_protocol protocol)
793 {
794 enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
795 struct ofpbuf *inner;
796
797 switch (rf->reason) {
798 case OFPRFR_GROUP_MOD:
799 inner = ofputil_encode_group_mod(ofp_version, rf->group_mod);
800 break;
801
802 case OFPRFR_METER_MOD:
803 inner = ofputil_encode_meter_mod(ofp_version, rf->meter_mod);
804 break;
805
806 case OFPRFR_N_REASONS:
807 default:
808 OVS_NOT_REACHED();
809 }
810
811 struct ofp_header *inner_oh = inner->data;
812 inner_oh->xid = rf->xid;
813 inner_oh->length = htons(inner->size);
814
815 struct ofpbuf *outer = ofpraw_alloc_xid(OFPRAW_OFPT14_REQUESTFORWARD,
816 ofp_version, htonl(0),
817 inner->size);
818 ofpbuf_put(outer, inner->data, inner->size);
819 ofpbuf_delete(inner);
820
821 return outer;
822 }
823
824 /* Decodes OFPT_REQUESTFORWARD message 'outer'. On success, puts the decoded
825 * form into '*rf' and returns 0, and the caller is later responsible for
826 * freeing the content of 'rf', with ofputil_destroy_requestforward(rf). On
827 * failure, returns an ofperr and '*rf' is indeterminate. */
828 enum ofperr
829 ofputil_decode_requestforward(const struct ofp_header *outer,
830 struct ofputil_requestforward *rf)
831 {
832 struct ofpbuf b = ofpbuf_const_initializer(outer, ntohs(outer->length));
833
834 /* Skip past outer message. */
835 ovs_assert(ofpraw_pull_assert(&b) == OFPRAW_OFPT14_REQUESTFORWARD);
836
837 /* Validate inner message. */
838 if (b.size < sizeof(struct ofp_header)) {
839 return OFPERR_OFPBFC_MSG_BAD_LEN;
840 }
841 const struct ofp_header *inner = b.data;
842 unsigned int inner_len = ntohs(inner->length);
843 if (inner_len < sizeof(struct ofp_header) || inner_len > b.size) {
844 return OFPERR_OFPBFC_MSG_BAD_LEN;
845 }
846 if (inner->version != outer->version) {
847 return OFPERR_OFPBRC_BAD_VERSION;
848 }
849
850 /* Parse inner message. */
851 enum ofptype type;
852 enum ofperr error = ofptype_decode(&type, inner);
853 if (error) {
854 return error;
855 }
856
857 rf->xid = inner->xid;
858 if (type == OFPTYPE_GROUP_MOD) {
859 rf->reason = OFPRFR_GROUP_MOD;
860 rf->group_mod = xmalloc(sizeof *rf->group_mod);
861 error = ofputil_decode_group_mod(inner, rf->group_mod);
862 if (error) {
863 free(rf->group_mod);
864 return error;
865 }
866 } else if (type == OFPTYPE_METER_MOD) {
867 rf->reason = OFPRFR_METER_MOD;
868 rf->meter_mod = xmalloc(sizeof *rf->meter_mod);
869 ofpbuf_init(&rf->bands, 64);
870 error = ofputil_decode_meter_mod(inner, rf->meter_mod, &rf->bands);
871 if (error) {
872 free(rf->meter_mod);
873 ofpbuf_uninit(&rf->bands);
874 return error;
875 }
876 } else {
877 return OFPERR_OFPBFC_MSG_UNSUP;
878 }
879
880 return 0;
881 }
882
883 /* Frees the content of 'rf', which should have been initialized through a
884 * successful call to ofputil_decode_requestforward(). */
885 void
886 ofputil_destroy_requestforward(struct ofputil_requestforward *rf)
887 {
888 if (!rf) {
889 return;
890 }
891
892 switch (rf->reason) {
893 case OFPRFR_GROUP_MOD:
894 ofputil_uninit_group_mod(rf->group_mod);
895 free(rf->group_mod);
896 break;
897
898 case OFPRFR_METER_MOD:
899 ofpbuf_uninit(&rf->bands);
900 free(rf->meter_mod);
901 break;
902
903 case OFPRFR_N_REASONS:
904 OVS_NOT_REACHED();
905 }
906 }