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. */
41 #define OFP_FLOW_REMOVED_REASON_BUFSIZE (INT_STRLEN(int) + 1)
43 ofp_flow_removed_reason_to_string(enum ofp_flow_removed_reason reason
,
44 char *reasonbuf
, size_t bufsize
)
47 case OFPRR_IDLE_TIMEOUT
:
49 case OFPRR_HARD_TIMEOUT
:
53 case OFPRR_GROUP_DELETE
:
54 return "group_delete";
57 case OFPRR_METER_DELETE
:
58 return "meter_delete";
61 snprintf(reasonbuf
, bufsize
, "%d", (int) reason
);
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. */
70 ofputil_decode_flow_removed(struct ofputil_flow_removed
*fr
,
71 const struct ofp_header
*oh
)
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
;
79 ofr
= ofpbuf_pull(&b
, sizeof *ofr
);
81 error
= ofputil_pull_ofp11_match(&b
, NULL
, NULL
, &fr
->match
, NULL
);
86 struct oxs_stats stats
;
88 uint8_t oxs_field_set
;
89 error
= oxs_pull_stat(&b
, &stats
, &statlen
, &oxs_field_set
);
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
;
108 ofr
= ofpbuf_pull(&b
, sizeof *ofr
);
110 error
= ofputil_pull_ofp11_match(&b
, NULL
, NULL
, &fr
->match
, NULL
);
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
;
128 ofr
= ofpbuf_pull(&b
, sizeof *ofr
);
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
;
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
;
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
);
152 return OFPERR_OFPBRC_BAD_LEN
;
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
);
172 /* Returns 'count' unchanged except that UINT64_MAX becomes 0.
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. */
177 unknown_to_zero(uint64_t count
)
179 return count
!= UINT64_MAX
? count
: 0;
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
186 ofputil_encode_flow_removed(const struct ofputil_flow_removed
*fr
,
187 enum ofputil_protocol protocol
)
190 enum ofp_flow_removed_reason reason
= fr
->reason
;
192 if (reason
== OFPRR_METER_DELETE
&& !(protocol
& OFPUTIL_P_OF14_UP
)) {
193 reason
= OFPRR_DELETE
;
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
;
203 msg
= ofpraw_alloc_xid(OFPRAW_OFPT11_FLOW_REMOVED
,
204 ofputil_protocol_to_ofp_version(protocol
),
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
);
221 case OFPUTIL_P_OF15_OXM
:
222 case OFPUTIL_P_OF16_OXM
: {
223 struct ofp15_flow_removed
*ofr
;
225 msg
= ofpraw_alloc_xid(OFPRAW_OFPT15_FLOW_REMOVED
,
226 ofputil_protocol_to_ofp_version(protocol
),
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
);
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
,
246 oxs_put_stats(msg
, &oxs
);
249 case OFPUTIL_P_OF10_STD
:
250 case OFPUTIL_P_OF10_STD_TID
: {
251 struct ofp10_flow_removed
*ofr
;
253 msg
= ofpraw_alloc_xid(OFPRAW_OFPT10_FLOW_REMOVED
, OFP10_VERSION
,
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
));
268 case OFPUTIL_P_OF10_NXM
:
269 case OFPUTIL_P_OF10_NXM_TID
: {
270 struct nx_flow_removed
*nfr
;
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);
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
);
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
)
305 char reasonbuf
[OFP_FLOW_REMOVED_REASON_BUFSIZE
];
308 match_format(&fr
->match
, port_map
, s
, fr
->priority
);
310 ds_put_format(s
, " reason=%s",
311 ofp_flow_removed_reason_to_string(fr
->reason
, reasonbuf
,
314 if (fr
->table_id
!= 255) {
315 ds_put_format(s
, " table_id=");
316 ofputil_format_table(fr
->table_id
, table_map
, s
);
319 if (fr
->cookie
!= htonll(0)) {
320 ds_put_format(s
, " cookie:0x%"PRIx64
, ntohll(fr
->cookie
));
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
);
330 ds_put_format(s
, " pkts%"PRIu64
" bytes%"PRIu64
"\n",
331 fr
->packet_count
, fr
->byte_count
);
334 /* ofputil_flow_monitor_request */
336 /* Converts an NXST_FLOW_MONITOR request in 'msg' into an abstract
337 * ofputil_flow_monitor_request in 'rq'.
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.
344 * Returns 0 if successful, EOF if no requests were left in this 'msg',
345 * otherwise an OFPERR_* value. */
347 ofputil_decode_flow_monitor_request(struct ofputil_flow_monitor_request
*rq
,
350 struct nx_flow_monitor_request
*nfmr
;
354 ofpraw_pull_assert(msg
);
361 nfmr
= ofpbuf_try_pull(msg
, sizeof *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
;
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
;
376 if (!is_all_zeros(nfmr
->zeros
, sizeof nfmr
->zeros
)) {
377 return OFPERR_NXBRC_MUST_BE_ZERO
;
380 rq
->id
= ntohl(nfmr
->id
);
382 rq
->out_port
= u16_to_ofp(ntohs(nfmr
->out_port
));
383 rq
->table_id
= nfmr
->table_id
;
385 return nx_pull_match(msg
, ntohs(nfmr
->match_len
), &rq
->match
, NULL
,
386 NULL
, false, NULL
, NULL
);
390 ofputil_append_flow_monitor_request(
391 const struct ofputil_flow_monitor_request
*rq
, struct ofpbuf
*msg
)
393 struct nx_flow_monitor_request
*nfmr
;
398 ofpraw_put(OFPRAW_NXST_FLOW_MONITOR_REQUEST
, OFP10_VERSION
, msg
);
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));
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
;
414 nx_flow_monitor_flags_to_name(uint32_t bit
)
416 enum nx_flow_monitor_flags fmf
= bit
;
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";
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
)
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
, ',');
439 if (request
->out_port
!= OFPP_NONE
) {
440 ds_put_cstr(s
, " out_port=");
441 ofputil_format_port(request
->out_port
, port_map
, s
);
444 if (request
->table_id
!= 0xff) {
445 ds_put_format(s
, " table=");
446 ofputil_format_table(request
->table_id
, table_map
, s
);
450 match_format(&request
->match
, port_map
, s
, OFP_DEFAULT_PRIORITY
);
454 static char * OVS_WARN_UNUSED_RESULT
455 parse_flow_monitor_request__(struct ofputil_flow_monitor_request
*fmr
,
457 const struct ofputil_port_map
*port_map
,
458 const struct ofputil_table_map
*table_map
,
460 enum ofputil_protocol
*usable_protocols
)
462 static atomic_count id
= ATOMIC_COUNT_INIT(0);
465 fmr
->id
= atomic_count_inc(&id
);
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
);
473 while (ofputil_parse_key_value(&string
, &name
, &value
)) {
474 const struct ofp_protocol
*p
;
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
));
492 match_set_nw_proto(&fmr
->match
, p
->nw_proto
);
494 } else if (mf_from_name(name
)) {
495 error
= ofp_parse_field(mf_from_name(name
), value
, port_map
,
496 &fmr
->match
, usable_protocols
);
499 return xasprintf("%s: field %s missing value", str_
, name
);
502 if (!strcmp(name
, "table")) {
503 if (!ofputil_table_from_string(value
, table_map
,
505 error
= xasprintf("unknown table \"%s\"", value
);
507 } else if (!strcmp(name
, "out_port")) {
508 fmr
->out_port
= u16_to_ofp(atoi(value
));
510 return xasprintf("%s: unknown keyword %s", str_
, name
);
521 /* Convert 'str_' (as described in the documentation for the "monitor" command
522 * in the ovs-ofctl man page) into 'fmr'.
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
,
529 const struct ofputil_port_map
*port_map
,
530 const struct ofputil_table_map
*table_map
,
531 enum ofputil_protocol
*usable_protocols
)
533 char *string
= xstrdup(str_
);
534 char *error
= parse_flow_monitor_request__(fmr
, str_
, port_map
, table_map
,
535 string
, usable_protocols
);
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.
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.
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.
554 * Returns 0 if successful, EOF if no updates were left in this 'msg',
555 * otherwise an OFPERR_* value. */
557 ofputil_decode_flow_update(struct ofputil_flow_update
*update
,
558 struct ofpbuf
*msg
, struct ofpbuf
*ofpacts
)
560 struct nx_flow_update_header
*nfuh
;
562 struct ofp_header
*oh
;
565 ofpraw_pull_assert(msg
);
568 ofpbuf_clear(ofpacts
);
573 if (msg
->size
< sizeof(struct nx_flow_update_header
)) {
580 update
->event
= ntohs(nfuh
->event
);
581 length
= ntohs(nfuh
->length
);
582 if (length
> msg
->size
|| length
% 8) {
586 if (update
->event
== NXFME_ABBREV
) {
587 struct nx_flow_update_abbrev
*nfua
;
589 if (length
!= sizeof *nfua
) {
593 nfua
= ofpbuf_pull(msg
, sizeof *nfua
);
594 update
->xid
= nfua
->xid
;
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
;
604 if (length
< sizeof *nfuf
) {
608 nfuf
= ofpbuf_pull(msg
, sizeof *nfuf
);
609 match_len
= ntohs(nfuf
->match_len
);
610 if (sizeof *nfuf
+ match_len
> length
) {
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
);
621 error
= nx_pull_match(msg
, match_len
, &update
->match
, NULL
, NULL
,
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
);
634 update
->ofpacts
= ofpacts
->data
;
635 update
->ofpacts_len
= ofpacts
->size
;
638 VLOG_WARN_RL(&rl
, "NXST_FLOW_MONITOR reply has bad event %"PRIu16
,
640 return OFPERR_NXBRC_FM_BAD_EVENT
;
644 VLOG_WARN_RL(&rl
, "NXST_FLOW_MONITOR reply has %"PRIu32
" "
645 "leftover bytes at end", msg
->size
);
646 return OFPERR_OFPBRC_BAD_LEN
;
650 ofputil_decode_flow_monitor_cancel(const struct ofp_header
*oh
)
652 const struct nx_flow_monitor_cancel
*cancel
= ofpmsg_body(oh
);
654 return ntohl(cancel
->id
);
658 ofputil_encode_flow_monitor_cancel(uint32_t id
)
660 struct nx_flow_monitor_cancel
*nfmc
;
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
);
670 ofputil_start_flow_update(struct ovs_list
*replies
)
674 msg
= ofpraw_alloc_xid(OFPRAW_NXST_FLOW_MONITOR_REPLY
, OFP10_VERSION
,
677 ovs_list_init(replies
);
678 ovs_list_push_back(replies
, &msg
->list_node
);
682 ofputil_append_flow_update(const struct ofputil_flow_update
*update
,
683 struct ovs_list
*replies
,
684 const struct tun_table
*tun_table
)
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
;
694 orig_tun_table
= update
->match
.flow
.tunnel
.metadata
.tab
;
695 update_
->match
.flow
.tunnel
.metadata
.tab
= tun_table
;
697 msg
= ofpbuf_from_list(ovs_list_back(replies
));
698 start_ofs
= msg
->size
;
700 if (update
->event
== NXFME_ABBREV
) {
701 struct nx_flow_update_abbrev
*nfua
;
703 nfua
= ofpbuf_put_zeros(msg
, sizeof *nfua
);
704 nfua
->xid
= update
->xid
;
706 struct nx_flow_update_full
*nfuf
;
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
,
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
;
723 nfuh
= ofpbuf_at_assert(msg
, start_ofs
, sizeof *nfuh
);
724 nfuh
->length
= htons(msg
->size
- start_ofs
);
725 nfuh
->event
= htons(update
->event
);
727 ofpmp_postappend(replies
, start_ofs
);
728 update_
->match
.flow
.tunnel
.metadata
.tab
= orig_tun_table
;
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
)
737 char reasonbuf
[OFP_FLOW_REMOVED_REASON_BUFSIZE
];
739 ds_put_cstr(s
, "\n event=");
740 switch (update
->event
) {
742 ds_put_cstr(s
, "ADDED");
746 ds_put_format(s
, "DELETED reason=%s",
747 ofp_flow_removed_reason_to_string(update
->reason
,
753 ds_put_cstr(s
, "MODIFIED");
757 ds_put_format(s
, "ABBREV xid=0x%"PRIx32
, ntohl(update
->xid
));
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
);
766 if (update
->hard_timeout
!= OFP_FLOW_PERMANENT
) {
767 ds_put_format(s
, " hard_timeout=%"PRIu16
, update
->hard_timeout
);
769 ds_put_format(s
, " cookie=%#"PRIx64
, ntohll(update
->cookie
));
772 match_format(&update
->match
, port_map
, s
, OFP_DEFAULT_PRIORITY
);
774 if (update
->ofpacts_len
) {
775 if (s
->string
[s
->length
- 1] != ' ') {
778 ds_put_cstr(s
, "actions=");
779 struct ofpact_format_params fp
= {
780 .port_map
= port_map
,
781 .table_map
= table_map
,
784 ofpacts_format(update
->ofpacts
, update
->ofpacts_len
, &fp
);
788 /* Encodes 'rf' according to 'protocol', and returns the encoded message.
789 * 'protocol' must be for OpenFlow 1.4 or later. */
791 ofputil_encode_requestforward(const struct ofputil_requestforward
*rf
,
792 enum ofputil_protocol protocol
)
794 enum ofp_version ofp_version
= ofputil_protocol_to_ofp_version(protocol
);
795 struct ofpbuf
*inner
;
797 switch (rf
->reason
) {
798 case OFPRFR_GROUP_MOD
:
799 inner
= ofputil_encode_group_mod(ofp_version
, rf
->group_mod
);
802 case OFPRFR_METER_MOD
:
803 inner
= ofputil_encode_meter_mod(ofp_version
, rf
->meter_mod
);
806 case OFPRFR_N_REASONS
:
811 struct ofp_header
*inner_oh
= inner
->data
;
812 inner_oh
->xid
= rf
->xid
;
813 inner_oh
->length
= htons(inner
->size
);
815 struct ofpbuf
*outer
= ofpraw_alloc_xid(OFPRAW_OFPT14_REQUESTFORWARD
,
816 ofp_version
, htonl(0),
818 ofpbuf_put(outer
, inner
->data
, inner
->size
);
819 ofpbuf_delete(inner
);
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. */
829 ofputil_decode_requestforward(const struct ofp_header
*outer
,
830 struct ofputil_requestforward
*rf
)
832 struct ofpbuf b
= ofpbuf_const_initializer(outer
, ntohs(outer
->length
));
834 /* Skip past outer message. */
835 ovs_assert(ofpraw_pull_assert(&b
) == OFPRAW_OFPT14_REQUESTFORWARD
);
837 /* Validate inner message. */
838 if (b
.size
< sizeof(struct ofp_header
)) {
839 return OFPERR_OFPBFC_MSG_BAD_LEN
;
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
;
846 if (inner
->version
!= outer
->version
) {
847 return OFPERR_OFPBRC_BAD_VERSION
;
850 /* Parse inner message. */
852 enum ofperr error
= ofptype_decode(&type
, inner
);
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
);
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
);
873 ofpbuf_uninit(&rf
->bands
);
877 return OFPERR_OFPBFC_MSG_UNSUP
;
883 /* Frees the content of 'rf', which should have been initialized through a
884 * successful call to ofputil_decode_requestforward(). */
886 ofputil_destroy_requestforward(struct ofputil_requestforward
*rf
)
892 switch (rf
->reason
) {
893 case OFPRFR_GROUP_MOD
:
894 ofputil_uninit_group_mod(rf
->group_mod
);
898 case OFPRFR_METER_MOD
:
899 ofpbuf_uninit(&rf
->bands
);
903 case OFPRFR_N_REASONS
: