]> git.proxmox.com Git - mirror_ovs.git/blob - lib/ofp-switch.c
netdev-offload-tc: Use single 'once' variable for probing tc features
[mirror_ovs.git] / lib / ofp-switch.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-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"
26 #include "util.h"
27
28 /* ofputil_switch_features */
29
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);
41
42 static uint32_t
43 ofputil_capabilities_mask(enum ofp_version ofp_version)
44 {
45 /* Handle capabilities whose bit is unique for all OpenFlow versions */
46 switch (ofp_version) {
47 case OFP10_VERSION:
48 case OFP11_VERSION:
49 return OFPC_COMMON | OFPC_ARP_MATCH_IP;
50 case OFP12_VERSION:
51 case OFP13_VERSION:
52 return OFPC_COMMON | OFPC12_PORT_BLOCKED;
53 case OFP14_VERSION:
54 case OFP15_VERSION:
55 return OFPC_COMMON | OFPC12_PORT_BLOCKED | OFPC14_BUNDLES
56 | OFPC14_FLOW_MONITORING;
57 default:
58 /* Caller needs to check osf->header.version itself */
59 return 0;
60 }
61 }
62
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_*
67 * value. */
68 enum ofperr
69 ofputil_pull_switch_features(struct ofpbuf *b,
70 struct ofputil_switch_features *features)
71 {
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;
79
80 features->capabilities = ntohl(osf->capabilities) &
81 ofputil_capabilities_mask(oh->version);
82
83 if (raw == OFPRAW_OFPT10_FEATURES_REPLY) {
84 if (osf->capabilities & htonl(OFPC10_STP)) {
85 features->capabilities |= OFPUTIL_C_STP;
86 }
87 features->ofpacts = ofpact_bitmap_from_openflow(osf->actions,
88 OFP10_VERSION);
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;
93 }
94 features->ofpacts = 0;
95 if (raw == OFPRAW_OFPT13_FEATURES_REPLY) {
96 features->auxiliary_id = osf->auxiliary_id;
97 }
98 } else {
99 return OFPERR_OFPBRC_BAD_VERSION;
100 }
101
102 return 0;
103 }
104
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.
108 *
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
113 * message.
114 *
115 * When this function returns false, the caller should send an OFPST_PORT_DESC
116 * stats request to get the ports. */
117 bool
118 ofputil_switch_features_has_ports(struct ofpbuf *b)
119 {
120 struct ofp_header *oh = b->data;
121 size_t phy_port_size;
122
123 if (oh->version >= OFP13_VERSION) {
124 /* OpenFlow 1.3+ never has ports in the feature reply. */
125 return false;
126 }
127
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. */
134 return true;
135 }
136
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);
142 return false;
143 }
144
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(). */
149 struct ofpbuf *
150 ofputil_encode_switch_features(const struct ofputil_switch_features *features,
151 enum ofputil_protocol protocol, ovs_be32 xid)
152 {
153 struct ofp_switch_features *osf;
154 struct ofpbuf *b;
155 enum ofp_version version;
156 enum ofpraw raw;
157
158 version = ofputil_protocol_to_ofp_version(protocol);
159 switch (version) {
160 case OFP10_VERSION:
161 raw = OFPRAW_OFPT10_FEATURES_REPLY;
162 break;
163 case OFP11_VERSION:
164 case OFP12_VERSION:
165 raw = OFPRAW_OFPT11_FEATURES_REPLY;
166 break;
167 case OFP13_VERSION:
168 case OFP14_VERSION:
169 case OFP15_VERSION:
170 raw = OFPRAW_OFPT13_FEATURES_REPLY;
171 break;
172 default:
173 OVS_NOT_REACHED();
174 }
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;
180
181 osf->capabilities = htonl(features->capabilities &
182 ofputil_capabilities_mask(version));
183 switch (version) {
184 case OFP10_VERSION:
185 if (features->capabilities & OFPUTIL_C_STP) {
186 osf->capabilities |= htonl(OFPC10_STP);
187 }
188 osf->actions = ofpact_bitmap_to_openflow(features->ofpacts,
189 OFP10_VERSION);
190 break;
191 case OFP13_VERSION:
192 case OFP14_VERSION:
193 case OFP15_VERSION:
194 osf->auxiliary_id = features->auxiliary_id;
195 /* fall through */
196 case OFP11_VERSION:
197 case OFP12_VERSION:
198 if (features->capabilities & OFPUTIL_C_GROUP_STATS) {
199 osf->capabilities |= htonl(OFPC11_GROUP_STATS);
200 }
201 break;
202 default:
203 OVS_NOT_REACHED();
204 }
205
206 return b;
207 }
208
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'. */
212 void
213 ofputil_put_switch_features_port(const struct ofputil_phy_port *pp,
214 struct ofpbuf *b)
215 {
216 const struct ofp_header *oh = b->data;
217
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) {
225 b->size = start_ofs;
226 }
227 }
228 }
229
230 static const char *
231 ofputil_capabilities_to_name(uint32_t bit)
232 {
233 enum ofputil_capabilities capabilities = bit;
234
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";
247 }
248
249 return NULL;
250 }
251
252 void
253 ofputil_switch_features_format(struct ds *s,
254 const struct ofputil_switch_features *features)
255 {
256 ds_put_format(s, " dpid:%016"PRIx64"\n", features->datapath_id);
257
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);
262 }
263 ds_put_char(s, '\n');
264
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');
269
270 if (features->ofpacts) {
271 ds_put_cstr(s, "actions: ");
272 ofpact_bitmap_format(features->ofpacts, s);
273 ds_put_char(s, '\n');
274 }
275 }
276
277 const char *
278 ofputil_frag_handling_to_string(enum ofputil_frag_handling frag)
279 {
280 switch (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";
285 }
286
287 OVS_NOT_REACHED();
288 }
289
290 bool
291 ofputil_frag_handling_from_string(const char *s,
292 enum ofputil_frag_handling *frag)
293 {
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;
302 } else {
303 return false;
304 }
305 return true;
306 }
307 \f
308 /* ofputil_switch_config */
309
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. */
313 static bool
314 ofputil_decode_switch_config(const struct ofp_header *oh,
315 struct ofputil_switch_config *config)
316 {
317 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
318 ofpraw_pull_assert(&b);
319
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);
323
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;
329 } else {
330 config->invalid_ttl_to_controller = -1;
331 }
332
333 return !(osc->flags & ~valid_mask);
334 }
335
336 void
337 ofputil_decode_get_config_reply(const struct ofp_header *oh,
338 struct ofputil_switch_config *config)
339 {
340 ofputil_decode_switch_config(oh, config);
341 }
342
343 enum ofperr
344 ofputil_decode_set_config(const struct ofp_header *oh,
345 struct ofputil_switch_config *config)
346 {
347 return (ofputil_decode_switch_config(oh, config)
348 ? 0
349 : OFPERR_OFPSCFC_BAD_FLAGS);
350 }
351
352 static struct ofpbuf *
353 ofputil_put_switch_config(const struct ofputil_switch_config *config,
354 struct ofpbuf *b)
355 {
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);
361 }
362 osc->miss_send_len = htons(config->miss_send_len);
363 return b;
364 }
365
366 struct ofpbuf *
367 ofputil_encode_get_config_reply(const struct ofp_header *request,
368 const struct ofputil_switch_config *config)
369 {
370 struct ofpbuf *b = ofpraw_alloc_reply(OFPRAW_OFPT_GET_CONFIG_REPLY,
371 request, 0);
372 return ofputil_put_switch_config(config, b);
373 }
374
375 struct ofpbuf *
376 ofputil_encode_set_config(const struct ofputil_switch_config *config,
377 enum ofp_version version)
378 {
379 struct ofpbuf *b = ofpraw_alloc(OFPRAW_OFPT_SET_CONFIG, version, 0);
380 return ofputil_put_switch_config(config, b);
381 }
382
383 void
384 ofputil_switch_config_format(struct ds *s,
385 const struct ofputil_switch_config *config)
386 {
387 ds_put_format(s, " frags=%s",
388 ofputil_frag_handling_to_string(config->frag));
389
390 if (config->invalid_ttl_to_controller > 0) {
391 ds_put_format(s, " invalid_ttl_to_controller");
392 }
393
394 ds_put_format(s, " miss_send_len=%"PRIu16"\n", config->miss_send_len);
395 }