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-switch.h"
19 #include "byte-order.h"
20 #include "openvswitch/ofpbuf.h"
21 #include "openvswitch/ofp-actions.h"
22 #include "openvswitch/ofp-errors.h"
23 #include "openvswitch/ofp-msgs.h"
24 #include "openvswitch/ofp-port.h"
25 #include "openvswitch/ofp-print.h"
28 /* ofputil_switch_features */
30 #define OFPC_COMMON (OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS | \
31 OFPC_IP_REASM | OFPC_QUEUE_STATS)
32 BUILD_ASSERT_DECL((int) OFPUTIL_C_FLOW_STATS
== OFPC_FLOW_STATS
);
33 BUILD_ASSERT_DECL((int) OFPUTIL_C_TABLE_STATS
== OFPC_TABLE_STATS
);
34 BUILD_ASSERT_DECL((int) OFPUTIL_C_PORT_STATS
== OFPC_PORT_STATS
);
35 BUILD_ASSERT_DECL((int) OFPUTIL_C_IP_REASM
== OFPC_IP_REASM
);
36 BUILD_ASSERT_DECL((int) OFPUTIL_C_QUEUE_STATS
== OFPC_QUEUE_STATS
);
37 BUILD_ASSERT_DECL((int) OFPUTIL_C_ARP_MATCH_IP
== OFPC_ARP_MATCH_IP
);
38 BUILD_ASSERT_DECL((int) OFPUTIL_C_PORT_BLOCKED
== OFPC12_PORT_BLOCKED
);
39 BUILD_ASSERT_DECL((int) OFPUTIL_C_BUNDLES
== OFPC14_BUNDLES
);
40 BUILD_ASSERT_DECL((int) OFPUTIL_C_FLOW_MONITORING
== OFPC14_FLOW_MONITORING
);
43 ofputil_capabilities_mask(enum ofp_version ofp_version
)
45 /* Handle capabilities whose bit is unique for all OpenFlow versions */
46 switch (ofp_version
) {
49 return OFPC_COMMON
| OFPC_ARP_MATCH_IP
;
52 return OFPC_COMMON
| OFPC12_PORT_BLOCKED
;
55 return OFPC_COMMON
| OFPC12_PORT_BLOCKED
| OFPC14_BUNDLES
56 | OFPC14_FLOW_MONITORING
;
58 /* Caller needs to check osf->header.version itself */
63 /* Pulls an OpenFlow "switch_features" structure from 'b' and decodes it into
64 * an abstract representation in '*features', readying 'b' to iterate over the
65 * OpenFlow port structures following 'osf' with later calls to
66 * ofputil_pull_phy_port(). Returns 0 if successful, otherwise an OFPERR_*
69 ofputil_pull_switch_features(struct ofpbuf
*b
,
70 struct ofputil_switch_features
*features
)
72 const struct ofp_header
*oh
= b
->data
;
73 enum ofpraw raw
= ofpraw_pull_assert(b
);
74 const struct ofp_switch_features
*osf
= ofpbuf_pull(b
, sizeof *osf
);
75 features
->datapath_id
= ntohll(osf
->datapath_id
);
76 features
->n_buffers
= ntohl(osf
->n_buffers
);
77 features
->n_tables
= osf
->n_tables
;
78 features
->auxiliary_id
= 0;
80 features
->capabilities
= ntohl(osf
->capabilities
) &
81 ofputil_capabilities_mask(oh
->version
);
83 if (raw
== OFPRAW_OFPT10_FEATURES_REPLY
) {
84 if (osf
->capabilities
& htonl(OFPC10_STP
)) {
85 features
->capabilities
|= OFPUTIL_C_STP
;
87 features
->ofpacts
= ofpact_bitmap_from_openflow(osf
->actions
,
89 } else if (raw
== OFPRAW_OFPT11_FEATURES_REPLY
90 || raw
== OFPRAW_OFPT13_FEATURES_REPLY
) {
91 if (osf
->capabilities
& htonl(OFPC11_GROUP_STATS
)) {
92 features
->capabilities
|= OFPUTIL_C_GROUP_STATS
;
94 features
->ofpacts
= 0;
95 if (raw
== OFPRAW_OFPT13_FEATURES_REPLY
) {
96 features
->auxiliary_id
= osf
->auxiliary_id
;
99 return OFPERR_OFPBRC_BAD_VERSION
;
105 /* In OpenFlow 1.0, 1.1, and 1.2, an OFPT_FEATURES_REPLY message lists all the
106 * switch's ports, unless there are too many to fit. In OpenFlow 1.3 and
107 * later, an OFPT_FEATURES_REPLY does not list ports at all.
109 * Given a buffer 'b' that contains a Features Reply message, this message
110 * checks if it contains a complete list of the switch's ports. Returns true,
111 * if so. Returns false if the list is missing (OF1.3+) or incomplete
112 * (OF1.0/1.1/1.2), and in the latter case removes all of the ports from the
115 * When this function returns false, the caller should send an OFPST_PORT_DESC
116 * stats request to get the ports. */
118 ofputil_switch_features_has_ports(struct ofpbuf
*b
)
120 struct ofp_header
*oh
= b
->data
;
121 size_t phy_port_size
;
123 if (oh
->version
>= OFP13_VERSION
) {
124 /* OpenFlow 1.3+ never has ports in the feature reply. */
128 phy_port_size
= (oh
->version
== OFP10_VERSION
129 ? sizeof(struct ofp10_phy_port
)
130 : sizeof(struct ofp11_port
));
131 if (ntohs(oh
->length
) + phy_port_size
<= UINT16_MAX
) {
132 /* There's room for additional ports in the feature reply.
133 * Assume that the list is complete. */
137 /* The feature reply has no room for more ports. Probably the list is
138 * truncated. Drop the ports and tell the caller to retrieve them with
139 * OFPST_PORT_DESC. */
140 b
->size
= sizeof *oh
+ sizeof(struct ofp_switch_features
);
141 ofpmsg_update_length(b
);
145 /* Returns a buffer owned by the caller that encodes 'features' in the format
146 * required by 'protocol' with the given 'xid'. The caller should append port
147 * information to the buffer with subsequent calls to
148 * ofputil_put_switch_features_port(). */
150 ofputil_encode_switch_features(const struct ofputil_switch_features
*features
,
151 enum ofputil_protocol protocol
, ovs_be32 xid
)
153 struct ofp_switch_features
*osf
;
155 enum ofp_version version
;
158 version
= ofputil_protocol_to_ofp_version(protocol
);
161 raw
= OFPRAW_OFPT10_FEATURES_REPLY
;
165 raw
= OFPRAW_OFPT11_FEATURES_REPLY
;
170 raw
= OFPRAW_OFPT13_FEATURES_REPLY
;
175 b
= ofpraw_alloc_xid(raw
, version
, xid
, 0);
176 osf
= ofpbuf_put_zeros(b
, sizeof *osf
);
177 osf
->datapath_id
= htonll(features
->datapath_id
);
178 osf
->n_buffers
= htonl(features
->n_buffers
);
179 osf
->n_tables
= features
->n_tables
;
181 osf
->capabilities
= htonl(features
->capabilities
&
182 ofputil_capabilities_mask(version
));
185 if (features
->capabilities
& OFPUTIL_C_STP
) {
186 osf
->capabilities
|= htonl(OFPC10_STP
);
188 osf
->actions
= ofpact_bitmap_to_openflow(features
->ofpacts
,
194 osf
->auxiliary_id
= features
->auxiliary_id
;
198 if (features
->capabilities
& OFPUTIL_C_GROUP_STATS
) {
199 osf
->capabilities
|= htonl(OFPC11_GROUP_STATS
);
209 /* Encodes 'pp' into the format required by the switch_features message already
210 * in 'b', which should have been returned by ofputil_encode_switch_features(),
211 * and appends the encoded version to 'b'. */
213 ofputil_put_switch_features_port(const struct ofputil_phy_port
*pp
,
216 const struct ofp_header
*oh
= b
->data
;
218 if (oh
->version
< OFP13_VERSION
) {
219 /* Try adding a port description to the message, but drop it again if
220 * the buffer overflows. (This possibility for overflow is why
221 * OpenFlow 1.3+ moved port descriptions into a multipart message.) */
222 size_t start_ofs
= b
->size
;
223 ofputil_put_phy_port(oh
->version
, pp
, b
);
224 if (b
->size
> UINT16_MAX
) {
231 ofputil_capabilities_to_name(uint32_t bit
)
233 enum ofputil_capabilities capabilities
= bit
;
235 switch (capabilities
) {
236 case OFPUTIL_C_FLOW_STATS
: return "FLOW_STATS";
237 case OFPUTIL_C_TABLE_STATS
: return "TABLE_STATS";
238 case OFPUTIL_C_PORT_STATS
: return "PORT_STATS";
239 case OFPUTIL_C_IP_REASM
: return "IP_REASM";
240 case OFPUTIL_C_QUEUE_STATS
: return "QUEUE_STATS";
241 case OFPUTIL_C_ARP_MATCH_IP
: return "ARP_MATCH_IP";
242 case OFPUTIL_C_STP
: return "STP";
243 case OFPUTIL_C_GROUP_STATS
: return "GROUP_STATS";
244 case OFPUTIL_C_PORT_BLOCKED
: return "PORT_BLOCKED";
245 case OFPUTIL_C_BUNDLES
: return "BUNDLES";
246 case OFPUTIL_C_FLOW_MONITORING
: return "FLOW_MONITORING";
253 ofputil_switch_features_format(struct ds
*s
,
254 const struct ofputil_switch_features
*features
)
256 ds_put_format(s
, " dpid:%016"PRIx64
"\n", features
->datapath_id
);
258 ds_put_format(s
, "n_tables:%"PRIu8
", n_buffers:%"PRIu32
,
259 features
->n_tables
, features
->n_buffers
);
260 if (features
->auxiliary_id
) {
261 ds_put_format(s
, ", auxiliary_id:%"PRIu8
, features
->auxiliary_id
);
263 ds_put_char(s
, '\n');
265 ds_put_cstr(s
, "capabilities: ");
266 ofp_print_bit_names(s
, features
->capabilities
,
267 ofputil_capabilities_to_name
, ' ');
268 ds_put_char(s
, '\n');
270 if (features
->ofpacts
) {
271 ds_put_cstr(s
, "actions: ");
272 ofpact_bitmap_format(features
->ofpacts
, s
);
273 ds_put_char(s
, '\n');
278 ofputil_frag_handling_to_string(enum ofputil_frag_handling frag
)
281 case OFPUTIL_FRAG_NORMAL
: return "normal";
282 case OFPUTIL_FRAG_DROP
: return "drop";
283 case OFPUTIL_FRAG_REASM
: return "reassemble";
284 case OFPUTIL_FRAG_NX_MATCH
: return "nx-match";
291 ofputil_frag_handling_from_string(const char *s
,
292 enum ofputil_frag_handling
*frag
)
294 if (!strcasecmp(s
, "normal")) {
295 *frag
= OFPUTIL_FRAG_NORMAL
;
296 } else if (!strcasecmp(s
, "drop")) {
297 *frag
= OFPUTIL_FRAG_DROP
;
298 } else if (!strcasecmp(s
, "reassemble")) {
299 *frag
= OFPUTIL_FRAG_REASM
;
300 } else if (!strcasecmp(s
, "nx-match")) {
301 *frag
= OFPUTIL_FRAG_NX_MATCH
;
308 /* ofputil_switch_config */
310 /* Decodes 'oh', which must be an OFPT_GET_CONFIG_REPLY or OFPT_SET_CONFIG
311 * message, into 'config'. Returns false if 'oh' contained any flags that
312 * aren't specified in its version of OpenFlow, true otherwise. */
314 ofputil_decode_switch_config(const struct ofp_header
*oh
,
315 struct ofputil_switch_config
*config
)
317 struct ofpbuf b
= ofpbuf_const_initializer(oh
, ntohs(oh
->length
));
318 ofpraw_pull_assert(&b
);
320 const struct ofp_switch_config
*osc
= ofpbuf_pull(&b
, sizeof *osc
);
321 config
->frag
= ntohs(osc
->flags
) & OFPC_FRAG_MASK
;
322 config
->miss_send_len
= ntohs(osc
->miss_send_len
);
324 ovs_be16 valid_mask
= htons(OFPC_FRAG_MASK
);
325 if (oh
->version
< OFP13_VERSION
) {
326 const ovs_be16 ttl_bit
= htons(OFPC_INVALID_TTL_TO_CONTROLLER
);
327 valid_mask
|= ttl_bit
;
328 config
->invalid_ttl_to_controller
= (osc
->flags
& ttl_bit
) != 0;
330 config
->invalid_ttl_to_controller
= -1;
333 return !(osc
->flags
& ~valid_mask
);
337 ofputil_decode_get_config_reply(const struct ofp_header
*oh
,
338 struct ofputil_switch_config
*config
)
340 ofputil_decode_switch_config(oh
, config
);
344 ofputil_decode_set_config(const struct ofp_header
*oh
,
345 struct ofputil_switch_config
*config
)
347 return (ofputil_decode_switch_config(oh
, config
)
349 : OFPERR_OFPSCFC_BAD_FLAGS
);
352 static struct ofpbuf
*
353 ofputil_put_switch_config(const struct ofputil_switch_config
*config
,
356 const struct ofp_header
*oh
= b
->data
;
357 struct ofp_switch_config
*osc
= ofpbuf_put_zeros(b
, sizeof *osc
);
358 osc
->flags
= htons(config
->frag
);
359 if (config
->invalid_ttl_to_controller
> 0 && oh
->version
< OFP13_VERSION
) {
360 osc
->flags
|= htons(OFPC_INVALID_TTL_TO_CONTROLLER
);
362 osc
->miss_send_len
= htons(config
->miss_send_len
);
367 ofputil_encode_get_config_reply(const struct ofp_header
*request
,
368 const struct ofputil_switch_config
*config
)
370 struct ofpbuf
*b
= ofpraw_alloc_reply(OFPRAW_OFPT_GET_CONFIG_REPLY
,
372 return ofputil_put_switch_config(config
, b
);
376 ofputil_encode_set_config(const struct ofputil_switch_config
*config
,
377 enum ofp_version version
)
379 struct ofpbuf
*b
= ofpraw_alloc(OFPRAW_OFPT_SET_CONFIG
, version
, 0);
380 return ofputil_put_switch_config(config
, b
);
384 ofputil_switch_config_format(struct ds
*s
,
385 const struct ofputil_switch_config
*config
)
387 ds_put_format(s
, " frags=%s",
388 ofputil_frag_handling_to_string(config
->frag
));
390 if (config
->invalid_ttl_to_controller
> 0) {
391 ds_put_format(s
, " invalid_ttl_to_controller");
394 ds_put_format(s
, " miss_send_len=%"PRIu16
"\n", config
->miss_send_len
);