]>
Commit | Line | Data |
---|---|---|
b9e8b45a | 1 | /* |
e0edde6f | 2 | * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc. |
b9e8b45a BP |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | */ | |
16 | ||
17 | #include <config.h> | |
18 | #include "packets.h" | |
d31f1109 JP |
19 | #include <assert.h> |
20 | #include <arpa/inet.h> | |
6ca00f6f | 21 | #include <sys/socket.h> |
b9e8b45a | 22 | #include <netinet/in.h> |
76343538 | 23 | #include <stdlib.h> |
d31f1109 | 24 | #include "byte-order.h" |
c97664b3 | 25 | #include "csum.h" |
12113c39 | 26 | #include "flow.h" |
7d48a4cc | 27 | #include "hmap.h" |
d31f1109 | 28 | #include "dynamic-string.h" |
b9e8b45a BP |
29 | #include "ofpbuf.h" |
30 | ||
d31f1109 JP |
31 | const struct in6_addr in6addr_exact = IN6ADDR_EXACT_INIT; |
32 | ||
093ca5b3 BP |
33 | /* Parses 's' as a 16-digit hexadecimal number representing a datapath ID. On |
34 | * success stores the dpid into '*dpidp' and returns true, on failure stores 0 | |
35 | * into '*dpidp' and returns false. | |
36 | * | |
37 | * Rejects an all-zeros dpid as invalid. */ | |
76343538 BP |
38 | bool |
39 | dpid_from_string(const char *s, uint64_t *dpidp) | |
40 | { | |
b123cc3c | 41 | *dpidp = (strlen(s) == 16 && strspn(s, "0123456789abcdefABCDEF") == 16 |
093ca5b3 | 42 | ? strtoull(s, NULL, 16) |
76343538 BP |
43 | : 0); |
44 | return *dpidp != 0; | |
45 | } | |
46 | ||
7d48a4cc BP |
47 | /* Returns true if 'ea' is a reserved address, that a bridge must never |
48 | * forward, false otherwise. | |
05be4e2c EJ |
49 | * |
50 | * If you change this function's behavior, please update corresponding | |
51 | * documentation in vswitch.xml at the same time. */ | |
52 | bool | |
53 | eth_addr_is_reserved(const uint8_t ea[ETH_ADDR_LEN]) | |
54 | { | |
7d48a4cc BP |
55 | struct eth_addr_node { |
56 | struct hmap_node hmap_node; | |
57 | uint64_t ea64; | |
05be4e2c EJ |
58 | }; |
59 | ||
7d48a4cc BP |
60 | static struct eth_addr_node nodes[] = { |
61 | /* STP, IEEE pause frames, and other reserved protocols. */ | |
62 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000000ULL }, | |
63 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000001ULL }, | |
64 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000002ULL }, | |
65 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000003ULL }, | |
66 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000004ULL }, | |
67 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000005ULL }, | |
68 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000006ULL }, | |
69 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000007ULL }, | |
70 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000008ULL }, | |
71 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c2000009ULL }, | |
72 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c200000aULL }, | |
73 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c200000bULL }, | |
74 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c200000cULL }, | |
75 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c200000dULL }, | |
76 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c200000eULL }, | |
77 | { HMAP_NODE_NULL_INITIALIZER, 0x0108c200000fULL }, | |
78 | ||
79 | /* Extreme protocols. */ | |
80 | { HMAP_NODE_NULL_INITIALIZER, 0x00e02b000000ULL }, /* EDP. */ | |
81 | { HMAP_NODE_NULL_INITIALIZER, 0x00e02b000004ULL }, /* EAPS. */ | |
82 | { HMAP_NODE_NULL_INITIALIZER, 0x00e02b000006ULL }, /* EAPS. */ | |
83 | ||
84 | /* Cisco protocols. */ | |
85 | { HMAP_NODE_NULL_INITIALIZER, 0x01000c000000ULL }, /* ISL. */ | |
86 | { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccccULL }, /* PAgP, UDLD, CDP, | |
87 | * DTP, VTP. */ | |
88 | { HMAP_NODE_NULL_INITIALIZER, 0x01000ccccccdULL }, /* PVST+. */ | |
89 | { HMAP_NODE_NULL_INITIALIZER, 0x01000ccdcdcdULL }, /* STP Uplink Fast, | |
90 | * FlexLink. */ | |
91 | ||
92 | /* Cisco CFM. */ | |
93 | { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc0ULL }, | |
94 | { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc1ULL }, | |
95 | { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc2ULL }, | |
96 | { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc3ULL }, | |
97 | { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc4ULL }, | |
98 | { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc5ULL }, | |
99 | { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc6ULL }, | |
100 | { HMAP_NODE_NULL_INITIALIZER, 0x01000cccccc7ULL }, | |
101 | }; | |
05be4e2c | 102 | |
7d48a4cc BP |
103 | static struct hmap addrs = HMAP_INITIALIZER(&addrs); |
104 | struct eth_addr_node *node; | |
105 | uint64_t ea64; | |
05be4e2c | 106 | |
7d48a4cc BP |
107 | if (hmap_is_empty(&addrs)) { |
108 | for (node = nodes; node < &nodes[ARRAY_SIZE(nodes)]; node++) { | |
109 | hmap_insert(&addrs, &node->hmap_node, | |
110 | hash_2words(node->ea64, node->ea64 >> 32)); | |
111 | } | |
112 | } | |
05be4e2c | 113 | |
7d48a4cc BP |
114 | ea64 = eth_addr_to_uint64(ea); |
115 | HMAP_FOR_EACH_IN_BUCKET (node, hmap_node, hash_2words(ea64, ea64 >> 32), | |
116 | &addrs) { | |
117 | if (node->ea64 == ea64) { | |
05be4e2c EJ |
118 | return true; |
119 | } | |
120 | } | |
121 | return false; | |
122 | } | |
123 | ||
76343538 BP |
124 | bool |
125 | eth_addr_from_string(const char *s, uint8_t ea[ETH_ADDR_LEN]) | |
126 | { | |
127 | if (sscanf(s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea)) | |
128 | == ETH_ADDR_SCAN_COUNT) { | |
129 | return true; | |
130 | } else { | |
131 | memset(ea, 0, ETH_ADDR_LEN); | |
132 | return false; | |
133 | } | |
134 | } | |
135 | ||
38f7147c | 136 | /* Fills 'b' with a Reverse ARP packet with Ethernet source address 'eth_src'. |
b9e8b45a | 137 | * This function is used by Open vSwitch to compose packets in cases where |
38f7147c EJ |
138 | * context is important but content doesn't (or shouldn't) matter. |
139 | * | |
140 | * The returned packet has enough headroom to insert an 802.1Q VLAN header if | |
141 | * desired. */ | |
b9e8b45a | 142 | void |
2ea838ac | 143 | compose_rarp(struct ofpbuf *b, const uint8_t eth_src[ETH_ADDR_LEN]) |
b9e8b45a | 144 | { |
38f7147c | 145 | struct eth_header *eth; |
7cb57d10 | 146 | struct arp_eth_header *arp; |
b9e8b45a | 147 | |
38f7147c EJ |
148 | ofpbuf_clear(b); |
149 | ofpbuf_prealloc_tailroom(b, ETH_HEADER_LEN + VLAN_HEADER_LEN | |
7cb57d10 | 150 | + ARP_ETH_HEADER_LEN); |
38f7147c EJ |
151 | ofpbuf_reserve(b, VLAN_HEADER_LEN); |
152 | eth = ofpbuf_put_uninit(b, sizeof *eth); | |
153 | memcpy(eth->eth_dst, eth_addr_broadcast, ETH_ADDR_LEN); | |
154 | memcpy(eth->eth_src, eth_src, ETH_ADDR_LEN); | |
155 | eth->eth_type = htons(ETH_TYPE_RARP); | |
156 | ||
7cb57d10 EJ |
157 | arp = ofpbuf_put_uninit(b, sizeof *arp); |
158 | arp->ar_hrd = htons(ARP_HRD_ETHERNET); | |
159 | arp->ar_pro = htons(ARP_PRO_IP); | |
160 | arp->ar_hln = sizeof arp->ar_sha; | |
161 | arp->ar_pln = sizeof arp->ar_spa; | |
162 | arp->ar_op = htons(ARP_OP_RARP); | |
163 | memcpy(arp->ar_sha, eth_src, ETH_ADDR_LEN); | |
164 | arp->ar_spa = htonl(0); | |
165 | memcpy(arp->ar_tha, eth_src, ETH_ADDR_LEN); | |
166 | arp->ar_tpa = htonl(0); | |
b9e8b45a | 167 | } |
d31f1109 | 168 | |
d9065a90 | 169 | /* Insert VLAN header according to given TCI. Packet passed must be Ethernet |
2f4ca41b | 170 | * packet. Ignores the CFI bit of 'tci' using 0 instead. |
7c66b273 BP |
171 | * |
172 | * Also sets 'packet->l2' to point to the new Ethernet header. */ | |
173 | void | |
d9065a90 | 174 | eth_push_vlan(struct ofpbuf *packet, ovs_be16 tci) |
7c66b273 BP |
175 | { |
176 | struct eth_header *eh = packet->data; | |
177 | struct vlan_eth_header *veh; | |
178 | ||
d9065a90 PS |
179 | /* Insert new 802.1Q header. */ |
180 | struct vlan_eth_header tmp; | |
181 | memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN); | |
182 | memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN); | |
183 | tmp.veth_type = htons(ETH_TYPE_VLAN); | |
2f4ca41b | 184 | tmp.veth_tci = tci & htons(~VLAN_CFI); |
d9065a90 PS |
185 | tmp.veth_next_type = eh->eth_type; |
186 | ||
187 | veh = ofpbuf_push_uninit(packet, VLAN_HEADER_LEN); | |
188 | memcpy(veh, &tmp, sizeof tmp); | |
7c66b273 | 189 | |
7c66b273 BP |
190 | packet->l2 = packet->data; |
191 | } | |
192 | ||
f4ebc25e BP |
193 | /* Removes outermost VLAN header (if any is present) from 'packet'. |
194 | * | |
195 | * 'packet->l2' must initially point to 'packet''s Ethernet header. */ | |
196 | void | |
197 | eth_pop_vlan(struct ofpbuf *packet) | |
198 | { | |
199 | struct vlan_eth_header *veh = packet->l2; | |
200 | if (packet->size >= sizeof *veh | |
201 | && veh->veth_type == htons(ETH_TYPE_VLAN)) { | |
202 | struct eth_header tmp; | |
203 | ||
204 | memcpy(tmp.eth_dst, veh->veth_dst, ETH_ADDR_LEN); | |
205 | memcpy(tmp.eth_src, veh->veth_src, ETH_ADDR_LEN); | |
206 | tmp.eth_type = veh->veth_next_type; | |
207 | ||
208 | ofpbuf_pull(packet, VLAN_HEADER_LEN); | |
209 | packet->l2 = (char*)packet->l2 + VLAN_HEADER_LEN; | |
210 | memcpy(packet->data, &tmp, sizeof tmp); | |
211 | } | |
212 | } | |
213 | ||
e22f1753 BP |
214 | /* Converts hex digits in 'hex' to an Ethernet packet in '*packetp'. The |
215 | * caller must free '*packetp'. On success, returns NULL. On failure, returns | |
216 | * an error message and stores NULL in '*packetp'. */ | |
217 | const char * | |
218 | eth_from_hex(const char *hex, struct ofpbuf **packetp) | |
219 | { | |
220 | struct ofpbuf *packet; | |
221 | ||
222 | packet = *packetp = ofpbuf_new(strlen(hex) / 2); | |
223 | ||
224 | if (ofpbuf_put_hex(packet, hex, NULL)[0] != '\0') { | |
225 | ofpbuf_delete(packet); | |
226 | *packetp = NULL; | |
227 | return "Trailing garbage in packet data"; | |
228 | } | |
229 | ||
230 | if (packet->size < ETH_HEADER_LEN) { | |
231 | ofpbuf_delete(packet); | |
232 | *packetp = NULL; | |
233 | return "Packet data too short for Ethernet"; | |
234 | } | |
235 | ||
236 | return NULL; | |
237 | } | |
238 | ||
3b4d8ad3 JS |
239 | void |
240 | eth_format_masked(const uint8_t eth[ETH_ADDR_LEN], | |
241 | const uint8_t mask[ETH_ADDR_LEN], struct ds *s) | |
242 | { | |
243 | ds_put_format(s, ETH_ADDR_FMT, ETH_ADDR_ARGS(eth)); | |
73c0ce34 | 244 | if (mask && !eth_mask_is_exact(mask)) { |
3b4d8ad3 JS |
245 | ds_put_format(s, "/"ETH_ADDR_FMT, ETH_ADDR_ARGS(mask)); |
246 | } | |
247 | } | |
248 | ||
249 | void | |
250 | eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN], | |
251 | const uint8_t mask[ETH_ADDR_LEN], | |
252 | uint8_t dst[ETH_ADDR_LEN]) | |
253 | { | |
254 | int i; | |
255 | ||
256 | for (i = 0; i < ETH_ADDR_LEN; i++) { | |
257 | dst[i] = src[i] & mask[i]; | |
258 | } | |
259 | } | |
260 | ||
aad29cd1 | 261 | /* Given the IP netmask 'netmask', returns the number of bits of the IP address |
c08201d6 BP |
262 | * that it specifies, that is, the number of 1-bits in 'netmask'. |
263 | * | |
264 | * If 'netmask' is not a CIDR netmask (see ip_is_cidr()), the return value will | |
265 | * still be in the valid range but isn't otherwise meaningful. */ | |
aad29cd1 BP |
266 | int |
267 | ip_count_cidr_bits(ovs_be32 netmask) | |
268 | { | |
aad29cd1 BP |
269 | return 32 - ctz(ntohl(netmask)); |
270 | } | |
271 | ||
272 | void | |
273 | ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *s) | |
274 | { | |
275 | ds_put_format(s, IP_FMT, IP_ARGS(&ip)); | |
276 | if (mask != htonl(UINT32_MAX)) { | |
277 | if (ip_is_cidr(mask)) { | |
278 | ds_put_format(s, "/%d", ip_count_cidr_bits(mask)); | |
279 | } else { | |
280 | ds_put_format(s, "/"IP_FMT, IP_ARGS(&mask)); | |
281 | } | |
282 | } | |
283 | } | |
284 | ||
285 | ||
d31f1109 JP |
286 | /* Stores the string representation of the IPv6 address 'addr' into the |
287 | * character array 'addr_str', which must be at least INET6_ADDRSTRLEN | |
288 | * bytes long. */ | |
289 | void | |
290 | format_ipv6_addr(char *addr_str, const struct in6_addr *addr) | |
291 | { | |
292 | inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN); | |
293 | } | |
294 | ||
295 | void | |
296 | print_ipv6_addr(struct ds *string, const struct in6_addr *addr) | |
297 | { | |
aad29cd1 BP |
298 | char *dst; |
299 | ||
300 | ds_reserve(string, string->length + INET6_ADDRSTRLEN); | |
301 | ||
302 | dst = string->string + string->length; | |
303 | format_ipv6_addr(dst, addr); | |
304 | string->length += strlen(dst); | |
305 | } | |
d31f1109 | 306 | |
aad29cd1 BP |
307 | void |
308 | print_ipv6_masked(struct ds *s, const struct in6_addr *addr, | |
309 | const struct in6_addr *mask) | |
310 | { | |
311 | print_ipv6_addr(s, addr); | |
312 | if (mask && !ipv6_mask_is_exact(mask)) { | |
313 | if (ipv6_is_cidr(mask)) { | |
314 | int cidr_bits = ipv6_count_cidr_bits(mask); | |
315 | ds_put_format(s, "/%d", cidr_bits); | |
316 | } else { | |
317 | ds_put_char(s, '/'); | |
318 | print_ipv6_addr(s, mask); | |
319 | } | |
320 | } | |
d31f1109 JP |
321 | } |
322 | ||
323 | struct in6_addr ipv6_addr_bitand(const struct in6_addr *a, | |
324 | const struct in6_addr *b) | |
325 | { | |
326 | int i; | |
327 | struct in6_addr dst; | |
328 | ||
329 | #ifdef s6_addr32 | |
330 | for (i=0; i<4; i++) { | |
331 | dst.s6_addr32[i] = a->s6_addr32[i] & b->s6_addr32[i]; | |
332 | } | |
333 | #else | |
334 | for (i=0; i<16; i++) { | |
335 | dst.s6_addr[i] = a->s6_addr[i] & b->s6_addr[i]; | |
336 | } | |
337 | #endif | |
338 | ||
339 | return dst; | |
340 | } | |
341 | ||
342 | /* Returns an in6_addr consisting of 'mask' high-order 1-bits and 128-N | |
343 | * low-order 0-bits. */ | |
344 | struct in6_addr | |
345 | ipv6_create_mask(int mask) | |
346 | { | |
347 | struct in6_addr netmask; | |
348 | uint8_t *netmaskp = &netmask.s6_addr[0]; | |
349 | ||
350 | memset(&netmask, 0, sizeof netmask); | |
351 | while (mask > 8) { | |
352 | *netmaskp = 0xff; | |
353 | netmaskp++; | |
354 | mask -= 8; | |
355 | } | |
356 | ||
357 | if (mask) { | |
358 | *netmaskp = 0xff << (8 - mask); | |
359 | } | |
360 | ||
361 | return netmask; | |
362 | } | |
363 | ||
aad29cd1 BP |
364 | /* Given the IPv6 netmask 'netmask', returns the number of bits of the IPv6 |
365 | * address that it specifies, that is, the number of 1-bits in 'netmask'. | |
ff0b06ee BP |
366 | * 'netmask' must be a CIDR netmask (see ipv6_is_cidr()). |
367 | * | |
368 | * If 'netmask' is not a CIDR netmask (see ipv6_is_cidr()), the return value | |
369 | * will still be in the valid range but isn't otherwise meaningful. */ | |
d31f1109 JP |
370 | int |
371 | ipv6_count_cidr_bits(const struct in6_addr *netmask) | |
372 | { | |
373 | int i; | |
374 | int count = 0; | |
375 | const uint8_t *netmaskp = &netmask->s6_addr[0]; | |
376 | ||
d31f1109 JP |
377 | for (i=0; i<16; i++) { |
378 | if (netmaskp[i] == 0xff) { | |
379 | count += 8; | |
380 | } else { | |
381 | uint8_t nm; | |
382 | ||
383 | for(nm = netmaskp[i]; nm; nm <<= 1) { | |
384 | count++; | |
385 | } | |
386 | break; | |
387 | } | |
388 | ||
389 | } | |
390 | ||
391 | return count; | |
392 | } | |
393 | ||
d31f1109 JP |
394 | /* Returns true if 'netmask' is a CIDR netmask, that is, if it consists of N |
395 | * high-order 1-bits and 128-N low-order 0-bits. */ | |
396 | bool | |
397 | ipv6_is_cidr(const struct in6_addr *netmask) | |
398 | { | |
399 | const uint8_t *netmaskp = &netmask->s6_addr[0]; | |
400 | int i; | |
401 | ||
402 | for (i=0; i<16; i++) { | |
403 | if (netmaskp[i] != 0xff) { | |
404 | uint8_t x = ~netmaskp[i]; | |
405 | if (x & (x + 1)) { | |
406 | return false; | |
407 | } | |
408 | while (++i < 16) { | |
409 | if (netmaskp[i]) { | |
410 | return false; | |
411 | } | |
412 | } | |
413 | } | |
414 | } | |
415 | ||
416 | return true; | |
417 | } | |
c25c91fd | 418 | |
5de1bb5c BP |
419 | /* Populates 'b' with an Ethernet II packet headed with the given 'eth_dst', |
420 | * 'eth_src' and 'eth_type' parameters. A payload of 'size' bytes is allocated | |
421 | * in 'b' and returned. This payload may be populated with appropriate | |
75a4ead1 EJ |
422 | * information by the caller. Sets 'b''s 'l2' and 'l3' pointers to the |
423 | * Ethernet header and payload respectively. | |
eda1f38d BP |
424 | * |
425 | * The returned packet has enough headroom to insert an 802.1Q VLAN header if | |
426 | * desired. */ | |
40f78b38 | 427 | void * |
5de1bb5c BP |
428 | eth_compose(struct ofpbuf *b, const uint8_t eth_dst[ETH_ADDR_LEN], |
429 | const uint8_t eth_src[ETH_ADDR_LEN], uint16_t eth_type, | |
430 | size_t size) | |
c25c91fd | 431 | { |
40f78b38 | 432 | void *data; |
c25c91fd | 433 | struct eth_header *eth; |
c25c91fd EJ |
434 | |
435 | ofpbuf_clear(b); | |
436 | ||
eda1f38d BP |
437 | ofpbuf_prealloc_tailroom(b, ETH_HEADER_LEN + VLAN_HEADER_LEN + size); |
438 | ofpbuf_reserve(b, VLAN_HEADER_LEN); | |
40f78b38 EJ |
439 | eth = ofpbuf_put_uninit(b, ETH_HEADER_LEN); |
440 | data = ofpbuf_put_uninit(b, size); | |
c25c91fd | 441 | |
40f78b38 | 442 | memcpy(eth->eth_dst, eth_dst, ETH_ADDR_LEN); |
c25c91fd | 443 | memcpy(eth->eth_src, eth_src, ETH_ADDR_LEN); |
40f78b38 EJ |
444 | eth->eth_type = htons(eth_type); |
445 | ||
75a4ead1 EJ |
446 | b->l2 = eth; |
447 | b->l3 = data; | |
448 | ||
40f78b38 | 449 | return data; |
07a6cf77 EJ |
450 | } |
451 | ||
c97664b3 EJ |
452 | static void |
453 | packet_set_ipv4_addr(struct ofpbuf *packet, ovs_be32 *addr, ovs_be32 new_addr) | |
454 | { | |
455 | struct ip_header *nh = packet->l3; | |
456 | ||
457 | if (nh->ip_proto == IPPROTO_TCP && packet->l7) { | |
458 | struct tcp_header *th = packet->l4; | |
459 | ||
460 | th->tcp_csum = recalc_csum32(th->tcp_csum, *addr, new_addr); | |
461 | } else if (nh->ip_proto == IPPROTO_UDP && packet->l7) { | |
462 | struct udp_header *uh = packet->l4; | |
463 | ||
464 | if (uh->udp_csum) { | |
465 | uh->udp_csum = recalc_csum32(uh->udp_csum, *addr, new_addr); | |
466 | if (!uh->udp_csum) { | |
467 | uh->udp_csum = htons(0xffff); | |
468 | } | |
469 | } | |
470 | } | |
471 | nh->ip_csum = recalc_csum32(nh->ip_csum, *addr, new_addr); | |
472 | *addr = new_addr; | |
473 | } | |
474 | ||
475 | /* Modifies the IPv4 header fields of 'packet' to be consistent with 'src', | |
476 | * 'dst', 'tos', and 'ttl'. Updates 'packet''s L4 checksums as appropriate. | |
477 | * 'packet' must contain a valid IPv4 packet with correctly populated l[347] | |
478 | * markers. */ | |
479 | void | |
480 | packet_set_ipv4(struct ofpbuf *packet, ovs_be32 src, ovs_be32 dst, | |
481 | uint8_t tos, uint8_t ttl) | |
482 | { | |
483 | struct ip_header *nh = packet->l3; | |
484 | ||
485 | if (nh->ip_src != src) { | |
486 | packet_set_ipv4_addr(packet, &nh->ip_src, src); | |
487 | } | |
488 | ||
489 | if (nh->ip_dst != dst) { | |
490 | packet_set_ipv4_addr(packet, &nh->ip_dst, dst); | |
491 | } | |
492 | ||
493 | if (nh->ip_tos != tos) { | |
494 | uint8_t *field = &nh->ip_tos; | |
495 | ||
496 | nh->ip_csum = recalc_csum16(nh->ip_csum, htons((uint16_t) *field), | |
497 | htons((uint16_t) tos)); | |
498 | *field = tos; | |
499 | } | |
500 | ||
501 | if (nh->ip_ttl != ttl) { | |
502 | uint8_t *field = &nh->ip_ttl; | |
503 | ||
504 | nh->ip_csum = recalc_csum16(nh->ip_csum, htons(*field << 8), | |
505 | htons(ttl << 8)); | |
506 | *field = ttl; | |
507 | } | |
508 | } | |
509 | ||
510 | static void | |
511 | packet_set_port(ovs_be16 *port, ovs_be16 new_port, ovs_be16 *csum) | |
512 | { | |
513 | if (*port != new_port) { | |
514 | *csum = recalc_csum16(*csum, *port, new_port); | |
515 | *port = new_port; | |
516 | } | |
517 | } | |
518 | ||
519 | /* Sets the TCP source and destination port ('src' and 'dst' respectively) of | |
520 | * the TCP header contained in 'packet'. 'packet' must be a valid TCP packet | |
521 | * with its l4 marker properly populated. */ | |
522 | void | |
523 | packet_set_tcp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst) | |
524 | { | |
525 | struct tcp_header *th = packet->l4; | |
526 | ||
527 | packet_set_port(&th->tcp_src, src, &th->tcp_csum); | |
528 | packet_set_port(&th->tcp_dst, dst, &th->tcp_csum); | |
529 | } | |
530 | ||
531 | /* Sets the UDP source and destination port ('src' and 'dst' respectively) of | |
532 | * the UDP header contained in 'packet'. 'packet' must be a valid UDP packet | |
533 | * with its l4 marker properly populated. */ | |
534 | void | |
535 | packet_set_udp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst) | |
536 | { | |
537 | struct udp_header *uh = packet->l4; | |
538 | ||
539 | if (uh->udp_csum) { | |
540 | packet_set_port(&uh->udp_src, src, &uh->udp_csum); | |
541 | packet_set_port(&uh->udp_dst, dst, &uh->udp_csum); | |
542 | ||
543 | if (!uh->udp_csum) { | |
544 | uh->udp_csum = htons(0xffff); | |
545 | } | |
546 | } else { | |
547 | uh->udp_src = src; | |
548 | uh->udp_dst = dst; | |
549 | } | |
550 | } | |
12113c39 BP |
551 | |
552 | /* If 'packet' is a TCP packet, returns the TCP flags. Otherwise, returns 0. | |
553 | * | |
554 | * 'flow' must be the flow corresponding to 'packet' and 'packet''s header | |
555 | * pointers must be properly initialized (e.g. with flow_extract()). */ | |
556 | uint8_t | |
557 | packet_get_tcp_flags(const struct ofpbuf *packet, const struct flow *flow) | |
558 | { | |
734ec5ec JG |
559 | if ((flow->dl_type == htons(ETH_TYPE_IP) || |
560 | flow->dl_type == htons(ETH_TYPE_IPV6)) && | |
561 | flow->nw_proto == IPPROTO_TCP && packet->l7) { | |
12113c39 BP |
562 | const struct tcp_header *tcp = packet->l4; |
563 | return TCP_FLAGS(tcp->tcp_ctl); | |
564 | } else { | |
565 | return 0; | |
566 | } | |
567 | } | |
7393104d BP |
568 | |
569 | /* Appends a string representation of the TCP flags value 'tcp_flags' | |
570 | * (e.g. obtained via packet_get_tcp_flags() or TCP_FLAGS) to 's', in the | |
571 | * format used by tcpdump. */ | |
572 | void | |
573 | packet_format_tcp_flags(struct ds *s, uint8_t tcp_flags) | |
574 | { | |
575 | if (!tcp_flags) { | |
576 | ds_put_cstr(s, "none"); | |
577 | return; | |
578 | } | |
579 | ||
580 | if (tcp_flags & TCP_SYN) { | |
581 | ds_put_char(s, 'S'); | |
582 | } | |
583 | if (tcp_flags & TCP_FIN) { | |
584 | ds_put_char(s, 'F'); | |
585 | } | |
586 | if (tcp_flags & TCP_PSH) { | |
587 | ds_put_char(s, 'P'); | |
588 | } | |
589 | if (tcp_flags & TCP_RST) { | |
590 | ds_put_char(s, 'R'); | |
591 | } | |
592 | if (tcp_flags & TCP_URG) { | |
593 | ds_put_char(s, 'U'); | |
594 | } | |
595 | if (tcp_flags & TCP_ACK) { | |
596 | ds_put_char(s, '.'); | |
597 | } | |
598 | if (tcp_flags & 0x40) { | |
599 | ds_put_cstr(s, "[40]"); | |
600 | } | |
601 | if (tcp_flags & 0x80) { | |
602 | ds_put_cstr(s, "[80]"); | |
603 | } | |
604 | } |