]>
Commit | Line | Data |
---|---|---|
6a885fd0 BP |
1 | /* |
2 | * Copyright (c) 2011 Nicira Networks. | |
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 "meta-flow.h" | |
20 | ||
21 | #include <assert.h> | |
22 | #include <errno.h> | |
23 | #include <limits.h> | |
24 | #include <netinet/icmp6.h> | |
25 | #include <netinet/ip6.h> | |
26 | ||
27 | #include "classifier.h" | |
28 | #include "dynamic-string.h" | |
29 | #include "ofp-util.h" | |
30 | #include "packets.h" | |
31 | #include "random.h" | |
32 | #include "shash.h" | |
33 | #include "socket-util.h" | |
34 | #include "unaligned.h" | |
35 | ||
36 | #define MF_FIELD_SIZES(MEMBER) \ | |
37 | sizeof ((union mf_value *)0)->MEMBER, \ | |
38 | 8 * sizeof ((union mf_value *)0)->MEMBER | |
39 | ||
40 | static const struct mf_field mf_fields[MFF_N_IDS] = { | |
41 | /* ## -------- ## */ | |
42 | /* ## metadata ## */ | |
43 | /* ## -------- ## */ | |
44 | ||
45 | { | |
46 | MFF_TUN_ID, "tun_id", NULL, | |
47 | MF_FIELD_SIZES(be64), | |
48 | MFM_FULLY, 0, | |
49 | MFS_HEXADECIMAL, | |
50 | MFP_NONE, | |
51 | NXM_NX_TUN_ID, | |
52 | }, { | |
53 | MFF_IN_PORT, "in_port", NULL, | |
54 | MF_FIELD_SIZES(be16), | |
55 | MFM_NONE, FWW_IN_PORT, | |
56 | MFS_OFP_PORT, | |
57 | MFP_NONE, | |
58 | NXM_OF_IN_PORT, | |
59 | }, | |
60 | ||
61 | #define REGISTER(IDX) \ | |
62 | { \ | |
63 | MFF_REG##IDX, "reg" #IDX, NULL, \ | |
64 | MF_FIELD_SIZES(be32), \ | |
65 | MFM_FULLY, 0, \ | |
66 | MFS_HEXADECIMAL, \ | |
67 | MFP_NONE, \ | |
68 | NXM_NX_REG(IDX), \ | |
69 | } | |
70 | #if FLOW_N_REGS > 0 | |
71 | REGISTER(0), | |
72 | #endif | |
73 | #if FLOW_N_REGS > 1 | |
74 | REGISTER(1), | |
75 | #endif | |
76 | #if FLOW_N_REGS > 2 | |
77 | REGISTER(2), | |
78 | #endif | |
79 | #if FLOW_N_REGS > 3 | |
80 | REGISTER(3), | |
81 | #endif | |
82 | #if FLOW_N_REGS > 4 | |
d2c0fed9 JP |
83 | REGISTER(4), |
84 | #endif | |
85 | #if FLOW_N_REGS > 5 | |
6a885fd0 BP |
86 | #error |
87 | #endif | |
88 | ||
89 | /* ## -- ## */ | |
90 | /* ## L2 ## */ | |
91 | /* ## -- ## */ | |
92 | ||
93 | { | |
94 | MFF_ETH_SRC, "eth_src", "dl_src", | |
95 | MF_FIELD_SIZES(mac), | |
96 | MFM_NONE, FWW_DL_SRC, | |
97 | MFS_ETHERNET, | |
98 | MFP_NONE, | |
99 | NXM_OF_ETH_SRC, | |
100 | }, { | |
101 | MFF_ETH_DST, "eth_dst", "dl_dst", | |
102 | MF_FIELD_SIZES(mac), | |
103 | MFM_MCAST, 0, | |
104 | MFS_ETHERNET, | |
105 | MFP_NONE, | |
106 | NXM_OF_ETH_DST, | |
107 | }, { | |
108 | MFF_ETH_TYPE, "eth_type", "dl_type", | |
109 | MF_FIELD_SIZES(be16), | |
110 | MFM_NONE, FWW_DL_TYPE, | |
111 | MFS_HEXADECIMAL, | |
112 | MFP_NONE, | |
113 | NXM_OF_ETH_TYPE, | |
114 | }, | |
115 | ||
116 | { | |
117 | MFF_VLAN_TCI, "vlan_tci", NULL, | |
118 | MF_FIELD_SIZES(be16), | |
119 | MFM_FULLY, 0, | |
120 | MFS_HEXADECIMAL, | |
121 | MFP_NONE, | |
122 | NXM_OF_VLAN_TCI, | |
123 | }, { | |
124 | MFF_VLAN_VID, "dl_vlan", NULL, | |
125 | sizeof(ovs_be16), 12, | |
126 | MFM_NONE, 0, | |
127 | MFS_DECIMAL, | |
128 | MFP_NONE, | |
129 | 0, | |
130 | }, { | |
131 | MFF_VLAN_PCP, "dl_vlan_pcp", NULL, | |
132 | 1, 3, | |
133 | MFM_NONE, 0, | |
134 | MFS_DECIMAL, | |
135 | MFP_NONE, | |
136 | 0, | |
137 | }, | |
138 | ||
139 | /* ## -- ## */ | |
140 | /* ## L3 ## */ | |
141 | /* ## -- ## */ | |
142 | ||
143 | { | |
144 | MFF_IPV4_SRC, "ip_src", "nw_src", | |
145 | MF_FIELD_SIZES(be32), | |
146 | MFM_CIDR, 0, | |
147 | MFS_IPV4, | |
148 | MFP_IPV4, | |
149 | NXM_OF_IP_SRC, | |
150 | }, { | |
151 | MFF_IPV4_DST, "ip_dst", "nw_dst", | |
152 | MF_FIELD_SIZES(be32), | |
153 | MFM_CIDR, 0, | |
154 | MFS_IPV4, | |
155 | MFP_IPV4, | |
156 | NXM_OF_IP_DST, | |
157 | }, | |
158 | ||
159 | { | |
160 | MFF_IPV6_SRC, "ipv6_src", NULL, | |
161 | MF_FIELD_SIZES(ipv6), | |
162 | MFM_CIDR, 0, | |
163 | MFS_IPV6, | |
164 | MFP_IPV6, | |
165 | NXM_NX_IPV6_SRC, | |
166 | }, { | |
167 | MFF_IPV6_DST, "ipv6_dst", NULL, | |
168 | MF_FIELD_SIZES(ipv6), | |
169 | MFM_CIDR, 0, | |
170 | MFS_IPV6, | |
171 | MFP_IPV6, | |
172 | NXM_NX_IPV6_DST, | |
173 | }, | |
174 | ||
175 | { | |
176 | MFF_IP_PROTO, "nw_proto", NULL, | |
177 | MF_FIELD_SIZES(u8), | |
178 | MFM_NONE, FWW_NW_PROTO, | |
179 | MFS_DECIMAL, | |
180 | MFP_IP_ANY, | |
181 | NXM_OF_IP_PROTO, | |
182 | }, { | |
183 | MFF_IP_TOS, "nw_tos", NULL, | |
184 | MF_FIELD_SIZES(u8), | |
7257b535 | 185 | MFM_NONE, 0, |
6a885fd0 BP |
186 | MFS_DECIMAL, |
187 | MFP_IP_ANY, | |
188 | NXM_OF_IP_TOS, | |
7257b535 BP |
189 | }, { |
190 | MFF_IP_FRAG, "ip_frag", NULL, | |
191 | 1, 2, | |
192 | MFM_FULLY, 0, | |
193 | MFS_FRAG, | |
194 | MFP_IP_ANY, | |
195 | NXM_NX_IP_FRAG, | |
6a885fd0 BP |
196 | }, |
197 | ||
198 | { | |
199 | MFF_ARP_OP, "arp_op", NULL, | |
200 | MF_FIELD_SIZES(be16), | |
201 | MFM_NONE, FWW_NW_PROTO, | |
202 | MFS_DECIMAL, | |
203 | MFP_ARP, | |
204 | NXM_OF_ARP_OP, | |
205 | }, { | |
206 | MFF_ARP_SPA, "arp_spa", NULL, | |
207 | MF_FIELD_SIZES(be32), | |
208 | MFM_CIDR, 0, | |
209 | MFS_IPV4, | |
210 | MFP_ARP, | |
211 | NXM_OF_ARP_SPA, | |
212 | }, { | |
213 | MFF_ARP_TPA, "arp_tpa", NULL, | |
214 | MF_FIELD_SIZES(be32), | |
215 | MFM_CIDR, 0, | |
216 | MFS_IPV4, | |
217 | MFP_ARP, | |
218 | NXM_OF_ARP_TPA, | |
219 | }, { | |
220 | MFF_ARP_SHA, "arp_sha", NULL, | |
221 | MF_FIELD_SIZES(mac), | |
222 | MFM_NONE, FWW_ARP_SHA, | |
223 | MFS_ETHERNET, | |
224 | MFP_ARP, | |
225 | NXM_NX_ARP_SHA, | |
226 | }, { | |
227 | MFF_ARP_THA, "arp_tha", NULL, | |
228 | MF_FIELD_SIZES(mac), | |
229 | MFM_NONE, FWW_ARP_THA, | |
230 | MFS_ETHERNET, | |
231 | MFP_ARP, | |
232 | NXM_NX_ARP_THA, | |
233 | }, | |
234 | ||
235 | /* ## -- ## */ | |
236 | /* ## L4 ## */ | |
237 | /* ## -- ## */ | |
238 | ||
239 | { | |
240 | MFF_TCP_SRC, "tcp_src", "tp_src", | |
241 | MF_FIELD_SIZES(be16), | |
242 | MFM_NONE, FWW_TP_SRC, | |
243 | MFS_DECIMAL, | |
244 | MFP_TCP, | |
245 | NXM_OF_TCP_SRC, | |
246 | }, { | |
247 | MFF_TCP_DST, "tcp_dst", "tp_dst", | |
248 | MF_FIELD_SIZES(be16), | |
249 | MFM_NONE, FWW_TP_DST, | |
250 | MFS_DECIMAL, | |
251 | MFP_TCP, | |
252 | NXM_OF_TCP_DST, | |
253 | }, | |
254 | ||
255 | { | |
256 | MFF_UDP_SRC, "udp_src", NULL, | |
257 | MF_FIELD_SIZES(be16), | |
258 | MFM_NONE, FWW_TP_SRC, | |
259 | MFS_DECIMAL, | |
260 | MFP_UDP, | |
261 | NXM_OF_UDP_SRC, | |
262 | }, { | |
263 | MFF_UDP_DST, "udp_dst", NULL, | |
264 | MF_FIELD_SIZES(be16), | |
265 | MFM_NONE, FWW_TP_DST, | |
266 | MFS_DECIMAL, | |
267 | MFP_UDP, | |
268 | NXM_OF_UDP_DST, | |
269 | }, | |
270 | ||
271 | { | |
272 | MFF_ICMP_TYPE, "icmp_type", NULL, | |
273 | MF_FIELD_SIZES(u8), | |
274 | MFM_NONE, FWW_TP_SRC, | |
275 | MFS_DECIMAL, | |
276 | MFP_ICMP_ANY, | |
277 | NXM_OF_ICMP_TYPE, | |
278 | }, { | |
279 | MFF_ICMP_CODE, "icmp_code", NULL, | |
280 | MF_FIELD_SIZES(u8), | |
029b26f3 | 281 | MFM_NONE, FWW_TP_DST, |
6a885fd0 BP |
282 | MFS_DECIMAL, |
283 | MFP_ICMP_ANY, | |
284 | NXM_OF_ICMP_CODE, | |
285 | }, | |
286 | ||
287 | /* ## ---- ## */ | |
288 | /* ## L"5" ## */ | |
289 | /* ## ---- ## */ | |
290 | ||
291 | { | |
292 | MFF_ND_TARGET, "nd_target", NULL, | |
293 | MF_FIELD_SIZES(ipv6), | |
294 | MFM_NONE, FWW_ND_TARGET, | |
295 | MFS_IPV6, | |
296 | MFP_ND, | |
297 | NXM_NX_ND_TARGET, | |
298 | }, { | |
299 | MFF_ND_SLL, "nd_sll", NULL, | |
300 | MF_FIELD_SIZES(mac), | |
301 | MFM_NONE, FWW_ARP_SHA, | |
302 | MFS_ETHERNET, | |
303 | MFP_ND_SOLICIT, | |
304 | NXM_NX_ND_SLL, | |
305 | }, { | |
306 | MFF_ND_TLL, "nd_tll", NULL, | |
307 | MF_FIELD_SIZES(mac), | |
308 | MFM_NONE, FWW_ARP_THA, | |
309 | MFS_ETHERNET, | |
310 | MFP_ND_ADVERT, | |
311 | NXM_NX_ND_TLL, | |
312 | } | |
313 | }; | |
314 | ||
6a885fd0 BP |
315 | /* Returns the field with the given 'id'. */ |
316 | const struct mf_field * | |
317 | mf_from_id(enum mf_field_id id) | |
318 | { | |
319 | assert((unsigned int) id < MFF_N_IDS); | |
320 | return &mf_fields[id]; | |
321 | } | |
322 | ||
323 | /* Returns the field with the given 'name', or a null pointer if no field has | |
324 | * that name. */ | |
325 | const struct mf_field * | |
326 | mf_from_name(const char *name) | |
327 | { | |
328 | static struct shash mf_by_name = SHASH_INITIALIZER(&mf_by_name); | |
329 | ||
330 | if (shash_is_empty(&mf_by_name)) { | |
331 | const struct mf_field *mf; | |
332 | ||
333 | for (mf = mf_fields; mf < &mf_fields[MFF_N_IDS]; mf++) { | |
334 | shash_add_once(&mf_by_name, mf->name, mf); | |
335 | if (mf->extra_name) { | |
336 | shash_add_once(&mf_by_name, mf->extra_name, mf); | |
337 | } | |
338 | } | |
339 | } | |
340 | ||
341 | return shash_find_data(&mf_by_name, name); | |
342 | } | |
343 | ||
344 | /* Returns true if 'wc' wildcards all the bits in field 'mf', false if 'wc' | |
345 | * specifies at least one bit in the field. | |
346 | * | |
347 | * The caller is responsible for ensuring that 'wc' corresponds to a flow that | |
348 | * meets 'mf''s prerequisites. */ | |
349 | bool | |
350 | mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc) | |
351 | { | |
352 | switch (mf->id) { | |
353 | case MFF_IN_PORT: | |
354 | case MFF_ETH_SRC: | |
355 | case MFF_ETH_TYPE: | |
356 | case MFF_IP_PROTO: | |
6a885fd0 BP |
357 | case MFF_ARP_OP: |
358 | case MFF_ARP_SHA: | |
359 | case MFF_ARP_THA: | |
360 | case MFF_TCP_SRC: | |
361 | case MFF_TCP_DST: | |
362 | case MFF_UDP_SRC: | |
363 | case MFF_UDP_DST: | |
364 | case MFF_ICMP_TYPE: | |
365 | case MFF_ICMP_CODE: | |
366 | case MFF_ND_TARGET: | |
367 | case MFF_ND_SLL: | |
368 | case MFF_ND_TLL: | |
369 | assert(mf->fww_bit != 0); | |
370 | return (wc->wildcards & mf->fww_bit) != 0; | |
371 | ||
372 | case MFF_TUN_ID: | |
373 | return !wc->tun_id_mask; | |
374 | ||
375 | #if FLOW_N_REGS > 0 | |
376 | case MFF_REG0: | |
377 | #endif | |
378 | #if FLOW_N_REGS > 1 | |
379 | case MFF_REG1: | |
380 | #endif | |
381 | #if FLOW_N_REGS > 2 | |
382 | case MFF_REG2: | |
383 | #endif | |
384 | #if FLOW_N_REGS > 3 | |
385 | case MFF_REG3: | |
386 | #endif | |
387 | #if FLOW_N_REGS > 4 | |
d2c0fed9 JP |
388 | case MFF_REG4: |
389 | #endif | |
390 | #if FLOW_N_REGS > 5 | |
6a885fd0 BP |
391 | #error |
392 | #endif | |
393 | return !wc->reg_masks[mf->id - MFF_REG0]; | |
394 | ||
395 | case MFF_ETH_DST: | |
396 | return ((wc->wildcards & (FWW_ETH_MCAST | FWW_DL_DST)) | |
397 | == (FWW_ETH_MCAST | FWW_DL_DST)); | |
398 | ||
399 | case MFF_VLAN_TCI: | |
400 | return !wc->vlan_tci_mask; | |
401 | case MFF_VLAN_VID: | |
402 | return !(wc->vlan_tci_mask & htons(VLAN_VID_MASK)); | |
403 | case MFF_VLAN_PCP: | |
404 | return !(wc->vlan_tci_mask & htons(VLAN_PCP_MASK)); | |
405 | ||
406 | case MFF_IPV4_SRC: | |
407 | return !wc->nw_src_mask; | |
408 | case MFF_IPV4_DST: | |
409 | return !wc->nw_dst_mask; | |
410 | ||
411 | case MFF_IPV6_SRC: | |
412 | return ipv6_mask_is_any(&wc->ipv6_src_mask); | |
413 | case MFF_IPV6_DST: | |
414 | return ipv6_mask_is_any(&wc->ipv6_dst_mask); | |
415 | ||
7257b535 BP |
416 | case MFF_IP_TOS: |
417 | return !(wc->tos_frag_mask & IP_DSCP_MASK); | |
418 | case MFF_IP_FRAG: | |
419 | return !(wc->tos_frag_mask & FLOW_FRAG_MASK); | |
420 | ||
6a885fd0 BP |
421 | case MFF_ARP_SPA: |
422 | return !wc->nw_src_mask; | |
423 | case MFF_ARP_TPA: | |
424 | return !wc->nw_dst_mask; | |
425 | ||
426 | case MFF_N_IDS: | |
427 | default: | |
428 | NOT_REACHED(); | |
429 | } | |
430 | } | |
431 | ||
432 | /* Initializes 'mask' with the wildcard bit pattern for field 'mf' within 'wc'. | |
433 | * Each bit in 'mask' will be set to 1 if the bit is significant for matching | |
434 | * purposes, or to 0 if it is wildcarded. | |
435 | * | |
436 | * The caller is responsible for ensuring that 'wc' corresponds to a flow that | |
437 | * meets 'mf''s prerequisites. */ | |
438 | void | |
439 | mf_get_mask(const struct mf_field *mf, const struct flow_wildcards *wc, | |
440 | union mf_value *mask) | |
441 | { | |
442 | switch (mf->id) { | |
443 | case MFF_IN_PORT: | |
444 | case MFF_ETH_SRC: | |
445 | case MFF_ETH_TYPE: | |
446 | case MFF_IP_PROTO: | |
6a885fd0 BP |
447 | case MFF_ARP_OP: |
448 | case MFF_ARP_SHA: | |
449 | case MFF_ARP_THA: | |
450 | case MFF_TCP_SRC: | |
451 | case MFF_TCP_DST: | |
452 | case MFF_UDP_SRC: | |
453 | case MFF_UDP_DST: | |
454 | case MFF_ICMP_TYPE: | |
455 | case MFF_ICMP_CODE: | |
456 | case MFF_ND_TARGET: | |
457 | case MFF_ND_SLL: | |
458 | case MFF_ND_TLL: | |
459 | assert(mf->fww_bit != 0); | |
460 | memset(mask, wc->wildcards & mf->fww_bit ? 0x00 : 0xff, mf->n_bytes); | |
461 | break; | |
462 | ||
463 | case MFF_TUN_ID: | |
464 | mask->be64 = wc->tun_id_mask; | |
465 | break; | |
466 | ||
467 | #if FLOW_N_REGS > 0 | |
468 | case MFF_REG0: | |
469 | #endif | |
470 | #if FLOW_N_REGS > 1 | |
471 | case MFF_REG1: | |
472 | #endif | |
473 | #if FLOW_N_REGS > 2 | |
474 | case MFF_REG2: | |
475 | #endif | |
476 | #if FLOW_N_REGS > 3 | |
477 | case MFF_REG3: | |
478 | #endif | |
479 | #if FLOW_N_REGS > 4 | |
d2c0fed9 JP |
480 | case MFF_REG4: |
481 | #endif | |
482 | #if FLOW_N_REGS > 5 | |
6a885fd0 BP |
483 | #error |
484 | #endif | |
485 | mask->be32 = htonl(wc->reg_masks[mf->id - MFF_REG0]); | |
486 | break; | |
487 | ||
488 | case MFF_ETH_DST: | |
489 | memcpy(mask->mac, flow_wildcards_to_dl_dst_mask(wc->wildcards), | |
490 | ETH_ADDR_LEN); | |
491 | break; | |
492 | ||
493 | case MFF_VLAN_TCI: | |
494 | mask->be16 = wc->vlan_tci_mask; | |
495 | break; | |
496 | case MFF_VLAN_VID: | |
497 | mask->be16 = wc->vlan_tci_mask & htons(VLAN_VID_MASK); | |
498 | break; | |
499 | case MFF_VLAN_PCP: | |
500 | mask->u8 = vlan_tci_to_pcp(wc->vlan_tci_mask); | |
501 | break; | |
502 | ||
503 | case MFF_IPV4_SRC: | |
504 | mask->be32 = wc->nw_src_mask; | |
505 | break; | |
506 | case MFF_IPV4_DST: | |
507 | mask->be32 = wc->nw_dst_mask; | |
508 | break; | |
509 | ||
510 | case MFF_IPV6_SRC: | |
511 | mask->ipv6 = wc->ipv6_src_mask; | |
512 | break; | |
513 | case MFF_IPV6_DST: | |
514 | mask->ipv6 = wc->ipv6_dst_mask; | |
515 | break; | |
516 | ||
7257b535 BP |
517 | case MFF_IP_TOS: |
518 | mask->u8 = wc->tos_frag_mask & IP_DSCP_MASK; | |
519 | break; | |
520 | case MFF_IP_FRAG: | |
521 | mask->u8 = wc->tos_frag_mask & FLOW_FRAG_MASK; | |
522 | break; | |
523 | ||
6a885fd0 BP |
524 | case MFF_ARP_SPA: |
525 | mask->be32 = wc->nw_src_mask; | |
526 | break; | |
527 | case MFF_ARP_TPA: | |
528 | mask->be32 = wc->nw_dst_mask; | |
529 | break; | |
530 | ||
531 | case MFF_N_IDS: | |
532 | default: | |
533 | NOT_REACHED(); | |
534 | } | |
535 | } | |
536 | ||
537 | /* Tests whether 'mask' is a valid wildcard bit pattern for 'mf'. Returns true | |
538 | * if the mask is valid, false otherwise. */ | |
539 | bool | |
540 | mf_is_mask_valid(const struct mf_field *mf, const union mf_value *mask) | |
541 | { | |
542 | switch (mf->maskable) { | |
543 | case MFM_NONE: | |
544 | return (is_all_zeros((const uint8_t *) mask, mf->n_bytes) || | |
545 | is_all_ones((const uint8_t *) mask, mf->n_bytes)); | |
546 | ||
547 | case MFM_FULLY: | |
548 | return true; | |
549 | ||
550 | case MFM_CIDR: | |
551 | return (mf->n_bytes == 4 | |
552 | ? ip_is_cidr(mask->be32) | |
553 | : ipv6_is_cidr(&mask->ipv6)); | |
554 | ||
555 | case MFM_MCAST: | |
556 | return flow_wildcards_is_dl_dst_mask_valid(mask->mac); | |
557 | } | |
558 | ||
559 | NOT_REACHED(); | |
560 | } | |
561 | ||
562 | static bool | |
563 | is_ip_any(const struct flow *flow) | |
564 | { | |
565 | return (flow->dl_type == htons(ETH_TYPE_IP) || | |
566 | flow->dl_type == htons(ETH_TYPE_IPV6)); | |
567 | } | |
568 | ||
569 | static bool | |
570 | is_icmpv4(const struct flow *flow) | |
571 | { | |
572 | return (flow->dl_type == htons(ETH_TYPE_IP) | |
573 | && flow->nw_proto == IPPROTO_ICMP); | |
574 | } | |
575 | ||
576 | static bool | |
577 | is_icmpv6(const struct flow *flow) | |
578 | { | |
579 | return (flow->dl_type == htons(ETH_TYPE_IPV6) | |
580 | && flow->nw_proto == IPPROTO_ICMPV6); | |
581 | } | |
582 | ||
583 | /* Returns true if 'flow' meets the prerequisites for 'mf', false otherwise. */ | |
584 | bool | |
585 | mf_are_prereqs_ok(const struct mf_field *mf, const struct flow *flow) | |
586 | { | |
587 | switch (mf->prereqs) { | |
588 | case MFP_NONE: | |
589 | return true; | |
590 | ||
591 | case MFP_ARP: | |
592 | return flow->dl_type == htons(ETH_TYPE_ARP); | |
593 | case MFP_IPV4: | |
594 | return flow->dl_type == htons(ETH_TYPE_IP); | |
595 | case MFP_IPV6: | |
596 | return flow->dl_type == htons(ETH_TYPE_IPV6); | |
597 | case MFP_IP_ANY: | |
598 | return is_ip_any(flow); | |
599 | ||
600 | case MFP_TCP: | |
601 | return is_ip_any(flow) && flow->nw_proto == IPPROTO_TCP; | |
602 | case MFP_UDP: | |
603 | return is_ip_any(flow) && flow->nw_proto == IPPROTO_UDP; | |
604 | case MFP_ICMPV6: | |
605 | return is_icmpv6(flow); | |
606 | case MFP_ICMP_ANY: | |
607 | return is_icmpv4(flow) || is_icmpv6(flow); | |
608 | ||
609 | case MFP_ND: | |
610 | return (is_icmpv6(flow) | |
3ee8a9f0 BP |
611 | && flow->tp_dst == htons(0) |
612 | && (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) || | |
613 | flow->tp_src == htons(ND_NEIGHBOR_ADVERT))); | |
6a885fd0 BP |
614 | case MFP_ND_SOLICIT: |
615 | return (is_icmpv6(flow) | |
3ee8a9f0 BP |
616 | && flow->tp_dst == htons(0) |
617 | && (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT))); | |
6a885fd0 BP |
618 | case MFP_ND_ADVERT: |
619 | return (is_icmpv6(flow) | |
3ee8a9f0 BP |
620 | && flow->tp_dst == htons(0) |
621 | && (flow->tp_src == htons(ND_NEIGHBOR_ADVERT))); | |
6a885fd0 BP |
622 | } |
623 | ||
624 | NOT_REACHED(); | |
625 | } | |
626 | ||
627 | /* Returns true if 'value' may be a valid value *as part of a masked match*, | |
628 | * false otherwise. | |
629 | * | |
630 | * A value is not rejected just because it is not valid for the field in | |
631 | * question, but only if it doesn't make sense to test the bits in question at | |
632 | * all. For example, the MFF_VLAN_TCI field will never have a nonzero value | |
633 | * without the VLAN_CFI bit being set, but we can't reject those values because | |
634 | * it is still legitimate to test just for those bits (see the documentation | |
635 | * for NXM_OF_VLAN_TCI in nicira-ext.h). On the other hand, there is never a | |
636 | * reason to set the low bit of MFF_IP_TOS to 1, so we reject that. */ | |
637 | bool | |
638 | mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) | |
639 | { | |
640 | switch (mf->id) { | |
641 | case MFF_TUN_ID: | |
642 | case MFF_IN_PORT: | |
643 | #if FLOW_N_REGS > 0 | |
644 | case MFF_REG0: | |
645 | #endif | |
646 | #if FLOW_N_REGS > 1 | |
647 | case MFF_REG1: | |
648 | #endif | |
649 | #if FLOW_N_REGS > 2 | |
650 | case MFF_REG2: | |
651 | #endif | |
652 | #if FLOW_N_REGS > 3 | |
653 | case MFF_REG3: | |
654 | #endif | |
655 | #if FLOW_N_REGS > 4 | |
d2c0fed9 JP |
656 | case MFF_REG4: |
657 | #endif | |
658 | #if FLOW_N_REGS > 5 | |
6a885fd0 BP |
659 | #error |
660 | #endif | |
661 | case MFF_ETH_SRC: | |
662 | case MFF_ETH_DST: | |
663 | case MFF_ETH_TYPE: | |
664 | case MFF_VLAN_TCI: | |
665 | case MFF_IPV4_SRC: | |
666 | case MFF_IPV4_DST: | |
667 | case MFF_IPV6_SRC: | |
668 | case MFF_IPV6_DST: | |
669 | case MFF_IP_PROTO: | |
670 | case MFF_ARP_SPA: | |
671 | case MFF_ARP_TPA: | |
672 | case MFF_ARP_SHA: | |
673 | case MFF_ARP_THA: | |
674 | case MFF_TCP_SRC: | |
675 | case MFF_TCP_DST: | |
676 | case MFF_UDP_SRC: | |
677 | case MFF_UDP_DST: | |
678 | case MFF_ICMP_TYPE: | |
679 | case MFF_ICMP_CODE: | |
680 | case MFF_ND_TARGET: | |
681 | case MFF_ND_SLL: | |
682 | case MFF_ND_TLL: | |
683 | return true; | |
684 | ||
685 | case MFF_IP_TOS: | |
7257b535 BP |
686 | return !(value->u8 & ~IP_DSCP_MASK); |
687 | case MFF_IP_FRAG: | |
688 | return !(value->u8 & ~FLOW_FRAG_MASK); | |
6a885fd0 BP |
689 | |
690 | case MFF_ARP_OP: | |
691 | return !(value->be16 & htons(0xff00)); | |
692 | ||
693 | case MFF_VLAN_VID: | |
694 | return !(value->be16 & htons(VLAN_CFI | VLAN_PCP_MASK)); | |
695 | ||
696 | case MFF_VLAN_PCP: | |
697 | return !(value->u8 & ~7); | |
698 | ||
699 | case MFF_N_IDS: | |
700 | default: | |
701 | NOT_REACHED(); | |
702 | } | |
703 | } | |
704 | ||
705 | /* Copies the value of field 'mf' from 'flow' into 'value'. The caller is | |
706 | * responsible for ensuring that 'flow' meets 'mf''s prerequisites. */ | |
707 | void | |
708 | mf_get_value(const struct mf_field *mf, const struct flow *flow, | |
709 | union mf_value *value) | |
710 | { | |
711 | switch (mf->id) { | |
712 | case MFF_TUN_ID: | |
713 | value->be64 = flow->tun_id; | |
714 | break; | |
715 | ||
716 | case MFF_IN_PORT: | |
717 | value->be16 = htons(flow->in_port); | |
718 | break; | |
719 | ||
720 | #if FLOW_N_REGS > 0 | |
721 | case MFF_REG0: | |
722 | #endif | |
723 | #if FLOW_N_REGS > 1 | |
724 | case MFF_REG1: | |
725 | #endif | |
726 | #if FLOW_N_REGS > 2 | |
727 | case MFF_REG2: | |
728 | #endif | |
729 | #if FLOW_N_REGS > 3 | |
730 | case MFF_REG3: | |
731 | #endif | |
732 | #if FLOW_N_REGS > 4 | |
d2c0fed9 JP |
733 | case MFF_REG4: |
734 | #endif | |
735 | #if FLOW_N_REGS > 5 | |
6a885fd0 BP |
736 | #error |
737 | #endif | |
2f98b0b7 | 738 | value->be32 = htonl(flow->regs[mf->id - MFF_REG0]); |
6a885fd0 BP |
739 | break; |
740 | ||
741 | case MFF_ETH_SRC: | |
742 | memcpy(value->mac, flow->dl_src, ETH_ADDR_LEN); | |
743 | break; | |
744 | ||
745 | case MFF_ETH_DST: | |
746 | memcpy(value->mac, flow->dl_dst, ETH_ADDR_LEN); | |
747 | break; | |
748 | ||
749 | case MFF_ETH_TYPE: | |
750 | value->be16 = flow->dl_type; | |
751 | break; | |
752 | ||
753 | case MFF_VLAN_TCI: | |
754 | value->be16 = flow->vlan_tci; | |
755 | break; | |
756 | ||
757 | case MFF_VLAN_VID: | |
758 | value->be16 = flow->vlan_tci & htons(VLAN_VID_MASK); | |
759 | break; | |
760 | ||
761 | case MFF_VLAN_PCP: | |
762 | value->u8 = vlan_tci_to_pcp(flow->vlan_tci); | |
763 | break; | |
764 | ||
765 | case MFF_IPV4_SRC: | |
766 | value->be32 = flow->nw_src; | |
767 | break; | |
768 | ||
769 | case MFF_IPV4_DST: | |
770 | value->be32 = flow->nw_dst; | |
771 | break; | |
772 | ||
773 | case MFF_IPV6_SRC: | |
774 | value->ipv6 = flow->ipv6_src; | |
775 | break; | |
776 | ||
777 | case MFF_IPV6_DST: | |
778 | value->ipv6 = flow->ipv6_dst; | |
779 | break; | |
780 | ||
781 | case MFF_IP_PROTO: | |
782 | value->u8 = flow->nw_proto; | |
783 | break; | |
784 | ||
785 | case MFF_IP_TOS: | |
7257b535 BP |
786 | value->u8 = flow->tos_frag & IP_DSCP_MASK; |
787 | break; | |
788 | ||
789 | case MFF_IP_FRAG: | |
790 | value->u8 = flow->tos_frag & FLOW_FRAG_MASK; | |
6a885fd0 BP |
791 | break; |
792 | ||
793 | case MFF_ARP_OP: | |
794 | value->be16 = htons(flow->nw_proto); | |
795 | break; | |
796 | ||
797 | case MFF_ARP_SPA: | |
798 | value->be32 = flow->nw_src; | |
799 | break; | |
800 | ||
801 | case MFF_ARP_TPA: | |
802 | value->be32 = flow->nw_dst; | |
803 | break; | |
804 | ||
805 | case MFF_ARP_SHA: | |
806 | case MFF_ND_SLL: | |
807 | memcpy(value->mac, flow->arp_sha, ETH_ADDR_LEN); | |
808 | break; | |
809 | ||
810 | case MFF_ARP_THA: | |
811 | case MFF_ND_TLL: | |
812 | memcpy(value->mac, flow->arp_tha, ETH_ADDR_LEN); | |
813 | break; | |
814 | ||
815 | case MFF_TCP_SRC: | |
816 | value->be16 = flow->tp_src; | |
817 | break; | |
818 | ||
819 | case MFF_TCP_DST: | |
820 | value->be16 = flow->tp_dst; | |
821 | break; | |
822 | ||
823 | case MFF_UDP_SRC: | |
824 | value->be16 = flow->tp_src; | |
825 | break; | |
826 | ||
827 | case MFF_UDP_DST: | |
828 | value->be16 = flow->tp_dst; | |
829 | break; | |
830 | ||
831 | case MFF_ICMP_TYPE: | |
832 | value->u8 = ntohs(flow->tp_src); | |
833 | break; | |
834 | ||
835 | case MFF_ICMP_CODE: | |
836 | value->u8 = ntohs(flow->tp_dst); | |
837 | break; | |
838 | ||
839 | case MFF_ND_TARGET: | |
840 | value->ipv6 = flow->nd_target; | |
841 | break; | |
842 | ||
843 | case MFF_N_IDS: | |
844 | default: | |
845 | NOT_REACHED(); | |
846 | } | |
847 | } | |
848 | ||
849 | /* Makes 'rule' match field 'mf' exactly, with the value matched taken from | |
850 | * 'value'. The caller is responsible for ensuring that 'rule' meets 'mf''s | |
851 | * prerequisites. */ | |
852 | void | |
853 | mf_set_value(const struct mf_field *mf, | |
854 | const union mf_value *value, struct cls_rule *rule) | |
855 | { | |
856 | switch (mf->id) { | |
857 | case MFF_TUN_ID: | |
858 | cls_rule_set_tun_id(rule, value->be64); | |
859 | break; | |
860 | ||
861 | case MFF_IN_PORT: | |
862 | cls_rule_set_in_port(rule, ntohs(value->be16)); | |
863 | break; | |
864 | ||
865 | #if FLOW_N_REGS > 0 | |
866 | case MFF_REG0: | |
867 | #endif | |
868 | #if FLOW_N_REGS > 1 | |
869 | case MFF_REG1: | |
870 | #endif | |
871 | #if FLOW_N_REGS > 2 | |
872 | case MFF_REG2: | |
873 | #endif | |
874 | #if FLOW_N_REGS > 3 | |
875 | case MFF_REG3: | |
876 | #endif | |
877 | #if FLOW_N_REGS > 4 | |
d2c0fed9 JP |
878 | case MFF_REG4: |
879 | #endif | |
880 | #if FLOW_N_REGS > 5 | |
6a885fd0 BP |
881 | #error |
882 | #endif | |
883 | #if FLOW_N_REGS > 0 | |
884 | cls_rule_set_reg(rule, mf->id - MFF_REG0, ntohl(value->be32)); | |
885 | break; | |
886 | #endif | |
887 | ||
888 | case MFF_ETH_SRC: | |
889 | cls_rule_set_dl_src(rule, value->mac); | |
890 | break; | |
891 | ||
892 | case MFF_ETH_DST: | |
893 | cls_rule_set_dl_dst(rule, value->mac); | |
894 | break; | |
895 | ||
896 | case MFF_ETH_TYPE: | |
897 | cls_rule_set_dl_type(rule, value->be16); | |
898 | break; | |
899 | ||
900 | case MFF_VLAN_TCI: | |
901 | cls_rule_set_dl_tci(rule, value->be16); | |
902 | break; | |
903 | ||
904 | case MFF_VLAN_VID: | |
905 | cls_rule_set_dl_vlan(rule, value->be16); | |
906 | break; | |
907 | ||
908 | case MFF_VLAN_PCP: | |
909 | cls_rule_set_dl_vlan_pcp(rule, value->u8); | |
910 | break; | |
911 | ||
912 | case MFF_IPV4_SRC: | |
913 | cls_rule_set_nw_src(rule, value->be32); | |
914 | break; | |
915 | ||
916 | case MFF_IPV4_DST: | |
917 | cls_rule_set_nw_dst(rule, value->be32); | |
918 | break; | |
919 | ||
920 | case MFF_IPV6_SRC: | |
921 | cls_rule_set_ipv6_src(rule, &value->ipv6); | |
922 | break; | |
923 | ||
924 | case MFF_IPV6_DST: | |
925 | cls_rule_set_ipv6_dst(rule, &value->ipv6); | |
926 | break; | |
927 | ||
928 | case MFF_IP_PROTO: | |
929 | cls_rule_set_nw_proto(rule, value->u8); | |
930 | break; | |
931 | ||
932 | case MFF_IP_TOS: | |
933 | cls_rule_set_nw_tos(rule, value->u8); | |
934 | break; | |
935 | ||
7257b535 BP |
936 | case MFF_IP_FRAG: |
937 | cls_rule_set_frag(rule, value->u8); | |
938 | break; | |
939 | ||
6a885fd0 BP |
940 | case MFF_ARP_OP: |
941 | cls_rule_set_nw_proto(rule, ntohs(value->be16)); | |
942 | break; | |
943 | ||
944 | case MFF_ARP_SPA: | |
945 | cls_rule_set_nw_src(rule, value->be32); | |
946 | break; | |
947 | ||
948 | case MFF_ARP_TPA: | |
949 | cls_rule_set_nw_dst(rule, value->be32); | |
950 | break; | |
951 | ||
952 | case MFF_ARP_SHA: | |
953 | case MFF_ND_SLL: | |
954 | cls_rule_set_arp_sha(rule, value->mac); | |
955 | break; | |
956 | ||
957 | case MFF_ARP_THA: | |
958 | case MFF_ND_TLL: | |
959 | cls_rule_set_arp_tha(rule, value->mac); | |
960 | break; | |
961 | ||
962 | case MFF_TCP_SRC: | |
963 | cls_rule_set_tp_src(rule, value->be16); | |
964 | break; | |
965 | ||
966 | case MFF_TCP_DST: | |
967 | cls_rule_set_tp_dst(rule, value->be16); | |
968 | break; | |
969 | ||
970 | case MFF_UDP_SRC: | |
971 | cls_rule_set_tp_src(rule, value->be16); | |
972 | break; | |
973 | ||
974 | case MFF_UDP_DST: | |
975 | cls_rule_set_tp_dst(rule, value->be16); | |
976 | break; | |
977 | ||
978 | case MFF_ICMP_TYPE: | |
979 | cls_rule_set_icmp_type(rule, value->u8); | |
980 | break; | |
981 | ||
982 | case MFF_ICMP_CODE: | |
983 | cls_rule_set_icmp_code(rule, value->u8); | |
984 | break; | |
985 | ||
986 | case MFF_ND_TARGET: | |
987 | cls_rule_set_nd_target(rule, &value->ipv6); | |
988 | break; | |
989 | ||
990 | case MFF_N_IDS: | |
991 | default: | |
992 | NOT_REACHED(); | |
993 | } | |
994 | } | |
995 | ||
996 | /* Makes 'rule' wildcard field 'mf'. | |
997 | * | |
998 | * The caller is responsible for ensuring that 'rule' meets 'mf''s | |
999 | * prerequisites. */ | |
1000 | void | |
1001 | mf_set_wild(const struct mf_field *mf, struct cls_rule *rule) | |
1002 | { | |
1003 | switch (mf->id) { | |
1004 | case MFF_TUN_ID: | |
1005 | cls_rule_set_tun_id_masked(rule, htonll(0), htonll(0)); | |
1006 | break; | |
1007 | ||
1008 | case MFF_IN_PORT: | |
1009 | rule->wc.wildcards |= FWW_IN_PORT; | |
1010 | rule->flow.in_port = 0; | |
1011 | break; | |
1012 | ||
1013 | #if FLOW_N_REGS > 0 | |
1014 | case MFF_REG0: | |
1015 | cls_rule_set_reg_masked(rule, 0, 0, 0); | |
1016 | break; | |
1017 | #endif | |
1018 | #if FLOW_N_REGS > 1 | |
1019 | case MFF_REG1: | |
1020 | cls_rule_set_reg_masked(rule, 1, 0, 0); | |
1021 | break; | |
1022 | #endif | |
1023 | #if FLOW_N_REGS > 2 | |
1024 | case MFF_REG2: | |
1025 | cls_rule_set_reg_masked(rule, 2, 0, 0); | |
1026 | break; | |
1027 | #endif | |
1028 | #if FLOW_N_REGS > 3 | |
1029 | case MFF_REG3: | |
1030 | cls_rule_set_reg_masked(rule, 3, 0, 0); | |
1031 | break; | |
1032 | #endif | |
1033 | #if FLOW_N_REGS > 4 | |
d2c0fed9 JP |
1034 | case MFF_REG4: |
1035 | cls_rule_set_reg_masked(rule, 4, 0, 0); | |
1036 | break; | |
1037 | #endif | |
1038 | #if FLOW_N_REGS > 5 | |
6a885fd0 BP |
1039 | #error |
1040 | #endif | |
1041 | ||
1042 | case MFF_ETH_SRC: | |
1043 | rule->wc.wildcards |= FWW_DL_SRC; | |
1044 | memset(rule->flow.dl_src, 0, sizeof rule->flow.dl_src); | |
1045 | break; | |
1046 | ||
1047 | case MFF_ETH_DST: | |
1048 | rule->wc.wildcards |= FWW_DL_DST | FWW_ETH_MCAST; | |
1049 | memset(rule->flow.dl_dst, 0, sizeof rule->flow.dl_dst); | |
1050 | break; | |
1051 | ||
1052 | case MFF_ETH_TYPE: | |
1053 | rule->wc.wildcards |= FWW_DL_TYPE; | |
1054 | rule->flow.dl_type = htons(0); | |
1055 | break; | |
1056 | ||
1057 | case MFF_VLAN_TCI: | |
1058 | cls_rule_set_dl_tci_masked(rule, htons(0), htons(0)); | |
1059 | break; | |
1060 | ||
1061 | case MFF_VLAN_VID: | |
1062 | cls_rule_set_any_vid(rule); | |
1063 | break; | |
1064 | ||
1065 | case MFF_VLAN_PCP: | |
1066 | cls_rule_set_any_pcp(rule); | |
1067 | break; | |
1068 | ||
1069 | case MFF_IPV4_SRC: | |
1070 | case MFF_ARP_SPA: | |
1071 | cls_rule_set_nw_src_masked(rule, htonl(0), htonl(0)); | |
1072 | break; | |
1073 | ||
1074 | case MFF_IPV4_DST: | |
1075 | case MFF_ARP_TPA: | |
1076 | cls_rule_set_nw_dst_masked(rule, htonl(0), htonl(0)); | |
1077 | break; | |
1078 | ||
1079 | case MFF_IPV6_SRC: | |
1080 | memset(&rule->wc.ipv6_src_mask, 0, sizeof rule->wc.ipv6_src_mask); | |
1081 | memset(&rule->flow.ipv6_src, 0, sizeof rule->flow.ipv6_src); | |
1082 | break; | |
1083 | ||
1084 | case MFF_IPV6_DST: | |
1085 | memset(&rule->wc.ipv6_dst_mask, 0, sizeof rule->wc.ipv6_dst_mask); | |
1086 | memset(&rule->flow.ipv6_dst, 0, sizeof rule->flow.ipv6_dst); | |
1087 | break; | |
1088 | ||
1089 | case MFF_IP_PROTO: | |
1090 | rule->wc.wildcards |= FWW_NW_PROTO; | |
1091 | rule->flow.nw_proto = 0; | |
1092 | break; | |
1093 | ||
1094 | case MFF_IP_TOS: | |
7257b535 BP |
1095 | rule->wc.tos_frag_mask |= IP_DSCP_MASK; |
1096 | rule->flow.tos_frag &= ~IP_DSCP_MASK; | |
1097 | break; | |
1098 | ||
1099 | case MFF_IP_FRAG: | |
1100 | rule->wc.tos_frag_mask |= FLOW_FRAG_MASK; | |
1101 | rule->flow.tos_frag &= ~FLOW_FRAG_MASK; | |
6a885fd0 BP |
1102 | break; |
1103 | ||
1104 | case MFF_ARP_OP: | |
1105 | rule->wc.wildcards |= FWW_NW_PROTO; | |
1106 | rule->flow.nw_proto = 0; | |
1107 | break; | |
1108 | ||
1109 | case MFF_ARP_SHA: | |
1110 | case MFF_ND_SLL: | |
1111 | rule->wc.wildcards |= FWW_ARP_SHA; | |
1112 | memset(rule->flow.arp_sha, 0, sizeof rule->flow.arp_sha); | |
1113 | break; | |
1114 | ||
1115 | case MFF_ARP_THA: | |
1116 | case MFF_ND_TLL: | |
1117 | rule->wc.wildcards |= FWW_ARP_THA; | |
1118 | memset(rule->flow.arp_tha, 0, sizeof rule->flow.arp_tha); | |
1119 | break; | |
1120 | ||
1121 | case MFF_TCP_SRC: | |
1122 | case MFF_UDP_SRC: | |
1123 | case MFF_ICMP_TYPE: | |
1124 | rule->wc.wildcards |= FWW_TP_SRC; | |
1125 | rule->flow.tp_src = htons(0); | |
1126 | break; | |
1127 | ||
1128 | case MFF_TCP_DST: | |
1129 | case MFF_UDP_DST: | |
1130 | case MFF_ICMP_CODE: | |
1131 | rule->wc.wildcards |= FWW_TP_DST; | |
1132 | rule->flow.tp_dst = htons(0); | |
1133 | break; | |
1134 | ||
1135 | case MFF_ND_TARGET: | |
1136 | rule->wc.wildcards |= FWW_ND_TARGET; | |
1137 | memset(&rule->flow.nd_target, 0, sizeof rule->flow.nd_target); | |
1138 | break; | |
1139 | ||
1140 | case MFF_N_IDS: | |
1141 | default: | |
1142 | NOT_REACHED(); | |
1143 | } | |
1144 | } | |
1145 | ||
1146 | /* Makes 'rule' match field 'mf' with the specified 'value' and 'mask'. | |
1147 | * 'value' specifies a value to match and 'mask' specifies a wildcard pattern, | |
1148 | * with a 1-bit indicating that the corresponding value bit must match and a | |
1149 | * 0-bit indicating a don't-care. | |
1150 | * | |
1151 | * If 'mask' is NULL or points to all-1-bits, then this call is equivalent to | |
1152 | * mf_set_value(mf, value, rule). If 'mask' points to all-0-bits, then this | |
1153 | * call is equivalent to mf_set_wild(mf, rule). | |
1154 | * | |
1155 | * 'mask' must be a valid mask for 'mf' (see mf_is_mask_valid()). The caller | |
1156 | * is responsible for ensuring that 'rule' meets 'mf''s prerequisites. */ | |
1157 | void | |
1158 | mf_set(const struct mf_field *mf, | |
1159 | const union mf_value *value, const union mf_value *mask, | |
1160 | struct cls_rule *rule) | |
1161 | { | |
1162 | if (!mask || is_all_ones((const uint8_t *) mask, mf->n_bytes)) { | |
1163 | mf_set_value(mf, value, rule); | |
1164 | return; | |
1165 | } else if (is_all_zeros((const uint8_t *) mask, mf->n_bytes)) { | |
1166 | mf_set_wild(mf, rule); | |
1167 | return; | |
1168 | } | |
1169 | ||
1170 | switch (mf->id) { | |
1171 | case MFF_IN_PORT: | |
1172 | case MFF_ETH_SRC: | |
1173 | case MFF_ETH_TYPE: | |
1174 | case MFF_VLAN_VID: | |
1175 | case MFF_VLAN_PCP: | |
1176 | case MFF_IP_PROTO: | |
1177 | case MFF_IP_TOS: | |
1178 | case MFF_ARP_OP: | |
1179 | case MFF_ARP_SHA: | |
1180 | case MFF_ARP_THA: | |
1181 | case MFF_TCP_SRC: | |
1182 | case MFF_TCP_DST: | |
1183 | case MFF_UDP_SRC: | |
1184 | case MFF_UDP_DST: | |
1185 | case MFF_ICMP_TYPE: | |
1186 | case MFF_ICMP_CODE: | |
1187 | case MFF_ND_TARGET: | |
1188 | case MFF_ND_SLL: | |
1189 | case MFF_ND_TLL: | |
1190 | NOT_REACHED(); | |
1191 | ||
1192 | case MFF_TUN_ID: | |
1193 | cls_rule_set_tun_id_masked(rule, value->be64, mask->be64); | |
1194 | break; | |
1195 | ||
1196 | #if FLOW_N_REGS > 0 | |
1197 | case MFF_REG0: | |
1198 | #endif | |
1199 | #if FLOW_N_REGS > 1 | |
1200 | case MFF_REG1: | |
1201 | #endif | |
1202 | #if FLOW_N_REGS > 2 | |
1203 | case MFF_REG2: | |
1204 | #endif | |
1205 | #if FLOW_N_REGS > 3 | |
1206 | case MFF_REG3: | |
1207 | #endif | |
1208 | #if FLOW_N_REGS > 4 | |
d2c0fed9 JP |
1209 | case MFF_REG4: |
1210 | #endif | |
1211 | #if FLOW_N_REGS > 5 | |
6a885fd0 BP |
1212 | #error |
1213 | #endif | |
1214 | cls_rule_set_reg_masked(rule, mf->id - MFF_REG0, | |
1215 | ntohl(value->be32), ntohl(mask->be32)); | |
1216 | break; | |
1217 | ||
1218 | case MFF_ETH_DST: | |
1219 | if (flow_wildcards_is_dl_dst_mask_valid(mask->mac)) { | |
1220 | cls_rule_set_dl_dst_masked(rule, value->mac, mask->mac); | |
1221 | } | |
1222 | break; | |
1223 | ||
1224 | case MFF_VLAN_TCI: | |
1225 | cls_rule_set_dl_tci_masked(rule, value->be16, mask->be16); | |
1226 | break; | |
1227 | ||
1228 | case MFF_IPV4_SRC: | |
1229 | cls_rule_set_nw_src_masked(rule, value->be32, mask->be32); | |
1230 | break; | |
1231 | ||
1232 | case MFF_IPV4_DST: | |
1233 | cls_rule_set_nw_dst_masked(rule, value->be32, mask->be32); | |
1234 | break; | |
1235 | ||
1236 | case MFF_IPV6_SRC: | |
1237 | cls_rule_set_ipv6_src_masked(rule, &value->ipv6, &mask->ipv6); | |
1238 | break; | |
1239 | ||
1240 | case MFF_IPV6_DST: | |
1241 | cls_rule_set_ipv6_dst_masked(rule, &value->ipv6, &mask->ipv6); | |
1242 | break; | |
1243 | ||
7257b535 BP |
1244 | case MFF_IP_FRAG: |
1245 | cls_rule_set_frag_masked(rule, value->u8, mask->u8); | |
1246 | break; | |
1247 | ||
6a885fd0 BP |
1248 | case MFF_ARP_SPA: |
1249 | cls_rule_set_nw_src_masked(rule, value->be32, mask->be32); | |
1250 | break; | |
1251 | ||
1252 | case MFF_ARP_TPA: | |
1253 | cls_rule_set_nw_dst_masked(rule, value->be32, mask->be32); | |
1254 | break; | |
1255 | ||
1256 | case MFF_N_IDS: | |
1257 | default: | |
1258 | NOT_REACHED(); | |
1259 | } | |
1260 | } | |
1261 | ||
1262 | /* Makes a subfield starting at bit offset 'ofs' and continuing for 'n_bits' in | |
1263 | * 'rule''s field 'mf' exactly match the 'n_bits' least-significant bits of | |
1264 | * 'x'. | |
1265 | * | |
1266 | * Example: suppose that 'mf' is originally the following 2-byte field in | |
1267 | * 'rule': | |
1268 | * | |
1269 | * value == 0xe00a == 2#1110000000001010 | |
1270 | * mask == 0xfc3f == 2#1111110000111111 | |
1271 | * | |
1272 | * The call mf_set_subfield(mf, 0x55, 8, 7, rule) would have the following | |
1273 | * effect (note that 0x55 is 2#1010101): | |
1274 | * | |
1275 | * value == 0xd50a == 2#1101010100001010 | |
1276 | * mask == 0xff3f == 2#1111111100111111 | |
1277 | * | |
1278 | * The caller is responsible for ensuring that the result will be a valid | |
1279 | * wildcard pattern for 'mf'. The caller is responsible for ensuring that | |
1280 | * 'rule' meets 'mf''s prerequisites. */ | |
1281 | void | |
1282 | mf_set_subfield(const struct mf_field *mf, uint64_t x, unsigned int ofs, | |
1283 | unsigned int n_bits, struct cls_rule *rule) | |
1284 | { | |
1285 | if (ofs == 0 && mf->n_bytes * 8 == n_bits) { | |
1286 | union mf_value value; | |
1287 | int i; | |
1288 | ||
1289 | for (i = mf->n_bytes - 1; i >= 0; i--) { | |
1290 | ((uint8_t *) &value)[i] = x; | |
1291 | x >>= 8; | |
1292 | } | |
1293 | mf_set_value(mf, &value, rule); | |
1294 | } else { | |
1295 | union mf_value value, mask; | |
1296 | uint8_t *vp, *mp; | |
1297 | unsigned int byte_ofs; | |
1298 | ||
1299 | mf_get(mf, rule, &value, &mask); | |
1300 | ||
1301 | byte_ofs = mf->n_bytes - ofs / 8; | |
1302 | vp = &((uint8_t *) &value)[byte_ofs]; | |
1303 | mp = &((uint8_t *) &mask)[byte_ofs]; | |
1304 | if (ofs % 8) { | |
1305 | unsigned int chunk = MIN(8 - ofs % 8, n_bits); | |
1306 | uint8_t chunk_mask = ((1 << chunk) - 1) << (ofs % 8); | |
1307 | ||
1308 | *--vp &= ~chunk_mask; | |
1309 | *vp |= chunk_mask & (x << (ofs % 8)); | |
1310 | *--mp |= chunk_mask; | |
1311 | ||
1312 | x >>= chunk; | |
1313 | n_bits -= chunk; | |
1314 | ofs += chunk; | |
1315 | } | |
1316 | while (n_bits >= 8) { | |
1317 | *--vp = x; | |
1318 | *--mp = 0xff; | |
1319 | x >>= 8; | |
1320 | n_bits -= 8; | |
1321 | ofs += 8; | |
1322 | } | |
1323 | if (n_bits) { | |
1324 | uint8_t chunk_mask = (1 << n_bits) - 1; | |
1325 | ||
1326 | *--vp &= ~chunk_mask; | |
1327 | *vp |= chunk_mask & x; | |
1328 | *--mp |= chunk_mask; | |
1329 | } | |
1330 | ||
1331 | mf_set(mf, &value, &mask, rule); | |
1332 | } | |
1333 | } | |
1334 | ||
1335 | /* Copies the value and wildcard bit pattern for 'mf' from 'rule' into the | |
1336 | * 'value' and 'mask', respectively. */ | |
1337 | void | |
1338 | mf_get(const struct mf_field *mf, const struct cls_rule *rule, | |
1339 | union mf_value *value, union mf_value *mask) | |
1340 | { | |
1341 | mf_get_value(mf, &rule->flow, value); | |
1342 | mf_get_mask(mf, &rule->wc, mask); | |
1343 | } | |
1344 | ||
1345 | /* Assigns a random value for field 'mf' to 'value'. */ | |
1346 | void | |
1347 | mf_random_value(const struct mf_field *mf, union mf_value *value) | |
1348 | { | |
1349 | random_bytes(value, mf->n_bytes); | |
1350 | ||
1351 | switch (mf->id) { | |
1352 | case MFF_TUN_ID: | |
1353 | case MFF_IN_PORT: | |
1354 | #if FLOW_N_REGS > 0 | |
1355 | case MFF_REG0: | |
1356 | #endif | |
1357 | #if FLOW_N_REGS > 1 | |
1358 | case MFF_REG1: | |
1359 | #endif | |
1360 | #if FLOW_N_REGS > 2 | |
1361 | case MFF_REG2: | |
1362 | #endif | |
1363 | #if FLOW_N_REGS > 3 | |
1364 | case MFF_REG3: | |
1365 | #endif | |
1366 | #if FLOW_N_REGS > 4 | |
d2c0fed9 JP |
1367 | case MFF_REG4: |
1368 | #endif | |
1369 | #if FLOW_N_REGS > 5 | |
6a885fd0 BP |
1370 | #error |
1371 | #endif | |
1372 | case MFF_ETH_SRC: | |
1373 | case MFF_ETH_DST: | |
1374 | case MFF_ETH_TYPE: | |
1375 | case MFF_VLAN_TCI: | |
1376 | case MFF_IPV4_SRC: | |
1377 | case MFF_IPV4_DST: | |
1378 | case MFF_IPV6_SRC: | |
1379 | case MFF_IPV6_DST: | |
1380 | case MFF_IP_PROTO: | |
1381 | case MFF_ARP_SPA: | |
1382 | case MFF_ARP_TPA: | |
1383 | case MFF_ARP_SHA: | |
1384 | case MFF_ARP_THA: | |
1385 | case MFF_TCP_SRC: | |
1386 | case MFF_TCP_DST: | |
1387 | case MFF_UDP_SRC: | |
1388 | case MFF_UDP_DST: | |
1389 | case MFF_ICMP_TYPE: | |
1390 | case MFF_ICMP_CODE: | |
1391 | case MFF_ND_TARGET: | |
1392 | case MFF_ND_SLL: | |
1393 | case MFF_ND_TLL: | |
1394 | break; | |
1395 | ||
1396 | case MFF_IP_TOS: | |
1397 | value->u8 &= ~0x03; | |
1398 | break; | |
1399 | ||
7257b535 BP |
1400 | case MFF_IP_FRAG: |
1401 | value->u8 &= FLOW_FRAG_MASK; | |
1402 | break; | |
1403 | ||
6a885fd0 BP |
1404 | case MFF_ARP_OP: |
1405 | value->be16 &= htons(0xff); | |
1406 | break; | |
1407 | ||
1408 | case MFF_VLAN_VID: | |
1409 | value->be16 &= htons(VLAN_VID_MASK); | |
1410 | break; | |
1411 | ||
1412 | case MFF_VLAN_PCP: | |
1413 | value->u8 &= 0x07; | |
1414 | break; | |
1415 | ||
1416 | case MFF_N_IDS: | |
1417 | default: | |
1418 | NOT_REACHED(); | |
1419 | } | |
1420 | } | |
1421 | ||
1422 | static char * | |
1423 | mf_from_integer_string(const struct mf_field *mf, const char *s, | |
1424 | uint8_t *valuep, uint8_t *maskp) | |
1425 | { | |
1426 | unsigned long long int integer, mask; | |
1427 | char *tail; | |
1428 | int i; | |
1429 | ||
1430 | errno = 0; | |
1431 | integer = strtoull(s, &tail, 0); | |
1432 | if (errno || (*tail != '\0' && *tail != '/')) { | |
1433 | goto syntax_error; | |
1434 | } | |
1435 | ||
1436 | if (*tail == '/') { | |
1437 | mask = strtoull(tail + 1, &tail, 0); | |
1438 | if (errno || *tail != '\0') { | |
1439 | goto syntax_error; | |
1440 | } | |
1441 | } else { | |
1442 | mask = ULLONG_MAX; | |
1443 | } | |
1444 | ||
1445 | for (i = mf->n_bytes - 1; i >= 0; i--) { | |
1446 | valuep[i] = integer; | |
1447 | maskp[i] = mask; | |
1448 | integer >>= 8; | |
1449 | mask >>= 8; | |
1450 | } | |
1451 | if (integer) { | |
1452 | return xasprintf("%s: value too large for %u-byte field %s", | |
1453 | s, mf->n_bytes, mf->name); | |
1454 | } | |
1455 | return NULL; | |
1456 | ||
1457 | syntax_error: | |
1458 | return xasprintf("%s: bad syntax for %s", s, mf->name); | |
1459 | } | |
1460 | ||
1461 | static char * | |
1462 | mf_from_ethernet_string(const struct mf_field *mf, const char *s, | |
1463 | uint8_t mac[ETH_ADDR_LEN], | |
1464 | uint8_t mask[ETH_ADDR_LEN]) | |
1465 | { | |
1466 | assert(mf->n_bytes == ETH_ADDR_LEN); | |
1467 | ||
1468 | switch (sscanf(s, ETH_ADDR_SCAN_FMT"/"ETH_ADDR_SCAN_FMT, | |
1469 | ETH_ADDR_SCAN_ARGS(mac), ETH_ADDR_SCAN_ARGS(mask))){ | |
1470 | case ETH_ADDR_SCAN_COUNT * 2: | |
1471 | return NULL; | |
1472 | ||
1473 | case ETH_ADDR_SCAN_COUNT: | |
1474 | memset(mask, 0xff, ETH_ADDR_LEN); | |
1475 | return NULL; | |
1476 | ||
1477 | default: | |
1478 | return xasprintf("%s: invalid Ethernet address", s); | |
1479 | } | |
1480 | } | |
1481 | ||
1482 | static char * | |
1483 | mf_from_ipv4_string(const struct mf_field *mf, const char *s, | |
1484 | ovs_be32 *ip, ovs_be32 *mask) | |
1485 | { | |
1486 | int prefix; | |
1487 | ||
1488 | assert(mf->n_bytes == sizeof *ip); | |
1489 | ||
1490 | if (sscanf(s, IP_SCAN_FMT"/"IP_SCAN_FMT, | |
1491 | IP_SCAN_ARGS(ip), IP_SCAN_ARGS(mask)) == IP_SCAN_COUNT * 2) { | |
1492 | /* OK. */ | |
1493 | } else if (sscanf(s, IP_SCAN_FMT"/%d", | |
1494 | IP_SCAN_ARGS(ip), &prefix) == IP_SCAN_COUNT + 1) { | |
1495 | if (prefix <= 0 || prefix > 32) { | |
1496 | return xasprintf("%s: network prefix bits not between 1 and " | |
1497 | "32", s); | |
1498 | } else if (prefix == 32) { | |
1499 | *mask = htonl(UINT32_MAX); | |
1500 | } else { | |
1501 | *mask = htonl(((1u << prefix) - 1) << (32 - prefix)); | |
1502 | } | |
1503 | } else if (sscanf(s, IP_SCAN_FMT, IP_SCAN_ARGS(ip)) == IP_SCAN_COUNT) { | |
1504 | *mask = htonl(UINT32_MAX); | |
1505 | } else { | |
1506 | return xasprintf("%s: invalid IP address", s); | |
1507 | } | |
1508 | return NULL; | |
1509 | } | |
1510 | ||
1511 | static char * | |
1512 | mf_from_ipv6_string(const struct mf_field *mf, const char *s, | |
1513 | struct in6_addr *value, struct in6_addr *mask) | |
1514 | { | |
1515 | char *str = xstrdup(s); | |
1516 | char *save_ptr = NULL; | |
1517 | const char *name, *netmask; | |
1518 | int retval; | |
1519 | ||
1520 | assert(mf->n_bytes == sizeof *value); | |
1521 | ||
1522 | name = strtok_r(str, "/", &save_ptr); | |
1523 | retval = name ? lookup_ipv6(name, value) : EINVAL; | |
1524 | if (retval) { | |
1525 | char *err; | |
1526 | ||
1527 | err = xasprintf("%s: could not convert to IPv6 address", str); | |
1528 | free(str); | |
1529 | ||
1530 | return err; | |
1531 | } | |
1532 | ||
1533 | netmask = strtok_r(NULL, "/", &save_ptr); | |
1534 | if (netmask) { | |
1535 | int prefix = atoi(netmask); | |
1536 | if (prefix <= 0 || prefix > 128) { | |
1537 | free(str); | |
1538 | return xasprintf("%s: prefix bits not between 1 and 128", s); | |
1539 | } else { | |
1540 | *mask = ipv6_create_mask(prefix); | |
1541 | } | |
1542 | } else { | |
1543 | *mask = in6addr_exact; | |
1544 | } | |
1545 | free(str); | |
1546 | ||
1547 | return NULL; | |
1548 | } | |
1549 | ||
1550 | static char * | |
1551 | mf_from_ofp_port_string(const struct mf_field *mf, const char *s, | |
1552 | ovs_be16 *valuep, ovs_be16 *maskp) | |
1553 | { | |
1554 | uint16_t port; | |
1555 | ||
1556 | assert(mf->n_bytes == sizeof(ovs_be16)); | |
1557 | if (ofputil_port_from_string(s, &port)) { | |
1558 | *valuep = htons(port); | |
1559 | *maskp = htons(UINT16_MAX); | |
1560 | return NULL; | |
1561 | } else { | |
1562 | return mf_from_integer_string(mf, s, | |
1563 | (uint8_t *) valuep, (uint8_t *) maskp); | |
1564 | } | |
1565 | } | |
1566 | ||
7257b535 BP |
1567 | struct frag_handling { |
1568 | const char *name; | |
1569 | uint8_t mask; | |
1570 | uint8_t value; | |
1571 | }; | |
1572 | ||
1573 | static const struct frag_handling all_frags[] = { | |
1574 | #define A FLOW_FRAG_ANY | |
1575 | #define L FLOW_FRAG_LATER | |
1576 | /* name mask value */ | |
1577 | ||
1578 | { "no", A|L, 0 }, | |
1579 | { "first", A|L, A }, | |
1580 | { "later", A|L, A|L }, | |
1581 | ||
1582 | { "no", A, 0 }, | |
1583 | { "yes", A, A }, | |
1584 | ||
1585 | { "not_later", L, 0 }, | |
1586 | { "later", L, L }, | |
1587 | #undef A | |
1588 | #undef L | |
1589 | }; | |
1590 | ||
1591 | static char * | |
1592 | mf_from_frag_string(const char *s, uint8_t *valuep, uint8_t *maskp) | |
1593 | { | |
1594 | const struct frag_handling *h; | |
1595 | ||
1596 | for (h = all_frags; h < &all_frags[ARRAY_SIZE(all_frags)]; h++) { | |
1597 | if (!strcasecmp(s, h->name)) { | |
1598 | /* We force the upper bits of the mask on to make mf_parse_value() | |
1599 | * happy (otherwise it will never think it's an exact match.) */ | |
1600 | *maskp = h->mask | ~FLOW_FRAG_MASK; | |
1601 | *valuep = h->value; | |
1602 | return NULL; | |
1603 | } | |
1604 | } | |
1605 | ||
1606 | return xasprintf("%s: unknown fragment type (valid types are \"no\", " | |
1607 | "\"yes\", \"first\", \"later\", \"not_first\"", s); | |
1608 | } | |
1609 | ||
6a885fd0 BP |
1610 | /* Parses 's', a string value for field 'mf', into 'value' and 'mask'. Returns |
1611 | * NULL if successful, otherwise a malloc()'d string describing the error. */ | |
1612 | char * | |
1613 | mf_parse(const struct mf_field *mf, const char *s, | |
1614 | union mf_value *value, union mf_value *mask) | |
1615 | { | |
1616 | if (!strcasecmp(s, "any") || !strcmp(s, "*")) { | |
1617 | memset(value, 0, mf->n_bytes); | |
1618 | memset(mask, 0, mf->n_bytes); | |
1619 | return NULL; | |
1620 | } | |
1621 | ||
1622 | switch (mf->string) { | |
1623 | case MFS_DECIMAL: | |
1624 | case MFS_HEXADECIMAL: | |
1625 | return mf_from_integer_string(mf, s, | |
1626 | (uint8_t *) value, (uint8_t *) mask); | |
1627 | ||
1628 | case MFS_ETHERNET: | |
1629 | return mf_from_ethernet_string(mf, s, value->mac, mask->mac); | |
1630 | ||
1631 | case MFS_IPV4: | |
1632 | return mf_from_ipv4_string(mf, s, &value->be32, &mask->be32); | |
1633 | ||
1634 | case MFS_IPV6: | |
1635 | return mf_from_ipv6_string(mf, s, &value->ipv6, &mask->ipv6); | |
1636 | ||
1637 | case MFS_OFP_PORT: | |
1638 | return mf_from_ofp_port_string(mf, s, &value->be16, &mask->be16); | |
7257b535 BP |
1639 | |
1640 | case MFS_FRAG: | |
1641 | return mf_from_frag_string(s, &value->u8, &mask->u8); | |
6a885fd0 BP |
1642 | } |
1643 | NOT_REACHED(); | |
1644 | } | |
1645 | ||
1646 | /* Parses 's', a string value for field 'mf', into 'value'. Returns NULL if | |
1647 | * successful, otherwise a malloc()'d string describing the error. */ | |
1648 | char * | |
1649 | mf_parse_value(const struct mf_field *mf, const char *s, union mf_value *value) | |
1650 | { | |
1651 | union mf_value mask; | |
1652 | char *error; | |
1653 | ||
1654 | error = mf_parse(mf, s, value, &mask); | |
1655 | if (error) { | |
1656 | return error; | |
1657 | } | |
1658 | ||
1659 | if (!is_all_ones((const uint8_t *) &mask, mf->n_bytes)) { | |
1660 | return xasprintf("%s: wildcards not allowed here", s); | |
1661 | } | |
1662 | return NULL; | |
1663 | } | |
1664 | ||
1665 | static void | |
1666 | mf_format_integer_string(const struct mf_field *mf, const uint8_t *valuep, | |
1667 | const uint8_t *maskp, struct ds *s) | |
1668 | { | |
1669 | unsigned long long int integer; | |
1670 | int i; | |
1671 | ||
1672 | assert(mf->n_bytes <= 8); | |
1673 | ||
1674 | integer = 0; | |
1675 | for (i = 0; i < mf->n_bytes; i++) { | |
1676 | integer = (integer << 8) | valuep[i]; | |
1677 | } | |
1678 | if (mf->string == MFS_HEXADECIMAL) { | |
1679 | ds_put_format(s, "%#llx", integer); | |
1680 | } else { | |
1681 | ds_put_format(s, "%lld", integer); | |
1682 | } | |
1683 | ||
1684 | if (maskp) { | |
1685 | unsigned long long int mask; | |
1686 | ||
1687 | mask = 0; | |
1688 | for (i = 0; i < mf->n_bytes; i++) { | |
1689 | mask = (mask << 8) | maskp[i]; | |
1690 | } | |
1691 | ||
1692 | /* I guess we could write the mask in decimal for MFS_DECIMAL but I'm | |
1693 | * not sure that that a bit-mask written in decimal is ever easier to | |
1694 | * understand than the same bit-mask written in hexadecimal. */ | |
1695 | ds_put_format(s, "/%#llx", mask); | |
1696 | } | |
1697 | } | |
1698 | ||
7257b535 BP |
1699 | static void |
1700 | mf_format_frag_string(const uint8_t *valuep, const uint8_t *maskp, | |
1701 | struct ds *s) | |
1702 | { | |
1703 | const struct frag_handling *h; | |
1704 | uint8_t value = *valuep; | |
1705 | uint8_t mask = *maskp; | |
1706 | ||
1707 | value &= mask; | |
1708 | mask &= FLOW_FRAG_MASK; | |
1709 | ||
1710 | for (h = all_frags; h < &all_frags[ARRAY_SIZE(all_frags)]; h++) { | |
1711 | if (value == h->value && mask == h->mask) { | |
1712 | ds_put_cstr(s, h->name); | |
1713 | return; | |
1714 | } | |
1715 | } | |
1716 | ds_put_cstr(s, "<error>"); | |
1717 | } | |
1718 | ||
6a885fd0 BP |
1719 | /* Appends to 's' a string representation of field 'mf' whose value is in |
1720 | * 'value' and 'mask'. 'mask' may be NULL to indicate an exact match. */ | |
1721 | void | |
1722 | mf_format(const struct mf_field *mf, | |
1723 | const union mf_value *value, const union mf_value *mask, | |
1724 | struct ds *s) | |
1725 | { | |
1726 | if (mask) { | |
1727 | if (is_all_zeros((const uint8_t *) mask, mf->n_bytes)) { | |
1728 | ds_put_cstr(s, "ANY"); | |
1729 | return; | |
1730 | } else if (is_all_ones((const uint8_t *) mask, mf->n_bytes)) { | |
1731 | mask = NULL; | |
1732 | } | |
1733 | } | |
1734 | ||
1735 | switch (mf->string) { | |
1736 | case MFS_OFP_PORT: | |
1737 | if (!mask) { | |
1738 | ofputil_format_port(ntohs(value->be16), s); | |
1739 | break; | |
1740 | } | |
1741 | /* fall through */ | |
1742 | case MFS_DECIMAL: | |
1743 | case MFS_HEXADECIMAL: | |
1744 | mf_format_integer_string(mf, (uint8_t *) value, (uint8_t *) mask, s); | |
1745 | break; | |
1746 | ||
1747 | case MFS_ETHERNET: | |
1748 | ds_put_format(s, ETH_ADDR_FMT, ETH_ADDR_ARGS(value->mac)); | |
1749 | if (mask) { | |
1750 | ds_put_format(s, "/"ETH_ADDR_FMT, ETH_ADDR_ARGS(mask->mac)); | |
1751 | } | |
1752 | break; | |
1753 | ||
1754 | case MFS_IPV4: | |
1755 | ip_format_masked(value->be32, mask ? mask->be32 : htonl(UINT32_MAX), | |
1756 | s); | |
1757 | break; | |
1758 | ||
1759 | case MFS_IPV6: | |
1760 | print_ipv6_masked(s, &value->ipv6, mask ? &mask->ipv6 : NULL); | |
1761 | break; | |
1762 | ||
7257b535 BP |
1763 | case MFS_FRAG: |
1764 | mf_format_frag_string(&value->u8, &mask->u8, s); | |
1765 | break; | |
1766 | ||
6a885fd0 BP |
1767 | default: |
1768 | NOT_REACHED(); | |
1769 | } | |
1770 | } |