]>
Commit | Line | Data |
---|---|---|
0d71302e BP |
1 | /* |
2 | * Copyright (c) 2008-2017 Nicira, Inc. | |
3 | * | |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | */ | |
16 | ||
17 | #include <config.h> | |
18 | #include "openvswitch/ofp-match.h" | |
19 | #include "byte-order.h" | |
20 | #include "flow.h" | |
21 | #include "nx-match.h" | |
22 | #include "openvswitch/match.h" | |
23 | #include "openvswitch/ofp-errors.h" | |
24 | #include "openvswitch/ofp-msgs.h" | |
25 | #include "openvswitch/ofp-port.h" | |
26 | #include "openvswitch/packets.h" | |
27 | #include "openvswitch/vlog.h" | |
28 | ||
29 | VLOG_DEFINE_THIS_MODULE(ofp_match); | |
30 | ||
31 | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); | |
32 | ||
33 | /* Given the wildcard bit count in the least-significant 6 of 'wcbits', returns | |
34 | * an IP netmask with a 1 in each bit that must match and a 0 in each bit that | |
35 | * is wildcarded. | |
36 | * | |
37 | * The bits in 'wcbits' are in the format used in enum ofp_flow_wildcards: 0 | |
38 | * is exact match, 1 ignores the LSB, 2 ignores the 2 least-significant bits, | |
39 | * ..., 32 and higher wildcard the entire field. This is the *opposite* of the | |
40 | * usual convention where e.g. /24 indicates that 8 bits (not 24 bits) are | |
41 | * wildcarded. */ | |
11b1e59f | 42 | static ovs_be32 |
0d71302e BP |
43 | ofputil_wcbits_to_netmask(int wcbits) |
44 | { | |
45 | wcbits &= 0x3f; | |
46 | return wcbits < 32 ? htonl(~((1u << wcbits) - 1)) : 0; | |
47 | } | |
48 | ||
49 | /* Given the IP netmask 'netmask', returns the number of bits of the IP address | |
50 | * that it wildcards, that is, the number of 0-bits in 'netmask', a number | |
51 | * between 0 and 32 inclusive. | |
52 | * | |
53 | * If 'netmask' is not a CIDR netmask (see ip_is_cidr()), the return value will | |
54 | * still be in the valid range but isn't otherwise meaningful. */ | |
11b1e59f | 55 | static int |
0d71302e BP |
56 | ofputil_netmask_to_wcbits(ovs_be32 netmask) |
57 | { | |
58 | return 32 - ip_count_cidr_bits(netmask); | |
59 | } | |
60 | ||
61 | /* Converts the OpenFlow 1.0 wildcards in 'ofpfw' (OFPFW10_*) into a | |
62 | * flow_wildcards in 'wc' for use in struct match. It is the caller's | |
63 | * responsibility to handle the special case where the flow match's dl_vlan is | |
64 | * set to OFP_VLAN_NONE. */ | |
65 | void | |
66 | ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc) | |
67 | { | |
7dc18ae9 | 68 | BUILD_ASSERT_DECL(FLOW_WC_SEQ == 41); |
0d71302e BP |
69 | |
70 | /* Initialize most of wc. */ | |
71 | flow_wildcards_init_catchall(wc); | |
72 | ||
73 | if (!(ofpfw & OFPFW10_IN_PORT)) { | |
74 | wc->masks.in_port.ofp_port = u16_to_ofp(UINT16_MAX); | |
75 | } | |
76 | ||
77 | if (!(ofpfw & OFPFW10_NW_TOS)) { | |
78 | wc->masks.nw_tos |= IP_DSCP_MASK; | |
79 | } | |
80 | ||
81 | if (!(ofpfw & OFPFW10_NW_PROTO)) { | |
82 | wc->masks.nw_proto = UINT8_MAX; | |
83 | } | |
84 | wc->masks.nw_src = ofputil_wcbits_to_netmask(ofpfw | |
85 | >> OFPFW10_NW_SRC_SHIFT); | |
86 | wc->masks.nw_dst = ofputil_wcbits_to_netmask(ofpfw | |
87 | >> OFPFW10_NW_DST_SHIFT); | |
88 | ||
89 | if (!(ofpfw & OFPFW10_TP_SRC)) { | |
90 | wc->masks.tp_src = OVS_BE16_MAX; | |
91 | } | |
92 | if (!(ofpfw & OFPFW10_TP_DST)) { | |
93 | wc->masks.tp_dst = OVS_BE16_MAX; | |
94 | } | |
95 | ||
96 | if (!(ofpfw & OFPFW10_DL_SRC)) { | |
97 | WC_MASK_FIELD(wc, dl_src); | |
98 | } | |
99 | if (!(ofpfw & OFPFW10_DL_DST)) { | |
100 | WC_MASK_FIELD(wc, dl_dst); | |
101 | } | |
102 | if (!(ofpfw & OFPFW10_DL_TYPE)) { | |
103 | wc->masks.dl_type = OVS_BE16_MAX; | |
104 | } | |
105 | ||
106 | /* VLAN TCI mask. */ | |
107 | if (!(ofpfw & OFPFW10_DL_VLAN_PCP)) { | |
108 | wc->masks.vlans[0].tci |= htons(VLAN_PCP_MASK | VLAN_CFI); | |
109 | } | |
110 | if (!(ofpfw & OFPFW10_DL_VLAN)) { | |
111 | wc->masks.vlans[0].tci |= htons(VLAN_VID_MASK | VLAN_CFI); | |
112 | } | |
113 | } | |
114 | ||
115 | /* Converts the ofp10_match in 'ofmatch' into a struct match in 'match'. */ | |
116 | void | |
117 | ofputil_match_from_ofp10_match(const struct ofp10_match *ofmatch, | |
118 | struct match *match) | |
119 | { | |
120 | uint32_t ofpfw = ntohl(ofmatch->wildcards) & OFPFW10_ALL; | |
121 | ||
122 | /* Initialize match->wc. */ | |
123 | memset(&match->flow, 0, sizeof match->flow); | |
124 | ofputil_wildcard_from_ofpfw10(ofpfw, &match->wc); | |
125 | memset(&match->tun_md, 0, sizeof match->tun_md); | |
126 | ||
127 | /* If any fields, except in_port, are matched, then we also need to match | |
128 | * on the Ethernet packet_type. */ | |
129 | const uint32_t ofpfw_data_bits = (OFPFW10_NW_TOS | OFPFW10_NW_PROTO | |
130 | | OFPFW10_TP_SRC | OFPFW10_TP_DST | |
131 | | OFPFW10_DL_SRC | OFPFW10_DL_DST | |
132 | | OFPFW10_DL_TYPE | |
133 | | OFPFW10_DL_VLAN | OFPFW10_DL_VLAN_PCP); | |
134 | if ((ofpfw & ofpfw_data_bits) != ofpfw_data_bits | |
135 | || ofputil_wcbits_to_netmask(ofpfw >> OFPFW10_NW_SRC_SHIFT) | |
136 | || ofputil_wcbits_to_netmask(ofpfw >> OFPFW10_NW_DST_SHIFT)) { | |
137 | match_set_default_packet_type(match); | |
138 | } | |
139 | ||
140 | /* Initialize most of match->flow. */ | |
141 | match->flow.nw_src = ofmatch->nw_src; | |
142 | match->flow.nw_dst = ofmatch->nw_dst; | |
143 | match->flow.in_port.ofp_port = u16_to_ofp(ntohs(ofmatch->in_port)); | |
144 | match->flow.dl_type = ofputil_dl_type_from_openflow(ofmatch->dl_type); | |
145 | match->flow.tp_src = ofmatch->tp_src; | |
146 | match->flow.tp_dst = ofmatch->tp_dst; | |
147 | match->flow.dl_src = ofmatch->dl_src; | |
148 | match->flow.dl_dst = ofmatch->dl_dst; | |
149 | match->flow.nw_tos = ofmatch->nw_tos & IP_DSCP_MASK; | |
150 | match->flow.nw_proto = ofmatch->nw_proto; | |
151 | ||
152 | /* Translate VLANs. */ | |
153 | if (!(ofpfw & OFPFW10_DL_VLAN) && | |
154 | ofmatch->dl_vlan == htons(OFP10_VLAN_NONE)) { | |
155 | /* Match only packets without 802.1Q header. | |
156 | * | |
157 | * When OFPFW10_DL_VLAN_PCP is wildcarded, this is obviously correct. | |
158 | * | |
159 | * If OFPFW10_DL_VLAN_PCP is matched, the flow match is contradictory, | |
160 | * because we can't have a specific PCP without an 802.1Q header. | |
161 | * However, older versions of OVS treated this as matching packets | |
162 | * withut an 802.1Q header, so we do here too. */ | |
163 | match->flow.vlans[0].tci = htons(0); | |
164 | match->wc.masks.vlans[0].tci = htons(0xffff); | |
165 | } else { | |
166 | ovs_be16 vid, pcp, tci; | |
167 | uint16_t hpcp; | |
168 | ||
169 | vid = ofmatch->dl_vlan & htons(VLAN_VID_MASK); | |
170 | hpcp = (ofmatch->dl_vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK; | |
171 | pcp = htons(hpcp); | |
172 | tci = vid | pcp | htons(VLAN_CFI); | |
173 | match->flow.vlans[0].tci = tci & match->wc.masks.vlans[0].tci; | |
174 | } | |
175 | ||
176 | /* Clean up. */ | |
177 | match_zero_wildcarded_fields(match); | |
178 | } | |
179 | ||
180 | /* Convert 'match' into the OpenFlow 1.0 match structure 'ofmatch'. */ | |
181 | void | |
182 | ofputil_match_to_ofp10_match(const struct match *match, | |
183 | struct ofp10_match *ofmatch) | |
184 | { | |
185 | const struct flow_wildcards *wc = &match->wc; | |
186 | uint32_t ofpfw; | |
187 | ||
188 | /* Figure out most OpenFlow wildcards. */ | |
189 | ofpfw = 0; | |
190 | if (!wc->masks.in_port.ofp_port) { | |
191 | ofpfw |= OFPFW10_IN_PORT; | |
192 | } | |
193 | if (!wc->masks.dl_type) { | |
194 | ofpfw |= OFPFW10_DL_TYPE; | |
195 | } | |
196 | if (!wc->masks.nw_proto) { | |
197 | ofpfw |= OFPFW10_NW_PROTO; | |
198 | } | |
199 | ofpfw |= (ofputil_netmask_to_wcbits(wc->masks.nw_src) | |
200 | << OFPFW10_NW_SRC_SHIFT); | |
201 | ofpfw |= (ofputil_netmask_to_wcbits(wc->masks.nw_dst) | |
202 | << OFPFW10_NW_DST_SHIFT); | |
203 | if (!(wc->masks.nw_tos & IP_DSCP_MASK)) { | |
204 | ofpfw |= OFPFW10_NW_TOS; | |
205 | } | |
206 | if (!wc->masks.tp_src) { | |
207 | ofpfw |= OFPFW10_TP_SRC; | |
208 | } | |
209 | if (!wc->masks.tp_dst) { | |
210 | ofpfw |= OFPFW10_TP_DST; | |
211 | } | |
212 | if (eth_addr_is_zero(wc->masks.dl_src)) { | |
213 | ofpfw |= OFPFW10_DL_SRC; | |
214 | } | |
215 | if (eth_addr_is_zero(wc->masks.dl_dst)) { | |
216 | ofpfw |= OFPFW10_DL_DST; | |
217 | } | |
218 | ||
219 | /* Translate VLANs. */ | |
220 | ofmatch->dl_vlan = htons(0); | |
221 | ofmatch->dl_vlan_pcp = 0; | |
222 | if (match->wc.masks.vlans[0].tci == htons(0)) { | |
223 | ofpfw |= OFPFW10_DL_VLAN | OFPFW10_DL_VLAN_PCP; | |
224 | } else if (match->wc.masks.vlans[0].tci & htons(VLAN_CFI) | |
225 | && !(match->flow.vlans[0].tci & htons(VLAN_CFI))) { | |
226 | ofmatch->dl_vlan = htons(OFP10_VLAN_NONE); | |
227 | } else { | |
228 | if (!(match->wc.masks.vlans[0].tci & htons(VLAN_VID_MASK))) { | |
229 | ofpfw |= OFPFW10_DL_VLAN; | |
230 | } else { | |
231 | ofmatch->dl_vlan = | |
232 | htons(vlan_tci_to_vid(match->flow.vlans[0].tci)); | |
233 | } | |
234 | ||
235 | if (!(match->wc.masks.vlans[0].tci & htons(VLAN_PCP_MASK))) { | |
236 | ofpfw |= OFPFW10_DL_VLAN_PCP; | |
237 | } else { | |
238 | ofmatch->dl_vlan_pcp = vlan_tci_to_pcp(match->flow.vlans[0].tci); | |
239 | } | |
240 | } | |
241 | ||
242 | /* Compose most of the match structure. */ | |
243 | ofmatch->wildcards = htonl(ofpfw); | |
244 | ofmatch->in_port = htons(ofp_to_u16(match->flow.in_port.ofp_port)); | |
245 | ofmatch->dl_src = match->flow.dl_src; | |
246 | ofmatch->dl_dst = match->flow.dl_dst; | |
247 | ofmatch->dl_type = ofputil_dl_type_to_openflow(match->flow.dl_type); | |
248 | ofmatch->nw_src = match->flow.nw_src; | |
249 | ofmatch->nw_dst = match->flow.nw_dst; | |
250 | ofmatch->nw_tos = match->flow.nw_tos & IP_DSCP_MASK; | |
251 | ofmatch->nw_proto = match->flow.nw_proto; | |
252 | ofmatch->tp_src = match->flow.tp_src; | |
253 | ofmatch->tp_dst = match->flow.tp_dst; | |
254 | memset(ofmatch->pad1, '\0', sizeof ofmatch->pad1); | |
255 | memset(ofmatch->pad2, '\0', sizeof ofmatch->pad2); | |
256 | } | |
257 | ||
258 | enum ofperr | |
259 | ofputil_pull_ofp11_match(struct ofpbuf *buf, const struct tun_table *tun_table, | |
260 | const struct vl_mff_map *vl_mff_map, | |
261 | struct match *match, uint16_t *padded_match_len) | |
262 | { | |
263 | struct ofp11_match_header *omh = buf->data; | |
264 | uint16_t match_len; | |
265 | ||
266 | if (buf->size < sizeof *omh) { | |
267 | return OFPERR_OFPBMC_BAD_LEN; | |
268 | } | |
269 | ||
270 | match_len = ntohs(omh->length); | |
271 | ||
272 | switch (ntohs(omh->type)) { | |
273 | case OFPMT_STANDARD: { | |
274 | struct ofp11_match *om; | |
275 | ||
276 | if (match_len != sizeof *om || buf->size < sizeof *om) { | |
277 | return OFPERR_OFPBMC_BAD_LEN; | |
278 | } | |
279 | om = ofpbuf_pull(buf, sizeof *om); | |
280 | if (padded_match_len) { | |
281 | *padded_match_len = match_len; | |
282 | } | |
283 | return ofputil_match_from_ofp11_match(om, match); | |
284 | } | |
285 | ||
286 | case OFPMT_OXM: | |
287 | if (padded_match_len) { | |
288 | *padded_match_len = ROUND_UP(match_len, 8); | |
289 | } | |
290 | return oxm_pull_match(buf, false, tun_table, vl_mff_map, match); | |
291 | ||
292 | default: | |
293 | return OFPERR_OFPBMC_BAD_TYPE; | |
294 | } | |
295 | } | |
296 | ||
297 | /* Converts the ofp11_match in 'ofmatch' into a struct match in 'match'. | |
298 | * Returns 0 if successful, otherwise an OFPERR_* value. */ | |
299 | enum ofperr | |
300 | ofputil_match_from_ofp11_match(const struct ofp11_match *ofmatch, | |
301 | struct match *match) | |
302 | { | |
303 | uint16_t wc = ntohl(ofmatch->wildcards); | |
304 | bool ipv4, arp, rarp; | |
305 | ||
306 | match_init_catchall(match); | |
307 | match->flow.tunnel.metadata.tab = NULL; | |
308 | ||
309 | if (!(wc & OFPFW11_IN_PORT)) { | |
310 | ofp_port_t ofp_port; | |
311 | enum ofperr error; | |
312 | ||
313 | error = ofputil_port_from_ofp11(ofmatch->in_port, &ofp_port); | |
314 | if (error) { | |
315 | return OFPERR_OFPBMC_BAD_VALUE; | |
316 | } | |
317 | match_set_in_port(match, ofp_port); | |
318 | } | |
319 | ||
320 | struct eth_addr dl_src_mask = eth_addr_invert(ofmatch->dl_src_mask); | |
321 | struct eth_addr dl_dst_mask = eth_addr_invert(ofmatch->dl_dst_mask); | |
322 | if (!eth_addr_is_zero(dl_src_mask) || !eth_addr_is_zero(dl_dst_mask)) { | |
323 | match_set_dl_src_masked(match, ofmatch->dl_src, dl_src_mask); | |
324 | match_set_dl_dst_masked(match, ofmatch->dl_dst, dl_dst_mask); | |
325 | match_set_default_packet_type(match); | |
326 | } | |
327 | ||
328 | if (!(wc & OFPFW11_DL_VLAN)) { | |
329 | if (ofmatch->dl_vlan == htons(OFPVID11_NONE)) { | |
330 | /* Match only packets without a VLAN tag. */ | |
331 | match->flow.vlans[0].tci = htons(0); | |
332 | match->wc.masks.vlans[0].tci = OVS_BE16_MAX; | |
333 | } else { | |
334 | if (ofmatch->dl_vlan == htons(OFPVID11_ANY)) { | |
335 | /* Match any packet with a VLAN tag regardless of VID. */ | |
336 | match->flow.vlans[0].tci = htons(VLAN_CFI); | |
337 | match->wc.masks.vlans[0].tci = htons(VLAN_CFI); | |
338 | } else if (ntohs(ofmatch->dl_vlan) < 4096) { | |
339 | /* Match only packets with the specified VLAN VID. */ | |
340 | match->flow.vlans[0].tci = htons(VLAN_CFI) | ofmatch->dl_vlan; | |
341 | match->wc.masks.vlans[0].tci = htons(VLAN_CFI | VLAN_VID_MASK); | |
342 | } else { | |
343 | /* Invalid VID. */ | |
344 | return OFPERR_OFPBMC_BAD_VALUE; | |
345 | } | |
346 | ||
347 | if (!(wc & OFPFW11_DL_VLAN_PCP)) { | |
348 | if (ofmatch->dl_vlan_pcp <= 7) { | |
349 | match->flow.vlans[0].tci |= htons(ofmatch->dl_vlan_pcp | |
350 | << VLAN_PCP_SHIFT); | |
351 | match->wc.masks.vlans[0].tci |= htons(VLAN_PCP_MASK); | |
352 | } else { | |
353 | /* Invalid PCP. */ | |
354 | return OFPERR_OFPBMC_BAD_VALUE; | |
355 | } | |
356 | } | |
357 | } | |
358 | match_set_default_packet_type(match); | |
359 | } | |
360 | ||
361 | if (!(wc & OFPFW11_DL_TYPE)) { | |
362 | match_set_dl_type(match, | |
363 | ofputil_dl_type_from_openflow(ofmatch->dl_type)); | |
364 | match_set_default_packet_type(match); | |
365 | } | |
366 | ||
367 | ipv4 = match->flow.dl_type == htons(ETH_TYPE_IP); | |
368 | arp = match->flow.dl_type == htons(ETH_TYPE_ARP); | |
369 | rarp = match->flow.dl_type == htons(ETH_TYPE_RARP); | |
370 | ||
371 | if (ipv4 && !(wc & OFPFW11_NW_TOS)) { | |
372 | if (ofmatch->nw_tos & ~IP_DSCP_MASK) { | |
373 | /* Invalid TOS. */ | |
374 | return OFPERR_OFPBMC_BAD_VALUE; | |
375 | } | |
376 | ||
377 | match_set_nw_dscp(match, ofmatch->nw_tos); | |
378 | } | |
379 | ||
380 | if (ipv4 || arp || rarp) { | |
381 | if (!(wc & OFPFW11_NW_PROTO)) { | |
382 | match_set_nw_proto(match, ofmatch->nw_proto); | |
383 | } | |
384 | match_set_nw_src_masked(match, ofmatch->nw_src, ~ofmatch->nw_src_mask); | |
385 | match_set_nw_dst_masked(match, ofmatch->nw_dst, ~ofmatch->nw_dst_mask); | |
386 | } | |
387 | ||
388 | #define OFPFW11_TP_ALL (OFPFW11_TP_SRC | OFPFW11_TP_DST) | |
389 | if (ipv4 && (wc & OFPFW11_TP_ALL) != OFPFW11_TP_ALL) { | |
390 | switch (match->flow.nw_proto) { | |
391 | case IPPROTO_ICMP: | |
392 | /* "A.2.3 Flow Match Structures" in OF1.1 says: | |
393 | * | |
394 | * The tp_src and tp_dst fields will be ignored unless the | |
395 | * network protocol specified is as TCP, UDP or SCTP. | |
396 | * | |
397 | * but I'm pretty sure we should support ICMP too, otherwise | |
398 | * that's a regression from OF1.0. */ | |
399 | if (!(wc & OFPFW11_TP_SRC)) { | |
400 | uint16_t icmp_type = ntohs(ofmatch->tp_src); | |
401 | if (icmp_type < 0x100) { | |
402 | match_set_icmp_type(match, icmp_type); | |
403 | } else { | |
404 | return OFPERR_OFPBMC_BAD_FIELD; | |
405 | } | |
406 | } | |
407 | if (!(wc & OFPFW11_TP_DST)) { | |
408 | uint16_t icmp_code = ntohs(ofmatch->tp_dst); | |
409 | if (icmp_code < 0x100) { | |
410 | match_set_icmp_code(match, icmp_code); | |
411 | } else { | |
412 | return OFPERR_OFPBMC_BAD_FIELD; | |
413 | } | |
414 | } | |
415 | break; | |
416 | ||
417 | case IPPROTO_TCP: | |
418 | case IPPROTO_UDP: | |
419 | case IPPROTO_SCTP: | |
420 | if (!(wc & (OFPFW11_TP_SRC))) { | |
421 | match_set_tp_src(match, ofmatch->tp_src); | |
422 | } | |
423 | if (!(wc & (OFPFW11_TP_DST))) { | |
424 | match_set_tp_dst(match, ofmatch->tp_dst); | |
425 | } | |
426 | break; | |
427 | ||
428 | default: | |
429 | /* OF1.1 says explicitly to ignore this. */ | |
430 | break; | |
431 | } | |
432 | } | |
433 | ||
434 | if (eth_type_mpls(match->flow.dl_type)) { | |
435 | if (!(wc & OFPFW11_MPLS_LABEL)) { | |
436 | match_set_mpls_label(match, 0, ofmatch->mpls_label); | |
437 | } | |
438 | if (!(wc & OFPFW11_MPLS_TC)) { | |
439 | match_set_mpls_tc(match, 0, ofmatch->mpls_tc); | |
440 | } | |
441 | } | |
442 | ||
443 | match_set_metadata_masked(match, ofmatch->metadata, | |
444 | ~ofmatch->metadata_mask); | |
445 | ||
446 | return 0; | |
447 | } | |
448 | ||
449 | /* Convert 'match' into the OpenFlow 1.1 match structure 'ofmatch'. */ | |
450 | void | |
451 | ofputil_match_to_ofp11_match(const struct match *match, | |
452 | struct ofp11_match *ofmatch) | |
453 | { | |
454 | uint32_t wc = 0; | |
455 | ||
456 | memset(ofmatch, 0, sizeof *ofmatch); | |
457 | ofmatch->omh.type = htons(OFPMT_STANDARD); | |
458 | ofmatch->omh.length = htons(OFPMT11_STANDARD_LENGTH); | |
459 | ||
460 | if (!match->wc.masks.in_port.ofp_port) { | |
461 | wc |= OFPFW11_IN_PORT; | |
462 | } else { | |
463 | ofmatch->in_port = ofputil_port_to_ofp11(match->flow.in_port.ofp_port); | |
464 | } | |
465 | ||
466 | ofmatch->dl_src = match->flow.dl_src; | |
467 | ofmatch->dl_src_mask = eth_addr_invert(match->wc.masks.dl_src); | |
468 | ofmatch->dl_dst = match->flow.dl_dst; | |
469 | ofmatch->dl_dst_mask = eth_addr_invert(match->wc.masks.dl_dst); | |
470 | ||
471 | if (match->wc.masks.vlans[0].tci == htons(0)) { | |
472 | wc |= OFPFW11_DL_VLAN | OFPFW11_DL_VLAN_PCP; | |
473 | } else if (match->wc.masks.vlans[0].tci & htons(VLAN_CFI) | |
474 | && !(match->flow.vlans[0].tci & htons(VLAN_CFI))) { | |
475 | ofmatch->dl_vlan = htons(OFPVID11_NONE); | |
476 | wc |= OFPFW11_DL_VLAN_PCP; | |
477 | } else { | |
478 | if (!(match->wc.masks.vlans[0].tci & htons(VLAN_VID_MASK))) { | |
479 | ofmatch->dl_vlan = htons(OFPVID11_ANY); | |
480 | } else { | |
481 | ofmatch->dl_vlan = | |
482 | htons(vlan_tci_to_vid(match->flow.vlans[0].tci)); | |
483 | } | |
484 | ||
485 | if (!(match->wc.masks.vlans[0].tci & htons(VLAN_PCP_MASK))) { | |
486 | wc |= OFPFW11_DL_VLAN_PCP; | |
487 | } else { | |
488 | ofmatch->dl_vlan_pcp = vlan_tci_to_pcp(match->flow.vlans[0].tci); | |
489 | } | |
490 | } | |
491 | ||
492 | if (!match->wc.masks.dl_type) { | |
493 | wc |= OFPFW11_DL_TYPE; | |
494 | } else { | |
495 | ofmatch->dl_type = ofputil_dl_type_to_openflow(match->flow.dl_type); | |
496 | } | |
497 | ||
498 | if (!(match->wc.masks.nw_tos & IP_DSCP_MASK)) { | |
499 | wc |= OFPFW11_NW_TOS; | |
500 | } else { | |
501 | ofmatch->nw_tos = match->flow.nw_tos & IP_DSCP_MASK; | |
502 | } | |
503 | ||
504 | if (!match->wc.masks.nw_proto) { | |
505 | wc |= OFPFW11_NW_PROTO; | |
506 | } else { | |
507 | ofmatch->nw_proto = match->flow.nw_proto; | |
508 | } | |
509 | ||
510 | ofmatch->nw_src = match->flow.nw_src; | |
511 | ofmatch->nw_src_mask = ~match->wc.masks.nw_src; | |
512 | ofmatch->nw_dst = match->flow.nw_dst; | |
513 | ofmatch->nw_dst_mask = ~match->wc.masks.nw_dst; | |
514 | ||
515 | if (!match->wc.masks.tp_src) { | |
516 | wc |= OFPFW11_TP_SRC; | |
517 | } else { | |
518 | ofmatch->tp_src = match->flow.tp_src; | |
519 | } | |
520 | ||
521 | if (!match->wc.masks.tp_dst) { | |
522 | wc |= OFPFW11_TP_DST; | |
523 | } else { | |
524 | ofmatch->tp_dst = match->flow.tp_dst; | |
525 | } | |
526 | ||
527 | if (!(match->wc.masks.mpls_lse[0] & htonl(MPLS_LABEL_MASK))) { | |
528 | wc |= OFPFW11_MPLS_LABEL; | |
529 | } else { | |
530 | ofmatch->mpls_label = htonl(mpls_lse_to_label( | |
531 | match->flow.mpls_lse[0])); | |
532 | } | |
533 | ||
534 | if (!(match->wc.masks.mpls_lse[0] & htonl(MPLS_TC_MASK))) { | |
535 | wc |= OFPFW11_MPLS_TC; | |
536 | } else { | |
537 | ofmatch->mpls_tc = mpls_lse_to_tc(match->flow.mpls_lse[0]); | |
538 | } | |
539 | ||
540 | ofmatch->metadata = match->flow.metadata; | |
541 | ofmatch->metadata_mask = ~match->wc.masks.metadata; | |
542 | ||
543 | ofmatch->wildcards = htonl(wc); | |
544 | } | |
545 | ||
546 | /* Returns the "typical" length of a match for 'protocol', for use in | |
547 | * estimating space to preallocate. */ | |
548 | int | |
549 | ofputil_match_typical_len(enum ofputil_protocol protocol) | |
550 | { | |
551 | switch (protocol) { | |
552 | case OFPUTIL_P_OF10_STD: | |
553 | case OFPUTIL_P_OF10_STD_TID: | |
554 | return sizeof(struct ofp10_match); | |
555 | ||
556 | case OFPUTIL_P_OF10_NXM: | |
557 | case OFPUTIL_P_OF10_NXM_TID: | |
558 | return NXM_TYPICAL_LEN; | |
559 | ||
560 | case OFPUTIL_P_OF11_STD: | |
561 | return sizeof(struct ofp11_match); | |
562 | ||
563 | case OFPUTIL_P_OF12_OXM: | |
564 | case OFPUTIL_P_OF13_OXM: | |
565 | case OFPUTIL_P_OF14_OXM: | |
566 | case OFPUTIL_P_OF15_OXM: | |
0d71302e BP |
567 | return NXM_TYPICAL_LEN; |
568 | ||
569 | default: | |
570 | OVS_NOT_REACHED(); | |
571 | } | |
572 | } | |
573 | ||
574 | /* Appends to 'b' an struct ofp11_match_header followed by a match that | |
575 | * expresses 'match' properly for 'protocol', plus enough zero bytes to pad the | |
576 | * data appended out to a multiple of 8. 'protocol' must be one that is usable | |
577 | * in OpenFlow 1.1 or later. | |
578 | * | |
579 | * This function can cause 'b''s data to be reallocated. | |
580 | * | |
581 | * Returns the number of bytes appended to 'b', excluding the padding. Never | |
582 | * returns zero. */ | |
583 | int | |
584 | ofputil_put_ofp11_match(struct ofpbuf *b, const struct match *match, | |
585 | enum ofputil_protocol protocol) | |
586 | { | |
587 | switch (protocol) { | |
588 | case OFPUTIL_P_OF10_STD: | |
589 | case OFPUTIL_P_OF10_STD_TID: | |
590 | case OFPUTIL_P_OF10_NXM: | |
591 | case OFPUTIL_P_OF10_NXM_TID: | |
592 | OVS_NOT_REACHED(); | |
593 | ||
594 | case OFPUTIL_P_OF11_STD: { | |
595 | struct ofp11_match *om; | |
596 | ||
597 | /* Make sure that no padding is needed. */ | |
598 | BUILD_ASSERT_DECL(sizeof *om % 8 == 0); | |
599 | ||
600 | om = ofpbuf_put_uninit(b, sizeof *om); | |
601 | ofputil_match_to_ofp11_match(match, om); | |
602 | return sizeof *om; | |
603 | } | |
604 | ||
605 | case OFPUTIL_P_OF12_OXM: | |
606 | case OFPUTIL_P_OF13_OXM: | |
607 | case OFPUTIL_P_OF14_OXM: | |
608 | case OFPUTIL_P_OF15_OXM: | |
0d71302e BP |
609 | return oxm_put_match(b, match, |
610 | ofputil_protocol_to_ofp_version(protocol)); | |
611 | } | |
612 | ||
613 | OVS_NOT_REACHED(); | |
614 | } | |
615 | ||
616 | /* Given a 'dl_type' value in the format used in struct flow, returns the | |
617 | * corresponding 'dl_type' value for use in an ofp10_match or ofp11_match | |
618 | * structure. */ | |
619 | ovs_be16 | |
620 | ofputil_dl_type_to_openflow(ovs_be16 flow_dl_type) | |
621 | { | |
622 | return (flow_dl_type == htons(FLOW_DL_TYPE_NONE) | |
623 | ? htons(OFP_DL_TYPE_NOT_ETH_TYPE) | |
624 | : flow_dl_type); | |
625 | } | |
626 | ||
627 | /* Given a 'dl_type' value in the format used in an ofp10_match or ofp11_match | |
628 | * structure, returns the corresponding 'dl_type' value for use in struct | |
629 | * flow. */ | |
630 | ovs_be16 | |
631 | ofputil_dl_type_from_openflow(ovs_be16 ofp_dl_type) | |
632 | { | |
633 | return (ofp_dl_type == htons(OFP_DL_TYPE_NOT_ETH_TYPE) | |
634 | ? htons(FLOW_DL_TYPE_NONE) | |
635 | : ofp_dl_type); | |
636 | } | |
637 | \f | |
638 | static void | |
639 | encode_tlv_table_mappings(struct ofpbuf *b, struct ovs_list *mappings) | |
640 | { | |
641 | struct ofputil_tlv_map *map; | |
642 | ||
643 | LIST_FOR_EACH (map, list_node, mappings) { | |
644 | struct nx_tlv_map *nx_map; | |
645 | ||
646 | nx_map = ofpbuf_put_zeros(b, sizeof *nx_map); | |
647 | nx_map->option_class = htons(map->option_class); | |
648 | nx_map->option_type = map->option_type; | |
649 | nx_map->option_len = map->option_len; | |
650 | nx_map->index = htons(map->index); | |
651 | } | |
652 | } | |
653 | ||
654 | struct ofpbuf * | |
655 | ofputil_encode_tlv_table_mod(enum ofp_version ofp_version, | |
656 | struct ofputil_tlv_table_mod *ttm) | |
657 | { | |
658 | struct ofpbuf *b; | |
659 | struct nx_tlv_table_mod *nx_ttm; | |
660 | ||
661 | b = ofpraw_alloc(OFPRAW_NXT_TLV_TABLE_MOD, ofp_version, 0); | |
662 | nx_ttm = ofpbuf_put_zeros(b, sizeof *nx_ttm); | |
663 | nx_ttm->command = htons(ttm->command); | |
664 | encode_tlv_table_mappings(b, &ttm->mappings); | |
665 | ||
666 | return b; | |
667 | } | |
668 | ||
669 | static enum ofperr | |
670 | decode_tlv_table_mappings(struct ofpbuf *msg, unsigned int max_fields, | |
671 | struct ovs_list *mappings) | |
672 | { | |
673 | ovs_list_init(mappings); | |
674 | ||
675 | while (msg->size) { | |
676 | struct nx_tlv_map *nx_map; | |
677 | struct ofputil_tlv_map *map; | |
678 | ||
679 | nx_map = ofpbuf_pull(msg, sizeof *nx_map); | |
680 | map = xmalloc(sizeof *map); | |
681 | ovs_list_push_back(mappings, &map->list_node); | |
682 | ||
683 | map->option_class = ntohs(nx_map->option_class); | |
684 | map->option_type = nx_map->option_type; | |
685 | ||
686 | map->option_len = nx_map->option_len; | |
687 | if (map->option_len % 4 || map->option_len > TLV_MAX_OPT_SIZE) { | |
688 | VLOG_WARN_RL(&rl, "tlv table option length (%u) is not a " | |
689 | "valid option size", map->option_len); | |
690 | ofputil_uninit_tlv_table(mappings); | |
691 | return OFPERR_NXTTMFC_BAD_OPT_LEN; | |
692 | } | |
693 | ||
694 | map->index = ntohs(nx_map->index); | |
695 | if (map->index >= max_fields) { | |
696 | VLOG_WARN_RL(&rl, "tlv table field index (%u) is too large " | |
697 | "(max %u)", map->index, max_fields - 1); | |
698 | ofputil_uninit_tlv_table(mappings); | |
699 | return OFPERR_NXTTMFC_BAD_FIELD_IDX; | |
700 | } | |
701 | } | |
702 | ||
703 | return 0; | |
704 | } | |
705 | ||
706 | enum ofperr | |
707 | ofputil_decode_tlv_table_mod(const struct ofp_header *oh, | |
708 | struct ofputil_tlv_table_mod *ttm) | |
709 | { | |
710 | struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length)); | |
711 | ofpraw_pull_assert(&msg); | |
712 | ||
713 | struct nx_tlv_table_mod *nx_ttm = ofpbuf_pull(&msg, sizeof *nx_ttm); | |
714 | ttm->command = ntohs(nx_ttm->command); | |
715 | if (ttm->command > NXTTMC_CLEAR) { | |
716 | VLOG_WARN_RL(&rl, "tlv table mod command (%u) is out of range", | |
717 | ttm->command); | |
718 | return OFPERR_NXTTMFC_BAD_COMMAND; | |
719 | } | |
720 | ||
721 | return decode_tlv_table_mappings(&msg, TUN_METADATA_NUM_OPTS, | |
722 | &ttm->mappings); | |
723 | } | |
724 | ||
fe2c69f4 BP |
725 | static void |
726 | print_tlv_table(struct ds *s, const struct ovs_list *mappings) | |
727 | { | |
728 | struct ofputil_tlv_map *map; | |
729 | ||
730 | ds_put_cstr(s, " mapping table:\n"); | |
731 | ds_put_cstr(s, " class type length match field\n"); | |
732 | ds_put_cstr(s, " ------ ---- ------ --------------"); | |
733 | ||
734 | LIST_FOR_EACH (map, list_node, mappings) { | |
735 | ds_put_format(s, "\n %#6"PRIx16" %#4"PRIx8" %6"PRIu8" " | |
736 | "tun_metadata%"PRIu16, | |
737 | map->option_class, map->option_type, map->option_len, | |
738 | map->index); | |
739 | } | |
740 | } | |
741 | ||
742 | void | |
743 | ofputil_format_tlv_table_mod(struct ds *s, | |
744 | const struct ofputil_tlv_table_mod *ttm) | |
745 | { | |
746 | ds_put_cstr(s, "\n "); | |
747 | ||
748 | switch (ttm->command) { | |
749 | case NXTTMC_ADD: | |
750 | ds_put_cstr(s, "ADD"); | |
751 | break; | |
752 | case NXTTMC_DELETE: | |
753 | ds_put_cstr(s, "DEL"); | |
754 | break; | |
755 | case NXTTMC_CLEAR: | |
756 | ds_put_cstr(s, "CLEAR"); | |
757 | break; | |
758 | } | |
759 | ||
760 | if (ttm->command != NXTTMC_CLEAR) { | |
761 | print_tlv_table(s, &ttm->mappings); | |
762 | } | |
763 | } | |
764 | ||
0d71302e BP |
765 | struct ofpbuf * |
766 | ofputil_encode_tlv_table_reply(const struct ofp_header *oh, | |
767 | struct ofputil_tlv_table_reply *ttr) | |
768 | { | |
769 | struct ofpbuf *b; | |
770 | struct nx_tlv_table_reply *nx_ttr; | |
771 | ||
772 | b = ofpraw_alloc_reply(OFPRAW_NXT_TLV_TABLE_REPLY, oh, 0); | |
773 | nx_ttr = ofpbuf_put_zeros(b, sizeof *nx_ttr); | |
774 | nx_ttr->max_option_space = htonl(ttr->max_option_space); | |
775 | nx_ttr->max_fields = htons(ttr->max_fields); | |
776 | ||
777 | encode_tlv_table_mappings(b, &ttr->mappings); | |
778 | ||
779 | return b; | |
780 | } | |
781 | ||
782 | /* Decodes the NXT_TLV_TABLE_REPLY message in 'oh' into '*ttr'. Returns 0 | |
783 | * if successful, otherwise an ofperr. | |
784 | * | |
785 | * The decoder verifies that the indexes in 'ttr->mappings' are less than | |
786 | * 'ttr->max_fields', but the caller must ensure, if necessary, that they are | |
787 | * less than TUN_METADATA_NUM_OPTS. */ | |
788 | enum ofperr | |
789 | ofputil_decode_tlv_table_reply(const struct ofp_header *oh, | |
790 | struct ofputil_tlv_table_reply *ttr) | |
791 | { | |
792 | struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length)); | |
793 | ofpraw_pull_assert(&msg); | |
794 | ||
795 | struct nx_tlv_table_reply *nx_ttr = ofpbuf_pull(&msg, sizeof *nx_ttr); | |
796 | ttr->max_option_space = ntohl(nx_ttr->max_option_space); | |
797 | ttr->max_fields = ntohs(nx_ttr->max_fields); | |
798 | ||
799 | return decode_tlv_table_mappings(&msg, ttr->max_fields, &ttr->mappings); | |
800 | } | |
801 | ||
802 | char * OVS_WARN_UNUSED_RESULT | |
803 | parse_ofp_tlv_table_mod_str(struct ofputil_tlv_table_mod *ttm, | |
804 | uint16_t command, const char *s, | |
805 | enum ofputil_protocol *usable_protocols) | |
806 | { | |
807 | *usable_protocols = OFPUTIL_P_NXM_OXM_ANY; | |
808 | ||
809 | ttm->command = command; | |
810 | ovs_list_init(&ttm->mappings); | |
811 | ||
812 | while (*s) { | |
813 | struct ofputil_tlv_map *map = xmalloc(sizeof *map); | |
814 | int n; | |
815 | ||
816 | if (*s == ',') { | |
817 | s++; | |
818 | } | |
819 | ||
820 | ovs_list_push_back(&ttm->mappings, &map->list_node); | |
821 | ||
822 | if (!ovs_scan(s, "{class=%"SCNi16",type=%"SCNi8",len=%"SCNi8"}" | |
823 | "->tun_metadata%"SCNi16"%n", | |
824 | &map->option_class, &map->option_type, &map->option_len, | |
825 | &map->index, &n)) { | |
826 | ofputil_uninit_tlv_table(&ttm->mappings); | |
827 | return xstrdup("invalid tlv mapping"); | |
828 | } | |
829 | ||
830 | s += n; | |
831 | } | |
832 | ||
833 | return NULL; | |
834 | } | |
835 | ||
fe2c69f4 BP |
836 | void |
837 | ofputil_format_tlv_table_reply(struct ds *s, | |
838 | const struct ofputil_tlv_table_reply *ttr) | |
839 | { | |
840 | ds_put_char(s, '\n'); | |
841 | ||
842 | const struct ofputil_tlv_map *map; | |
843 | int allocated_space = 0; | |
844 | LIST_FOR_EACH (map, list_node, &ttr->mappings) { | |
845 | allocated_space += map->option_len; | |
846 | } | |
847 | ||
848 | ds_put_format(s, " max option space=%"PRIu32" max fields=%"PRIu16"\n", | |
849 | ttr->max_option_space, ttr->max_fields); | |
850 | ds_put_format(s, " allocated option space=%d\n", allocated_space); | |
851 | ds_put_char(s, '\n'); | |
852 | print_tlv_table(s, &ttr->mappings); | |
853 | } | |
854 | ||
0d71302e BP |
855 | void |
856 | ofputil_uninit_tlv_table(struct ovs_list *mappings) | |
857 | { | |
858 | struct ofputil_tlv_map *map; | |
859 | ||
860 | LIST_FOR_EACH_POP (map, list_node, mappings) { | |
861 | free(map); | |
862 | } | |
863 | } | |
864 | \f | |
865 | static void | |
866 | ofputil_normalize_match__(struct match *match, bool may_log) | |
867 | { | |
868 | enum { | |
869 | MAY_NW_ADDR = 1 << 0, /* nw_src, nw_dst */ | |
870 | MAY_TP_ADDR = 1 << 1, /* tp_src, tp_dst */ | |
871 | MAY_NW_PROTO = 1 << 2, /* nw_proto */ | |
872 | MAY_IPVx = 1 << 3, /* tos, frag, ttl */ | |
873 | MAY_ARP_SHA = 1 << 4, /* arp_sha */ | |
874 | MAY_ARP_THA = 1 << 5, /* arp_tha */ | |
875 | MAY_IPV6 = 1 << 6, /* ipv6_src, ipv6_dst, ipv6_label */ | |
876 | MAY_ND_TARGET = 1 << 7, /* nd_target */ | |
877 | MAY_MPLS = 1 << 8, /* mpls label and tc */ | |
878 | MAY_ETHER = 1 << 9, /* dl_src, dl_dst */ | |
879 | } may_match; | |
880 | ||
881 | struct flow_wildcards wc = match->wc; | |
882 | ovs_be16 dl_type; | |
883 | ||
884 | /* Figure out what fields may be matched. */ | |
885 | /* Check the packet_type first and extract dl_type. */ | |
886 | if (wc.masks.packet_type == 0 || match_has_default_packet_type(match)) { | |
887 | may_match = MAY_ETHER; | |
888 | dl_type = match->flow.dl_type; | |
889 | } else if (wc.masks.packet_type == OVS_BE32_MAX && | |
890 | pt_ns(match->flow.packet_type) == OFPHTN_ETHERTYPE) { | |
891 | may_match = 0; | |
892 | dl_type = pt_ns_type_be(match->flow.packet_type); | |
893 | } else { | |
894 | may_match = 0; | |
895 | dl_type = 0; | |
896 | } | |
897 | if (dl_type == htons(ETH_TYPE_IP)) { | |
898 | may_match |= MAY_NW_PROTO | MAY_IPVx | MAY_NW_ADDR; | |
899 | if (match->flow.nw_proto == IPPROTO_TCP || | |
900 | match->flow.nw_proto == IPPROTO_UDP || | |
901 | match->flow.nw_proto == IPPROTO_SCTP || | |
902 | match->flow.nw_proto == IPPROTO_ICMP) { | |
903 | may_match |= MAY_TP_ADDR; | |
904 | } | |
905 | } else if (dl_type == htons(ETH_TYPE_IPV6)) { | |
906 | may_match |= MAY_NW_PROTO | MAY_IPVx | MAY_IPV6; | |
907 | if (match->flow.nw_proto == IPPROTO_TCP || | |
908 | match->flow.nw_proto == IPPROTO_UDP || | |
909 | match->flow.nw_proto == IPPROTO_SCTP) { | |
910 | may_match |= MAY_TP_ADDR; | |
911 | } else if (match->flow.nw_proto == IPPROTO_ICMPV6) { | |
912 | may_match |= MAY_TP_ADDR; | |
913 | if (match->flow.tp_src == htons(ND_NEIGHBOR_SOLICIT)) { | |
914 | may_match |= MAY_ND_TARGET | MAY_ARP_SHA; | |
915 | } else if (match->flow.tp_src == htons(ND_NEIGHBOR_ADVERT)) { | |
916 | may_match |= MAY_ND_TARGET | MAY_ARP_THA; | |
917 | } | |
918 | } | |
919 | } else if (dl_type == htons(ETH_TYPE_ARP) || | |
920 | dl_type == htons(ETH_TYPE_RARP)) { | |
921 | may_match |= MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA; | |
922 | } else if (eth_type_mpls(dl_type)) { | |
923 | may_match |= MAY_MPLS; | |
924 | } | |
925 | ||
926 | /* Clear the fields that may not be matched. */ | |
927 | if (!(may_match & MAY_ETHER)) { | |
928 | wc.masks.dl_src = wc.masks.dl_dst = eth_addr_zero; | |
929 | } | |
930 | if (!(may_match & MAY_NW_ADDR)) { | |
931 | wc.masks.nw_src = wc.masks.nw_dst = htonl(0); | |
932 | } | |
933 | if (!(may_match & MAY_TP_ADDR)) { | |
934 | wc.masks.tp_src = wc.masks.tp_dst = htons(0); | |
935 | } | |
936 | if (!(may_match & MAY_NW_PROTO)) { | |
937 | wc.masks.nw_proto = 0; | |
938 | } | |
939 | if (!(may_match & MAY_IPVx)) { | |
940 | wc.masks.nw_tos = 0; | |
941 | wc.masks.nw_ttl = 0; | |
942 | } | |
943 | if (!(may_match & MAY_ARP_SHA)) { | |
944 | WC_UNMASK_FIELD(&wc, arp_sha); | |
945 | } | |
946 | if (!(may_match & MAY_ARP_THA)) { | |
947 | WC_UNMASK_FIELD(&wc, arp_tha); | |
948 | } | |
949 | if (!(may_match & MAY_IPV6)) { | |
950 | wc.masks.ipv6_src = wc.masks.ipv6_dst = in6addr_any; | |
951 | wc.masks.ipv6_label = htonl(0); | |
952 | } | |
953 | if (!(may_match & MAY_ND_TARGET)) { | |
954 | wc.masks.nd_target = in6addr_any; | |
955 | } | |
956 | if (!(may_match & MAY_MPLS)) { | |
957 | memset(wc.masks.mpls_lse, 0, sizeof wc.masks.mpls_lse); | |
958 | } | |
959 | ||
960 | /* Log any changes. */ | |
961 | if (!flow_wildcards_equal(&wc, &match->wc)) { | |
962 | bool log = may_log && !VLOG_DROP_INFO(&rl); | |
963 | char *pre = (log | |
964 | ? match_to_string(match, NULL, OFP_DEFAULT_PRIORITY) | |
965 | : NULL); | |
966 | ||
967 | match->wc = wc; | |
968 | match_zero_wildcarded_fields(match); | |
969 | ||
970 | if (log) { | |
971 | char *post = match_to_string(match, NULL, OFP_DEFAULT_PRIORITY); | |
972 | VLOG_INFO("normalization changed ofp_match, details:"); | |
973 | VLOG_INFO(" pre: %s", pre); | |
974 | VLOG_INFO("post: %s", post); | |
975 | free(pre); | |
976 | free(post); | |
977 | } | |
978 | } | |
979 | } | |
980 | ||
981 | /* "Normalizes" the wildcards in 'match'. That means: | |
982 | * | |
983 | * 1. If the type of level N is known, then only the valid fields for that | |
984 | * level may be specified. For example, ARP does not have a TOS field, | |
985 | * so nw_tos must be wildcarded if 'match' specifies an ARP flow. | |
986 | * Similarly, IPv4 does not have any IPv6 addresses, so ipv6_src and | |
987 | * ipv6_dst (and other fields) must be wildcarded if 'match' specifies an | |
988 | * IPv4 flow. | |
989 | * | |
990 | * 2. If the type of level N is not known (or not understood by Open | |
991 | * vSwitch), then no fields at all for that level may be specified. For | |
992 | * example, Open vSwitch does not understand SCTP, an L4 protocol, so the | |
993 | * L4 fields tp_src and tp_dst must be wildcarded if 'match' specifies an | |
994 | * SCTP flow. | |
995 | * | |
996 | * If this function changes 'match', it logs a rate-limited informational | |
997 | * message. */ | |
998 | void | |
999 | ofputil_normalize_match(struct match *match) | |
1000 | { | |
1001 | ofputil_normalize_match__(match, true); | |
1002 | } | |
1003 | ||
1004 | /* Same as ofputil_normalize_match() without the logging. Thus, this function | |
1005 | * is suitable for a program's internal use, whereas ofputil_normalize_match() | |
1006 | * sense for use on flows received from elsewhere (so that a bug in the program | |
1007 | * that sent them can be reported and corrected). */ | |
1008 | void | |
1009 | ofputil_normalize_match_quiet(struct match *match) | |
1010 | { | |
1011 | ofputil_normalize_match__(match, false); | |
1012 | } | |
dfc77282 BP |
1013 | \f |
1014 | static void OVS_PRINTF_FORMAT(5, 6) | |
1015 | print_wild(struct ds *string, const char *leader, int is_wild, | |
1016 | int verbosity, const char *format, ...) | |
1017 | { | |
1018 | if (is_wild && verbosity < 2) { | |
1019 | return; | |
1020 | } | |
1021 | ds_put_cstr(string, leader); | |
1022 | if (!is_wild) { | |
1023 | va_list args; | |
1024 | ||
1025 | va_start(args, format); | |
1026 | ds_put_format_valist(string, format, args); | |
1027 | va_end(args); | |
1028 | } else { | |
1029 | ds_put_char(string, '*'); | |
1030 | } | |
1031 | ds_put_char(string, ','); | |
1032 | } | |
1033 | ||
1034 | static void | |
1035 | print_wild_port(struct ds *string, const char *leader, int is_wild, | |
1036 | int verbosity, ofp_port_t port, | |
1037 | const struct ofputil_port_map *port_map) | |
1038 | { | |
1039 | if (is_wild && verbosity < 2) { | |
1040 | return; | |
1041 | } | |
1042 | ds_put_cstr(string, leader); | |
1043 | if (!is_wild) { | |
1044 | ofputil_format_port(port, port_map, string); | |
1045 | } else { | |
1046 | ds_put_char(string, '*'); | |
1047 | } | |
1048 | ds_put_char(string, ','); | |
1049 | } | |
1050 | ||
1051 | static void | |
1052 | print_ip_netmask(struct ds *string, const char *leader, ovs_be32 ip, | |
1053 | uint32_t wild_bits, int verbosity) | |
1054 | { | |
1055 | if (wild_bits >= 32 && verbosity < 2) { | |
1056 | return; | |
1057 | } | |
1058 | ds_put_cstr(string, leader); | |
1059 | if (wild_bits < 32) { | |
1060 | ds_put_format(string, IP_FMT, IP_ARGS(ip)); | |
1061 | if (wild_bits) { | |
1062 | ds_put_format(string, "/%d", 32 - wild_bits); | |
1063 | } | |
1064 | } else { | |
1065 | ds_put_char(string, '*'); | |
1066 | } | |
1067 | ds_put_char(string, ','); | |
1068 | } | |
1069 | ||
1070 | void | |
1071 | ofp10_match_print(struct ds *f, const struct ofp10_match *om, | |
1072 | const struct ofputil_port_map *port_map, int verbosity) | |
1073 | { | |
1074 | char *s = ofp10_match_to_string(om, port_map, verbosity); | |
1075 | ds_put_cstr(f, s); | |
1076 | free(s); | |
1077 | } | |
1078 | ||
1079 | char * | |
1080 | ofp10_match_to_string(const struct ofp10_match *om, | |
1081 | const struct ofputil_port_map *port_map, int verbosity) | |
1082 | { | |
1083 | struct ds f = DS_EMPTY_INITIALIZER; | |
1084 | uint32_t w = ntohl(om->wildcards); | |
1085 | bool skip_type = false; | |
1086 | bool skip_proto = false; | |
1087 | ||
1088 | if (!(w & OFPFW10_DL_TYPE)) { | |
1089 | skip_type = true; | |
1090 | if (om->dl_type == htons(ETH_TYPE_IP)) { | |
1091 | if (!(w & OFPFW10_NW_PROTO)) { | |
1092 | skip_proto = true; | |
1093 | if (om->nw_proto == IPPROTO_ICMP) { | |
1094 | ds_put_cstr(&f, "icmp,"); | |
1095 | } else if (om->nw_proto == IPPROTO_TCP) { | |
1096 | ds_put_cstr(&f, "tcp,"); | |
1097 | } else if (om->nw_proto == IPPROTO_UDP) { | |
1098 | ds_put_cstr(&f, "udp,"); | |
1099 | } else if (om->nw_proto == IPPROTO_SCTP) { | |
1100 | ds_put_cstr(&f, "sctp,"); | |
1101 | } else { | |
1102 | ds_put_cstr(&f, "ip,"); | |
1103 | skip_proto = false; | |
1104 | } | |
1105 | } else { | |
1106 | ds_put_cstr(&f, "ip,"); | |
1107 | } | |
1108 | } else if (om->dl_type == htons(ETH_TYPE_ARP)) { | |
1109 | ds_put_cstr(&f, "arp,"); | |
1110 | } else if (om->dl_type == htons(ETH_TYPE_RARP)){ | |
1111 | ds_put_cstr(&f, "rarp,"); | |
1112 | } else if (om->dl_type == htons(ETH_TYPE_MPLS)) { | |
1113 | ds_put_cstr(&f, "mpls,"); | |
1114 | } else if (om->dl_type == htons(ETH_TYPE_MPLS_MCAST)) { | |
1115 | ds_put_cstr(&f, "mplsm,"); | |
1116 | } else { | |
1117 | skip_type = false; | |
1118 | } | |
1119 | } | |
1120 | print_wild_port(&f, "in_port=", w & OFPFW10_IN_PORT, verbosity, | |
1121 | u16_to_ofp(ntohs(om->in_port)), port_map); | |
1122 | print_wild(&f, "dl_vlan=", w & OFPFW10_DL_VLAN, verbosity, | |
1123 | "%d", ntohs(om->dl_vlan)); | |
1124 | print_wild(&f, "dl_vlan_pcp=", w & OFPFW10_DL_VLAN_PCP, verbosity, | |
1125 | "%d", om->dl_vlan_pcp); | |
1126 | print_wild(&f, "dl_src=", w & OFPFW10_DL_SRC, verbosity, | |
1127 | ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_src)); | |
1128 | print_wild(&f, "dl_dst=", w & OFPFW10_DL_DST, verbosity, | |
1129 | ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_dst)); | |
1130 | if (!skip_type) { | |
1131 | print_wild(&f, "dl_type=", w & OFPFW10_DL_TYPE, verbosity, | |
1132 | "0x%04x", ntohs(om->dl_type)); | |
1133 | } | |
1134 | print_ip_netmask(&f, "nw_src=", om->nw_src, | |
1135 | (w & OFPFW10_NW_SRC_MASK) >> OFPFW10_NW_SRC_SHIFT, | |
1136 | verbosity); | |
1137 | print_ip_netmask(&f, "nw_dst=", om->nw_dst, | |
1138 | (w & OFPFW10_NW_DST_MASK) >> OFPFW10_NW_DST_SHIFT, | |
1139 | verbosity); | |
1140 | if (!skip_proto) { | |
1141 | if (om->dl_type == htons(ETH_TYPE_ARP) || | |
1142 | om->dl_type == htons(ETH_TYPE_RARP)) { | |
1143 | print_wild(&f, "arp_op=", w & OFPFW10_NW_PROTO, verbosity, | |
1144 | "%u", om->nw_proto); | |
1145 | } else { | |
1146 | print_wild(&f, "nw_proto=", w & OFPFW10_NW_PROTO, verbosity, | |
1147 | "%u", om->nw_proto); | |
1148 | } | |
1149 | } | |
1150 | print_wild(&f, "nw_tos=", w & OFPFW10_NW_TOS, verbosity, | |
1151 | "%u", om->nw_tos); | |
1152 | if (om->nw_proto == IPPROTO_ICMP) { | |
1153 | print_wild(&f, "icmp_type=", w & OFPFW10_ICMP_TYPE, verbosity, | |
1154 | "%d", ntohs(om->tp_src)); | |
1155 | print_wild(&f, "icmp_code=", w & OFPFW10_ICMP_CODE, verbosity, | |
1156 | "%d", ntohs(om->tp_dst)); | |
1157 | } else { | |
1158 | print_wild(&f, "tp_src=", w & OFPFW10_TP_SRC, verbosity, | |
1159 | "%d", ntohs(om->tp_src)); | |
1160 | print_wild(&f, "tp_dst=", w & OFPFW10_TP_DST, verbosity, | |
1161 | "%d", ntohs(om->tp_dst)); | |
1162 | } | |
1163 | ds_chomp(&f, ','); | |
1164 | return ds_cstr(&f); | |
1165 | } | |
1166 |