/src/openvswitch/lib/ofp-match.c
Line | Count | Source (jump to first uncovered line) |
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. */ |
42 | | static ovs_be32 |
43 | | ofputil_wcbits_to_netmask(int wcbits) |
44 | 0 | { |
45 | 0 | wcbits &= 0x3f; |
46 | 0 | return wcbits < 32 ? htonl(~((1u << wcbits) - 1)) : 0; |
47 | 0 | } |
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. */ |
55 | | static int |
56 | | ofputil_netmask_to_wcbits(ovs_be32 netmask) |
57 | 3.86k | { |
58 | 3.86k | return 32 - ip_count_cidr_bits(netmask); |
59 | 3.86k | } |
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 | 0 | { |
68 | 0 | BUILD_ASSERT_DECL(FLOW_WC_SEQ == 42); |
69 | | |
70 | | /* Initialize most of wc. */ |
71 | 0 | flow_wildcards_init_catchall(wc); |
72 | |
|
73 | 0 | if (!(ofpfw & OFPFW10_IN_PORT)) { |
74 | 0 | wc->masks.in_port.ofp_port = u16_to_ofp(UINT16_MAX); |
75 | 0 | } |
76 | |
|
77 | 0 | if (!(ofpfw & OFPFW10_NW_TOS)) { |
78 | 0 | wc->masks.nw_tos |= IP_DSCP_MASK; |
79 | 0 | } |
80 | |
|
81 | 0 | if (!(ofpfw & OFPFW10_NW_PROTO)) { |
82 | 0 | wc->masks.nw_proto = UINT8_MAX; |
83 | 0 | } |
84 | 0 | wc->masks.nw_src = ofputil_wcbits_to_netmask(ofpfw |
85 | 0 | >> OFPFW10_NW_SRC_SHIFT); |
86 | 0 | wc->masks.nw_dst = ofputil_wcbits_to_netmask(ofpfw |
87 | 0 | >> OFPFW10_NW_DST_SHIFT); |
88 | |
|
89 | 0 | if (!(ofpfw & OFPFW10_TP_SRC)) { |
90 | 0 | wc->masks.tp_src = OVS_BE16_MAX; |
91 | 0 | } |
92 | 0 | if (!(ofpfw & OFPFW10_TP_DST)) { |
93 | 0 | wc->masks.tp_dst = OVS_BE16_MAX; |
94 | 0 | } |
95 | |
|
96 | 0 | if (!(ofpfw & OFPFW10_DL_SRC)) { |
97 | 0 | WC_MASK_FIELD(wc, dl_src); |
98 | 0 | } |
99 | 0 | if (!(ofpfw & OFPFW10_DL_DST)) { |
100 | 0 | WC_MASK_FIELD(wc, dl_dst); |
101 | 0 | } |
102 | 0 | if (!(ofpfw & OFPFW10_DL_TYPE)) { |
103 | 0 | wc->masks.dl_type = OVS_BE16_MAX; |
104 | 0 | } |
105 | | |
106 | | /* VLAN TCI mask. */ |
107 | 0 | if (!(ofpfw & OFPFW10_DL_VLAN_PCP)) { |
108 | 0 | wc->masks.vlans[0].tci |= htons(VLAN_PCP_MASK | VLAN_CFI); |
109 | 0 | } |
110 | 0 | if (!(ofpfw & OFPFW10_DL_VLAN)) { |
111 | 0 | wc->masks.vlans[0].tci |= htons(VLAN_VID_MASK | VLAN_CFI); |
112 | 0 | } |
113 | 0 | } |
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 | 0 | { |
120 | 0 | uint32_t ofpfw = ntohl(ofmatch->wildcards) & OFPFW10_ALL; |
121 | | |
122 | | /* Initialize match->wc. */ |
123 | 0 | memset(&match->flow, 0, sizeof match->flow); |
124 | 0 | ofputil_wildcard_from_ofpfw10(ofpfw, &match->wc); |
125 | 0 | 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 | 0 | const uint32_t ofpfw_data_bits = (OFPFW10_NW_TOS | OFPFW10_NW_PROTO |
130 | 0 | | OFPFW10_TP_SRC | OFPFW10_TP_DST |
131 | 0 | | OFPFW10_DL_SRC | OFPFW10_DL_DST |
132 | 0 | | OFPFW10_DL_TYPE |
133 | 0 | | OFPFW10_DL_VLAN | OFPFW10_DL_VLAN_PCP); |
134 | 0 | if ((ofpfw & ofpfw_data_bits) != ofpfw_data_bits |
135 | 0 | || ofputil_wcbits_to_netmask(ofpfw >> OFPFW10_NW_SRC_SHIFT) |
136 | 0 | || ofputil_wcbits_to_netmask(ofpfw >> OFPFW10_NW_DST_SHIFT)) { |
137 | 0 | match_set_default_packet_type(match); |
138 | 0 | } |
139 | | |
140 | | /* Initialize most of match->flow. */ |
141 | 0 | match->flow.nw_src = ofmatch->nw_src; |
142 | 0 | match->flow.nw_dst = ofmatch->nw_dst; |
143 | 0 | match->flow.in_port.ofp_port = u16_to_ofp(ntohs(ofmatch->in_port)); |
144 | 0 | match->flow.dl_type = ofputil_dl_type_from_openflow(ofmatch->dl_type); |
145 | 0 | match->flow.tp_src = ofmatch->tp_src; |
146 | 0 | match->flow.tp_dst = ofmatch->tp_dst; |
147 | 0 | match->flow.dl_src = ofmatch->dl_src; |
148 | 0 | match->flow.dl_dst = ofmatch->dl_dst; |
149 | 0 | match->flow.nw_tos = ofmatch->nw_tos & IP_DSCP_MASK; |
150 | 0 | match->flow.nw_proto = ofmatch->nw_proto; |
151 | | |
152 | | /* Translate VLANs. */ |
153 | 0 | if (!(ofpfw & OFPFW10_DL_VLAN) && |
154 | 0 | 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 | 0 | match->flow.vlans[0].tci = htons(0); |
164 | 0 | match->wc.masks.vlans[0].tci = htons(0xffff); |
165 | 0 | } else { |
166 | 0 | ovs_be16 vid, pcp, tci; |
167 | 0 | uint16_t hpcp; |
168 | |
|
169 | 0 | vid = ofmatch->dl_vlan & htons(VLAN_VID_MASK); |
170 | 0 | hpcp = (ofmatch->dl_vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK; |
171 | 0 | pcp = htons(hpcp); |
172 | 0 | tci = vid | pcp | htons(VLAN_CFI); |
173 | 0 | match->flow.vlans[0].tci = tci & match->wc.masks.vlans[0].tci; |
174 | 0 | } |
175 | | |
176 | | /* Clean up. */ |
177 | 0 | match_zero_wildcarded_fields(match); |
178 | 0 | } |
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 | 1.93k | { |
185 | 1.93k | const struct flow_wildcards *wc = &match->wc; |
186 | 1.93k | uint32_t ofpfw; |
187 | | |
188 | | /* Figure out most OpenFlow wildcards. */ |
189 | 1.93k | ofpfw = 0; |
190 | 1.93k | if (!wc->masks.in_port.ofp_port) { |
191 | 0 | ofpfw |= OFPFW10_IN_PORT; |
192 | 0 | } |
193 | 1.93k | if (!wc->masks.dl_type) { |
194 | 0 | ofpfw |= OFPFW10_DL_TYPE; |
195 | 0 | } |
196 | 1.93k | if (!wc->masks.nw_proto) { |
197 | 407 | ofpfw |= OFPFW10_NW_PROTO; |
198 | 407 | } |
199 | 1.93k | ofpfw |= (ofputil_netmask_to_wcbits(wc->masks.nw_src) |
200 | 1.93k | << OFPFW10_NW_SRC_SHIFT); |
201 | 1.93k | ofpfw |= (ofputil_netmask_to_wcbits(wc->masks.nw_dst) |
202 | 1.93k | << OFPFW10_NW_DST_SHIFT); |
203 | 1.93k | if (!(wc->masks.nw_tos & IP_DSCP_MASK)) { |
204 | 480 | ofpfw |= OFPFW10_NW_TOS; |
205 | 480 | } |
206 | 1.93k | if (!wc->masks.tp_src) { |
207 | 1.10k | ofpfw |= OFPFW10_TP_SRC; |
208 | 1.10k | } |
209 | 1.93k | if (!wc->masks.tp_dst) { |
210 | 1.10k | ofpfw |= OFPFW10_TP_DST; |
211 | 1.10k | } |
212 | 1.93k | if (eth_addr_is_zero(wc->masks.dl_src)) { |
213 | 0 | ofpfw |= OFPFW10_DL_SRC; |
214 | 0 | } |
215 | 1.93k | if (eth_addr_is_zero(wc->masks.dl_dst)) { |
216 | 0 | ofpfw |= OFPFW10_DL_DST; |
217 | 0 | } |
218 | | |
219 | | /* Translate VLANs. */ |
220 | 1.93k | ofmatch->dl_vlan = htons(0); |
221 | 1.93k | ofmatch->dl_vlan_pcp = 0; |
222 | 1.93k | if (match->wc.masks.vlans[0].tci == htons(0)) { |
223 | 0 | ofpfw |= OFPFW10_DL_VLAN | OFPFW10_DL_VLAN_PCP; |
224 | 1.93k | } else if (match->wc.masks.vlans[0].tci & htons(VLAN_CFI) |
225 | 1.93k | && !(match->flow.vlans[0].tci & htons(VLAN_CFI))) { |
226 | 1.85k | ofmatch->dl_vlan = htons(OFP10_VLAN_NONE); |
227 | 1.85k | } else { |
228 | 81 | if (!(match->wc.masks.vlans[0].tci & htons(VLAN_VID_MASK))) { |
229 | 0 | ofpfw |= OFPFW10_DL_VLAN; |
230 | 81 | } else { |
231 | 81 | ofmatch->dl_vlan = |
232 | 81 | htons(vlan_tci_to_vid(match->flow.vlans[0].tci)); |
233 | 81 | } |
234 | | |
235 | 81 | if (!(match->wc.masks.vlans[0].tci & htons(VLAN_PCP_MASK))) { |
236 | 0 | ofpfw |= OFPFW10_DL_VLAN_PCP; |
237 | 81 | } else { |
238 | 81 | ofmatch->dl_vlan_pcp = vlan_tci_to_pcp(match->flow.vlans[0].tci); |
239 | 81 | } |
240 | 81 | } |
241 | | |
242 | | /* Compose most of the match structure. */ |
243 | 1.93k | ofmatch->wildcards = htonl(ofpfw); |
244 | 1.93k | ofmatch->in_port = htons(ofp_to_u16(match->flow.in_port.ofp_port)); |
245 | 1.93k | ofmatch->dl_src = match->flow.dl_src; |
246 | 1.93k | ofmatch->dl_dst = match->flow.dl_dst; |
247 | 1.93k | ofmatch->dl_type = ofputil_dl_type_to_openflow(match->flow.dl_type); |
248 | 1.93k | ofmatch->nw_src = match->flow.nw_src; |
249 | 1.93k | ofmatch->nw_dst = match->flow.nw_dst; |
250 | 1.93k | ofmatch->nw_tos = match->flow.nw_tos & IP_DSCP_MASK; |
251 | 1.93k | ofmatch->nw_proto = match->flow.nw_proto; |
252 | 1.93k | ofmatch->tp_src = match->flow.tp_src; |
253 | 1.93k | ofmatch->tp_dst = match->flow.tp_dst; |
254 | 1.93k | memset(ofmatch->pad1, '\0', sizeof ofmatch->pad1); |
255 | 1.93k | memset(ofmatch->pad2, '\0', sizeof ofmatch->pad2); |
256 | 1.93k | } |
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 | 0 | { |
263 | 0 | struct ofp11_match_header *omh = buf->data; |
264 | 0 | uint16_t match_len; |
265 | |
|
266 | 0 | if (buf->size < sizeof *omh) { |
267 | 0 | return OFPERR_OFPBMC_BAD_LEN; |
268 | 0 | } |
269 | | |
270 | 0 | match_len = ntohs(omh->length); |
271 | |
|
272 | 0 | switch (ntohs(omh->type)) { |
273 | 0 | case OFPMT_STANDARD: { |
274 | 0 | struct ofp11_match *om; |
275 | |
|
276 | 0 | if (match_len != sizeof *om || buf->size < sizeof *om) { |
277 | 0 | return OFPERR_OFPBMC_BAD_LEN; |
278 | 0 | } |
279 | 0 | om = ofpbuf_pull(buf, sizeof *om); |
280 | 0 | if (padded_match_len) { |
281 | 0 | *padded_match_len = match_len; |
282 | 0 | } |
283 | 0 | return ofputil_match_from_ofp11_match(om, match); |
284 | 0 | } |
285 | | |
286 | 0 | case OFPMT_OXM: |
287 | 0 | if (padded_match_len) { |
288 | 0 | *padded_match_len = ROUND_UP(match_len, 8); |
289 | 0 | } |
290 | 0 | return oxm_pull_match(buf, false, tun_table, vl_mff_map, match); |
291 | | |
292 | 0 | default: |
293 | 0 | return OFPERR_OFPBMC_BAD_TYPE; |
294 | 0 | } |
295 | 0 | } |
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 | 0 | { |
303 | 0 | uint16_t wc = ntohl(ofmatch->wildcards); |
304 | 0 | bool ipv4, arp, rarp; |
305 | |
|
306 | 0 | match_init_catchall(match); |
307 | 0 | match->flow.tunnel.metadata.tab = NULL; |
308 | |
|
309 | 0 | if (!(wc & OFPFW11_IN_PORT)) { |
310 | 0 | ofp_port_t ofp_port; |
311 | 0 | enum ofperr error; |
312 | |
|
313 | 0 | error = ofputil_port_from_ofp11(ofmatch->in_port, &ofp_port); |
314 | 0 | if (error) { |
315 | 0 | return OFPERR_OFPBMC_BAD_VALUE; |
316 | 0 | } |
317 | 0 | match_set_in_port(match, ofp_port); |
318 | 0 | } |
319 | | |
320 | 0 | struct eth_addr dl_src_mask = eth_addr_invert(ofmatch->dl_src_mask); |
321 | 0 | struct eth_addr dl_dst_mask = eth_addr_invert(ofmatch->dl_dst_mask); |
322 | 0 | if (!eth_addr_is_zero(dl_src_mask) || !eth_addr_is_zero(dl_dst_mask)) { |
323 | 0 | match_set_dl_src_masked(match, ofmatch->dl_src, dl_src_mask); |
324 | 0 | match_set_dl_dst_masked(match, ofmatch->dl_dst, dl_dst_mask); |
325 | 0 | match_set_default_packet_type(match); |
326 | 0 | } |
327 | |
|
328 | 0 | if (!(wc & OFPFW11_DL_VLAN)) { |
329 | 0 | if (ofmatch->dl_vlan == htons(OFPVID11_NONE)) { |
330 | | /* Match only packets without a VLAN tag. */ |
331 | 0 | match->flow.vlans[0].tci = htons(0); |
332 | 0 | match->wc.masks.vlans[0].tci = OVS_BE16_MAX; |
333 | 0 | } else { |
334 | 0 | if (ofmatch->dl_vlan == htons(OFPVID11_ANY)) { |
335 | | /* Match any packet with a VLAN tag regardless of VID. */ |
336 | 0 | match->flow.vlans[0].tci = htons(VLAN_CFI); |
337 | 0 | match->wc.masks.vlans[0].tci = htons(VLAN_CFI); |
338 | 0 | } else if (ntohs(ofmatch->dl_vlan) < 4096) { |
339 | | /* Match only packets with the specified VLAN VID. */ |
340 | 0 | match->flow.vlans[0].tci = htons(VLAN_CFI) | ofmatch->dl_vlan; |
341 | 0 | match->wc.masks.vlans[0].tci = htons(VLAN_CFI | VLAN_VID_MASK); |
342 | 0 | } else { |
343 | | /* Invalid VID. */ |
344 | 0 | return OFPERR_OFPBMC_BAD_VALUE; |
345 | 0 | } |
346 | | |
347 | 0 | if (!(wc & OFPFW11_DL_VLAN_PCP)) { |
348 | 0 | if (ofmatch->dl_vlan_pcp <= 7) { |
349 | 0 | match->flow.vlans[0].tci |= htons(ofmatch->dl_vlan_pcp |
350 | 0 | << VLAN_PCP_SHIFT); |
351 | 0 | match->wc.masks.vlans[0].tci |= htons(VLAN_PCP_MASK); |
352 | 0 | } else { |
353 | | /* Invalid PCP. */ |
354 | 0 | return OFPERR_OFPBMC_BAD_VALUE; |
355 | 0 | } |
356 | 0 | } |
357 | 0 | } |
358 | 0 | match_set_default_packet_type(match); |
359 | 0 | } |
360 | | |
361 | 0 | if (!(wc & OFPFW11_DL_TYPE)) { |
362 | 0 | match_set_dl_type(match, |
363 | 0 | ofputil_dl_type_from_openflow(ofmatch->dl_type)); |
364 | 0 | match_set_default_packet_type(match); |
365 | 0 | } |
366 | |
|
367 | 0 | ipv4 = match->flow.dl_type == htons(ETH_TYPE_IP); |
368 | 0 | arp = match->flow.dl_type == htons(ETH_TYPE_ARP); |
369 | 0 | rarp = match->flow.dl_type == htons(ETH_TYPE_RARP); |
370 | |
|
371 | 0 | if (ipv4 && !(wc & OFPFW11_NW_TOS)) { |
372 | 0 | if (ofmatch->nw_tos & ~IP_DSCP_MASK) { |
373 | | /* Invalid TOS. */ |
374 | 0 | return OFPERR_OFPBMC_BAD_VALUE; |
375 | 0 | } |
376 | | |
377 | 0 | match_set_nw_dscp(match, ofmatch->nw_tos); |
378 | 0 | } |
379 | | |
380 | 0 | if (ipv4 || arp || rarp) { |
381 | 0 | if (!(wc & OFPFW11_NW_PROTO)) { |
382 | 0 | match_set_nw_proto(match, ofmatch->nw_proto); |
383 | 0 | } |
384 | 0 | match_set_nw_src_masked(match, ofmatch->nw_src, ~ofmatch->nw_src_mask); |
385 | 0 | match_set_nw_dst_masked(match, ofmatch->nw_dst, ~ofmatch->nw_dst_mask); |
386 | 0 | } |
387 | |
|
388 | 0 | #define OFPFW11_TP_ALL (OFPFW11_TP_SRC | OFPFW11_TP_DST) |
389 | 0 | if (ipv4 && (wc & OFPFW11_TP_ALL) != OFPFW11_TP_ALL) { |
390 | 0 | switch (match->flow.nw_proto) { |
391 | 0 | 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 | 0 | if (!(wc & OFPFW11_TP_SRC)) { |
400 | 0 | uint16_t icmp_type = ntohs(ofmatch->tp_src); |
401 | 0 | if (icmp_type < 0x100) { |
402 | 0 | match_set_icmp_type(match, icmp_type); |
403 | 0 | } else { |
404 | 0 | return OFPERR_OFPBMC_BAD_FIELD; |
405 | 0 | } |
406 | 0 | } |
407 | 0 | if (!(wc & OFPFW11_TP_DST)) { |
408 | 0 | uint16_t icmp_code = ntohs(ofmatch->tp_dst); |
409 | 0 | if (icmp_code < 0x100) { |
410 | 0 | match_set_icmp_code(match, icmp_code); |
411 | 0 | } else { |
412 | 0 | return OFPERR_OFPBMC_BAD_FIELD; |
413 | 0 | } |
414 | 0 | } |
415 | 0 | break; |
416 | | |
417 | 0 | case IPPROTO_TCP: |
418 | 0 | case IPPROTO_UDP: |
419 | 0 | case IPPROTO_SCTP: |
420 | 0 | if (!(wc & (OFPFW11_TP_SRC))) { |
421 | 0 | match_set_tp_src(match, ofmatch->tp_src); |
422 | 0 | } |
423 | 0 | if (!(wc & (OFPFW11_TP_DST))) { |
424 | 0 | match_set_tp_dst(match, ofmatch->tp_dst); |
425 | 0 | } |
426 | 0 | break; |
427 | | |
428 | 0 | default: |
429 | | /* OF1.1 says explicitly to ignore this. */ |
430 | 0 | break; |
431 | 0 | } |
432 | 0 | } |
433 | | |
434 | 0 | if (eth_type_mpls(match->flow.dl_type)) { |
435 | 0 | if (!(wc & OFPFW11_MPLS_LABEL)) { |
436 | 0 | match_set_mpls_label(match, 0, ofmatch->mpls_label); |
437 | 0 | } |
438 | 0 | if (!(wc & OFPFW11_MPLS_TC)) { |
439 | 0 | match_set_mpls_tc(match, 0, ofmatch->mpls_tc); |
440 | 0 | } |
441 | 0 | } |
442 | |
|
443 | 0 | match_set_metadata_masked(match, ofmatch->metadata, |
444 | 0 | ~ofmatch->metadata_mask); |
445 | |
|
446 | 0 | return 0; |
447 | 0 | } |
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 | 0 | { |
454 | 0 | uint32_t wc = 0; |
455 | |
|
456 | 0 | memset(ofmatch, 0, sizeof *ofmatch); |
457 | 0 | ofmatch->omh.type = htons(OFPMT_STANDARD); |
458 | 0 | ofmatch->omh.length = htons(OFPMT11_STANDARD_LENGTH); |
459 | |
|
460 | 0 | if (!match->wc.masks.in_port.ofp_port) { |
461 | 0 | wc |= OFPFW11_IN_PORT; |
462 | 0 | } else { |
463 | 0 | ofmatch->in_port = ofputil_port_to_ofp11(match->flow.in_port.ofp_port); |
464 | 0 | } |
465 | |
|
466 | 0 | ofmatch->dl_src = match->flow.dl_src; |
467 | 0 | ofmatch->dl_src_mask = eth_addr_invert(match->wc.masks.dl_src); |
468 | 0 | ofmatch->dl_dst = match->flow.dl_dst; |
469 | 0 | ofmatch->dl_dst_mask = eth_addr_invert(match->wc.masks.dl_dst); |
470 | |
|
471 | 0 | if (match->wc.masks.vlans[0].tci == htons(0)) { |
472 | 0 | wc |= OFPFW11_DL_VLAN | OFPFW11_DL_VLAN_PCP; |
473 | 0 | } else if (match->wc.masks.vlans[0].tci & htons(VLAN_CFI) |
474 | 0 | && !(match->flow.vlans[0].tci & htons(VLAN_CFI))) { |
475 | 0 | ofmatch->dl_vlan = htons(OFPVID11_NONE); |
476 | 0 | wc |= OFPFW11_DL_VLAN_PCP; |
477 | 0 | } else { |
478 | 0 | if (!(match->wc.masks.vlans[0].tci & htons(VLAN_VID_MASK))) { |
479 | 0 | ofmatch->dl_vlan = htons(OFPVID11_ANY); |
480 | 0 | } else { |
481 | 0 | ofmatch->dl_vlan = |
482 | 0 | htons(vlan_tci_to_vid(match->flow.vlans[0].tci)); |
483 | 0 | } |
484 | |
|
485 | 0 | if (!(match->wc.masks.vlans[0].tci & htons(VLAN_PCP_MASK))) { |
486 | 0 | wc |= OFPFW11_DL_VLAN_PCP; |
487 | 0 | } else { |
488 | 0 | ofmatch->dl_vlan_pcp = vlan_tci_to_pcp(match->flow.vlans[0].tci); |
489 | 0 | } |
490 | 0 | } |
491 | |
|
492 | 0 | if (!match->wc.masks.dl_type) { |
493 | 0 | wc |= OFPFW11_DL_TYPE; |
494 | 0 | } else { |
495 | 0 | ofmatch->dl_type = ofputil_dl_type_to_openflow(match->flow.dl_type); |
496 | 0 | } |
497 | |
|
498 | 0 | if (!(match->wc.masks.nw_tos & IP_DSCP_MASK)) { |
499 | 0 | wc |= OFPFW11_NW_TOS; |
500 | 0 | } else { |
501 | 0 | ofmatch->nw_tos = match->flow.nw_tos & IP_DSCP_MASK; |
502 | 0 | } |
503 | |
|
504 | 0 | if (!match->wc.masks.nw_proto) { |
505 | 0 | wc |= OFPFW11_NW_PROTO; |
506 | 0 | } else { |
507 | 0 | ofmatch->nw_proto = match->flow.nw_proto; |
508 | 0 | } |
509 | |
|
510 | 0 | ofmatch->nw_src = match->flow.nw_src; |
511 | 0 | ofmatch->nw_src_mask = ~match->wc.masks.nw_src; |
512 | 0 | ofmatch->nw_dst = match->flow.nw_dst; |
513 | 0 | ofmatch->nw_dst_mask = ~match->wc.masks.nw_dst; |
514 | |
|
515 | 0 | if (!match->wc.masks.tp_src) { |
516 | 0 | wc |= OFPFW11_TP_SRC; |
517 | 0 | } else { |
518 | 0 | ofmatch->tp_src = match->flow.tp_src; |
519 | 0 | } |
520 | |
|
521 | 0 | if (!match->wc.masks.tp_dst) { |
522 | 0 | wc |= OFPFW11_TP_DST; |
523 | 0 | } else { |
524 | 0 | ofmatch->tp_dst = match->flow.tp_dst; |
525 | 0 | } |
526 | |
|
527 | 0 | if (!(match->wc.masks.mpls_lse[0] & htonl(MPLS_LABEL_MASK))) { |
528 | 0 | wc |= OFPFW11_MPLS_LABEL; |
529 | 0 | } else { |
530 | 0 | ofmatch->mpls_label = htonl(mpls_lse_to_label( |
531 | 0 | match->flow.mpls_lse[0])); |
532 | 0 | } |
533 | |
|
534 | 0 | if (!(match->wc.masks.mpls_lse[0] & htonl(MPLS_TC_MASK))) { |
535 | 0 | wc |= OFPFW11_MPLS_TC; |
536 | 0 | } else { |
537 | 0 | ofmatch->mpls_tc = mpls_lse_to_tc(match->flow.mpls_lse[0]); |
538 | 0 | } |
539 | |
|
540 | 0 | ofmatch->metadata = match->flow.metadata; |
541 | 0 | ofmatch->metadata_mask = ~match->wc.masks.metadata; |
542 | |
|
543 | 0 | ofmatch->wildcards = htonl(wc); |
544 | 0 | } |
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 | 0 | { |
551 | 0 | switch (protocol) { |
552 | 0 | case OFPUTIL_P_OF10_STD: |
553 | 0 | case OFPUTIL_P_OF10_STD_TID: |
554 | 0 | return sizeof(struct ofp10_match); |
555 | | |
556 | 0 | case OFPUTIL_P_OF10_NXM: |
557 | 0 | case OFPUTIL_P_OF10_NXM_TID: |
558 | 0 | return NXM_TYPICAL_LEN; |
559 | | |
560 | 0 | case OFPUTIL_P_OF11_STD: |
561 | 0 | return sizeof(struct ofp11_match); |
562 | | |
563 | 0 | case OFPUTIL_P_OF12_OXM: |
564 | 0 | case OFPUTIL_P_OF13_OXM: |
565 | 0 | case OFPUTIL_P_OF14_OXM: |
566 | 0 | case OFPUTIL_P_OF15_OXM: |
567 | 0 | return NXM_TYPICAL_LEN; |
568 | | |
569 | 0 | default: |
570 | 0 | OVS_NOT_REACHED(); |
571 | 0 | } |
572 | 0 | } |
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 | 0 | { |
587 | 0 | switch (protocol) { |
588 | 0 | case OFPUTIL_P_OF10_STD: |
589 | 0 | case OFPUTIL_P_OF10_STD_TID: |
590 | 0 | case OFPUTIL_P_OF10_NXM: |
591 | 0 | case OFPUTIL_P_OF10_NXM_TID: |
592 | 0 | OVS_NOT_REACHED(); |
593 | | |
594 | 0 | case OFPUTIL_P_OF11_STD: { |
595 | 0 | struct ofp11_match *om; |
596 | | |
597 | | /* Make sure that no padding is needed. */ |
598 | 0 | BUILD_ASSERT_DECL(sizeof *om % 8 == 0); |
599 | |
|
600 | 0 | om = ofpbuf_put_uninit(b, sizeof *om); |
601 | 0 | ofputil_match_to_ofp11_match(match, om); |
602 | 0 | return sizeof *om; |
603 | 0 | } |
604 | | |
605 | 0 | case OFPUTIL_P_OF12_OXM: |
606 | 0 | case OFPUTIL_P_OF13_OXM: |
607 | 0 | case OFPUTIL_P_OF14_OXM: |
608 | 0 | case OFPUTIL_P_OF15_OXM: |
609 | 0 | return oxm_put_match(b, match, |
610 | 0 | ofputil_protocol_to_ofp_version(protocol)); |
611 | 0 | } |
612 | | |
613 | 0 | OVS_NOT_REACHED(); |
614 | 0 | } |
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 | 1.93k | { |
622 | 1.93k | return (flow_dl_type == htons(FLOW_DL_TYPE_NONE) |
623 | 1.93k | ? htons(OFP_DL_TYPE_NOT_ETH_TYPE) |
624 | 1.93k | : flow_dl_type); |
625 | 1.93k | } |
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 | 0 | { |
633 | 0 | return (ofp_dl_type == htons(OFP_DL_TYPE_NOT_ETH_TYPE) |
634 | 0 | ? htons(FLOW_DL_TYPE_NONE) |
635 | 0 | : ofp_dl_type); |
636 | 0 | } |
637 | | |
638 | | static void |
639 | | encode_tlv_table_mappings(struct ofpbuf *b, struct ovs_list *mappings) |
640 | 0 | { |
641 | 0 | struct ofputil_tlv_map *map; |
642 | |
|
643 | 0 | LIST_FOR_EACH (map, list_node, mappings) { |
644 | 0 | struct nx_tlv_map *nx_map; |
645 | |
|
646 | 0 | nx_map = ofpbuf_put_zeros(b, sizeof *nx_map); |
647 | 0 | nx_map->option_class = htons(map->option_class); |
648 | 0 | nx_map->option_type = map->option_type; |
649 | 0 | nx_map->option_len = map->option_len; |
650 | 0 | nx_map->index = htons(map->index); |
651 | 0 | } |
652 | 0 | } |
653 | | |
654 | | struct ofpbuf * |
655 | | ofputil_encode_tlv_table_mod(enum ofp_version ofp_version, |
656 | | struct ofputil_tlv_table_mod *ttm) |
657 | 0 | { |
658 | 0 | struct ofpbuf *b; |
659 | 0 | struct nx_tlv_table_mod *nx_ttm; |
660 | |
|
661 | 0 | b = ofpraw_alloc(OFPRAW_NXT_TLV_TABLE_MOD, ofp_version, 0); |
662 | 0 | nx_ttm = ofpbuf_put_zeros(b, sizeof *nx_ttm); |
663 | 0 | nx_ttm->command = htons(ttm->command); |
664 | 0 | encode_tlv_table_mappings(b, &ttm->mappings); |
665 | |
|
666 | 0 | return b; |
667 | 0 | } |
668 | | |
669 | | static enum ofperr |
670 | | decode_tlv_table_mappings(struct ofpbuf *msg, unsigned int max_fields, |
671 | | struct ovs_list *mappings) |
672 | 0 | { |
673 | 0 | ovs_list_init(mappings); |
674 | |
|
675 | 0 | while (msg->size) { |
676 | 0 | struct nx_tlv_map *nx_map; |
677 | 0 | struct ofputil_tlv_map *map; |
678 | |
|
679 | 0 | nx_map = ofpbuf_pull(msg, sizeof *nx_map); |
680 | 0 | map = xmalloc(sizeof *map); |
681 | 0 | ovs_list_push_back(mappings, &map->list_node); |
682 | |
|
683 | 0 | map->option_class = ntohs(nx_map->option_class); |
684 | 0 | map->option_type = nx_map->option_type; |
685 | |
|
686 | 0 | map->option_len = nx_map->option_len; |
687 | 0 | if (map->option_len % 4 || map->option_len > TLV_MAX_OPT_SIZE) { |
688 | 0 | VLOG_WARN_RL(&rl, "tlv table option length (%u) is not a " |
689 | 0 | "valid option size", map->option_len); |
690 | 0 | ofputil_uninit_tlv_table(mappings); |
691 | 0 | return OFPERR_NXTTMFC_BAD_OPT_LEN; |
692 | 0 | } |
693 | | |
694 | 0 | map->index = ntohs(nx_map->index); |
695 | 0 | if (map->index >= max_fields) { |
696 | 0 | VLOG_WARN_RL(&rl, "tlv table field index (%u) is too large " |
697 | 0 | "(max %u)", map->index, max_fields - 1); |
698 | 0 | ofputil_uninit_tlv_table(mappings); |
699 | 0 | return OFPERR_NXTTMFC_BAD_FIELD_IDX; |
700 | 0 | } |
701 | 0 | } |
702 | | |
703 | 0 | return 0; |
704 | 0 | } |
705 | | |
706 | | enum ofperr |
707 | | ofputil_decode_tlv_table_mod(const struct ofp_header *oh, |
708 | | struct ofputil_tlv_table_mod *ttm) |
709 | 0 | { |
710 | 0 | struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
711 | 0 | ofpraw_pull_assert(&msg); |
712 | |
|
713 | 0 | struct nx_tlv_table_mod *nx_ttm = ofpbuf_pull(&msg, sizeof *nx_ttm); |
714 | 0 | ttm->command = ntohs(nx_ttm->command); |
715 | 0 | if (ttm->command > NXTTMC_CLEAR) { |
716 | 0 | VLOG_WARN_RL(&rl, "tlv table mod command (%u) is out of range", |
717 | 0 | ttm->command); |
718 | 0 | return OFPERR_NXTTMFC_BAD_COMMAND; |
719 | 0 | } |
720 | | |
721 | 0 | return decode_tlv_table_mappings(&msg, TUN_METADATA_NUM_OPTS, |
722 | 0 | &ttm->mappings); |
723 | 0 | } |
724 | | |
725 | | static void |
726 | | print_tlv_table(struct ds *s, const struct ovs_list *mappings) |
727 | 0 | { |
728 | 0 | struct ofputil_tlv_map *map; |
729 | |
|
730 | 0 | ds_put_cstr(s, " mapping table:\n"); |
731 | 0 | ds_put_cstr(s, " class type length match field\n"); |
732 | 0 | ds_put_cstr(s, " ------ ---- ------ --------------"); |
733 | |
|
734 | 0 | LIST_FOR_EACH (map, list_node, mappings) { |
735 | 0 | ds_put_format(s, "\n %#6"PRIx16" %#4"PRIx8" %6"PRIu8" " |
736 | 0 | "tun_metadata%"PRIu16, |
737 | 0 | map->option_class, map->option_type, map->option_len, |
738 | 0 | map->index); |
739 | 0 | } |
740 | 0 | } |
741 | | |
742 | | void |
743 | | ofputil_format_tlv_table_mod(struct ds *s, |
744 | | const struct ofputil_tlv_table_mod *ttm) |
745 | 0 | { |
746 | 0 | ds_put_cstr(s, "\n "); |
747 | |
|
748 | 0 | switch (ttm->command) { |
749 | 0 | case NXTTMC_ADD: |
750 | 0 | ds_put_cstr(s, "ADD"); |
751 | 0 | break; |
752 | 0 | case NXTTMC_DELETE: |
753 | 0 | ds_put_cstr(s, "DEL"); |
754 | 0 | break; |
755 | 0 | case NXTTMC_CLEAR: |
756 | 0 | ds_put_cstr(s, "CLEAR"); |
757 | 0 | break; |
758 | 0 | } |
759 | | |
760 | 0 | if (ttm->command != NXTTMC_CLEAR) { |
761 | 0 | print_tlv_table(s, &ttm->mappings); |
762 | 0 | } |
763 | 0 | } |
764 | | |
765 | | struct ofpbuf * |
766 | | ofputil_encode_tlv_table_reply(const struct ofp_header *oh, |
767 | | struct ofputil_tlv_table_reply *ttr) |
768 | 0 | { |
769 | 0 | struct ofpbuf *b; |
770 | 0 | struct nx_tlv_table_reply *nx_ttr; |
771 | |
|
772 | 0 | b = ofpraw_alloc_reply(OFPRAW_NXT_TLV_TABLE_REPLY, oh, 0); |
773 | 0 | nx_ttr = ofpbuf_put_zeros(b, sizeof *nx_ttr); |
774 | 0 | nx_ttr->max_option_space = htonl(ttr->max_option_space); |
775 | 0 | nx_ttr->max_fields = htons(ttr->max_fields); |
776 | |
|
777 | 0 | encode_tlv_table_mappings(b, &ttr->mappings); |
778 | |
|
779 | 0 | return b; |
780 | 0 | } |
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 | 0 | { |
792 | 0 | struct ofpbuf msg = ofpbuf_const_initializer(oh, ntohs(oh->length)); |
793 | 0 | ofpraw_pull_assert(&msg); |
794 | |
|
795 | 0 | struct nx_tlv_table_reply *nx_ttr = ofpbuf_pull(&msg, sizeof *nx_ttr); |
796 | 0 | ttr->max_option_space = ntohl(nx_ttr->max_option_space); |
797 | 0 | ttr->max_fields = ntohs(nx_ttr->max_fields); |
798 | |
|
799 | 0 | return decode_tlv_table_mappings(&msg, ttr->max_fields, &ttr->mappings); |
800 | 0 | } |
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 | 0 | { |
807 | 0 | *usable_protocols = OFPUTIL_P_NXM_OXM_ANY; |
808 | |
|
809 | 0 | ttm->command = command; |
810 | 0 | ovs_list_init(&ttm->mappings); |
811 | |
|
812 | 0 | while (*s) { |
813 | 0 | struct ofputil_tlv_map *map = xmalloc(sizeof *map); |
814 | 0 | int n; |
815 | |
|
816 | 0 | if (*s == ',') { |
817 | 0 | s++; |
818 | 0 | } |
819 | |
|
820 | 0 | ovs_list_push_back(&ttm->mappings, &map->list_node); |
821 | |
|
822 | 0 | if (!ovs_scan(s, "{class=%"SCNi16",type=%"SCNi8",len=%"SCNi8"}" |
823 | 0 | "->tun_metadata%"SCNi16"%n", |
824 | 0 | &map->option_class, &map->option_type, &map->option_len, |
825 | 0 | &map->index, &n)) { |
826 | 0 | ofputil_uninit_tlv_table(&ttm->mappings); |
827 | 0 | return xstrdup("invalid tlv mapping"); |
828 | 0 | } |
829 | | |
830 | 0 | s += n; |
831 | 0 | } |
832 | | |
833 | 0 | return NULL; |
834 | 0 | } |
835 | | |
836 | | void |
837 | | ofputil_format_tlv_table_reply(struct ds *s, |
838 | | const struct ofputil_tlv_table_reply *ttr) |
839 | 0 | { |
840 | 0 | ds_put_char(s, '\n'); |
841 | |
|
842 | 0 | const struct ofputil_tlv_map *map; |
843 | 0 | int allocated_space = 0; |
844 | 0 | LIST_FOR_EACH (map, list_node, &ttr->mappings) { |
845 | 0 | allocated_space += map->option_len; |
846 | 0 | } |
847 | |
|
848 | 0 | ds_put_format(s, " max option space=%"PRIu32" max fields=%"PRIu16"\n", |
849 | 0 | ttr->max_option_space, ttr->max_fields); |
850 | 0 | ds_put_format(s, " allocated option space=%d\n", allocated_space); |
851 | 0 | ds_put_char(s, '\n'); |
852 | 0 | print_tlv_table(s, &ttr->mappings); |
853 | 0 | } |
854 | | |
855 | | void |
856 | | ofputil_uninit_tlv_table(struct ovs_list *mappings) |
857 | 0 | { |
858 | 0 | struct ofputil_tlv_map *map; |
859 | |
|
860 | 0 | LIST_FOR_EACH_POP (map, list_node, mappings) { |
861 | 0 | free(map); |
862 | 0 | } |
863 | 0 | } |
864 | | |
865 | | static void |
866 | | ofputil_normalize_match__(struct match *match, bool may_log) |
867 | 0 | { |
868 | 0 | enum { |
869 | 0 | MAY_NW_ADDR = 1 << 0, /* nw_src, nw_dst */ |
870 | 0 | MAY_TP_ADDR = 1 << 1, /* tp_src, tp_dst */ |
871 | 0 | MAY_NW_PROTO = 1 << 2, /* nw_proto */ |
872 | 0 | MAY_IPVx = 1 << 3, /* tos, frag, ttl */ |
873 | 0 | MAY_ARP_SHA = 1 << 4, /* arp_sha */ |
874 | 0 | MAY_ARP_THA = 1 << 5, /* arp_tha */ |
875 | 0 | MAY_IPV6 = 1 << 6, /* ipv6_src, ipv6_dst, ipv6_label */ |
876 | 0 | MAY_ND_TARGET = 1 << 7, /* nd_target */ |
877 | 0 | MAY_MPLS = 1 << 8, /* mpls label and tc */ |
878 | 0 | MAY_ETHER = 1 << 9, /* dl_src, dl_dst */ |
879 | 0 | } may_match; |
880 | |
|
881 | 0 | struct flow_wildcards wc = match->wc; |
882 | 0 | ovs_be16 dl_type; |
883 | | |
884 | | /* Figure out what fields may be matched. */ |
885 | | /* Check the packet_type first and extract dl_type. */ |
886 | 0 | if (wc.masks.packet_type == 0 || match_has_default_packet_type(match)) { |
887 | 0 | may_match = MAY_ETHER; |
888 | 0 | dl_type = match->flow.dl_type; |
889 | 0 | } else if (wc.masks.packet_type == OVS_BE32_MAX && |
890 | 0 | pt_ns(match->flow.packet_type) == OFPHTN_ETHERTYPE) { |
891 | 0 | may_match = 0; |
892 | 0 | dl_type = pt_ns_type_be(match->flow.packet_type); |
893 | 0 | } else { |
894 | 0 | may_match = 0; |
895 | 0 | dl_type = 0; |
896 | 0 | } |
897 | 0 | if (dl_type == htons(ETH_TYPE_IP)) { |
898 | 0 | may_match |= MAY_NW_PROTO | MAY_IPVx | MAY_NW_ADDR; |
899 | 0 | if (match->flow.nw_proto == IPPROTO_TCP || |
900 | 0 | match->flow.nw_proto == IPPROTO_UDP || |
901 | 0 | match->flow.nw_proto == IPPROTO_SCTP || |
902 | 0 | match->flow.nw_proto == IPPROTO_ICMP) { |
903 | 0 | may_match |= MAY_TP_ADDR; |
904 | 0 | } |
905 | 0 | } else if (dl_type == htons(ETH_TYPE_IPV6)) { |
906 | 0 | may_match |= MAY_NW_PROTO | MAY_IPVx | MAY_IPV6; |
907 | 0 | if (match->flow.nw_proto == IPPROTO_TCP || |
908 | 0 | match->flow.nw_proto == IPPROTO_UDP || |
909 | 0 | match->flow.nw_proto == IPPROTO_SCTP) { |
910 | 0 | may_match |= MAY_TP_ADDR; |
911 | 0 | } else if (match->flow.nw_proto == IPPROTO_ICMPV6) { |
912 | 0 | may_match |= MAY_TP_ADDR; |
913 | 0 | if (match->flow.tp_src == htons(ND_NEIGHBOR_SOLICIT)) { |
914 | 0 | may_match |= MAY_ND_TARGET | MAY_ARP_SHA; |
915 | 0 | } else if (match->flow.tp_src == htons(ND_NEIGHBOR_ADVERT)) { |
916 | 0 | may_match |= MAY_ND_TARGET | MAY_ARP_THA; |
917 | 0 | } |
918 | 0 | } |
919 | 0 | } else if (dl_type == htons(ETH_TYPE_ARP) || |
920 | 0 | dl_type == htons(ETH_TYPE_RARP)) { |
921 | 0 | may_match |= MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA; |
922 | 0 | } else if (eth_type_mpls(dl_type)) { |
923 | 0 | may_match |= MAY_MPLS; |
924 | 0 | } |
925 | | |
926 | | /* Clear the fields that may not be matched. */ |
927 | 0 | if (!(may_match & MAY_ETHER)) { |
928 | 0 | wc.masks.dl_src = wc.masks.dl_dst = eth_addr_zero; |
929 | 0 | } |
930 | 0 | if (!(may_match & MAY_NW_ADDR)) { |
931 | 0 | wc.masks.nw_src = wc.masks.nw_dst = htonl(0); |
932 | 0 | } |
933 | 0 | if (!(may_match & MAY_TP_ADDR)) { |
934 | 0 | wc.masks.tp_src = wc.masks.tp_dst = htons(0); |
935 | 0 | } |
936 | 0 | if (!(may_match & MAY_NW_PROTO)) { |
937 | 0 | wc.masks.nw_proto = 0; |
938 | 0 | } |
939 | 0 | if (!(may_match & MAY_IPVx)) { |
940 | 0 | wc.masks.nw_tos = 0; |
941 | 0 | wc.masks.nw_ttl = 0; |
942 | 0 | } |
943 | 0 | if (!(may_match & MAY_ARP_SHA)) { |
944 | 0 | WC_UNMASK_FIELD(&wc, arp_sha); |
945 | 0 | } |
946 | 0 | if (!(may_match & MAY_ARP_THA)) { |
947 | 0 | WC_UNMASK_FIELD(&wc, arp_tha); |
948 | 0 | } |
949 | 0 | if (!(may_match & MAY_IPV6)) { |
950 | 0 | wc.masks.ipv6_src = wc.masks.ipv6_dst = in6addr_any; |
951 | 0 | wc.masks.ipv6_label = htonl(0); |
952 | 0 | } |
953 | 0 | if (!(may_match & MAY_ND_TARGET)) { |
954 | 0 | wc.masks.nd_target = in6addr_any; |
955 | 0 | } |
956 | 0 | if (!(may_match & MAY_MPLS)) { |
957 | 0 | memset(wc.masks.mpls_lse, 0, sizeof wc.masks.mpls_lse); |
958 | 0 | } |
959 | | |
960 | | /* Log any changes. */ |
961 | 0 | if (!flow_wildcards_equal(&wc, &match->wc)) { |
962 | 0 | bool log = may_log && !VLOG_DROP_INFO(&rl); |
963 | 0 | char *pre = (log |
964 | 0 | ? match_to_string(match, NULL, OFP_DEFAULT_PRIORITY) |
965 | 0 | : NULL); |
966 | |
|
967 | 0 | match->wc = wc; |
968 | 0 | match_zero_wildcarded_fields(match); |
969 | |
|
970 | 0 | if (log) { |
971 | 0 | char *post = match_to_string(match, NULL, OFP_DEFAULT_PRIORITY); |
972 | 0 | VLOG_INFO("normalization changed ofp_match, details:"); |
973 | 0 | VLOG_INFO(" pre: %s", pre); |
974 | 0 | VLOG_INFO("post: %s", post); |
975 | 0 | free(pre); |
976 | 0 | free(post); |
977 | 0 | } |
978 | 0 | } |
979 | 0 | } |
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 | 0 | { |
1001 | 0 | ofputil_normalize_match__(match, true); |
1002 | 0 | } |
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 | 0 | { |
1011 | 0 | ofputil_normalize_match__(match, false); |
1012 | 0 | } |
1013 | | |
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 | 0 | { |
1018 | 0 | if (is_wild && verbosity < 2) { |
1019 | 0 | return; |
1020 | 0 | } |
1021 | 0 | ds_put_cstr(string, leader); |
1022 | 0 | if (!is_wild) { |
1023 | 0 | va_list args; |
1024 | |
|
1025 | 0 | va_start(args, format); |
1026 | 0 | ds_put_format_valist(string, format, args); |
1027 | 0 | va_end(args); |
1028 | 0 | } else { |
1029 | 0 | ds_put_char(string, '*'); |
1030 | 0 | } |
1031 | 0 | ds_put_char(string, ','); |
1032 | 0 | } |
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 | 0 | { |
1039 | 0 | if (is_wild && verbosity < 2) { |
1040 | 0 | return; |
1041 | 0 | } |
1042 | 0 | ds_put_cstr(string, leader); |
1043 | 0 | if (!is_wild) { |
1044 | 0 | ofputil_format_port(port, port_map, string); |
1045 | 0 | } else { |
1046 | 0 | ds_put_char(string, '*'); |
1047 | 0 | } |
1048 | 0 | ds_put_char(string, ','); |
1049 | 0 | } |
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 | 0 | { |
1055 | 0 | if (wild_bits >= 32 && verbosity < 2) { |
1056 | 0 | return; |
1057 | 0 | } |
1058 | 0 | ds_put_cstr(string, leader); |
1059 | 0 | if (wild_bits < 32) { |
1060 | 0 | ds_put_format(string, IP_FMT, IP_ARGS(ip)); |
1061 | 0 | if (wild_bits) { |
1062 | 0 | ds_put_format(string, "/%d", 32 - wild_bits); |
1063 | 0 | } |
1064 | 0 | } else { |
1065 | 0 | ds_put_char(string, '*'); |
1066 | 0 | } |
1067 | 0 | ds_put_char(string, ','); |
1068 | 0 | } |
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 | 0 | { |
1074 | 0 | char *s = ofp10_match_to_string(om, port_map, verbosity); |
1075 | 0 | ds_put_cstr(f, s); |
1076 | 0 | free(s); |
1077 | 0 | } |
1078 | | |
1079 | | char * |
1080 | | ofp10_match_to_string(const struct ofp10_match *om, |
1081 | | const struct ofputil_port_map *port_map, int verbosity) |
1082 | 0 | { |
1083 | 0 | struct ds f = DS_EMPTY_INITIALIZER; |
1084 | 0 | uint32_t w = ntohl(om->wildcards); |
1085 | 0 | bool skip_type = false; |
1086 | 0 | bool skip_proto = false; |
1087 | |
|
1088 | 0 | if (!(w & OFPFW10_DL_TYPE)) { |
1089 | 0 | skip_type = true; |
1090 | 0 | if (om->dl_type == htons(ETH_TYPE_IP)) { |
1091 | 0 | if (!(w & OFPFW10_NW_PROTO)) { |
1092 | 0 | skip_proto = true; |
1093 | 0 | if (om->nw_proto == IPPROTO_ICMP) { |
1094 | 0 | ds_put_cstr(&f, "icmp,"); |
1095 | 0 | } else if (om->nw_proto == IPPROTO_TCP) { |
1096 | 0 | ds_put_cstr(&f, "tcp,"); |
1097 | 0 | } else if (om->nw_proto == IPPROTO_UDP) { |
1098 | 0 | ds_put_cstr(&f, "udp,"); |
1099 | 0 | } else if (om->nw_proto == IPPROTO_SCTP) { |
1100 | 0 | ds_put_cstr(&f, "sctp,"); |
1101 | 0 | } else { |
1102 | 0 | ds_put_cstr(&f, "ip,"); |
1103 | 0 | skip_proto = false; |
1104 | 0 | } |
1105 | 0 | } else { |
1106 | 0 | ds_put_cstr(&f, "ip,"); |
1107 | 0 | } |
1108 | 0 | } else if (om->dl_type == htons(ETH_TYPE_ARP)) { |
1109 | 0 | ds_put_cstr(&f, "arp,"); |
1110 | 0 | } else if (om->dl_type == htons(ETH_TYPE_RARP)){ |
1111 | 0 | ds_put_cstr(&f, "rarp,"); |
1112 | 0 | } else if (om->dl_type == htons(ETH_TYPE_MPLS)) { |
1113 | 0 | ds_put_cstr(&f, "mpls,"); |
1114 | 0 | } else if (om->dl_type == htons(ETH_TYPE_MPLS_MCAST)) { |
1115 | 0 | ds_put_cstr(&f, "mplsm,"); |
1116 | 0 | } else { |
1117 | 0 | skip_type = false; |
1118 | 0 | } |
1119 | 0 | } |
1120 | 0 | print_wild_port(&f, "in_port=", w & OFPFW10_IN_PORT, verbosity, |
1121 | 0 | u16_to_ofp(ntohs(om->in_port)), port_map); |
1122 | 0 | print_wild(&f, "dl_vlan=", w & OFPFW10_DL_VLAN, verbosity, |
1123 | 0 | "%d", ntohs(om->dl_vlan)); |
1124 | 0 | print_wild(&f, "dl_vlan_pcp=", w & OFPFW10_DL_VLAN_PCP, verbosity, |
1125 | 0 | "%d", om->dl_vlan_pcp); |
1126 | 0 | print_wild(&f, "dl_src=", w & OFPFW10_DL_SRC, verbosity, |
1127 | 0 | ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_src)); |
1128 | 0 | print_wild(&f, "dl_dst=", w & OFPFW10_DL_DST, verbosity, |
1129 | 0 | ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_dst)); |
1130 | 0 | if (!skip_type) { |
1131 | 0 | print_wild(&f, "dl_type=", w & OFPFW10_DL_TYPE, verbosity, |
1132 | 0 | "0x%04x", ntohs(om->dl_type)); |
1133 | 0 | } |
1134 | 0 | print_ip_netmask(&f, "nw_src=", om->nw_src, |
1135 | 0 | (w & OFPFW10_NW_SRC_MASK) >> OFPFW10_NW_SRC_SHIFT, |
1136 | 0 | verbosity); |
1137 | 0 | print_ip_netmask(&f, "nw_dst=", om->nw_dst, |
1138 | 0 | (w & OFPFW10_NW_DST_MASK) >> OFPFW10_NW_DST_SHIFT, |
1139 | 0 | verbosity); |
1140 | 0 | if (!skip_proto) { |
1141 | 0 | if (om->dl_type == htons(ETH_TYPE_ARP) || |
1142 | 0 | om->dl_type == htons(ETH_TYPE_RARP)) { |
1143 | 0 | print_wild(&f, "arp_op=", w & OFPFW10_NW_PROTO, verbosity, |
1144 | 0 | "%u", om->nw_proto); |
1145 | 0 | } else { |
1146 | 0 | print_wild(&f, "nw_proto=", w & OFPFW10_NW_PROTO, verbosity, |
1147 | 0 | "%u", om->nw_proto); |
1148 | 0 | } |
1149 | 0 | } |
1150 | 0 | print_wild(&f, "nw_tos=", w & OFPFW10_NW_TOS, verbosity, |
1151 | 0 | "%u", om->nw_tos); |
1152 | 0 | if (om->nw_proto == IPPROTO_ICMP) { |
1153 | 0 | print_wild(&f, "icmp_type=", w & OFPFW10_ICMP_TYPE, verbosity, |
1154 | 0 | "%d", ntohs(om->tp_src)); |
1155 | 0 | print_wild(&f, "icmp_code=", w & OFPFW10_ICMP_CODE, verbosity, |
1156 | 0 | "%d", ntohs(om->tp_dst)); |
1157 | 0 | } else { |
1158 | 0 | print_wild(&f, "tp_src=", w & OFPFW10_TP_SRC, verbosity, |
1159 | 0 | "%d", ntohs(om->tp_src)); |
1160 | 0 | print_wild(&f, "tp_dst=", w & OFPFW10_TP_DST, verbosity, |
1161 | 0 | "%d", ntohs(om->tp_dst)); |
1162 | 0 | } |
1163 | 0 | ds_chomp(&f, ','); |
1164 | 0 | return ds_cstr(&f); |
1165 | 0 | } |
1166 | | |