]>
Commit | Line | Data |
---|---|---|
09246b99 | 1 | /* |
f6e984d7 | 2 | * Copyright (c) 2010, 2011, 2012, 2013, 2014 Nicira, Inc. |
09246b99 BP |
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 | ||
19 | #include "nx-match.h" | |
20 | ||
685a51a5 JP |
21 | #include <netinet/icmp6.h> |
22 | ||
09246b99 BP |
23 | #include "classifier.h" |
24 | #include "dynamic-string.h" | |
178742f9 | 25 | #include "hmap.h" |
6a885fd0 | 26 | #include "meta-flow.h" |
f25d0cf3 | 27 | #include "ofp-actions.h" |
90bf1e07 | 28 | #include "ofp-errors.h" |
09246b99 BP |
29 | #include "ofp-util.h" |
30 | #include "ofpbuf.h" | |
31 | #include "openflow/nicira-ext.h" | |
32 | #include "packets.h" | |
178742f9 | 33 | #include "shash.h" |
09246b99 | 34 | #include "unaligned.h" |
ddc4f8e2 | 35 | #include "util.h" |
09246b99 BP |
36 | #include "vlog.h" |
37 | ||
38 | VLOG_DEFINE_THIS_MODULE(nx_match); | |
39 | ||
178742f9 BP |
40 | /* |
41 | * OXM Class IDs. | |
42 | * The high order bit differentiate reserved classes from member classes. | |
43 | * Classes 0x0000 to 0x7FFF are member classes, allocated by ONF. | |
44 | * Classes 0x8000 to 0xFFFE are reserved classes, reserved for standardisation. | |
45 | */ | |
46 | enum ofp12_oxm_class { | |
47 | OFPXMC12_NXM_0 = 0x0000, /* Backward compatibility with NXM */ | |
48 | OFPXMC12_NXM_1 = 0x0001, /* Backward compatibility with NXM */ | |
49 | OFPXMC12_OPENFLOW_BASIC = 0x8000, /* Basic class for OpenFlow */ | |
50 | OFPXMC15_PACKET_REGS = 0x8001, /* Packet registers (pipeline fields). */ | |
51 | OFPXMC12_EXPERIMENTER = 0xffff, /* Experimenter class */ | |
52 | }; | |
53 | ||
54 | /* Functions for extracting fields from OXM/NXM headers. */ | |
55 | static int nxm_vendor(uint32_t header) { return header >> 16; } | |
56 | static int nxm_field(uint32_t header) { return (header >> 9) & 0x7f; } | |
57 | static bool nxm_hasmask(uint32_t header) { return (header & 0x100) != 0; } | |
58 | static int nxm_length(uint32_t header) { return header & 0xff; } | |
59 | ||
60 | /* Returns true if 'header' is a legacy NXM header, false if it is an OXM | |
61 | * header.*/ | |
62 | static bool | |
63 | is_nxm_header(uint32_t header) | |
64 | { | |
65 | return nxm_vendor(header) <= 1; | |
66 | } | |
67 | ||
68 | #define NXM_HEADER(VENDOR, FIELD, HASMASK, LENGTH) \ | |
69 | (((VENDOR) << 16) | ((FIELD) << 9) | ((HASMASK) << 8) | (LENGTH)) | |
70 | ||
71 | #define NXM_HEADER_FMT "%d:%d:%d:%d" | |
72 | #define NXM_HEADER_ARGS(HEADER) \ | |
73 | nxm_vendor(HEADER), nxm_field(HEADER), \ | |
74 | nxm_hasmask(HEADER), nxm_length(HEADER) | |
75 | ||
76 | /* Functions for turning the "hasmask" bit on or off. (This also requires | |
77 | * adjusting the length.) */ | |
78 | static uint32_t | |
79 | nxm_make_exact_header(uint32_t header) | |
80 | { | |
81 | return NXM_HEADER(nxm_vendor(header), nxm_field(header), 0, | |
82 | nxm_length(header) / 2); | |
83 | } | |
84 | static uint32_t | |
85 | nxm_make_wild_header(uint32_t header) | |
86 | { | |
87 | return NXM_HEADER(nxm_vendor(header), nxm_field(header), 1, | |
88 | nxm_length(header) * 2); | |
89 | } | |
90 | ||
91 | /* Flow cookie. | |
92 | * | |
93 | * This may be used to gain the OpenFlow 1.1-like ability to restrict | |
94 | * certain NXM-based Flow Mod and Flow Stats Request messages to flows | |
95 | * with specific cookies. See the "nx_flow_mod" and "nx_flow_stats_request" | |
96 | * structure definitions for more details. This match is otherwise not | |
97 | * allowed. */ | |
98 | #define NXM_NX_COOKIE NXM_HEADER (0x0001, 30, 0, 8) | |
99 | #define NXM_NX_COOKIE_W nxm_make_wild_header(NXM_NX_COOKIE) | |
100 | ||
101 | struct nxm_field { | |
102 | uint32_t header; | |
103 | enum ofp_version version; | |
104 | const char *name; /* e.g. "NXM_OF_IN_PORT". */ | |
105 | ||
106 | enum mf_field_id id; | |
107 | }; | |
108 | ||
109 | static const struct nxm_field *nxm_field_by_header(uint32_t header); | |
110 | static const struct nxm_field *nxm_field_by_name(const char *name, size_t len); | |
111 | static const struct nxm_field *nxm_field_by_mf_id(enum mf_field_id); | |
112 | static const struct nxm_field *oxm_field_by_mf_id(enum mf_field_id); | |
113 | ||
09246b99 BP |
114 | /* Rate limit for nx_match parse errors. These always indicate a bug in the |
115 | * peer and so there's not much point in showing a lot of them. */ | |
116 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); | |
117 | ||
178742f9 BP |
118 | static const struct nxm_field * |
119 | mf_parse_subfield_name(const char *name, int name_len, bool *wild); | |
120 | ||
121 | static const struct nxm_field * | |
122 | nxm_field_from_mf_field(enum mf_field_id id, enum ofp_version version) | |
123 | { | |
124 | const struct nxm_field *oxm = oxm_field_by_mf_id(id); | |
125 | const struct nxm_field *nxm = nxm_field_by_mf_id(id); | |
126 | return oxm && (version >= oxm->version || !nxm) ? oxm : nxm; | |
127 | } | |
128 | ||
129 | /* Returns the preferred OXM header to use for field 'id' in OpenFlow version | |
130 | * 'version'. Specify 0 for 'version' if an NXM legacy header should be | |
131 | * preferred over any standardized OXM header. Returns 0 if field 'id' cannot | |
132 | * be expressed in NXM or OXM. */ | |
133 | uint32_t | |
134 | mf_oxm_header(enum mf_field_id id, enum ofp_version version) | |
135 | { | |
136 | const struct nxm_field *f = nxm_field_from_mf_field(id, version); | |
137 | return f ? f->header : 0; | |
138 | } | |
139 | ||
140 | /* Returns the "struct mf_field" that corresponds to NXM or OXM header | |
141 | * 'header', or NULL if 'header' doesn't correspond to any known field. */ | |
142 | const struct mf_field * | |
143 | mf_from_nxm_header(uint32_t header) | |
144 | { | |
145 | const struct nxm_field *f = nxm_field_by_header(header); | |
146 | return f ? mf_from_id(f->id) : NULL; | |
147 | } | |
148 | ||
09246b99 BP |
149 | /* Returns the width of the data for a field with the given 'header', in |
150 | * bytes. */ | |
178742f9 | 151 | static int |
09246b99 BP |
152 | nxm_field_bytes(uint32_t header) |
153 | { | |
178742f9 BP |
154 | unsigned int length = nxm_length(header); |
155 | return nxm_hasmask(header) ? length / 2 : length; | |
09246b99 | 156 | } |
b6c9e612 | 157 | |
178742f9 BP |
158 | /* Returns the earliest version of OpenFlow that standardized an OXM header for |
159 | * field 'id', or UINT8_MAX if no version of OpenFlow does. */ | |
160 | static enum ofp_version | |
161 | mf_oxm_version(enum mf_field_id id) | |
b6c9e612 | 162 | { |
178742f9 BP |
163 | const struct nxm_field *oxm = oxm_field_by_mf_id(id); |
164 | return oxm ? oxm->version : UINT8_MAX; | |
b6c9e612 | 165 | } |
178742f9 | 166 | \f |
6a885fd0 | 167 | /* nx_pull_match() and helpers. */ |
09246b99 | 168 | |
178742f9 BP |
169 | /* Given NXM/OXM value 'value' and mask 'mask' associated with 'header', checks |
170 | * for any 1-bit in the value where there is a 0-bit in the mask. Returns 0 if | |
171 | * none, otherwise an error code. */ | |
172 | static bool | |
173 | is_mask_consistent(uint32_t header, const uint8_t *value, const uint8_t *mask) | |
09246b99 | 174 | { |
178742f9 BP |
175 | unsigned int width = nxm_field_bytes(header); |
176 | unsigned int i; | |
09246b99 | 177 | |
178742f9 BP |
178 | for (i = 0; i < width; i++) { |
179 | if (value[i] & ~mask[i]) { | |
180 | if (!VLOG_DROP_WARN(&rl)) { | |
181 | VLOG_WARN_RL(&rl, "Rejecting NXM/OXM entry "NXM_HEADER_FMT " " | |
182 | "with 1-bits in value for bits wildcarded by the " | |
183 | "mask.", NXM_HEADER_ARGS(header)); | |
184 | } | |
185 | return false; | |
09246b99 | 186 | } |
09246b99 | 187 | } |
178742f9 BP |
188 | return true; |
189 | } | |
09246b99 | 190 | |
178742f9 BP |
191 | static bool |
192 | is_cookie_pseudoheader(uint32_t header) | |
193 | { | |
194 | return header == NXM_NX_COOKIE || header == NXM_NX_COOKIE_W; | |
195 | } | |
196 | ||
197 | static enum ofperr | |
198 | nx_pull_header__(struct ofpbuf *b, bool allow_cookie, uint32_t *header, | |
199 | const struct mf_field **field) | |
200 | { | |
201 | if (ofpbuf_size(b) < 4) { | |
202 | VLOG_DBG_RL(&rl, "encountered partial (%"PRIu32"-byte) OXM entry", | |
203 | ofpbuf_size(b)); | |
204 | goto error; | |
09246b99 | 205 | } |
178742f9 BP |
206 | *header = ntohl(get_unaligned_be32(ofpbuf_pull(b, 4))); |
207 | if (nxm_length(*header) == 0) { | |
208 | VLOG_WARN_RL(&rl, "OXM header "NXM_HEADER_FMT" has zero length", | |
209 | NXM_HEADER_ARGS(*header)); | |
210 | goto error; | |
211 | } | |
212 | if (field) { | |
213 | *field = mf_from_nxm_header(*header); | |
214 | if (!*field && !(allow_cookie && is_cookie_pseudoheader(*header))) { | |
215 | VLOG_DBG_RL(&rl, "OXM header "NXM_HEADER_FMT" is unknown", | |
216 | NXM_HEADER_ARGS(*header)); | |
217 | return OFPERR_OFPBMC_BAD_FIELD; | |
218 | } | |
09246b99 BP |
219 | } |
220 | ||
178742f9 BP |
221 | return 0; |
222 | ||
223 | error: | |
224 | *header = 0; | |
225 | *field = NULL; | |
226 | return OFPERR_OFPBMC_BAD_LEN; | |
09246b99 BP |
227 | } |
228 | ||
3947cc76 | 229 | static enum ofperr |
178742f9 BP |
230 | nx_pull_entry__(struct ofpbuf *b, bool allow_cookie, uint32_t *header, |
231 | const struct mf_field **field, | |
232 | union mf_value *value, union mf_value *mask) | |
e1cfc4e4 | 233 | { |
178742f9 BP |
234 | enum ofperr header_error; |
235 | unsigned int payload_len; | |
236 | const uint8_t *payload; | |
237 | int width; | |
e1cfc4e4 | 238 | |
178742f9 BP |
239 | header_error = nx_pull_header__(b, allow_cookie, header, field); |
240 | if (header_error && header_error != OFPERR_OFPBMC_BAD_FIELD) { | |
241 | return header_error; | |
242 | } | |
243 | ||
244 | payload_len = nxm_length(*header); | |
245 | payload = ofpbuf_try_pull(b, payload_len); | |
246 | if (!payload) { | |
247 | VLOG_DBG_RL(&rl, "OXM header "NXM_HEADER_FMT" calls for %u-byte " | |
248 | "payload but only %"PRIu32" bytes follow OXM header", | |
249 | NXM_HEADER_ARGS(*header), payload_len, ofpbuf_size(b)); | |
250 | return OFPERR_OFPBMC_BAD_LEN; | |
251 | } | |
252 | ||
253 | width = nxm_field_bytes(*header); | |
254 | if (nxm_hasmask(*header) | |
255 | && !is_mask_consistent(*header, payload, payload + width)) { | |
256 | return OFPERR_OFPBMC_BAD_WILDCARDS; | |
257 | } | |
258 | ||
259 | memcpy(value, payload, MIN(width, sizeof *value)); | |
260 | if (mask) { | |
261 | if (nxm_hasmask(*header)) { | |
262 | memcpy(mask, payload + width, MIN(width, sizeof *mask)); | |
263 | } else { | |
264 | memset(mask, 0xff, MIN(width, sizeof *mask)); | |
265 | } | |
266 | } else if (nxm_hasmask(*header)) { | |
267 | VLOG_DBG_RL(&rl, "OXM header "NXM_HEADER_FMT" includes mask but " | |
268 | "masked OXMs are not allowed here", | |
269 | NXM_HEADER_ARGS(*header)); | |
270 | return OFPERR_OFPBMC_BAD_MASK; | |
271 | } | |
272 | ||
273 | return header_error; | |
274 | } | |
275 | ||
276 | /* Attempts to pull an NXM or OXM header, value, and mask (if present) from the | |
277 | * beginning of 'b'. If successful, stores a pointer to the "struct mf_field" | |
278 | * corresponding to the pulled header in '*field', the value into '*value', | |
279 | * and the mask into '*mask', and returns 0. On error, returns an OpenFlow | |
280 | * error; in this case, some bytes might have been pulled off 'b' anyhow, and | |
281 | * the output parameters might have been modified. | |
282 | * | |
283 | * If a NULL 'mask' is supplied, masked OXM or NXM entries are treated as | |
284 | * errors (with OFPERR_OFPBMC_BAD_MASK). | |
285 | */ | |
286 | enum ofperr | |
287 | nx_pull_entry(struct ofpbuf *b, const struct mf_field **field, | |
288 | union mf_value *value, union mf_value *mask) | |
289 | { | |
290 | uint32_t header; | |
291 | ||
292 | return nx_pull_entry__(b, false, &header, field, value, mask); | |
293 | } | |
294 | ||
295 | /* Attempts to pull an NXM or OXM header from the beginning of 'b'. If | |
296 | * successful, stores a pointer to the "struct mf_field" corresponding to the | |
297 | * pulled header in '*field', stores the header's hasmask bit in '*masked' | |
298 | * (true if hasmask=1, false if hasmask=0), and returns 0. On error, returns | |
299 | * an OpenFlow error; in this case, some bytes might have been pulled off 'b' | |
300 | * anyhow, and the output parameters might have been modified. | |
301 | * | |
302 | * If NULL 'masked' is supplied, masked OXM or NXM headers are treated as | |
303 | * errors (with OFPERR_OFPBMC_BAD_MASK). | |
304 | */ | |
305 | enum ofperr | |
306 | nx_pull_header(struct ofpbuf *b, const struct mf_field **field, bool *masked) | |
307 | { | |
308 | enum ofperr error; | |
309 | uint32_t header; | |
310 | ||
311 | error = nx_pull_header__(b, false, &header, field); | |
312 | if (masked) { | |
313 | *masked = !error && nxm_hasmask(header); | |
314 | } else if (!error && nxm_hasmask(header)) { | |
315 | error = OFPERR_OFPBMC_BAD_MASK; | |
316 | } | |
317 | return error; | |
318 | } | |
319 | ||
320 | static enum ofperr | |
321 | nx_pull_match_entry(struct ofpbuf *b, bool allow_cookie, | |
322 | const struct mf_field **field, | |
323 | union mf_value *value, union mf_value *mask) | |
324 | { | |
325 | enum ofperr error; | |
326 | uint32_t header; | |
327 | ||
328 | error = nx_pull_entry__(b, allow_cookie, &header, field, value, mask); | |
329 | if (error) { | |
330 | return error; | |
331 | } | |
332 | if (field && *field) { | |
333 | if (!mf_is_mask_valid(*field, mask)) { | |
334 | VLOG_DBG_RL(&rl, "bad mask for field %s", (*field)->name); | |
335 | return OFPERR_OFPBMC_BAD_MASK; | |
336 | } | |
337 | if (!mf_is_value_valid(*field, value)) { | |
338 | VLOG_DBG_RL(&rl, "bad value for field %s", (*field)->name); | |
339 | return OFPERR_OFPBMC_BAD_VALUE; | |
e1cfc4e4 BP |
340 | } |
341 | } | |
3947cc76 | 342 | return 0; |
e1cfc4e4 BP |
343 | } |
344 | ||
90bf1e07 | 345 | static enum ofperr |
7623f4dd | 346 | nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict, |
81a76618 | 347 | struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask) |
09246b99 | 348 | { |
178742f9 | 349 | struct ofpbuf b; |
09246b99 | 350 | |
cb22974d | 351 | ovs_assert((cookie != NULL) == (cookie_mask != NULL)); |
e729e793 | 352 | |
81a76618 | 353 | match_init_catchall(match); |
a3a0c29e BP |
354 | if (cookie) { |
355 | *cookie = *cookie_mask = htonll(0); | |
356 | } | |
a3a0c29e | 357 | |
178742f9 BP |
358 | ofpbuf_use_const(&b, p, match_len); |
359 | while (ofpbuf_size(&b)) { | |
360 | const uint8_t *pos = ofpbuf_data(&b); | |
361 | const struct mf_field *field; | |
362 | union mf_value value; | |
363 | union mf_value mask; | |
90bf1e07 | 364 | enum ofperr error; |
09246b99 | 365 | |
178742f9 BP |
366 | error = nx_pull_match_entry(&b, cookie != NULL, &field, &value, &mask); |
367 | if (error) { | |
368 | if (error == OFPERR_OFPBMC_BAD_FIELD && !strict) { | |
369 | continue; | |
370 | } | |
371 | } else if (!field) { | |
372 | if (!cookie) { | |
2e0525bc | 373 | error = OFPERR_OFPBMC_BAD_FIELD; |
178742f9 BP |
374 | } else if (*cookie_mask) { |
375 | error = OFPERR_OFPBMC_DUP_FIELD; | |
102ce766 | 376 | } else { |
178742f9 BP |
377 | *cookie = value.be64; |
378 | *cookie_mask = mask.be64; | |
102ce766 | 379 | } |
178742f9 | 380 | } else if (!mf_are_prereqs_ok(field, &match->flow)) { |
2e0525bc | 381 | error = OFPERR_OFPBMC_BAD_PREREQ; |
178742f9 | 382 | } else if (!mf_is_all_wild(field, &match->wc)) { |
2e0525bc | 383 | error = OFPERR_OFPBMC_DUP_FIELD; |
72333065 | 384 | } else { |
178742f9 | 385 | mf_set(field, &value, &mask, match); |
e729e793 JP |
386 | } |
387 | ||
09246b99 | 388 | if (error) { |
178742f9 BP |
389 | VLOG_DBG_RL(&rl, "error parsing OXM at offset %"PRIdPTR" " |
390 | "within match (%s)", pos - | |
391 | p, ofperr_to_string(error)); | |
09246b99 BP |
392 | return error; |
393 | } | |
09246b99 BP |
394 | } |
395 | ||
178742f9 | 396 | return 0; |
09246b99 | 397 | } |
102ce766 | 398 | |
7623f4dd SH |
399 | static enum ofperr |
400 | nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict, | |
81a76618 | 401 | struct match *match, |
7623f4dd SH |
402 | ovs_be64 *cookie, ovs_be64 *cookie_mask) |
403 | { | |
404 | uint8_t *p = NULL; | |
405 | ||
406 | if (match_len) { | |
407 | p = ofpbuf_try_pull(b, ROUND_UP(match_len, 8)); | |
408 | if (!p) { | |
409 | VLOG_DBG_RL(&rl, "nx_match length %u, rounded up to a " | |
410 | "multiple of 8, is longer than space in message (max " | |
1f317cb5 | 411 | "length %"PRIu32")", match_len, ofpbuf_size(b)); |
7623f4dd SH |
412 | return OFPERR_OFPBMC_BAD_LEN; |
413 | } | |
414 | } | |
415 | ||
81a76618 | 416 | return nx_pull_raw(p, match_len, strict, match, cookie, cookie_mask); |
7623f4dd SH |
417 | } |
418 | ||
102ce766 | 419 | /* Parses the nx_match formatted match description in 'b' with length |
81a76618 BP |
420 | * 'match_len'. Stores the results in 'match'. If 'cookie' and 'cookie_mask' |
421 | * are valid pointers, then stores the cookie and mask in them if 'b' contains | |
422 | * a "NXM_NX_COOKIE*" match. Otherwise, stores 0 in both. | |
102ce766 | 423 | * |
81a76618 | 424 | * Fails with an error upon encountering an unknown NXM header. |
102ce766 EJ |
425 | * |
426 | * Returns 0 if successful, otherwise an OpenFlow error code. */ | |
90bf1e07 | 427 | enum ofperr |
81a76618 | 428 | nx_pull_match(struct ofpbuf *b, unsigned int match_len, struct match *match, |
102ce766 EJ |
429 | ovs_be64 *cookie, ovs_be64 *cookie_mask) |
430 | { | |
81a76618 | 431 | return nx_pull_match__(b, match_len, true, match, cookie, cookie_mask); |
102ce766 EJ |
432 | } |
433 | ||
81a76618 BP |
434 | /* Behaves the same as nx_pull_match(), but skips over unknown NXM headers, |
435 | * instead of failing with an error. */ | |
90bf1e07 | 436 | enum ofperr |
102ce766 | 437 | nx_pull_match_loose(struct ofpbuf *b, unsigned int match_len, |
81a76618 | 438 | struct match *match, |
102ce766 EJ |
439 | ovs_be64 *cookie, ovs_be64 *cookie_mask) |
440 | { | |
81a76618 | 441 | return nx_pull_match__(b, match_len, false, match, cookie, cookie_mask); |
102ce766 | 442 | } |
7623f4dd SH |
443 | |
444 | static enum ofperr | |
81a76618 | 445 | oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match) |
7623f4dd | 446 | { |
1f317cb5 | 447 | struct ofp11_match_header *omh = ofpbuf_data(b); |
7623f4dd SH |
448 | uint8_t *p; |
449 | uint16_t match_len; | |
450 | ||
1f317cb5 | 451 | if (ofpbuf_size(b) < sizeof *omh) { |
7623f4dd SH |
452 | return OFPERR_OFPBMC_BAD_LEN; |
453 | } | |
454 | ||
455 | match_len = ntohs(omh->length); | |
456 | if (match_len < sizeof *omh) { | |
457 | return OFPERR_OFPBMC_BAD_LEN; | |
458 | } | |
459 | ||
460 | if (omh->type != htons(OFPMT_OXM)) { | |
461 | return OFPERR_OFPBMC_BAD_TYPE; | |
462 | } | |
463 | ||
464 | p = ofpbuf_try_pull(b, ROUND_UP(match_len, 8)); | |
465 | if (!p) { | |
466 | VLOG_DBG_RL(&rl, "oxm length %u, rounded up to a " | |
467 | "multiple of 8, is longer than space in message (max " | |
1f317cb5 | 468 | "length %"PRIu32")", match_len, ofpbuf_size(b)); |
7623f4dd SH |
469 | return OFPERR_OFPBMC_BAD_LEN; |
470 | } | |
471 | ||
472 | return nx_pull_raw(p + sizeof *omh, match_len - sizeof *omh, | |
81a76618 | 473 | strict, match, NULL, NULL); |
7623f4dd SH |
474 | } |
475 | ||
aa0667bc YT |
476 | /* Parses the oxm formatted match description preceded by a struct |
477 | * ofp11_match_header in 'b'. Stores the result in 'match'. | |
7623f4dd SH |
478 | * |
479 | * Fails with an error when encountering unknown OXM headers. | |
480 | * | |
481 | * Returns 0 if successful, otherwise an OpenFlow error code. */ | |
482 | enum ofperr | |
81a76618 | 483 | oxm_pull_match(struct ofpbuf *b, struct match *match) |
7623f4dd | 484 | { |
81a76618 | 485 | return oxm_pull_match__(b, true, match); |
7623f4dd SH |
486 | } |
487 | ||
488 | /* Behaves the same as oxm_pull_match() with one exception. Skips over unknown | |
aa0667bc | 489 | * OXM headers instead of failing with an error when they are encountered. */ |
7623f4dd | 490 | enum ofperr |
81a76618 | 491 | oxm_pull_match_loose(struct ofpbuf *b, struct match *match) |
7623f4dd | 492 | { |
81a76618 | 493 | return oxm_pull_match__(b, false, match); |
7623f4dd | 494 | } |
09246b99 BP |
495 | \f |
496 | /* nx_put_match() and helpers. | |
497 | * | |
498 | * 'put' functions whose names end in 'w' add a wildcarded field. | |
499 | * 'put' functions whose names end in 'm' add a field that might be wildcarded. | |
500 | * Other 'put' functions add exact-match fields. | |
501 | */ | |
502 | ||
503 | static void | |
504 | nxm_put_header(struct ofpbuf *b, uint32_t header) | |
505 | { | |
506 | ovs_be32 n_header = htonl(header); | |
507 | ofpbuf_put(b, &n_header, sizeof n_header); | |
508 | } | |
509 | ||
510 | static void | |
511 | nxm_put_8(struct ofpbuf *b, uint32_t header, uint8_t value) | |
512 | { | |
513 | nxm_put_header(b, header); | |
514 | ofpbuf_put(b, &value, sizeof value); | |
515 | } | |
516 | ||
7257b535 BP |
517 | static void |
518 | nxm_put_8m(struct ofpbuf *b, uint32_t header, uint8_t value, uint8_t mask) | |
519 | { | |
520 | switch (mask) { | |
521 | case 0: | |
522 | break; | |
523 | ||
524 | case UINT8_MAX: | |
525 | nxm_put_8(b, header, value); | |
526 | break; | |
527 | ||
528 | default: | |
178742f9 | 529 | nxm_put_header(b, nxm_make_wild_header(header)); |
7257b535 BP |
530 | ofpbuf_put(b, &value, sizeof value); |
531 | ofpbuf_put(b, &mask, sizeof mask); | |
532 | } | |
533 | } | |
534 | ||
09246b99 BP |
535 | static void |
536 | nxm_put_16(struct ofpbuf *b, uint32_t header, ovs_be16 value) | |
537 | { | |
538 | nxm_put_header(b, header); | |
539 | ofpbuf_put(b, &value, sizeof value); | |
540 | } | |
541 | ||
542 | static void | |
543 | nxm_put_16w(struct ofpbuf *b, uint32_t header, ovs_be16 value, ovs_be16 mask) | |
544 | { | |
545 | nxm_put_header(b, header); | |
546 | ofpbuf_put(b, &value, sizeof value); | |
547 | ofpbuf_put(b, &mask, sizeof mask); | |
548 | } | |
549 | ||
66642cb4 BP |
550 | static void |
551 | nxm_put_16m(struct ofpbuf *b, uint32_t header, ovs_be16 value, ovs_be16 mask) | |
552 | { | |
553 | switch (mask) { | |
554 | case 0: | |
555 | break; | |
556 | ||
b8266395 | 557 | case OVS_BE16_MAX: |
66642cb4 BP |
558 | nxm_put_16(b, header, value); |
559 | break; | |
560 | ||
561 | default: | |
178742f9 | 562 | nxm_put_16w(b, nxm_make_wild_header(header), value, mask); |
66642cb4 BP |
563 | break; |
564 | } | |
565 | } | |
566 | ||
09246b99 BP |
567 | static void |
568 | nxm_put_32(struct ofpbuf *b, uint32_t header, ovs_be32 value) | |
569 | { | |
570 | nxm_put_header(b, header); | |
571 | ofpbuf_put(b, &value, sizeof value); | |
572 | } | |
573 | ||
574 | static void | |
575 | nxm_put_32w(struct ofpbuf *b, uint32_t header, ovs_be32 value, ovs_be32 mask) | |
576 | { | |
577 | nxm_put_header(b, header); | |
578 | ofpbuf_put(b, &value, sizeof value); | |
579 | ofpbuf_put(b, &mask, sizeof mask); | |
580 | } | |
581 | ||
582 | static void | |
583 | nxm_put_32m(struct ofpbuf *b, uint32_t header, ovs_be32 value, ovs_be32 mask) | |
584 | { | |
585 | switch (mask) { | |
586 | case 0: | |
587 | break; | |
588 | ||
b8266395 | 589 | case OVS_BE32_MAX: |
09246b99 BP |
590 | nxm_put_32(b, header, value); |
591 | break; | |
592 | ||
593 | default: | |
178742f9 | 594 | nxm_put_32w(b, nxm_make_wild_header(header), value, mask); |
09246b99 BP |
595 | break; |
596 | } | |
597 | } | |
598 | ||
599 | static void | |
600 | nxm_put_64(struct ofpbuf *b, uint32_t header, ovs_be64 value) | |
601 | { | |
602 | nxm_put_header(b, header); | |
603 | ofpbuf_put(b, &value, sizeof value); | |
604 | } | |
605 | ||
8368c090 BP |
606 | static void |
607 | nxm_put_64w(struct ofpbuf *b, uint32_t header, ovs_be64 value, ovs_be64 mask) | |
608 | { | |
609 | nxm_put_header(b, header); | |
610 | ofpbuf_put(b, &value, sizeof value); | |
611 | ofpbuf_put(b, &mask, sizeof mask); | |
612 | } | |
613 | ||
614 | static void | |
615 | nxm_put_64m(struct ofpbuf *b, uint32_t header, ovs_be64 value, ovs_be64 mask) | |
616 | { | |
617 | switch (mask) { | |
618 | case 0: | |
619 | break; | |
620 | ||
b8266395 | 621 | case OVS_BE64_MAX: |
8368c090 BP |
622 | nxm_put_64(b, header, value); |
623 | break; | |
624 | ||
625 | default: | |
178742f9 | 626 | nxm_put_64w(b, nxm_make_wild_header(header), value, mask); |
8368c090 BP |
627 | break; |
628 | } | |
629 | } | |
630 | ||
09246b99 BP |
631 | static void |
632 | nxm_put_eth(struct ofpbuf *b, uint32_t header, | |
633 | const uint8_t value[ETH_ADDR_LEN]) | |
634 | { | |
635 | nxm_put_header(b, header); | |
636 | ofpbuf_put(b, value, ETH_ADDR_LEN); | |
637 | } | |
638 | ||
1e37a2d7 | 639 | static void |
73c0ce34 JS |
640 | nxm_put_eth_masked(struct ofpbuf *b, uint32_t header, |
641 | const uint8_t value[ETH_ADDR_LEN], | |
642 | const uint8_t mask[ETH_ADDR_LEN]) | |
1e37a2d7 | 643 | { |
73c0ce34 JS |
644 | if (!eth_addr_is_zero(mask)) { |
645 | if (eth_mask_is_exact(mask)) { | |
646 | nxm_put_eth(b, header, value); | |
647 | } else { | |
178742f9 | 648 | nxm_put_header(b, nxm_make_wild_header(header)); |
73c0ce34 JS |
649 | ofpbuf_put(b, value, ETH_ADDR_LEN); |
650 | ofpbuf_put(b, mask, ETH_ADDR_LEN); | |
651 | } | |
1e37a2d7 BP |
652 | } |
653 | } | |
654 | ||
d31f1109 JP |
655 | static void |
656 | nxm_put_ipv6(struct ofpbuf *b, uint32_t header, | |
657 | const struct in6_addr *value, const struct in6_addr *mask) | |
658 | { | |
659 | if (ipv6_mask_is_any(mask)) { | |
660 | return; | |
661 | } else if (ipv6_mask_is_exact(mask)) { | |
662 | nxm_put_header(b, header); | |
663 | ofpbuf_put(b, value, sizeof *value); | |
664 | } else { | |
178742f9 | 665 | nxm_put_header(b, nxm_make_wild_header(header)); |
d31f1109 JP |
666 | ofpbuf_put(b, value, sizeof *value); |
667 | ofpbuf_put(b, mask, sizeof *mask); | |
668 | } | |
669 | } | |
670 | ||
7257b535 | 671 | static void |
21119b3e | 672 | nxm_put_frag(struct ofpbuf *b, const struct match *match, enum ofp_version oxm) |
7257b535 | 673 | { |
21119b3e | 674 | uint32_t header = mf_oxm_header(MFF_IP_FRAG, oxm); |
81a76618 BP |
675 | uint8_t nw_frag = match->flow.nw_frag; |
676 | uint8_t nw_frag_mask = match->wc.masks.nw_frag; | |
7257b535 | 677 | |
eadef313 | 678 | switch (nw_frag_mask) { |
7257b535 BP |
679 | case 0: |
680 | break; | |
681 | ||
eadef313 | 682 | case FLOW_NW_FRAG_MASK: |
21119b3e | 683 | nxm_put_8(b, header, nw_frag); |
7257b535 BP |
684 | break; |
685 | ||
686 | default: | |
21119b3e | 687 | nxm_put_8m(b, header, nw_frag, nw_frag_mask & FLOW_NW_FRAG_MASK); |
7257b535 BP |
688 | break; |
689 | } | |
690 | } | |
691 | ||
5e10215d BP |
692 | /* Appends to 'b' a set of OXM or NXM matches for the IPv4 or IPv6 fields in |
693 | * 'match'. */ | |
8e7082b0 | 694 | static void |
9d84066c | 695 | nxm_put_ip(struct ofpbuf *b, const struct match *match, enum ofp_version oxm) |
8e7082b0 | 696 | { |
81a76618 | 697 | const struct flow *flow = &match->flow; |
8e7082b0 | 698 | |
5e10215d | 699 | if (flow->dl_type == htons(ETH_TYPE_IP)) { |
9d84066c | 700 | nxm_put_32m(b, mf_oxm_header(MFF_IPV4_SRC, oxm), |
5e10215d | 701 | flow->nw_src, match->wc.masks.nw_src); |
9d84066c | 702 | nxm_put_32m(b, mf_oxm_header(MFF_IPV4_DST, oxm), |
5e10215d BP |
703 | flow->nw_dst, match->wc.masks.nw_dst); |
704 | } else { | |
9d84066c | 705 | nxm_put_ipv6(b, mf_oxm_header(MFF_IPV6_SRC, oxm), |
5e10215d | 706 | &flow->ipv6_src, &match->wc.masks.ipv6_src); |
9d84066c | 707 | nxm_put_ipv6(b, mf_oxm_header(MFF_IPV6_DST, oxm), |
5e10215d BP |
708 | &flow->ipv6_dst, &match->wc.masks.ipv6_dst); |
709 | } | |
710 | ||
21119b3e | 711 | nxm_put_frag(b, match, oxm); |
8e7082b0 | 712 | |
81a76618 | 713 | if (match->wc.masks.nw_tos & IP_DSCP_MASK) { |
1638b906 | 714 | if (oxm) { |
9d84066c BP |
715 | nxm_put_8(b, mf_oxm_header(MFF_IP_DSCP_SHIFTED, oxm), |
716 | flow->nw_tos >> 2); | |
1638b906 | 717 | } else { |
9d84066c BP |
718 | nxm_put_8(b, mf_oxm_header(MFF_IP_DSCP, oxm), |
719 | flow->nw_tos & IP_DSCP_MASK); | |
1638b906 | 720 | } |
8e7082b0 BP |
721 | } |
722 | ||
81a76618 | 723 | if (match->wc.masks.nw_tos & IP_ECN_MASK) { |
9d84066c | 724 | nxm_put_8(b, mf_oxm_header(MFF_IP_ECN, oxm), |
b5ae8913 | 725 | flow->nw_tos & IP_ECN_MASK); |
8e7082b0 BP |
726 | } |
727 | ||
81a76618 | 728 | if (!oxm && match->wc.masks.nw_ttl) { |
9d84066c | 729 | nxm_put_8(b, mf_oxm_header(MFF_IP_TTL, oxm), flow->nw_ttl); |
8e7082b0 BP |
730 | } |
731 | ||
9d84066c | 732 | nxm_put_32m(b, mf_oxm_header(MFF_IPV6_LABEL, oxm), |
5e10215d BP |
733 | flow->ipv6_label, match->wc.masks.ipv6_label); |
734 | ||
81a76618 | 735 | if (match->wc.masks.nw_proto) { |
9d84066c | 736 | nxm_put_8(b, mf_oxm_header(MFF_IP_PROTO, oxm), flow->nw_proto); |
8e7082b0 BP |
737 | |
738 | if (flow->nw_proto == IPPROTO_TCP) { | |
9d84066c | 739 | nxm_put_16m(b, mf_oxm_header(MFF_TCP_SRC, oxm), |
81a76618 | 740 | flow->tp_src, match->wc.masks.tp_src); |
9d84066c | 741 | nxm_put_16m(b, mf_oxm_header(MFF_TCP_DST, oxm), |
81a76618 | 742 | flow->tp_dst, match->wc.masks.tp_dst); |
9d84066c | 743 | nxm_put_16m(b, mf_oxm_header(MFF_TCP_FLAGS, oxm), |
dc235f7f | 744 | flow->tcp_flags, match->wc.masks.tcp_flags); |
8e7082b0 | 745 | } else if (flow->nw_proto == IPPROTO_UDP) { |
9d84066c | 746 | nxm_put_16m(b, mf_oxm_header(MFF_UDP_SRC, oxm), |
81a76618 | 747 | flow->tp_src, match->wc.masks.tp_src); |
9d84066c | 748 | nxm_put_16m(b, mf_oxm_header(MFF_UDP_DST, oxm), |
81a76618 | 749 | flow->tp_dst, match->wc.masks.tp_dst); |
0d56eaf2 | 750 | } else if (flow->nw_proto == IPPROTO_SCTP) { |
9d84066c | 751 | nxm_put_16m(b, mf_oxm_header(MFF_SCTP_SRC, oxm), flow->tp_src, |
0d56eaf2 | 752 | match->wc.masks.tp_src); |
9d84066c | 753 | nxm_put_16m(b, mf_oxm_header(MFF_SCTP_DST, oxm), flow->tp_dst, |
0d56eaf2 | 754 | match->wc.masks.tp_dst); |
5e10215d BP |
755 | } else if (is_icmpv4(flow)) { |
756 | if (match->wc.masks.tp_src) { | |
9d84066c | 757 | nxm_put_8(b, mf_oxm_header(MFF_ICMPV4_TYPE, oxm), |
5e10215d BP |
758 | ntohs(flow->tp_src)); |
759 | } | |
760 | if (match->wc.masks.tp_dst) { | |
9d84066c | 761 | nxm_put_8(b, mf_oxm_header(MFF_ICMPV4_CODE, oxm), |
5e10215d BP |
762 | ntohs(flow->tp_dst)); |
763 | } | |
764 | } else if (is_icmpv6(flow)) { | |
81a76618 | 765 | if (match->wc.masks.tp_src) { |
9d84066c | 766 | nxm_put_8(b, mf_oxm_header(MFF_ICMPV6_TYPE, oxm), |
5e10215d | 767 | ntohs(flow->tp_src)); |
8e7082b0 | 768 | } |
81a76618 | 769 | if (match->wc.masks.tp_dst) { |
9d84066c | 770 | nxm_put_8(b, mf_oxm_header(MFF_ICMPV6_CODE, oxm), |
5e10215d BP |
771 | ntohs(flow->tp_dst)); |
772 | } | |
773 | if (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) || | |
774 | flow->tp_src == htons(ND_NEIGHBOR_ADVERT)) { | |
9d84066c | 775 | nxm_put_ipv6(b, mf_oxm_header(MFF_ND_TARGET, oxm), |
5e10215d BP |
776 | &flow->nd_target, &match->wc.masks.nd_target); |
777 | if (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT)) { | |
9d84066c | 778 | nxm_put_eth_masked(b, mf_oxm_header(MFF_ND_SLL, oxm), |
5e10215d BP |
779 | flow->arp_sha, match->wc.masks.arp_sha); |
780 | } | |
781 | if (flow->tp_src == htons(ND_NEIGHBOR_ADVERT)) { | |
9d84066c | 782 | nxm_put_eth_masked(b, mf_oxm_header(MFF_ND_TLL, oxm), |
5e10215d BP |
783 | flow->arp_tha, match->wc.masks.arp_tha); |
784 | } | |
8e7082b0 BP |
785 | } |
786 | } | |
787 | } | |
788 | } | |
789 | ||
81a76618 | 790 | /* Appends to 'b' the nx_match format that expresses 'match'. For Flow Mod and |
7623f4dd SH |
791 | * Flow Stats Requests messages, a 'cookie' and 'cookie_mask' may be supplied. |
792 | * Otherwise, 'cookie_mask' should be zero. | |
4d0ed519 | 793 | * |
9d84066c BP |
794 | * Specify 'oxm' as 0 to express the match in NXM format; otherwise, specify |
795 | * 'oxm' as the OpenFlow version number for the OXM format to use. | |
796 | * | |
4d0ed519 BP |
797 | * This function can cause 'b''s data to be reallocated. |
798 | * | |
799 | * Returns the number of bytes appended to 'b', excluding padding. | |
800 | * | |
81a76618 | 801 | * If 'match' is a catch-all rule that matches every packet, then this function |
4d0ed519 | 802 | * appends nothing to 'b' and returns 0. */ |
7623f4dd | 803 | static int |
9d84066c | 804 | nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, |
7623f4dd | 805 | ovs_be64 cookie, ovs_be64 cookie_mask) |
09246b99 | 806 | { |
81a76618 | 807 | const struct flow *flow = &match->flow; |
1f317cb5 | 808 | const size_t start_len = ofpbuf_size(b); |
09246b99 | 809 | int match_len; |
b6c9e612 | 810 | int i; |
09246b99 | 811 | |
0e612675 | 812 | BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27); |
a877206f | 813 | |
09246b99 | 814 | /* Metadata. */ |
a79f29f2 | 815 | if (match->wc.masks.dp_hash) { |
447b6582 BP |
816 | nxm_put_32m(b, mf_oxm_header(MFF_DP_HASH, oxm), |
817 | htonl(flow->dp_hash), htonl(match->wc.masks.dp_hash)); | |
a79f29f2 AZ |
818 | } |
819 | ||
820 | if (match->wc.masks.recirc_id) { | |
447b6582 BP |
821 | nxm_put_32(b, mf_oxm_header(MFF_RECIRC_ID, oxm), |
822 | htonl(flow->recirc_id)); | |
a79f29f2 AZ |
823 | } |
824 | ||
4e022ec0 AW |
825 | if (match->wc.masks.in_port.ofp_port) { |
826 | ofp_port_t in_port = flow->in_port.ofp_port; | |
b5ae8913 | 827 | if (oxm) { |
9d84066c BP |
828 | nxm_put_32(b, mf_oxm_header(MFF_IN_PORT_OXM, oxm), |
829 | ofputil_port_to_ofp11(in_port)); | |
b5ae8913 | 830 | } else { |
9d84066c BP |
831 | nxm_put_16(b, mf_oxm_header(MFF_IN_PORT, oxm), |
832 | htons(ofp_to_u16(in_port))); | |
b5ae8913 | 833 | } |
09246b99 BP |
834 | } |
835 | ||
836 | /* Ethernet. */ | |
9d84066c | 837 | nxm_put_eth_masked(b, mf_oxm_header(MFF_ETH_SRC, oxm), |
81a76618 | 838 | flow->dl_src, match->wc.masks.dl_src); |
9d84066c | 839 | nxm_put_eth_masked(b, mf_oxm_header(MFF_ETH_DST, oxm), |
81a76618 | 840 | flow->dl_dst, match->wc.masks.dl_dst); |
9d84066c | 841 | nxm_put_16m(b, mf_oxm_header(MFF_ETH_TYPE, oxm), |
e2170cff | 842 | ofputil_dl_type_to_openflow(flow->dl_type), |
81a76618 | 843 | match->wc.masks.dl_type); |
09246b99 | 844 | |
95f61ba8 SH |
845 | /* 802.1Q. */ |
846 | if (oxm) { | |
26720e24 BP |
847 | ovs_be16 VID_CFI_MASK = htons(VLAN_VID_MASK | VLAN_CFI); |
848 | ovs_be16 vid = flow->vlan_tci & VID_CFI_MASK; | |
81a76618 | 849 | ovs_be16 mask = match->wc.masks.vlan_tci & VID_CFI_MASK; |
95f61ba8 SH |
850 | |
851 | if (mask == htons(VLAN_VID_MASK | VLAN_CFI)) { | |
9d84066c | 852 | nxm_put_16(b, mf_oxm_header(MFF_VLAN_VID, oxm), vid); |
95f61ba8 | 853 | } else if (mask) { |
9d84066c | 854 | nxm_put_16m(b, mf_oxm_header(MFF_VLAN_VID, oxm), vid, mask); |
95f61ba8 SH |
855 | } |
856 | ||
81a76618 | 857 | if (vid && vlan_tci_to_pcp(match->wc.masks.vlan_tci)) { |
9d84066c BP |
858 | nxm_put_8(b, mf_oxm_header(MFF_VLAN_PCP, oxm), |
859 | vlan_tci_to_pcp(flow->vlan_tci)); | |
95f61ba8 SH |
860 | } |
861 | ||
862 | } else { | |
9d84066c | 863 | nxm_put_16m(b, mf_oxm_header(MFF_VLAN_TCI, oxm), flow->vlan_tci, |
81a76618 | 864 | match->wc.masks.vlan_tci); |
95f61ba8 | 865 | } |
09246b99 | 866 | |
b02475c5 SH |
867 | /* MPLS. */ |
868 | if (eth_type_mpls(flow->dl_type)) { | |
8bfd0fda | 869 | if (match->wc.masks.mpls_lse[0] & htonl(MPLS_TC_MASK)) { |
9d84066c BP |
870 | nxm_put_8(b, mf_oxm_header(MFF_MPLS_TC, oxm), |
871 | mpls_lse_to_tc(flow->mpls_lse[0])); | |
b02475c5 SH |
872 | } |
873 | ||
8bfd0fda | 874 | if (match->wc.masks.mpls_lse[0] & htonl(MPLS_BOS_MASK)) { |
9d84066c BP |
875 | nxm_put_8(b, mf_oxm_header(MFF_MPLS_BOS, oxm), |
876 | mpls_lse_to_bos(flow->mpls_lse[0])); | |
b02475c5 SH |
877 | } |
878 | ||
8bfd0fda | 879 | if (match->wc.masks.mpls_lse[0] & htonl(MPLS_LABEL_MASK)) { |
9d84066c | 880 | nxm_put_32(b, mf_oxm_header(MFF_MPLS_LABEL, oxm), |
8bfd0fda | 881 | htonl(mpls_lse_to_label(flow->mpls_lse[0]))); |
b02475c5 SH |
882 | } |
883 | } | |
884 | ||
66642cb4 | 885 | /* L3. */ |
5e10215d BP |
886 | if (is_ip_any(flow)) { |
887 | nxm_put_ip(b, match, oxm); | |
8087f5ff MM |
888 | } else if (flow->dl_type == htons(ETH_TYPE_ARP) || |
889 | flow->dl_type == htons(ETH_TYPE_RARP)) { | |
09246b99 | 890 | /* ARP. */ |
81a76618 | 891 | if (match->wc.masks.nw_proto) { |
9d84066c | 892 | nxm_put_16(b, mf_oxm_header(MFF_ARP_OP, oxm), |
b5ae8913 | 893 | htons(flow->nw_proto)); |
09246b99 | 894 | } |
9d84066c | 895 | nxm_put_32m(b, mf_oxm_header(MFF_ARP_SPA, oxm), |
81a76618 | 896 | flow->nw_src, match->wc.masks.nw_src); |
9d84066c | 897 | nxm_put_32m(b, mf_oxm_header(MFF_ARP_TPA, oxm), |
81a76618 | 898 | flow->nw_dst, match->wc.masks.nw_dst); |
9d84066c | 899 | nxm_put_eth_masked(b, mf_oxm_header(MFF_ARP_SHA, oxm), |
81a76618 | 900 | flow->arp_sha, match->wc.masks.arp_sha); |
9d84066c | 901 | nxm_put_eth_masked(b, mf_oxm_header(MFF_ARP_THA, oxm), |
81a76618 | 902 | flow->arp_tha, match->wc.masks.arp_tha); |
09246b99 BP |
903 | } |
904 | ||
905 | /* Tunnel ID. */ | |
9d84066c | 906 | nxm_put_64m(b, mf_oxm_header(MFF_TUN_ID, oxm), |
0ad90c84 JR |
907 | flow->tunnel.tun_id, match->wc.masks.tunnel.tun_id); |
908 | ||
909 | /* Other tunnel metadata. */ | |
9d84066c | 910 | nxm_put_32m(b, mf_oxm_header(MFF_TUN_SRC, oxm), |
0ad90c84 | 911 | flow->tunnel.ip_src, match->wc.masks.tunnel.ip_src); |
9d84066c | 912 | nxm_put_32m(b, mf_oxm_header(MFF_TUN_DST, oxm), |
0ad90c84 | 913 | flow->tunnel.ip_dst, match->wc.masks.tunnel.ip_dst); |
09246b99 | 914 | |
b6c9e612 | 915 | /* Registers. */ |
a678b23e BP |
916 | if (oxm < OFP15_VERSION) { |
917 | for (i = 0; i < FLOW_N_REGS; i++) { | |
918 | nxm_put_32m(b, mf_oxm_header(MFF_REG0 + i, oxm), | |
919 | htonl(flow->regs[i]), htonl(match->wc.masks.regs[i])); | |
920 | } | |
921 | } else { | |
922 | for (i = 0; i < FLOW_N_XREGS; i++) { | |
923 | nxm_put_64m(b, mf_oxm_header(MFF_XREG0 + i, oxm), | |
924 | htonll(flow_get_xreg(flow, i)), | |
925 | htonll(flow_get_xreg(&match->wc.masks, i))); | |
926 | } | |
b6c9e612 BP |
927 | } |
928 | ||
ac923e91 | 929 | /* Mark. */ |
9d84066c | 930 | nxm_put_32m(b, mf_oxm_header(MFF_PKT_MARK, oxm), htonl(flow->pkt_mark), |
ac923e91 JG |
931 | htonl(match->wc.masks.pkt_mark)); |
932 | ||
969fc56c | 933 | /* OpenFlow 1.1+ Metadata. */ |
9d84066c BP |
934 | nxm_put_64m(b, mf_oxm_header(MFF_METADATA, oxm), |
935 | flow->metadata, match->wc.masks.metadata); | |
969fc56c | 936 | |
e729e793 | 937 | /* Cookie. */ |
ba5cc068 | 938 | nxm_put_64m(b, NXM_NX_COOKIE, cookie & cookie_mask, cookie_mask); |
e729e793 | 939 | |
1f317cb5 | 940 | match_len = ofpbuf_size(b) - start_len; |
7623f4dd SH |
941 | return match_len; |
942 | } | |
943 | ||
81a76618 | 944 | /* Appends to 'b' the nx_match format that expresses 'match', plus enough zero |
7623f4dd SH |
945 | * bytes to pad the nx_match out to a multiple of 8. For Flow Mod and Flow |
946 | * Stats Requests messages, a 'cookie' and 'cookie_mask' may be supplied. | |
947 | * Otherwise, 'cookie_mask' should be zero. | |
948 | * | |
949 | * This function can cause 'b''s data to be reallocated. | |
950 | * | |
951 | * Returns the number of bytes appended to 'b', excluding padding. The return | |
952 | * value can be zero if it appended nothing at all to 'b' (which happens if | |
953 | * 'cr' is a catch-all rule that matches every packet). */ | |
954 | int | |
81a76618 | 955 | nx_put_match(struct ofpbuf *b, const struct match *match, |
7623f4dd SH |
956 | ovs_be64 cookie, ovs_be64 cookie_mask) |
957 | { | |
9d84066c | 958 | int match_len = nx_put_raw(b, 0, match, cookie, cookie_mask); |
7623f4dd | 959 | |
f6e984d7 | 960 | ofpbuf_put_zeros(b, PAD_SIZE(match_len, 8)); |
7623f4dd SH |
961 | return match_len; |
962 | } | |
963 | ||
9d84066c | 964 | /* Appends to 'b' an struct ofp11_match_header followed by the OXM format that |
81a76618 BP |
965 | * expresses 'cr', plus enough zero bytes to pad the data appended out to a |
966 | * multiple of 8. | |
7623f4dd | 967 | * |
9d84066c BP |
968 | * OXM differs slightly among versions of OpenFlow. Specify the OpenFlow |
969 | * version in use as 'version'. | |
970 | * | |
7623f4dd SH |
971 | * This function can cause 'b''s data to be reallocated. |
972 | * | |
973 | * Returns the number of bytes appended to 'b', excluding the padding. Never | |
974 | * returns zero. */ | |
975 | int | |
9d84066c BP |
976 | oxm_put_match(struct ofpbuf *b, const struct match *match, |
977 | enum ofp_version version) | |
7623f4dd SH |
978 | { |
979 | int match_len; | |
980 | struct ofp11_match_header *omh; | |
1f317cb5 | 981 | size_t start_len = ofpbuf_size(b); |
7623f4dd SH |
982 | ovs_be64 cookie = htonll(0), cookie_mask = htonll(0); |
983 | ||
984 | ofpbuf_put_uninit(b, sizeof *omh); | |
9d84066c BP |
985 | match_len = (nx_put_raw(b, version, match, cookie, cookie_mask) |
986 | + sizeof *omh); | |
f6e984d7 | 987 | ofpbuf_put_zeros(b, PAD_SIZE(match_len, 8)); |
7623f4dd | 988 | |
db5a1019 | 989 | omh = ofpbuf_at(b, start_len, sizeof *omh); |
7623f4dd SH |
990 | omh->type = htons(OFPMT_OXM); |
991 | omh->length = htons(match_len); | |
992 | ||
09246b99 BP |
993 | return match_len; |
994 | } | |
178742f9 BP |
995 | |
996 | void | |
997 | nx_put_header(struct ofpbuf *b, enum mf_field_id field, | |
998 | enum ofp_version version, bool masked) | |
999 | { | |
1000 | uint32_t header = mf_oxm_header(field, version); | |
1001 | nxm_put_header(b, masked ? nxm_make_wild_header(header) : header); | |
1002 | } | |
1003 | ||
1004 | void | |
1005 | nx_put_entry(struct ofpbuf *b, | |
1006 | enum mf_field_id field, enum ofp_version version, | |
1007 | const union mf_value *value, const union mf_value *mask) | |
1008 | { | |
1009 | int n_bytes = mf_from_id(field)->n_bytes; | |
1010 | bool masked = mask && !is_all_ones(mask, n_bytes); | |
1011 | ||
1012 | nx_put_header(b, field, version, masked); | |
1013 | ofpbuf_put(b, value, n_bytes); | |
1014 | if (masked) { | |
1015 | ofpbuf_put(b, mask, n_bytes); | |
1016 | } | |
1017 | } | |
09246b99 BP |
1018 | \f |
1019 | /* nx_match_to_string() and helpers. */ | |
1020 | ||
f393f81e BP |
1021 | static void format_nxm_field_name(struct ds *, uint32_t header); |
1022 | ||
09246b99 BP |
1023 | char * |
1024 | nx_match_to_string(const uint8_t *p, unsigned int match_len) | |
1025 | { | |
178742f9 | 1026 | struct ofpbuf b; |
09246b99 BP |
1027 | struct ds s; |
1028 | ||
1029 | if (!match_len) { | |
1030 | return xstrdup("<any>"); | |
1031 | } | |
1032 | ||
178742f9 | 1033 | ofpbuf_use_const(&b, p, match_len); |
09246b99 | 1034 | ds_init(&s); |
178742f9 BP |
1035 | while (ofpbuf_size(&b)) { |
1036 | union mf_value value; | |
1037 | union mf_value mask; | |
1038 | enum ofperr error; | |
1039 | uint32_t header; | |
1040 | int value_len; | |
1041 | ||
1042 | error = nx_pull_entry__(&b, true, &header, NULL, &value, &mask); | |
1043 | if (error) { | |
1044 | break; | |
1045 | } | |
1046 | value_len = MIN(sizeof value, nxm_field_bytes(header)); | |
09246b99 BP |
1047 | |
1048 | if (s.length) { | |
1049 | ds_put_cstr(&s, ", "); | |
1050 | } | |
1051 | ||
f393f81e | 1052 | format_nxm_field_name(&s, header); |
09246b99 BP |
1053 | ds_put_char(&s, '('); |
1054 | ||
178742f9 BP |
1055 | for (int i = 0; i < value_len; i++) { |
1056 | ds_put_format(&s, "%02x", ((const uint8_t *) &value)[i]); | |
09246b99 | 1057 | } |
178742f9 | 1058 | if (nxm_hasmask(header)) { |
09246b99 | 1059 | ds_put_char(&s, '/'); |
178742f9 BP |
1060 | for (int i = 0; i < value_len; i++) { |
1061 | ds_put_format(&s, "%02x", ((const uint8_t *) &mask)[i]); | |
09246b99 BP |
1062 | } |
1063 | } | |
1064 | ds_put_char(&s, ')'); | |
09246b99 BP |
1065 | } |
1066 | ||
178742f9 | 1067 | if (ofpbuf_size(&b)) { |
09246b99 BP |
1068 | if (s.length) { |
1069 | ds_put_cstr(&s, ", "); | |
1070 | } | |
1071 | ||
178742f9 | 1072 | ds_put_format(&s, "<%u invalid bytes>", ofpbuf_size(&b)); |
09246b99 BP |
1073 | } |
1074 | ||
1075 | return ds_steal_cstr(&s); | |
1076 | } | |
1077 | ||
7623f4dd | 1078 | char * |
db5a1019 | 1079 | oxm_match_to_string(const struct ofpbuf *p, unsigned int match_len) |
7623f4dd | 1080 | { |
1f317cb5 | 1081 | const struct ofp11_match_header *omh = ofpbuf_data(p); |
7623f4dd SH |
1082 | uint16_t match_len_; |
1083 | struct ds s; | |
1084 | ||
1085 | ds_init(&s); | |
1086 | ||
1087 | if (match_len < sizeof *omh) { | |
1088 | ds_put_format(&s, "<match too short: %u>", match_len); | |
1089 | goto err; | |
1090 | } | |
1091 | ||
1092 | if (omh->type != htons(OFPMT_OXM)) { | |
1093 | ds_put_format(&s, "<bad match type field: %u>", ntohs(omh->type)); | |
1094 | goto err; | |
1095 | } | |
1096 | ||
1097 | match_len_ = ntohs(omh->length); | |
1098 | if (match_len_ < sizeof *omh) { | |
1099 | ds_put_format(&s, "<match length field too short: %u>", match_len_); | |
1100 | goto err; | |
1101 | } | |
1102 | ||
1103 | if (match_len_ != match_len) { | |
1104 | ds_put_format(&s, "<match length field incorrect: %u != %u>", | |
1105 | match_len_, match_len); | |
1106 | goto err; | |
1107 | } | |
1108 | ||
db5a1019 AW |
1109 | return nx_match_to_string(ofpbuf_at(p, sizeof *omh, 0), |
1110 | match_len - sizeof *omh); | |
7623f4dd SH |
1111 | |
1112 | err: | |
1113 | return ds_steal_cstr(&s); | |
1114 | } | |
1115 | ||
178742f9 BP |
1116 | void |
1117 | nx_format_field_name(enum mf_field_id id, enum ofp_version version, | |
1118 | struct ds *s) | |
1119 | { | |
1120 | format_nxm_field_name(s, mf_oxm_header(id, version)); | |
1121 | } | |
1122 | ||
f393f81e BP |
1123 | static void |
1124 | format_nxm_field_name(struct ds *s, uint32_t header) | |
1125 | { | |
178742f9 BP |
1126 | const struct nxm_field *f = nxm_field_by_header(header); |
1127 | if (f) { | |
1128 | ds_put_cstr(s, f->name); | |
1129 | if (nxm_hasmask(header)) { | |
28da1f8f BP |
1130 | ds_put_cstr(s, "_W"); |
1131 | } | |
e729e793 JP |
1132 | } else if (header == NXM_NX_COOKIE) { |
1133 | ds_put_cstr(s, "NXM_NX_COOKIE"); | |
1134 | } else if (header == NXM_NX_COOKIE_W) { | |
1135 | ds_put_cstr(s, "NXM_NX_COOKIE_W"); | |
f393f81e | 1136 | } else { |
178742f9 | 1137 | ds_put_format(s, "%d:%d", nxm_vendor(header), nxm_field(header)); |
f393f81e BP |
1138 | } |
1139 | } | |
1140 | ||
178742f9 BP |
1141 | static bool |
1142 | streq_len(const char *a, size_t a_len, const char *b) | |
1143 | { | |
1144 | return strlen(b) == a_len && !memcmp(a, b, a_len); | |
1145 | } | |
1146 | ||
558d80cb BP |
1147 | static uint32_t |
1148 | parse_nxm_field_name(const char *name, int name_len) | |
09246b99 | 1149 | { |
178742f9 | 1150 | const struct nxm_field *f; |
28da1f8f | 1151 | bool wild; |
28da1f8f | 1152 | |
178742f9 BP |
1153 | f = mf_parse_subfield_name(name, name_len, &wild); |
1154 | if (f) { | |
b5ae8913 | 1155 | if (!wild) { |
178742f9 BP |
1156 | return f->header; |
1157 | } else if (mf_from_id(f->id)->maskable != MFM_NONE) { | |
1158 | return nxm_make_wild_header(f->header); | |
09246b99 BP |
1159 | } |
1160 | } | |
1161 | ||
178742f9 BP |
1162 | if (streq_len(name, name_len, "NXM_NX_COOKIE")) { |
1163 | return NXM_NX_COOKIE; | |
1164 | } else if (streq_len(name, name_len, "NXM_NX_COOKIE_W")) { | |
1165 | return NXM_NX_COOKIE_W; | |
e729e793 JP |
1166 | } |
1167 | ||
558d80cb BP |
1168 | /* Check whether it's a 32-bit field header value as hex. |
1169 | * (This isn't ordinarily useful except for testing error behavior.) */ | |
1170 | if (name_len == 8) { | |
1171 | uint32_t header = hexits_value(name, name_len, NULL); | |
1172 | if (header != UINT_MAX) { | |
1173 | return header; | |
1174 | } | |
1175 | } | |
1176 | ||
1177 | return 0; | |
09246b99 | 1178 | } |
09246b99 BP |
1179 | \f |
1180 | /* nx_match_from_string(). */ | |
1181 | ||
7623f4dd SH |
1182 | static int |
1183 | nx_match_from_string_raw(const char *s, struct ofpbuf *b) | |
09246b99 BP |
1184 | { |
1185 | const char *full_s = s; | |
1f317cb5 | 1186 | const size_t start_len = ofpbuf_size(b); |
09246b99 BP |
1187 | |
1188 | if (!strcmp(s, "<any>")) { | |
1f317cb5 | 1189 | /* Ensure that 'ofpbuf_data(b)' isn't actually null. */ |
09246b99 BP |
1190 | ofpbuf_prealloc_tailroom(b, 1); |
1191 | return 0; | |
1192 | } | |
1193 | ||
1194 | for (s += strspn(s, ", "); *s; s += strspn(s, ", ")) { | |
558d80cb BP |
1195 | const char *name; |
1196 | uint32_t header; | |
09246b99 | 1197 | int name_len; |
78090f63 | 1198 | size_t n; |
09246b99 | 1199 | |
558d80cb | 1200 | name = s; |
09246b99 BP |
1201 | name_len = strcspn(s, "("); |
1202 | if (s[name_len] != '(') { | |
1203 | ovs_fatal(0, "%s: missing ( at end of nx_match", full_s); | |
1204 | } | |
1205 | ||
558d80cb BP |
1206 | header = parse_nxm_field_name(name, name_len); |
1207 | if (!header) { | |
09246b99 BP |
1208 | ovs_fatal(0, "%s: unknown field `%.*s'", full_s, name_len, s); |
1209 | } | |
1210 | ||
1211 | s += name_len + 1; | |
1212 | ||
558d80cb | 1213 | nxm_put_header(b, header); |
78090f63 BP |
1214 | s = ofpbuf_put_hex(b, s, &n); |
1215 | if (n != nxm_field_bytes(header)) { | |
1216 | ovs_fatal(0, "%.2s: hex digits expected", s); | |
1217 | } | |
178742f9 | 1218 | if (nxm_hasmask(header)) { |
09246b99 BP |
1219 | s += strspn(s, " "); |
1220 | if (*s != '/') { | |
558d80cb BP |
1221 | ovs_fatal(0, "%s: missing / in masked field %.*s", |
1222 | full_s, name_len, name); | |
09246b99 | 1223 | } |
78090f63 BP |
1224 | s = ofpbuf_put_hex(b, s + 1, &n); |
1225 | if (n != nxm_field_bytes(header)) { | |
1226 | ovs_fatal(0, "%.2s: hex digits expected", s); | |
1227 | } | |
09246b99 BP |
1228 | } |
1229 | ||
1230 | s += strspn(s, " "); | |
1231 | if (*s != ')') { | |
558d80cb BP |
1232 | ovs_fatal(0, "%s: missing ) following field %.*s", |
1233 | full_s, name_len, name); | |
09246b99 BP |
1234 | } |
1235 | s++; | |
1236 | } | |
1237 | ||
1f317cb5 | 1238 | return ofpbuf_size(b) - start_len; |
7623f4dd SH |
1239 | } |
1240 | ||
1241 | int | |
1242 | nx_match_from_string(const char *s, struct ofpbuf *b) | |
1243 | { | |
1244 | int match_len = nx_match_from_string_raw(s, b); | |
f6e984d7 | 1245 | ofpbuf_put_zeros(b, PAD_SIZE(match_len, 8)); |
7623f4dd SH |
1246 | return match_len; |
1247 | } | |
1248 | ||
1249 | int | |
1250 | oxm_match_from_string(const char *s, struct ofpbuf *b) | |
1251 | { | |
1252 | int match_len; | |
1253 | struct ofp11_match_header *omh; | |
1f317cb5 | 1254 | size_t start_len = ofpbuf_size(b); |
7623f4dd SH |
1255 | |
1256 | ofpbuf_put_uninit(b, sizeof *omh); | |
1257 | match_len = nx_match_from_string_raw(s, b) + sizeof *omh; | |
f6e984d7 | 1258 | ofpbuf_put_zeros(b, PAD_SIZE(match_len, 8)); |
7623f4dd | 1259 | |
db5a1019 | 1260 | omh = ofpbuf_at(b, start_len, sizeof *omh); |
7623f4dd SH |
1261 | omh->type = htons(OFPMT_OXM); |
1262 | omh->length = htons(match_len); | |
1263 | ||
09246b99 BP |
1264 | return match_len; |
1265 | } | |
b6c9e612 | 1266 | \f |
bdda5aca BP |
1267 | /* Parses 's' as a "move" action, in the form described in ovs-ofctl(8), into |
1268 | * '*move'. | |
1269 | * | |
1270 | * Returns NULL if successful, otherwise a malloc()'d string describing the | |
1271 | * error. The caller is responsible for freeing the returned string. */ | |
1272 | char * WARN_UNUSED_RESULT | |
f25d0cf3 | 1273 | nxm_parse_reg_move(struct ofpact_reg_move *move, const char *s) |
f393f81e BP |
1274 | { |
1275 | const char *full_s = s; | |
bdda5aca | 1276 | char *error; |
f393f81e | 1277 | |
bdda5aca BP |
1278 | error = mf_parse_subfield__(&move->src, &s); |
1279 | if (error) { | |
1280 | return error; | |
1281 | } | |
f393f81e | 1282 | if (strncmp(s, "->", 2)) { |
bdda5aca | 1283 | return xasprintf("%s: missing `->' following source", full_s); |
f393f81e BP |
1284 | } |
1285 | s += 2; | |
bdda5aca BP |
1286 | error = mf_parse_subfield(&move->dst, s); |
1287 | if (error) { | |
1288 | return error; | |
f393f81e BP |
1289 | } |
1290 | ||
f25d0cf3 | 1291 | if (move->src.n_bits != move->dst.n_bits) { |
bdda5aca BP |
1292 | return xasprintf("%s: source field is %d bits wide but destination is " |
1293 | "%d bits wide", full_s, | |
1294 | move->src.n_bits, move->dst.n_bits); | |
f393f81e | 1295 | } |
bdda5aca | 1296 | return NULL; |
f393f81e | 1297 | } |
f393f81e | 1298 | \f |
7eb4b1f1 | 1299 | /* nxm_format_reg_move(). */ |
f393f81e | 1300 | |
f393f81e | 1301 | void |
f25d0cf3 | 1302 | nxm_format_reg_move(const struct ofpact_reg_move *move, struct ds *s) |
f393f81e | 1303 | { |
f393f81e | 1304 | ds_put_format(s, "move:"); |
f25d0cf3 | 1305 | mf_format_subfield(&move->src, s); |
f393f81e | 1306 | ds_put_cstr(s, "->"); |
f25d0cf3 | 1307 | mf_format_subfield(&move->dst, s); |
f393f81e BP |
1308 | } |
1309 | ||
f25d0cf3 BP |
1310 | \f |
1311 | enum ofperr | |
f25d0cf3 | 1312 | nxm_reg_move_check(const struct ofpact_reg_move *move, const struct flow *flow) |
43edca57 | 1313 | { |
90bf1e07 | 1314 | enum ofperr error; |
43edca57 | 1315 | |
f25d0cf3 | 1316 | error = mf_check_src(&move->src, flow); |
43edca57 EJ |
1317 | if (error) { |
1318 | return error; | |
b6c9e612 BP |
1319 | } |
1320 | ||
f25d0cf3 BP |
1321 | return mf_check_dst(&move->dst, NULL); |
1322 | } | |
f25d0cf3 | 1323 | \f |
7eb4b1f1 | 1324 | /* nxm_execute_reg_move(). */ |
b6c9e612 BP |
1325 | |
1326 | void | |
f25d0cf3 | 1327 | nxm_execute_reg_move(const struct ofpact_reg_move *move, |
bcd2633a | 1328 | struct flow *flow, struct flow_wildcards *wc) |
b6c9e612 | 1329 | { |
f25d0cf3 BP |
1330 | union mf_value src_value; |
1331 | union mf_value dst_value; | |
816fd533 | 1332 | |
f47ea021 JR |
1333 | mf_mask_field_and_prereqs(move->dst.field, &wc->masks); |
1334 | mf_mask_field_and_prereqs(move->src.field, &wc->masks); | |
bcd2633a | 1335 | |
f25d0cf3 BP |
1336 | mf_get_value(move->dst.field, flow, &dst_value); |
1337 | mf_get_value(move->src.field, flow, &src_value); | |
1338 | bitwise_copy(&src_value, move->src.field->n_bytes, move->src.ofs, | |
1339 | &dst_value, move->dst.field->n_bytes, move->dst.ofs, | |
1340 | move->src.n_bits); | |
1341 | mf_set_flow_value(move->dst.field, &dst_value, flow); | |
43edca57 | 1342 | } |
b6c9e612 | 1343 | |
816fd533 | 1344 | void |
f25d0cf3 | 1345 | nxm_reg_load(const struct mf_subfield *dst, uint64_t src_data, |
f74e7df7 | 1346 | struct flow *flow, struct flow_wildcards *wc) |
816fd533 | 1347 | { |
9bab681f | 1348 | union mf_subvalue src_subvalue; |
f74e7df7 | 1349 | union mf_subvalue mask_value; |
9bab681f | 1350 | ovs_be64 src_data_be = htonll(src_data); |
f25d0cf3 | 1351 | |
f74e7df7 JP |
1352 | memset(&mask_value, 0xff, sizeof mask_value); |
1353 | mf_write_subfield_flow(dst, &mask_value, &wc->masks); | |
1354 | ||
9bab681f IY |
1355 | bitwise_copy(&src_data_be, sizeof src_data_be, 0, |
1356 | &src_subvalue, sizeof src_subvalue, 0, | |
1357 | sizeof src_data_be * 8); | |
1358 | mf_write_subfield_flow(dst, &src_subvalue, flow); | |
b6c9e612 | 1359 | } |
bd85dac1 AZ |
1360 | \f |
1361 | /* nxm_parse_stack_action, works for both push() and pop(). */ | |
bdda5aca BP |
1362 | |
1363 | /* Parses 's' as a "push" or "pop" action, in the form described in | |
1364 | * ovs-ofctl(8), into '*stack_action'. | |
1365 | * | |
1366 | * Returns NULL if successful, otherwise a malloc()'d string describing the | |
1367 | * error. The caller is responsible for freeing the returned string. */ | |
1368 | char * WARN_UNUSED_RESULT | |
bd85dac1 AZ |
1369 | nxm_parse_stack_action(struct ofpact_stack *stack_action, const char *s) |
1370 | { | |
bdda5aca BP |
1371 | char *error; |
1372 | ||
1373 | error = mf_parse_subfield__(&stack_action->subfield, &s); | |
1374 | if (error) { | |
1375 | return error; | |
1376 | } | |
1377 | ||
bd85dac1 | 1378 | if (*s != '\0') { |
bdda5aca | 1379 | return xasprintf("%s: trailing garbage following push or pop", s); |
bd85dac1 | 1380 | } |
bdda5aca BP |
1381 | |
1382 | return NULL; | |
bd85dac1 AZ |
1383 | } |
1384 | ||
1385 | void | |
1386 | nxm_format_stack_push(const struct ofpact_stack *push, struct ds *s) | |
1387 | { | |
1388 | ds_put_cstr(s, "push:"); | |
1389 | mf_format_subfield(&push->subfield, s); | |
1390 | } | |
1391 | ||
1392 | void | |
1393 | nxm_format_stack_pop(const struct ofpact_stack *pop, struct ds *s) | |
1394 | { | |
1395 | ds_put_cstr(s, "pop:"); | |
1396 | mf_format_subfield(&pop->subfield, s); | |
1397 | } | |
1398 | ||
bd85dac1 AZ |
1399 | enum ofperr |
1400 | nxm_stack_push_check(const struct ofpact_stack *push, | |
1401 | const struct flow *flow) | |
1402 | { | |
1403 | return mf_check_src(&push->subfield, flow); | |
1404 | } | |
1405 | ||
1406 | enum ofperr | |
1407 | nxm_stack_pop_check(const struct ofpact_stack *pop, | |
1408 | const struct flow *flow) | |
1409 | { | |
1410 | return mf_check_dst(&pop->subfield, flow); | |
1411 | } | |
1412 | ||
bd85dac1 AZ |
1413 | /* nxm_execute_stack_push(), nxm_execute_stack_pop(). */ |
1414 | static void | |
1415 | nx_stack_push(struct ofpbuf *stack, union mf_subvalue *v) | |
1416 | { | |
1417 | ofpbuf_put(stack, v, sizeof *v); | |
1418 | } | |
1419 | ||
1420 | static union mf_subvalue * | |
1421 | nx_stack_pop(struct ofpbuf *stack) | |
1422 | { | |
1423 | union mf_subvalue *v = NULL; | |
1424 | ||
1f317cb5 PS |
1425 | if (ofpbuf_size(stack)) { |
1426 | ||
1427 | ofpbuf_set_size(stack, ofpbuf_size(stack) - sizeof *v); | |
bd85dac1 AZ |
1428 | v = (union mf_subvalue *) ofpbuf_tail(stack); |
1429 | } | |
1430 | ||
1431 | return v; | |
1432 | } | |
1433 | ||
1434 | void | |
1435 | nxm_execute_stack_push(const struct ofpact_stack *push, | |
bcd2633a JP |
1436 | const struct flow *flow, struct flow_wildcards *wc, |
1437 | struct ofpbuf *stack) | |
bd85dac1 | 1438 | { |
bcd2633a | 1439 | union mf_subvalue mask_value; |
bd85dac1 AZ |
1440 | union mf_subvalue dst_value; |
1441 | ||
bcd2633a JP |
1442 | memset(&mask_value, 0xff, sizeof mask_value); |
1443 | mf_write_subfield_flow(&push->subfield, &mask_value, &wc->masks); | |
1444 | ||
bd85dac1 AZ |
1445 | mf_read_subfield(&push->subfield, flow, &dst_value); |
1446 | nx_stack_push(stack, &dst_value); | |
1447 | } | |
1448 | ||
1449 | void | |
1450 | nxm_execute_stack_pop(const struct ofpact_stack *pop, | |
f74e7df7 JP |
1451 | struct flow *flow, struct flow_wildcards *wc, |
1452 | struct ofpbuf *stack) | |
bd85dac1 AZ |
1453 | { |
1454 | union mf_subvalue *src_value; | |
1455 | ||
1456 | src_value = nx_stack_pop(stack); | |
1457 | ||
1458 | /* Only pop if stack is not empty. Otherwise, give warning. */ | |
1459 | if (src_value) { | |
f74e7df7 JP |
1460 | union mf_subvalue mask_value; |
1461 | ||
1462 | memset(&mask_value, 0xff, sizeof mask_value); | |
1463 | mf_write_subfield_flow(&pop->subfield, &mask_value, &wc->masks); | |
bd85dac1 AZ |
1464 | mf_write_subfield_flow(&pop->subfield, src_value, flow); |
1465 | } else { | |
1466 | if (!VLOG_DROP_WARN(&rl)) { | |
1467 | char *flow_str = flow_to_string(flow); | |
1468 | VLOG_WARN_RL(&rl, "Failed to pop from an empty stack. On flow \n" | |
1469 | " %s", flow_str); | |
1470 | free(flow_str); | |
1471 | } | |
1472 | } | |
1473 | } | |
178742f9 BP |
1474 | \f |
1475 | /* Formats 'sf' into 's' in a format normally acceptable to | |
1476 | * mf_parse_subfield(). (It won't be acceptable if sf->field is NULL or if | |
1477 | * sf->field has no NXM name.) */ | |
1478 | void | |
1479 | mf_format_subfield(const struct mf_subfield *sf, struct ds *s) | |
1480 | { | |
1481 | if (!sf->field) { | |
1482 | ds_put_cstr(s, "<unknown>"); | |
1483 | } else { | |
1484 | const struct nxm_field *f = nxm_field_from_mf_field(sf->field->id, 0); | |
1485 | ds_put_cstr(s, f ? f->name : sf->field->name); | |
1486 | } | |
1487 | ||
1488 | if (sf->field && sf->ofs == 0 && sf->n_bits == sf->field->n_bits) { | |
1489 | ds_put_cstr(s, "[]"); | |
1490 | } else if (sf->n_bits == 1) { | |
1491 | ds_put_format(s, "[%d]", sf->ofs); | |
1492 | } else { | |
1493 | ds_put_format(s, "[%d..%d]", sf->ofs, sf->ofs + sf->n_bits - 1); | |
1494 | } | |
1495 | } | |
1496 | ||
1497 | static const struct nxm_field * | |
1498 | mf_parse_subfield_name(const char *name, int name_len, bool *wild) | |
1499 | { | |
1500 | *wild = name_len > 2 && !memcmp(&name[name_len - 2], "_W", 2); | |
1501 | if (*wild) { | |
1502 | name_len -= 2; | |
1503 | } | |
1504 | ||
1505 | return nxm_field_by_name(name, name_len); | |
1506 | } | |
1507 | ||
1508 | /* Parses a subfield from the beginning of '*sp' into 'sf'. If successful, | |
1509 | * returns NULL and advances '*sp' to the first byte following the parsed | |
1510 | * string. On failure, returns a malloc()'d error message, does not modify | |
1511 | * '*sp', and does not properly initialize 'sf'. | |
1512 | * | |
1513 | * The syntax parsed from '*sp' takes the form "header[start..end]" where | |
1514 | * 'header' is the name of an NXM field and 'start' and 'end' are (inclusive) | |
1515 | * bit indexes. "..end" may be omitted to indicate a single bit. "start..end" | |
1516 | * may both be omitted (the [] are still required) to indicate an entire | |
1517 | * field. */ | |
1518 | char * WARN_UNUSED_RESULT | |
1519 | mf_parse_subfield__(struct mf_subfield *sf, const char **sp) | |
1520 | { | |
1521 | const struct mf_field *field; | |
1522 | const struct nxm_field *f; | |
1523 | const char *name; | |
1524 | int start, end; | |
1525 | const char *s; | |
1526 | int name_len; | |
1527 | bool wild; | |
1528 | ||
1529 | s = *sp; | |
1530 | name = s; | |
1531 | name_len = strcspn(s, "["); | |
1532 | if (s[name_len] != '[') { | |
1533 | return xasprintf("%s: missing [ looking for field name", *sp); | |
1534 | } | |
1535 | ||
1536 | f = mf_parse_subfield_name(name, name_len, &wild); | |
1537 | if (!f) { | |
1538 | return xasprintf("%s: unknown field `%.*s'", *sp, name_len, s); | |
1539 | } | |
1540 | field = mf_from_id(f->id); | |
1541 | ||
1542 | s += name_len; | |
1543 | if (ovs_scan(s, "[%d..%d]", &start, &end)) { | |
1544 | /* Nothing to do. */ | |
1545 | } else if (ovs_scan(s, "[%d]", &start)) { | |
1546 | end = start; | |
1547 | } else if (!strncmp(s, "[]", 2)) { | |
1548 | start = 0; | |
1549 | end = field->n_bits - 1; | |
1550 | } else { | |
1551 | return xasprintf("%s: syntax error expecting [] or [<bit>] or " | |
1552 | "[<start>..<end>]", *sp); | |
1553 | } | |
1554 | s = strchr(s, ']') + 1; | |
1555 | ||
1556 | if (start > end) { | |
1557 | return xasprintf("%s: starting bit %d is after ending bit %d", | |
1558 | *sp, start, end); | |
1559 | } else if (start >= field->n_bits) { | |
1560 | return xasprintf("%s: starting bit %d is not valid because field is " | |
1561 | "only %d bits wide", *sp, start, field->n_bits); | |
1562 | } else if (end >= field->n_bits){ | |
1563 | return xasprintf("%s: ending bit %d is not valid because field is " | |
1564 | "only %d bits wide", *sp, end, field->n_bits); | |
1565 | } | |
1566 | ||
1567 | sf->field = field; | |
1568 | sf->ofs = start; | |
1569 | sf->n_bits = end - start + 1; | |
1570 | ||
1571 | *sp = s; | |
1572 | return NULL; | |
1573 | } | |
1574 | ||
1575 | /* Parses a subfield from the entirety of 's' into 'sf'. Returns NULL if | |
1576 | * successful, otherwise a malloc()'d string describing the error. The caller | |
1577 | * is responsible for freeing the returned string. | |
1578 | * | |
1579 | * The syntax parsed from 's' takes the form "header[start..end]" where | |
1580 | * 'header' is the name of an NXM field and 'start' and 'end' are (inclusive) | |
1581 | * bit indexes. "..end" may be omitted to indicate a single bit. "start..end" | |
1582 | * may both be omitted (the [] are still required) to indicate an entire | |
1583 | * field. */ | |
1584 | char * WARN_UNUSED_RESULT | |
1585 | mf_parse_subfield(struct mf_subfield *sf, const char *s) | |
1586 | { | |
1587 | char *error = mf_parse_subfield__(sf, &s); | |
1588 | if (!error && s[0]) { | |
1589 | error = xstrdup("unexpected input following field syntax"); | |
1590 | } | |
1591 | return error; | |
1592 | } | |
1593 | \f | |
1594 | /* Returns an bitmap in which each bit corresponds to the like-numbered field | |
1595 | * in the OFPXMC12_OPENFLOW_BASIC OXM class, in which the bit values are taken | |
1596 | * from the 'fields' bitmap. Only fields defined in OpenFlow 'version' are | |
1597 | * considered. | |
1598 | * | |
1599 | * This is useful for encoding OpenFlow 1.2 table stats messages. */ | |
1600 | ovs_be64 | |
1601 | oxm_bitmap_from_mf_bitmap(const struct mf_bitmap *fields, | |
1602 | enum ofp_version version) | |
1603 | { | |
1604 | uint64_t oxm_bitmap = 0; | |
1605 | int i; | |
1606 | ||
1607 | BITMAP_FOR_EACH_1 (i, MFF_N_IDS, fields->bm) { | |
1608 | uint32_t oxm = mf_oxm_header(i, version); | |
1609 | uint32_t vendor = nxm_vendor(oxm); | |
1610 | int field = nxm_field(oxm); | |
1611 | ||
1612 | if (vendor == OFPXMC12_OPENFLOW_BASIC && field < 64) { | |
1613 | oxm_bitmap |= UINT64_C(1) << field; | |
1614 | } | |
1615 | } | |
1616 | return htonll(oxm_bitmap); | |
1617 | } | |
1618 | ||
1619 | /* Opposite conversion from oxm_bitmap_from_mf_bitmap(). | |
1620 | * | |
1621 | * This is useful for decoding OpenFlow 1.2 table stats messages. */ | |
1622 | struct mf_bitmap | |
1623 | oxm_bitmap_to_mf_bitmap(ovs_be64 oxm_bitmap, enum ofp_version version) | |
1624 | { | |
1625 | struct mf_bitmap fields = MF_BITMAP_INITIALIZER; | |
1626 | ||
1627 | for (enum mf_field_id id = 0; id < MFF_N_IDS; id++) { | |
1628 | if (version >= mf_oxm_version(id)) { | |
1629 | uint32_t oxm = mf_oxm_header(id, version); | |
1630 | uint32_t vendor = nxm_vendor(oxm); | |
1631 | int field = nxm_field(oxm); | |
1632 | ||
1633 | if (vendor == OFPXMC12_OPENFLOW_BASIC | |
1634 | && field < 64 | |
1635 | && oxm_bitmap & htonll(UINT64_C(1) << field)) { | |
1636 | bitmap_set1(fields.bm, id); | |
1637 | } | |
1638 | } | |
1639 | } | |
1640 | return fields; | |
1641 | } | |
1642 | ||
1643 | /* Returns a bitmap of fields that can be encoded in OXM and that can be | |
1644 | * modified with a "set_field" action. */ | |
1645 | struct mf_bitmap | |
1646 | oxm_writable_fields(void) | |
1647 | { | |
1648 | struct mf_bitmap b = MF_BITMAP_INITIALIZER; | |
1649 | int i; | |
1650 | ||
1651 | for (i = 0; i < MFF_N_IDS; i++) { | |
1652 | if (mf_oxm_header(i, 0) && mf_from_id(i)->writable) { | |
1653 | bitmap_set1(b.bm, i); | |
1654 | } | |
1655 | } | |
1656 | return b; | |
1657 | } | |
1658 | ||
1659 | /* Returns a bitmap of fields that can be encoded in OXM and that can be | |
1660 | * matched in a flow table. */ | |
1661 | struct mf_bitmap | |
1662 | oxm_matchable_fields(void) | |
1663 | { | |
1664 | struct mf_bitmap b = MF_BITMAP_INITIALIZER; | |
1665 | int i; | |
1666 | ||
1667 | for (i = 0; i < MFF_N_IDS; i++) { | |
1668 | if (mf_oxm_header(i, 0)) { | |
1669 | bitmap_set1(b.bm, i); | |
1670 | } | |
1671 | } | |
1672 | return b; | |
1673 | } | |
1674 | ||
1675 | /* Returns a bitmap of fields that can be encoded in OXM and that can be | |
1676 | * matched in a flow table with an arbitrary bitmask. */ | |
1677 | struct mf_bitmap | |
1678 | oxm_maskable_fields(void) | |
1679 | { | |
1680 | struct mf_bitmap b = MF_BITMAP_INITIALIZER; | |
1681 | int i; | |
1682 | ||
1683 | for (i = 0; i < MFF_N_IDS; i++) { | |
1684 | if (mf_oxm_header(i, 0) && mf_from_id(i)->maskable == MFM_FULLY) { | |
1685 | bitmap_set1(b.bm, i); | |
1686 | } | |
1687 | } | |
1688 | return b; | |
1689 | } | |
1690 | \f | |
1691 | struct nxm_field_index { | |
1692 | struct hmap_node header_node; | |
1693 | struct hmap_node name_node; | |
1694 | struct nxm_field nf; | |
1695 | }; | |
1696 | ||
1697 | #include "nx-match.inc" | |
1698 | ||
1699 | static struct hmap nxm_header_map; | |
1700 | static struct hmap nxm_name_map; | |
1701 | static struct nxm_field *nxm_fields[MFF_N_IDS]; | |
1702 | static struct nxm_field *oxm_fields[MFF_N_IDS]; | |
1703 | ||
1704 | static void | |
1705 | nxm_init(void) | |
1706 | { | |
1707 | static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; | |
1708 | if (ovsthread_once_start(&once)) { | |
1709 | hmap_init(&nxm_header_map); | |
1710 | hmap_init(&nxm_name_map); | |
1711 | for (struct nxm_field_index *nfi = all_nxm_fields; | |
1712 | nfi < &all_nxm_fields[ARRAY_SIZE(all_nxm_fields)]; nfi++) { | |
1713 | hmap_insert(&nxm_header_map, &nfi->header_node, | |
1714 | hash_int(nfi->nf.header, 0)); | |
1715 | hmap_insert(&nxm_name_map, &nfi->name_node, | |
1716 | hash_string(nfi->nf.name, 0)); | |
1717 | if (is_nxm_header(nfi->nf.header)) { | |
1718 | nxm_fields[nfi->nf.id] = &nfi->nf; | |
1719 | } else { | |
1720 | oxm_fields[nfi->nf.id] = &nfi->nf; | |
1721 | } | |
1722 | } | |
1723 | ovsthread_once_done(&once); | |
1724 | } | |
1725 | } | |
1726 | ||
1727 | static const struct nxm_field * | |
1728 | nxm_field_by_header(uint32_t header) | |
1729 | { | |
1730 | const struct nxm_field_index *nfi; | |
1731 | ||
1732 | nxm_init(); | |
1733 | if (nxm_hasmask(header)) { | |
1734 | header = nxm_make_exact_header(header); | |
1735 | } | |
1736 | ||
1737 | HMAP_FOR_EACH_IN_BUCKET (nfi, header_node, hash_int(header, 0), | |
1738 | &nxm_header_map) { | |
1739 | if (header == nfi->nf.header) { | |
1740 | return &nfi->nf; | |
1741 | } | |
1742 | } | |
1743 | return NULL; | |
1744 | } | |
1745 | ||
1746 | static const struct nxm_field * | |
1747 | nxm_field_by_name(const char *name, size_t len) | |
1748 | { | |
1749 | const struct nxm_field_index *nfi; | |
1750 | ||
1751 | nxm_init(); | |
1752 | HMAP_FOR_EACH_WITH_HASH (nfi, name_node, hash_bytes(name, len, 0), | |
1753 | &nxm_name_map) { | |
1754 | if (strlen(nfi->nf.name) == len && !memcmp(nfi->nf.name, name, len)) { | |
1755 | return &nfi->nf; | |
1756 | } | |
1757 | } | |
1758 | return NULL; | |
1759 | } | |
1760 | ||
1761 | static const struct nxm_field * | |
1762 | nxm_field_by_mf_id(enum mf_field_id id) | |
1763 | { | |
1764 | nxm_init(); | |
1765 | return nxm_fields[id]; | |
1766 | } | |
1767 | ||
1768 | static const struct nxm_field * | |
1769 | oxm_field_by_mf_id(enum mf_field_id id) | |
1770 | { | |
1771 | nxm_init(); | |
1772 | return oxm_fields[id]; | |
1773 | } | |
1774 |