2 * Copyright (c) 2008-2017 Nicira, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "openvswitch/ofp-monitor.h"
19 #include "byte-order.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"
34 VLOG_DEFINE_THIS_MODULE(ofp_monitor
);
36 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
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. */
42 ofp_flow_removed_reason_to_string(enum ofp_flow_removed_reason reason
,
43 char *reasonbuf
, size_t bufsize
)
46 case OFPRR_IDLE_TIMEOUT
:
48 case OFPRR_HARD_TIMEOUT
:
52 case OFPRR_GROUP_DELETE
:
53 return "group_delete";
56 case OFPRR_METER_DELETE
:
57 return "meter_delete";
60 snprintf(reasonbuf
, bufsize
, "%d", (int) reason
);
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. */
69 ofputil_decode_flow_removed(struct ofputil_flow_removed
*fr
,
70 const struct ofp_header
*oh
)
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
;
78 ofr
= ofpbuf_pull(&b
, sizeof *ofr
);
80 error
= ofputil_pull_ofp11_match(&b
, NULL
, NULL
, &fr
->match
, NULL
);
85 struct oxs_stats stats
;
87 uint8_t oxs_field_set
;
88 error
= oxs_pull_stat(&b
, &stats
, &statlen
, &oxs_field_set
);
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
;
107 ofr
= ofpbuf_pull(&b
, sizeof *ofr
);
109 error
= ofputil_pull_ofp11_match(&b
, NULL
, NULL
, &fr
->match
, NULL
);
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
;
127 ofr
= ofpbuf_pull(&b
, sizeof *ofr
);
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
;
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
;
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
);
151 return OFPERR_OFPBRC_BAD_LEN
;
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
);
171 /* Returns 'count' unchanged except that UINT64_MAX becomes 0.
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. */
176 unknown_to_zero(uint64_t count
)
178 return count
!= UINT64_MAX
? count
: 0;
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
185 ofputil_encode_flow_removed(const struct ofputil_flow_removed
*fr
,
186 enum ofputil_protocol protocol
)
189 enum ofp_flow_removed_reason reason
= fr
->reason
;
191 if (reason
== OFPRR_METER_DELETE
&& !(protocol
& OFPUTIL_P_OF14_UP
)) {
192 reason
= OFPRR_DELETE
;
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
;
202 msg
= ofpraw_alloc_xid(OFPRAW_OFPT11_FLOW_REMOVED
,
203 ofputil_protocol_to_ofp_version(protocol
),
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
);
220 case OFPUTIL_P_OF15_OXM
: {
221 struct ofp15_flow_removed
*ofr
;
223 msg
= ofpraw_alloc_xid(OFPRAW_OFPT15_FLOW_REMOVED
,
224 ofputil_protocol_to_ofp_version(protocol
),
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
);
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
,
244 oxs_put_stats(msg
, &oxs
);
247 case OFPUTIL_P_OF10_STD
:
248 case OFPUTIL_P_OF10_STD_TID
: {
249 struct ofp10_flow_removed
*ofr
;
251 msg
= ofpraw_alloc_xid(OFPRAW_OFPT10_FLOW_REMOVED
, OFP10_VERSION
,
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
));
266 case OFPUTIL_P_OF10_NXM
:
267 case OFPUTIL_P_OF10_NXM_TID
: {
268 struct nx_flow_removed
*nfr
;
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);
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
);
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
)
303 char reasonbuf
[OFP_FLOW_REMOVED_REASON_BUFSIZE
];
306 match_format(&fr
->match
, port_map
, s
, fr
->priority
);
308 ds_put_format(s
, " reason=%s",
309 ofp_flow_removed_reason_to_string(fr
->reason
, reasonbuf
,
312 if (fr
->table_id
!= 255) {
313 ds_put_format(s
, " table_id=");
314 ofputil_format_table(fr
->table_id
, table_map
, s
);
317 if (fr
->cookie
!= htonll(0)) {
318 ds_put_format(s
, " cookie:0x%"PRIx64
, ntohll(fr
->cookie
));
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
);
328 ds_put_format(s
, " pkts%"PRIu64
" bytes%"PRIu64
"\n",
329 fr
->packet_count
, fr
->byte_count
);
332 /* ofputil_flow_monitor_request */
334 /* Converts an NXST_FLOW_MONITOR request in 'msg' into an abstract
335 * ofputil_flow_monitor_request in 'rq'.
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.
342 * Returns 0 if successful, EOF if no requests were left in this 'msg',
343 * otherwise an OFPERR_* value. */
345 ofputil_decode_flow_monitor_request(struct ofputil_flow_monitor_request
*rq
,
348 struct nx_flow_monitor_request
*nfmr
;
352 ofpraw_pull_assert(msg
);
359 nfmr
= ofpbuf_try_pull(msg
, sizeof *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
;
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
;
374 if (!is_all_zeros(nfmr
->zeros
, sizeof nfmr
->zeros
)) {
375 return OFPERR_NXBRC_MUST_BE_ZERO
;
378 rq
->id
= ntohl(nfmr
->id
);
380 rq
->out_port
= u16_to_ofp(ntohs(nfmr
->out_port
));
381 rq
->table_id
= nfmr
->table_id
;
383 return nx_pull_match(msg
, ntohs(nfmr
->match_len
), &rq
->match
, NULL
,
384 NULL
, false, NULL
, NULL
);
388 ofputil_append_flow_monitor_request(
389 const struct ofputil_flow_monitor_request
*rq
, struct ofpbuf
*msg
)
391 struct nx_flow_monitor_request
*nfmr
;
396 ofpraw_put(OFPRAW_NXST_FLOW_MONITOR_REQUEST
, OFP10_VERSION
, msg
);
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));
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
;
412 nx_flow_monitor_flags_to_name(uint32_t bit
)
414 enum nx_flow_monitor_flags fmf
= bit
;
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";
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
)
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
, ',');
437 if (request
->out_port
!= OFPP_NONE
) {
438 ds_put_cstr(s
, " out_port=");
439 ofputil_format_port(request
->out_port
, port_map
, s
);
442 if (request
->table_id
!= 0xff) {
443 ds_put_format(s
, " table=");
444 ofputil_format_table(request
->table_id
, table_map
, s
);
448 match_format(&request
->match
, port_map
, s
, OFP_DEFAULT_PRIORITY
);
452 static char * OVS_WARN_UNUSED_RESULT
453 parse_flow_monitor_request__(struct ofputil_flow_monitor_request
*fmr
,
455 const struct ofputil_port_map
*port_map
,
456 const struct ofputil_table_map
*table_map
,
458 enum ofputil_protocol
*usable_protocols
)
460 static atomic_count id
= ATOMIC_COUNT_INIT(0);
463 fmr
->id
= atomic_count_inc(&id
);
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
);
471 *usable_protocols
= OFPUTIL_P_ANY
;
472 while (ofputil_parse_key_value(&string
, &name
, &value
)) {
473 const struct ofp_protocol
*p
;
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
));
491 match_set_nw_proto(&fmr
->match
, p
->nw_proto
);
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
);
502 return xasprintf("%s: field %s missing value", str_
, name
);
505 if (!strcmp(name
, "table")) {
506 if (!ofputil_table_from_string(value
, table_map
,
508 error
= xasprintf("unknown table \"%s\"", value
);
510 } else if (!strcmp(name
, "out_port")) {
511 fmr
->out_port
= u16_to_ofp(atoi(value
));
513 return xasprintf("%s: unknown keyword %s", str_
, name
);
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
;
527 /* Convert 'str_' (as described in the documentation for the "monitor" command
528 * in the ovs-ofctl man page) into 'fmr'.
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
,
535 const struct ofputil_port_map
*port_map
,
536 const struct ofputil_table_map
*table_map
,
537 enum ofputil_protocol
*usable_protocols
)
539 char *string
= xstrdup(str_
);
540 char *error
= parse_flow_monitor_request__(fmr
, str_
, port_map
, table_map
,
541 string
, usable_protocols
);
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.
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.
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.
560 * Returns 0 if successful, EOF if no updates were left in this 'msg',
561 * otherwise an OFPERR_* value. */
563 ofputil_decode_flow_update(struct ofputil_flow_update
*update
,
564 struct ofpbuf
*msg
, struct ofpbuf
*ofpacts
)
566 struct nx_flow_update_header
*nfuh
;
568 struct ofp_header
*oh
;
571 ofpraw_pull_assert(msg
);
574 ofpbuf_clear(ofpacts
);
579 if (msg
->size
< sizeof(struct nx_flow_update_header
)) {
586 update
->event
= ntohs(nfuh
->event
);
587 length
= ntohs(nfuh
->length
);
588 if (length
> msg
->size
|| length
% 8) {
592 if (update
->event
== NXFME_ABBREV
) {
593 struct nx_flow_update_abbrev
*nfua
;
595 if (length
!= sizeof *nfua
) {
599 nfua
= ofpbuf_pull(msg
, sizeof *nfua
);
600 update
->xid
= nfua
->xid
;
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
;
610 if (length
< sizeof *nfuf
) {
614 nfuf
= ofpbuf_pull(msg
, sizeof *nfuf
);
615 match_len
= ntohs(nfuf
->match_len
);
616 if (sizeof *nfuf
+ match_len
> length
) {
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
);
627 error
= nx_pull_match(msg
, match_len
, &update
->match
, NULL
, NULL
,
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
);
640 update
->ofpacts
= ofpacts
->data
;
641 update
->ofpacts_len
= ofpacts
->size
;
644 VLOG_WARN_RL(&rl
, "NXST_FLOW_MONITOR reply has bad event %"PRIu16
,
646 return OFPERR_NXBRC_FM_BAD_EVENT
;
650 VLOG_WARN_RL(&rl
, "NXST_FLOW_MONITOR reply has %"PRIu32
" "
651 "leftover bytes at end", msg
->size
);
652 return OFPERR_OFPBRC_BAD_LEN
;
656 ofputil_decode_flow_monitor_cancel(const struct ofp_header
*oh
)
658 const struct nx_flow_monitor_cancel
*cancel
= ofpmsg_body(oh
);
660 return ntohl(cancel
->id
);
664 ofputil_encode_flow_monitor_cancel(uint32_t id
)
666 struct nx_flow_monitor_cancel
*nfmc
;
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
);
676 ofputil_start_flow_update(struct ovs_list
*replies
)
680 msg
= ofpraw_alloc_xid(OFPRAW_NXST_FLOW_MONITOR_REPLY
, OFP10_VERSION
,
683 ovs_list_init(replies
);
684 ovs_list_push_back(replies
, &msg
->list_node
);
688 ofputil_append_flow_update(const struct ofputil_flow_update
*update
,
689 struct ovs_list
*replies
,
690 const struct tun_table
*tun_table
)
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
;
700 orig_tun_table
= update
->match
.flow
.tunnel
.metadata
.tab
;
701 update_
->match
.flow
.tunnel
.metadata
.tab
= tun_table
;
703 msg
= ofpbuf_from_list(ovs_list_back(replies
));
704 start_ofs
= msg
->size
;
706 if (update
->event
== NXFME_ABBREV
) {
707 struct nx_flow_update_abbrev
*nfua
;
709 nfua
= ofpbuf_put_zeros(msg
, sizeof *nfua
);
710 nfua
->xid
= update
->xid
;
712 struct nx_flow_update_full
*nfuf
;
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
,
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
;
729 nfuh
= ofpbuf_at_assert(msg
, start_ofs
, sizeof *nfuh
);
730 nfuh
->length
= htons(msg
->size
- start_ofs
);
731 nfuh
->event
= htons(update
->event
);
733 ofpmp_postappend(replies
, start_ofs
);
734 update_
->match
.flow
.tunnel
.metadata
.tab
= orig_tun_table
;
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
)
743 char reasonbuf
[OFP_FLOW_REMOVED_REASON_BUFSIZE
];
745 ds_put_cstr(s
, "\n event=");
746 switch (update
->event
) {
748 ds_put_cstr(s
, "ADDED");
752 ds_put_format(s
, "DELETED reason=%s",
753 ofp_flow_removed_reason_to_string(update
->reason
,
759 ds_put_cstr(s
, "MODIFIED");
763 ds_put_format(s
, "ABBREV xid=0x%"PRIx32
, ntohl(update
->xid
));
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
);
772 if (update
->hard_timeout
!= OFP_FLOW_PERMANENT
) {
773 ds_put_format(s
, " hard_timeout=%"PRIu16
, update
->hard_timeout
);
775 ds_put_format(s
, " cookie=%#"PRIx64
, ntohll(update
->cookie
));
778 match_format(&update
->match
, port_map
, s
, OFP_DEFAULT_PRIORITY
);
780 if (update
->ofpacts_len
) {
781 if (s
->string
[s
->length
- 1] != ' ') {
784 ds_put_cstr(s
, "actions=");
785 struct ofpact_format_params fp
= {
786 .port_map
= port_map
,
787 .table_map
= table_map
,
790 ofpacts_format(update
->ofpacts
, update
->ofpacts_len
, &fp
);
794 /* Encodes 'rf' according to 'protocol', and returns the encoded message. */
796 ofputil_encode_requestforward(const struct ofputil_requestforward
*rf
,
797 enum ofputil_protocol protocol
)
799 enum ofp_version ofp_version
= ofputil_protocol_to_ofp_version(protocol
);
800 enum ofpraw raw_msg_type
;
801 struct ofpbuf
*inner
;
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
);
809 case OFPRFR_METER_MOD
:
810 inner
= ofputil_encode_meter_mod(ofp_version
, rf
->meter_mod
);
813 case OFPRFR_N_REASONS
:
818 struct ofp_header
*inner_oh
= inner
->data
;
819 inner_oh
->xid
= rf
->xid
;
820 inner_oh
->length
= htons(inner
->size
);
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
;
827 raw_msg_type
= OFPRAW_OFPT14_REQUESTFORWARD
;
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
);
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. */
843 ofputil_decode_requestforward(const struct ofp_header
*outer
,
844 struct ofputil_requestforward
*rf
)
846 rf
->new_buckets
= NULL
;
847 rf
->group_existed
= -1;
849 struct ofpbuf b
= ofpbuf_const_initializer(outer
, ntohs(outer
->length
));
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
);
857 /* Validate inner message. */
858 if (b
.size
< sizeof(struct ofp_header
)) {
859 return OFPERR_OFPBFC_MSG_BAD_LEN
;
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
;
866 if (inner
->version
!= outer
->version
) {
867 return OFPERR_OFPBRC_BAD_VERSION
;
870 /* Parse inner message. */
872 enum ofperr error
= ofptype_decode(&type
, inner
);
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
);
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
);
893 ofpbuf_uninit(&rf
->bands
);
897 return OFPERR_OFPBFC_MSG_UNSUP
;
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
)
910 ds_put_cstr(string
, " reason=");
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
);
919 case OFPRFR_METER_MOD
:
920 ds_put_cstr(string
, "meter_mod");
921 ofputil_format_meter_mod(string
, rf
->meter_mod
);
924 case OFPRFR_N_REASONS
:
930 /* Frees the content of 'rf', which should have been initialized through a
931 * successful call to ofputil_decode_requestforward(). */
933 ofputil_destroy_requestforward(struct ofputil_requestforward
*rf
)
939 switch (rf
->reason
) {
940 case OFPRFR_GROUP_MOD
:
941 ofputil_uninit_group_mod(rf
->group_mod
);
943 /* 'rf' does not own rf->new_buckets. */
946 case OFPRFR_METER_MOD
:
947 ofpbuf_uninit(&rf
->bands
);
951 case OFPRFR_N_REASONS
: