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