]>
Commit | Line | Data |
---|---|---|
6a885fd0 | 1 | /* |
1638b906 | 2 | * Copyright (c) 2011, 2012, 2013 Nicira, Inc. |
6a885fd0 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 | #ifndef META_FLOW_H | |
18 | #define META_FLOW_H 1 | |
19 | ||
6ca00f6f ETN |
20 | #include <sys/types.h> |
21 | #include <netinet/in.h> | |
6a885fd0 BP |
22 | #include <netinet/ip6.h> |
23 | #include "flow.h" | |
816fd533 | 24 | #include "ofp-errors.h" |
db0b6c29 | 25 | #include "ofp-util.h" |
6a885fd0 | 26 | #include "packets.h" |
7f98c44d | 27 | #include "util.h" |
6a885fd0 | 28 | |
6a885fd0 | 29 | struct ds; |
81a76618 | 30 | struct match; |
6a885fd0 BP |
31 | |
32 | /* The comment on each of these indicates the member in "union mf_value" used | |
33 | * to represent its value. */ | |
7f98c44d | 34 | enum OVS_PACKED_ENUM mf_field_id { |
6a885fd0 | 35 | /* Metadata. */ |
a79f29f2 AZ |
36 | MFF_DP_HASH, /* be32 */ |
37 | MFF_RECIRC_ID, /* be32 */ | |
6a885fd0 | 38 | MFF_TUN_ID, /* be64 */ |
4fe3445a PS |
39 | MFF_TUN_SRC, /* be32 */ |
40 | MFF_TUN_DST, /* be32 */ | |
41 | MFF_TUN_FLAGS, /* be16 */ | |
42 | MFF_TUN_TTL, /* u8 */ | |
43 | MFF_TUN_TOS, /* u8 */ | |
969fc56c | 44 | MFF_METADATA, /* be64 */ |
6a885fd0 | 45 | MFF_IN_PORT, /* be16 */ |
72333065 | 46 | MFF_IN_PORT_OXM, /* be32 */ |
1b567fb9 | 47 | MFF_SKB_PRIORITY, /* be32 */ |
1362e248 | 48 | MFF_PKT_MARK, /* be32 */ |
6a885fd0 BP |
49 | |
50 | #if FLOW_N_REGS > 0 | |
51 | MFF_REG0, /* be32 */ | |
52 | #endif | |
53 | #if FLOW_N_REGS > 1 | |
54 | MFF_REG1, /* be32 */ | |
55 | #endif | |
56 | #if FLOW_N_REGS > 2 | |
57 | MFF_REG2, /* be32 */ | |
58 | #endif | |
59 | #if FLOW_N_REGS > 3 | |
60 | MFF_REG3, /* be32 */ | |
61 | #endif | |
62 | #if FLOW_N_REGS > 4 | |
d2c0fed9 JP |
63 | MFF_REG4, /* be32 */ |
64 | #endif | |
65 | #if FLOW_N_REGS > 5 | |
e9358af6 EJ |
66 | MFF_REG5, /* be32 */ |
67 | #endif | |
68 | #if FLOW_N_REGS > 6 | |
69 | MFF_REG6, /* be32 */ | |
70 | #endif | |
71 | #if FLOW_N_REGS > 7 | |
72 | MFF_REG7, /* be32 */ | |
6a885fd0 BP |
73 | #endif |
74 | ||
75 | /* L2. */ | |
76 | MFF_ETH_SRC, /* mac */ | |
77 | MFF_ETH_DST, /* mac */ | |
78 | MFF_ETH_TYPE, /* be16 */ | |
79 | ||
80 | MFF_VLAN_TCI, /* be16 */ | |
441c57a9 | 81 | MFF_DL_VLAN, /* be16 (OpenFlow 1.0 compatibility) */ |
cc34bc8c | 82 | MFF_VLAN_VID, /* be16 (OpenFlow 1.2 compatibility) */ |
441c57a9 | 83 | MFF_DL_VLAN_PCP, /* u8 (OpenFlow 1.0 compatibility) */ |
cc34bc8c | 84 | MFF_VLAN_PCP, /* be16 (OpenFlow 1.2 compatibility) */ |
6a885fd0 | 85 | |
b02475c5 SH |
86 | /* L2.5 */ |
87 | MFF_MPLS_LABEL, /* be32 */ | |
88 | MFF_MPLS_TC, /* u8 */ | |
89 | MFF_MPLS_BOS, /* u8 */ | |
90 | ||
6a885fd0 | 91 | /* L3. */ |
d4e78198 SH |
92 | /* Update mf_is_l3_or_higher() if MFF_IPV4_SRC is |
93 | * no longer the first element for a field of layer 3 or higher */ | |
6a885fd0 BP |
94 | MFF_IPV4_SRC, /* be32 */ |
95 | MFF_IPV4_DST, /* be32 */ | |
96 | ||
97 | MFF_IPV6_SRC, /* ipv6 */ | |
98 | MFF_IPV6_DST, /* ipv6 */ | |
fa8223b7 | 99 | MFF_IPV6_LABEL, /* be32 */ |
6a885fd0 | 100 | |
1638b906 BP |
101 | /* The IPv4/IPv6 DSCP field has two different views: |
102 | * | |
103 | * - MFF_IP_DSCP has the DSCP in bits 2-7, their bit positions in the | |
104 | * IPv4 and IPv6 "traffic class" field, as used in OpenFlow 1.0 and 1.1 | |
105 | * flow format and in NXM's NXM_OF_IP_TOS | |
106 | * | |
107 | * - MFF_IP_DSCP has the DSCP in bits 0-5, shifted right two bits from | |
108 | * their positions in the IPv4 and IPv6 "traffic class" field, as used | |
109 | * in OpenFlow 1.2+ OXM's OXM_OF_IP_DSCP. */ | |
6a885fd0 | 110 | MFF_IP_PROTO, /* u8 (used for IPv4 or IPv6) */ |
530180fd | 111 | MFF_IP_DSCP, /* u8 (used for IPv4 or IPv6) */ |
1638b906 | 112 | MFF_IP_DSCP_SHIFTED, /* u8 (used for IPv4 or IPv6) (OF1.2 compat) */ |
530180fd | 113 | MFF_IP_ECN, /* u8 (used for IPv4 or IPv6) */ |
a61680c6 | 114 | MFF_IP_TTL, /* u8 (used for IPv4 or IPv6) */ |
7257b535 | 115 | MFF_IP_FRAG, /* u8 (used for IPv4 or IPv6) */ |
6a885fd0 BP |
116 | |
117 | MFF_ARP_OP, /* be16 */ | |
118 | MFF_ARP_SPA, /* be32 */ | |
119 | MFF_ARP_TPA, /* be32 */ | |
120 | MFF_ARP_SHA, /* mac */ | |
121 | MFF_ARP_THA, /* mac */ | |
122 | ||
123 | /* L4. */ | |
124 | MFF_TCP_SRC, /* be16 (used for IPv4 or IPv6) */ | |
125 | MFF_TCP_DST, /* be16 (used for IPv4 or IPv6) */ | |
dc235f7f JR |
126 | MFF_TCP_FLAGS, /* be16, 12 bits (4 MSB zeroed, |
127 | * used for IPv4 or IPv6) */ | |
6a885fd0 BP |
128 | |
129 | MFF_UDP_SRC, /* be16 (used for IPv4 or IPv6) */ | |
130 | MFF_UDP_DST, /* be16 (used for IPv4 or IPv6) */ | |
131 | ||
0d56eaf2 JS |
132 | MFF_SCTP_SRC, /* be16 (used for IPv4 or IPv6) */ |
133 | MFF_SCTP_DST, /* be16 (used for IPv4 or IPv6) */ | |
134 | ||
268a95e0 BP |
135 | MFF_ICMPV4_TYPE, /* u8 */ |
136 | MFF_ICMPV4_CODE, /* u8 */ | |
137 | ||
138 | MFF_ICMPV6_TYPE, /* u8 */ | |
139 | MFF_ICMPV6_CODE, /* u8 */ | |
6a885fd0 BP |
140 | |
141 | /* ICMPv6 Neighbor Discovery. */ | |
142 | MFF_ND_TARGET, /* ipv6 */ | |
143 | MFF_ND_SLL, /* mac */ | |
144 | MFF_ND_TLL, /* mac */ | |
145 | ||
146 | MFF_N_IDS | |
147 | }; | |
148 | ||
0d7e2fe4 IY |
149 | /* Use this macro as CASE_MFF_REGS: in a switch statement to choose all of the |
150 | * MFF_REGx cases. */ | |
151 | #if FLOW_N_REGS == 1 | |
152 | # define CASE_MFF_REGS \ | |
153 | case MFF_REG0 | |
154 | #elif FLOW_N_REGS == 2 | |
155 | # define CASE_MFF_REGS \ | |
156 | case MFF_REG0: case MFF_REG1 | |
157 | #elif FLOW_N_REGS == 3 | |
158 | # define CASE_MFF_REGS \ | |
159 | case MFF_REG0: case MFF_REG1: case MFF_REG2 | |
160 | #elif FLOW_N_REGS == 4 | |
161 | # define CASE_MFF_REGS \ | |
162 | case MFF_REG0: case MFF_REG1: case MFF_REG2: case MFF_REG3 | |
163 | #elif FLOW_N_REGS == 5 | |
164 | # define CASE_MFF_REGS \ | |
165 | case MFF_REG0: case MFF_REG1: case MFF_REG2: case MFF_REG3: \ | |
166 | case MFF_REG4 | |
167 | #elif FLOW_N_REGS == 6 | |
168 | # define CASE_MFF_REGS \ | |
169 | case MFF_REG0: case MFF_REG1: case MFF_REG2: case MFF_REG3: \ | |
170 | case MFF_REG4: case MFF_REG5 | |
171 | #elif FLOW_N_REGS == 7 | |
172 | # define CASE_MFF_REGS \ | |
173 | case MFF_REG0: case MFF_REG1: case MFF_REG2: case MFF_REG3: \ | |
174 | case MFF_REG4: case MFF_REG5: case MFF_REG6 | |
175 | #elif FLOW_N_REGS == 8 | |
176 | # define CASE_MFF_REGS \ | |
177 | case MFF_REG0: case MFF_REG1: case MFF_REG2: case MFF_REG3: \ | |
178 | case MFF_REG4: case MFF_REG5: case MFF_REG6: case MFF_REG7 | |
179 | #else | |
180 | # error | |
181 | #endif | |
182 | ||
6a885fd0 BP |
183 | /* Prerequisites for matching a field. |
184 | * | |
185 | * A field may only be matched if the correct lower-level protocols are also | |
186 | * matched. For example, the TCP port may be matched only if the Ethernet type | |
187 | * matches ETH_TYPE_IP and the IP protocol matches IPPROTO_TCP. */ | |
7f98c44d | 188 | enum OVS_PACKED_ENUM mf_prereqs { |
6a885fd0 BP |
189 | MFP_NONE, |
190 | ||
191 | /* L2 requirements. */ | |
192 | MFP_ARP, | |
8069b0da | 193 | MFP_VLAN_VID, |
6a885fd0 BP |
194 | MFP_IPV4, |
195 | MFP_IPV6, | |
196 | MFP_IP_ANY, | |
197 | ||
b02475c5 SH |
198 | /* L2.5 requirements. */ |
199 | MFP_MPLS, | |
200 | ||
6a885fd0 BP |
201 | /* L2+L3 requirements. */ |
202 | MFP_TCP, /* On IPv4 or IPv6. */ | |
203 | MFP_UDP, /* On IPv4 or IPv6. */ | |
0d56eaf2 | 204 | MFP_SCTP, /* On IPv4 or IPv6. */ |
268a95e0 | 205 | MFP_ICMPV4, |
6a885fd0 | 206 | MFP_ICMPV6, |
6a885fd0 BP |
207 | |
208 | /* L2+L3+L4 requirements. */ | |
209 | MFP_ND, | |
210 | MFP_ND_SOLICIT, | |
211 | MFP_ND_ADVERT | |
212 | }; | |
213 | ||
214 | /* Forms of partial-field masking allowed for a field. | |
215 | * | |
216 | * Every field may be masked as a whole. */ | |
7f98c44d | 217 | enum OVS_PACKED_ENUM mf_maskable { |
6a885fd0 BP |
218 | MFM_NONE, /* No sub-field masking. */ |
219 | MFM_FULLY, /* Every bit is individually maskable. */ | |
6a885fd0 BP |
220 | }; |
221 | ||
222 | /* How to format or parse a field's value. */ | |
7f98c44d | 223 | enum OVS_PACKED_ENUM mf_string { |
6a885fd0 BP |
224 | /* Integer formats. |
225 | * | |
226 | * The particular MFS_* constant sets the output format. On input, either | |
227 | * decimal or hexadecimal (prefixed with 0x) is accepted. */ | |
228 | MFS_DECIMAL, | |
229 | MFS_HEXADECIMAL, | |
230 | ||
231 | /* Other formats. */ | |
232 | MFS_ETHERNET, | |
233 | MFS_IPV4, | |
234 | MFS_IPV6, | |
7257b535 | 235 | MFS_OFP_PORT, /* An OpenFlow port number or name. */ |
72333065 | 236 | MFS_OFP_PORT_OXM, /* An OpenFlow port number or name (32-bit). */ |
4fe3445a PS |
237 | MFS_FRAG, /* no, yes, first, later, not_later */ |
238 | MFS_TNL_FLAGS, /* FLOW_TNL_F_* flags */ | |
61bf6666 | 239 | MFS_TCP_FLAGS, /* TCP_* flags */ |
6a885fd0 BP |
240 | }; |
241 | ||
242 | struct mf_field { | |
243 | /* Identification. */ | |
244 | enum mf_field_id id; /* MFF_*. */ | |
245 | const char *name; /* Name of this field, e.g. "eth_type". */ | |
246 | const char *extra_name; /* Alternate name, e.g. "dl_type", or NULL. */ | |
247 | ||
248 | /* Size. | |
249 | * | |
9df6a679 JP |
250 | * Most fields have n_bytes * 8 == n_bits. There are a few exceptions: |
251 | * | |
252 | * - "dl_vlan" is 2 bytes but only 12 bits. | |
253 | * - "dl_vlan_pcp" is 1 byte but only 3 bits. | |
254 | * - "is_frag" is 1 byte but only 2 bits. | |
fa8223b7 | 255 | * - "ipv6_label" is 4 bytes but only 20 bits. |
b02475c5 SH |
256 | * - "mpls_label" is 4 bytes but only 20 bits. |
257 | * - "mpls_tc" is 1 byte but only 3 bits. | |
258 | * - "mpls_bos" is 1 byte but only 1 bit. | |
9df6a679 | 259 | */ |
6a885fd0 BP |
260 | unsigned int n_bytes; /* Width of the field in bytes. */ |
261 | unsigned int n_bits; /* Number of significant bits in field. */ | |
262 | ||
263 | /* Properties. */ | |
264 | enum mf_maskable maskable; | |
6a885fd0 BP |
265 | enum mf_string string; |
266 | enum mf_prereqs prereqs; | |
28da1f8f BP |
267 | bool writable; /* May be written by actions? */ |
268 | ||
b5e5143b | 269 | /* NXM and OXM properties. |
28da1f8f | 270 | * |
b5e5143b BP |
271 | * There are the following possibilities for these members for a given |
272 | * mf_field: | |
273 | * | |
274 | * - Neither NXM nor OXM defines such a field: these members will all be | |
275 | * zero or NULL. | |
276 | * | |
277 | * - NXM and OXM both define such a field: nxm_header and oxm_header will | |
278 | * both be nonzero and different, similarly for nxm_name and oxm_name. | |
9d84066c BP |
279 | * In this case, 'oxm_version' is significant: if it is greater than |
280 | * OFP12_VERSION, then only that version of OpenFlow introduced this | |
281 | * OXM header, so ovs-vswitchd should send 'nxm_header' instead with | |
282 | * earlier protocol versions to avoid confusing controllers that were | |
283 | * using a previous Open vSwitch extension. | |
b5e5143b BP |
284 | * |
285 | * - Only NXM or only OXM defines such a field: nxm_header and oxm_header | |
286 | * will both have the same value (either an OXM_* or NXM_* value) and | |
287 | * similarly for nxm_name and oxm_name. | |
288 | * | |
289 | * Thus, 'nxm_header' is the appropriate header to use when outputting an | |
290 | * NXM formatted match, since it will be an NXM_* constant when possible | |
291 | * for compatibility with OpenFlow implementations that expect that, with | |
292 | * OXM_* constants used for fields that OXM adds. Conversely, 'oxm_header' | |
9d84066c BP |
293 | * is the header to use when outputting an OXM formatted match to an |
294 | * OpenFlow connection of version 'oxm_version' or above (and otherwise | |
295 | * 'nxm_header'). */ | |
b5e5143b BP |
296 | uint32_t nxm_header; /* An NXM_* (or OXM_*) constant. */ |
297 | const char *nxm_name; /* The nxm_header constant's name. */ | |
298 | uint32_t oxm_header; /* An OXM_* (or NXM_*) constant. */ | |
db0b6c29 | 299 | const char *oxm_name; /* The oxm_header constant's name */ |
9d84066c | 300 | enum ofp_version oxm_version; /* OpenFlow version that added oxm_header. */ |
db0b6c29 JR |
301 | |
302 | /* Usable protocols. | |
303 | * NXM and OXM are extensible, allowing later extensions to be sent in | |
304 | * earlier protocol versions, so this does not necessarily correspond to | |
305 | * the OpenFlow protocol version the field was introduced in. | |
306 | * Also, some field types are tranparently mapped to each other via the | |
307 | * struct flow (like vlan and dscp/tos fields), so each variant supports | |
308 | * all protocols. */ | |
309 | enum ofputil_protocol usable_protocols; /* If fully/cidr masked. */ | |
310 | /* If partially/non-cidr masked. */ | |
311 | enum ofputil_protocol usable_protocols_bitwise; | |
13751fd8 JR |
312 | |
313 | int flow_be32ofs; /* Field's be32 offset in "struct flow", if prefix tree | |
314 | * lookup is supported for the field, or -1. */ | |
6a885fd0 BP |
315 | }; |
316 | ||
317 | /* The representation of a field's value. */ | |
318 | union mf_value { | |
6a885fd0 | 319 | struct in6_addr ipv6; |
b283836c JR |
320 | uint8_t mac[ETH_ADDR_LEN]; |
321 | ovs_be64 be64; | |
322 | ovs_be32 be32; | |
323 | ovs_be16 be16; | |
324 | uint8_t u8; | |
6a885fd0 | 325 | }; |
1b35df45 | 326 | BUILD_ASSERT_DECL(sizeof(union mf_value) == 16); |
6a885fd0 | 327 | |
b283836c JR |
328 | #define MF_EXACT_MASK_INITIALIZER { IN6ADDR_EXACT_INIT } |
329 | ||
816fd533 BP |
330 | /* Part of a field. */ |
331 | struct mf_subfield { | |
332 | const struct mf_field *field; | |
333 | unsigned int ofs; /* Bit offset. */ | |
334 | unsigned int n_bits; /* Number of bits. */ | |
335 | }; | |
336 | ||
1b35df45 BP |
337 | /* Data for some part of an mf_field. |
338 | * | |
339 | * The data is stored "right-justified". For example, if "union mf_subvalue | |
340 | * value" contains NXM_OF_VLAN_TCI[0..11], then one could access the | |
341 | * corresponding data in value.be16[7] as the bits in the mask htons(0xfff). */ | |
342 | union mf_subvalue { | |
343 | uint8_t u8[16]; | |
344 | ovs_be16 be16[8]; | |
345 | ovs_be32 be32[4]; | |
346 | ovs_be64 be64[2]; | |
347 | }; | |
348 | BUILD_ASSERT_DECL(sizeof(union mf_value) == sizeof (union mf_subvalue)); | |
349 | ||
6a885fd0 | 350 | /* Finding mf_fields. */ |
6a885fd0 | 351 | const struct mf_field *mf_from_name(const char *name); |
28da1f8f BP |
352 | const struct mf_field *mf_from_nxm_header(uint32_t nxm_header); |
353 | const struct mf_field *mf_from_nxm_name(const char *nxm_name); | |
6a885fd0 | 354 | |
7f98c44d JR |
355 | static inline const struct mf_field * |
356 | mf_from_id(enum mf_field_id id) | |
357 | { | |
358 | extern const struct mf_field mf_fields[MFF_N_IDS]; | |
359 | ovs_assert((unsigned int) id < MFF_N_IDS); | |
360 | return &mf_fields[id]; | |
361 | } | |
362 | ||
9d84066c BP |
363 | /* NXM and OXM protocol headers. */ |
364 | uint32_t mf_oxm_header(enum mf_field_id, enum ofp_version oxm_version); | |
365 | ||
6a885fd0 BP |
366 | /* Inspecting wildcarded bits. */ |
367 | bool mf_is_all_wild(const struct mf_field *, const struct flow_wildcards *); | |
368 | ||
369 | bool mf_is_mask_valid(const struct mf_field *, const union mf_value *mask); | |
370 | void mf_get_mask(const struct mf_field *, const struct flow_wildcards *, | |
371 | union mf_value *mask); | |
372 | ||
373 | /* Prerequisites. */ | |
374 | bool mf_are_prereqs_ok(const struct mf_field *, const struct flow *); | |
b283836c | 375 | void mf_mask_field_and_prereqs(const struct mf_field *, struct flow *mask); |
6a885fd0 | 376 | |
d4e78198 SH |
377 | static inline bool |
378 | mf_is_l3_or_higher(const struct mf_field *mf) | |
379 | { | |
380 | return mf->id >= MFF_IPV4_SRC; | |
381 | } | |
382 | ||
6a885fd0 BP |
383 | /* Field values. */ |
384 | bool mf_is_value_valid(const struct mf_field *, const union mf_value *value); | |
385 | ||
386 | void mf_get_value(const struct mf_field *, const struct flow *, | |
387 | union mf_value *value); | |
388 | void mf_set_value(const struct mf_field *, const union mf_value *value, | |
81a76618 | 389 | struct match *); |
28da1f8f BP |
390 | void mf_set_flow_value(const struct mf_field *, const union mf_value *value, |
391 | struct flow *); | |
ccbe50f8 | 392 | bool mf_is_zero(const struct mf_field *, const struct flow *); |
5a0a5702 | 393 | void mf_mask_field(const struct mf_field *, struct flow *); |
6a885fd0 | 394 | |
81a76618 | 395 | void mf_get(const struct mf_field *, const struct match *, |
6a885fd0 | 396 | union mf_value *value, union mf_value *mask); |
db0b6c29 JR |
397 | |
398 | /* Returns the set of usable protocols. */ | |
399 | enum ofputil_protocol mf_set(const struct mf_field *, | |
400 | const union mf_value *value, | |
401 | const union mf_value *mask, | |
402 | struct match *); | |
6a885fd0 | 403 | |
81a76618 | 404 | void mf_set_wild(const struct mf_field *, struct match *); |
6a885fd0 | 405 | |
816fd533 | 406 | /* Subfields. */ |
9bab681f IY |
407 | void mf_write_subfield_flow(const struct mf_subfield *, |
408 | const union mf_subvalue *, struct flow *); | |
1b35df45 | 409 | void mf_write_subfield(const struct mf_subfield *, const union mf_subvalue *, |
81a76618 | 410 | struct match *); |
1b35df45 BP |
411 | |
412 | void mf_read_subfield(const struct mf_subfield *, const struct flow *, | |
413 | union mf_subvalue *); | |
816fd533 BP |
414 | uint64_t mf_get_subfield(const struct mf_subfield *, const struct flow *); |
415 | ||
1b35df45 | 416 | |
816fd533 | 417 | void mf_format_subfield(const struct mf_subfield *, struct ds *); |
bdda5aca BP |
418 | char *mf_parse_subfield__(struct mf_subfield *sf, const char **s) |
419 | WARN_UNUSED_RESULT; | |
420 | char *mf_parse_subfield(struct mf_subfield *, const char *s) | |
421 | WARN_UNUSED_RESULT; | |
816fd533 BP |
422 | |
423 | enum ofperr mf_check_src(const struct mf_subfield *, const struct flow *); | |
424 | enum ofperr mf_check_dst(const struct mf_subfield *, const struct flow *); | |
425 | ||
6a885fd0 BP |
426 | /* Parsing and formatting. */ |
427 | char *mf_parse(const struct mf_field *, const char *, | |
428 | union mf_value *value, union mf_value *mask); | |
429 | char *mf_parse_value(const struct mf_field *, const char *, union mf_value *); | |
430 | void mf_format(const struct mf_field *, | |
431 | const union mf_value *value, const union mf_value *mask, | |
432 | struct ds *); | |
9bab681f | 433 | void mf_format_subvalue(const union mf_subvalue *subvalue, struct ds *s); |
6a885fd0 BP |
434 | |
435 | #endif /* meta-flow.h */ |