]> git.proxmox.com Git - mirror_ovs.git/blame - lib/ofp-switch.c
ovs-vswitchd: Better document that ovs-vswitchd manages its own datapaths.
[mirror_ovs.git] / lib / ofp-switch.c
CommitLineData
0d71302e
BP
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"
dfc77282 25#include "openvswitch/ofp-print.h"
0d71302e
BP
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)
32BUILD_ASSERT_DECL((int) OFPUTIL_C_FLOW_STATS == OFPC_FLOW_STATS);
33BUILD_ASSERT_DECL((int) OFPUTIL_C_TABLE_STATS == OFPC_TABLE_STATS);
34BUILD_ASSERT_DECL((int) OFPUTIL_C_PORT_STATS == OFPC_PORT_STATS);
35BUILD_ASSERT_DECL((int) OFPUTIL_C_IP_REASM == OFPC_IP_REASM);
36BUILD_ASSERT_DECL((int) OFPUTIL_C_QUEUE_STATS == OFPC_QUEUE_STATS);
37BUILD_ASSERT_DECL((int) OFPUTIL_C_ARP_MATCH_IP == OFPC_ARP_MATCH_IP);
38BUILD_ASSERT_DECL((int) OFPUTIL_C_PORT_BLOCKED == OFPC12_PORT_BLOCKED);
39BUILD_ASSERT_DECL((int) OFPUTIL_C_BUNDLES == OFPC14_BUNDLES);
40BUILD_ASSERT_DECL((int) OFPUTIL_C_FLOW_MONITORING == OFPC14_FLOW_MONITORING);
41
42static uint32_t
43ofputil_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 case OFP16_VERSION:
56 return OFPC_COMMON | OFPC12_PORT_BLOCKED | OFPC14_BUNDLES
57 | OFPC14_FLOW_MONITORING;
58 default:
59 /* Caller needs to check osf->header.version itself */
60 return 0;
61 }
62}
63
64/* Pulls an OpenFlow "switch_features" structure from 'b' and decodes it into
65 * an abstract representation in '*features', readying 'b' to iterate over the
66 * OpenFlow port structures following 'osf' with later calls to
67 * ofputil_pull_phy_port(). Returns 0 if successful, otherwise an OFPERR_*
68 * value. */
69enum ofperr
70ofputil_pull_switch_features(struct ofpbuf *b,
71 struct ofputil_switch_features *features)
72{
73 const struct ofp_header *oh = b->data;
74 enum ofpraw raw = ofpraw_pull_assert(b);
75 const struct ofp_switch_features *osf = ofpbuf_pull(b, sizeof *osf);
76 features->datapath_id = ntohll(osf->datapath_id);
77 features->n_buffers = ntohl(osf->n_buffers);
78 features->n_tables = osf->n_tables;
79 features->auxiliary_id = 0;
80
81 features->capabilities = ntohl(osf->capabilities) &
82 ofputil_capabilities_mask(oh->version);
83
84 if (raw == OFPRAW_OFPT10_FEATURES_REPLY) {
85 if (osf->capabilities & htonl(OFPC10_STP)) {
86 features->capabilities |= OFPUTIL_C_STP;
87 }
88 features->ofpacts = ofpact_bitmap_from_openflow(osf->actions,
89 OFP10_VERSION);
90 } else if (raw == OFPRAW_OFPT11_FEATURES_REPLY
91 || raw == OFPRAW_OFPT13_FEATURES_REPLY) {
92 if (osf->capabilities & htonl(OFPC11_GROUP_STATS)) {
93 features->capabilities |= OFPUTIL_C_GROUP_STATS;
94 }
95 features->ofpacts = 0;
96 if (raw == OFPRAW_OFPT13_FEATURES_REPLY) {
97 features->auxiliary_id = osf->auxiliary_id;
98 }
99 } else {
100 return OFPERR_OFPBRC_BAD_VERSION;
101 }
102
103 return 0;
104}
105
106/* In OpenFlow 1.0, 1.1, and 1.2, an OFPT_FEATURES_REPLY message lists all the
107 * switch's ports, unless there are too many to fit. In OpenFlow 1.3 and
108 * later, an OFPT_FEATURES_REPLY does not list ports at all.
109 *
110 * Given a buffer 'b' that contains a Features Reply message, this message
111 * checks if it contains a complete list of the switch's ports. Returns true,
112 * if so. Returns false if the list is missing (OF1.3+) or incomplete
113 * (OF1.0/1.1/1.2), and in the latter case removes all of the ports from the
114 * message.
115 *
116 * When this function returns false, the caller should send an OFPST_PORT_DESC
117 * stats request to get the ports. */
118bool
119ofputil_switch_features_has_ports(struct ofpbuf *b)
120{
121 struct ofp_header *oh = b->data;
122 size_t phy_port_size;
123
124 if (oh->version >= OFP13_VERSION) {
125 /* OpenFlow 1.3+ never has ports in the feature reply. */
126 return false;
127 }
128
129 phy_port_size = (oh->version == OFP10_VERSION
130 ? sizeof(struct ofp10_phy_port)
131 : sizeof(struct ofp11_port));
132 if (ntohs(oh->length) + phy_port_size <= UINT16_MAX) {
133 /* There's room for additional ports in the feature reply.
134 * Assume that the list is complete. */
135 return true;
136 }
137
138 /* The feature reply has no room for more ports. Probably the list is
139 * truncated. Drop the ports and tell the caller to retrieve them with
140 * OFPST_PORT_DESC. */
141 b->size = sizeof *oh + sizeof(struct ofp_switch_features);
142 ofpmsg_update_length(b);
143 return false;
144}
145
146/* Returns a buffer owned by the caller that encodes 'features' in the format
147 * required by 'protocol' with the given 'xid'. The caller should append port
148 * information to the buffer with subsequent calls to
149 * ofputil_put_switch_features_port(). */
150struct ofpbuf *
151ofputil_encode_switch_features(const struct ofputil_switch_features *features,
152 enum ofputil_protocol protocol, ovs_be32 xid)
153{
154 struct ofp_switch_features *osf;
155 struct ofpbuf *b;
156 enum ofp_version version;
157 enum ofpraw raw;
158
159 version = ofputil_protocol_to_ofp_version(protocol);
160 switch (version) {
161 case OFP10_VERSION:
162 raw = OFPRAW_OFPT10_FEATURES_REPLY;
163 break;
164 case OFP11_VERSION:
165 case OFP12_VERSION:
166 raw = OFPRAW_OFPT11_FEATURES_REPLY;
167 break;
168 case OFP13_VERSION:
169 case OFP14_VERSION:
170 case OFP15_VERSION:
171 case OFP16_VERSION:
172 raw = OFPRAW_OFPT13_FEATURES_REPLY;
173 break;
174 default:
175 OVS_NOT_REACHED();
176 }
177 b = ofpraw_alloc_xid(raw, version, xid, 0);
178 osf = ofpbuf_put_zeros(b, sizeof *osf);
179 osf->datapath_id = htonll(features->datapath_id);
180 osf->n_buffers = htonl(features->n_buffers);
181 osf->n_tables = features->n_tables;
182
183 osf->capabilities = htonl(features->capabilities &
184 ofputil_capabilities_mask(version));
185 switch (version) {
186 case OFP10_VERSION:
187 if (features->capabilities & OFPUTIL_C_STP) {
188 osf->capabilities |= htonl(OFPC10_STP);
189 }
190 osf->actions = ofpact_bitmap_to_openflow(features->ofpacts,
191 OFP10_VERSION);
192 break;
193 case OFP13_VERSION:
194 case OFP14_VERSION:
195 case OFP15_VERSION:
196 case OFP16_VERSION:
197 osf->auxiliary_id = features->auxiliary_id;
198 /* fall through */
199 case OFP11_VERSION:
200 case OFP12_VERSION:
201 if (features->capabilities & OFPUTIL_C_GROUP_STATS) {
202 osf->capabilities |= htonl(OFPC11_GROUP_STATS);
203 }
204 break;
205 default:
206 OVS_NOT_REACHED();
207 }
208
209 return b;
210}
211
212/* Encodes 'pp' into the format required by the switch_features message already
213 * in 'b', which should have been returned by ofputil_encode_switch_features(),
214 * and appends the encoded version to 'b'. */
215void
216ofputil_put_switch_features_port(const struct ofputil_phy_port *pp,
217 struct ofpbuf *b)
218{
219 const struct ofp_header *oh = b->data;
220
221 if (oh->version < OFP13_VERSION) {
222 /* Try adding a port description to the message, but drop it again if
223 * the buffer overflows. (This possibility for overflow is why
224 * OpenFlow 1.3+ moved port descriptions into a multipart message.) */
225 size_t start_ofs = b->size;
226 ofputil_put_phy_port(oh->version, pp, b);
227 if (b->size > UINT16_MAX) {
228 b->size = start_ofs;
229 }
230 }
231}
232
dfc77282
BP
233static const char *
234ofputil_capabilities_to_name(uint32_t bit)
235{
236 enum ofputil_capabilities capabilities = bit;
237
238 switch (capabilities) {
239 case OFPUTIL_C_FLOW_STATS: return "FLOW_STATS";
240 case OFPUTIL_C_TABLE_STATS: return "TABLE_STATS";
241 case OFPUTIL_C_PORT_STATS: return "PORT_STATS";
242 case OFPUTIL_C_IP_REASM: return "IP_REASM";
243 case OFPUTIL_C_QUEUE_STATS: return "QUEUE_STATS";
244 case OFPUTIL_C_ARP_MATCH_IP: return "ARP_MATCH_IP";
245 case OFPUTIL_C_STP: return "STP";
246 case OFPUTIL_C_GROUP_STATS: return "GROUP_STATS";
247 case OFPUTIL_C_PORT_BLOCKED: return "PORT_BLOCKED";
248 case OFPUTIL_C_BUNDLES: return "BUNDLES";
249 case OFPUTIL_C_FLOW_MONITORING: return "FLOW_MONITORING";
250 }
251
252 return NULL;
253}
254
255void
256ofputil_switch_features_format(struct ds *s,
257 const struct ofputil_switch_features *features)
258{
259 ds_put_format(s, " dpid:%016"PRIx64"\n", features->datapath_id);
260
261 ds_put_format(s, "n_tables:%"PRIu8", n_buffers:%"PRIu32,
262 features->n_tables, features->n_buffers);
263 if (features->auxiliary_id) {
264 ds_put_format(s, ", auxiliary_id:%"PRIu8, features->auxiliary_id);
265 }
266 ds_put_char(s, '\n');
267
268 ds_put_cstr(s, "capabilities: ");
269 ofp_print_bit_names(s, features->capabilities,
270 ofputil_capabilities_to_name, ' ');
271 ds_put_char(s, '\n');
272
273 if (features->ofpacts) {
274 ds_put_cstr(s, "actions: ");
275 ofpact_bitmap_format(features->ofpacts, s);
276 ds_put_char(s, '\n');
277 }
278}
279
0d71302e
BP
280const char *
281ofputil_frag_handling_to_string(enum ofputil_frag_handling frag)
282{
283 switch (frag) {
284 case OFPUTIL_FRAG_NORMAL: return "normal";
285 case OFPUTIL_FRAG_DROP: return "drop";
286 case OFPUTIL_FRAG_REASM: return "reassemble";
287 case OFPUTIL_FRAG_NX_MATCH: return "nx-match";
288 }
289
290 OVS_NOT_REACHED();
291}
292
293bool
294ofputil_frag_handling_from_string(const char *s,
295 enum ofputil_frag_handling *frag)
296{
297 if (!strcasecmp(s, "normal")) {
298 *frag = OFPUTIL_FRAG_NORMAL;
299 } else if (!strcasecmp(s, "drop")) {
300 *frag = OFPUTIL_FRAG_DROP;
301 } else if (!strcasecmp(s, "reassemble")) {
302 *frag = OFPUTIL_FRAG_REASM;
303 } else if (!strcasecmp(s, "nx-match")) {
304 *frag = OFPUTIL_FRAG_NX_MATCH;
305 } else {
306 return false;
307 }
308 return true;
309}
310\f
311/* ofputil_switch_config */
312
313/* Decodes 'oh', which must be an OFPT_GET_CONFIG_REPLY or OFPT_SET_CONFIG
314 * message, into 'config'. Returns false if 'oh' contained any flags that
315 * aren't specified in its version of OpenFlow, true otherwise. */
316static bool
317ofputil_decode_switch_config(const struct ofp_header *oh,
318 struct ofputil_switch_config *config)
319{
320 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
321 ofpraw_pull_assert(&b);
322
323 const struct ofp_switch_config *osc = ofpbuf_pull(&b, sizeof *osc);
324 config->frag = ntohs(osc->flags) & OFPC_FRAG_MASK;
325 config->miss_send_len = ntohs(osc->miss_send_len);
326
327 ovs_be16 valid_mask = htons(OFPC_FRAG_MASK);
328 if (oh->version < OFP13_VERSION) {
329 const ovs_be16 ttl_bit = htons(OFPC_INVALID_TTL_TO_CONTROLLER);
330 valid_mask |= ttl_bit;
331 config->invalid_ttl_to_controller = (osc->flags & ttl_bit) != 0;
332 } else {
333 config->invalid_ttl_to_controller = -1;
334 }
335
336 return !(osc->flags & ~valid_mask);
337}
338
339void
340ofputil_decode_get_config_reply(const struct ofp_header *oh,
341 struct ofputil_switch_config *config)
342{
343 ofputil_decode_switch_config(oh, config);
344}
345
346enum ofperr
347ofputil_decode_set_config(const struct ofp_header *oh,
348 struct ofputil_switch_config *config)
349{
350 return (ofputil_decode_switch_config(oh, config)
351 ? 0
352 : OFPERR_OFPSCFC_BAD_FLAGS);
353}
354
355static struct ofpbuf *
356ofputil_put_switch_config(const struct ofputil_switch_config *config,
357 struct ofpbuf *b)
358{
359 const struct ofp_header *oh = b->data;
360 struct ofp_switch_config *osc = ofpbuf_put_zeros(b, sizeof *osc);
361 osc->flags = htons(config->frag);
362 if (config->invalid_ttl_to_controller > 0 && oh->version < OFP13_VERSION) {
363 osc->flags |= htons(OFPC_INVALID_TTL_TO_CONTROLLER);
364 }
365 osc->miss_send_len = htons(config->miss_send_len);
366 return b;
367}
368
369struct ofpbuf *
370ofputil_encode_get_config_reply(const struct ofp_header *request,
371 const struct ofputil_switch_config *config)
372{
373 struct ofpbuf *b = ofpraw_alloc_reply(OFPRAW_OFPT_GET_CONFIG_REPLY,
374 request, 0);
375 return ofputil_put_switch_config(config, b);
376}
377
378struct ofpbuf *
379ofputil_encode_set_config(const struct ofputil_switch_config *config,
380 enum ofp_version version)
381{
382 struct ofpbuf *b = ofpraw_alloc(OFPRAW_OFPT_SET_CONFIG, version, 0);
383 return ofputil_put_switch_config(config, b);
384}
dfc77282
BP
385
386void
387ofputil_switch_config_format(struct ds *s,
388 const struct ofputil_switch_config *config)
389{
390 ds_put_format(s, " frags=%s",
391 ofputil_frag_handling_to_string(config->frag));
392
393 if (config->invalid_ttl_to_controller > 0) {
394 ds_put_format(s, " invalid_ttl_to_controller");
395 }
396
397 ds_put_format(s, " miss_send_len=%"PRIu16"\n", config->miss_send_len);
398}