]>
Commit | Line | Data |
---|---|---|
d1eb60cc | 1 | /* |
e0edde6f | 2 | * Copyright (c) 2007-2012 Nicira, Inc. |
d1eb60cc | 3 | * |
a9a29d22 JG |
4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of version 2 of the GNU General Public | |
6 | * License as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, but | |
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
11 | * General Public License for more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License | |
14 | * along with this program; if not, write to the Free Software | |
15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
16 | * 02110-1301, USA | |
d1eb60cc JG |
17 | */ |
18 | ||
2a4999f3 PS |
19 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
20 | ||
d1eb60cc JG |
21 | #include <linux/if_arp.h> |
22 | #include <linux/if_ether.h> | |
23 | #include <linux/ip.h> | |
24 | #include <linux/if_vlan.h> | |
b37e6334 | 25 | #include <linux/igmp.h> |
d1eb60cc JG |
26 | #include <linux/in.h> |
27 | #include <linux/in_route.h> | |
b37e6334 | 28 | #include <linux/inetdevice.h> |
d1eb60cc | 29 | #include <linux/jhash.h> |
3544358a | 30 | #include <linux/list.h> |
d1eb60cc JG |
31 | #include <linux/kernel.h> |
32 | #include <linux/version.h> | |
842cf6f4 | 33 | #include <linux/workqueue.h> |
3544358a | 34 | #include <linux/rculist.h> |
d1eb60cc JG |
35 | |
36 | #include <net/dsfield.h> | |
37 | #include <net/dst.h> | |
38 | #include <net/icmp.h> | |
39 | #include <net/inet_ecn.h> | |
40 | #include <net/ip.h> | |
41 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | |
42 | #include <net/ipv6.h> | |
43 | #endif | |
44 | #include <net/route.h> | |
45 | #include <net/xfrm.h> | |
46 | ||
dd8d6b8c | 47 | #include "checksum.h" |
4b5fbf85 | 48 | #include "compat.h" |
d1eb60cc | 49 | #include "datapath.h" |
d1eb60cc | 50 | #include "tunnel.h" |
6ce39213 | 51 | #include "vlan.h" |
d1eb60cc | 52 | #include "vport.h" |
842cf6f4 JG |
53 | #include "vport-internal_dev.h" |
54 | ||
3544358a | 55 | #define PORT_TABLE_SIZE 1024 |
d1eb60cc | 56 | |
3544358a | 57 | static struct hlist_head *port_table __read_mostly; |
842cf6f4 | 58 | |
d1eb60cc JG |
59 | /* |
60 | * These are just used as an optimization: they don't require any kind of | |
61 | * synchronization because we could have just as easily read the value before | |
62 | * the port change happened. | |
63 | */ | |
83e3e75b JG |
64 | static unsigned int key_local_remote_ports __read_mostly; |
65 | static unsigned int key_remote_ports __read_mostly; | |
bb635d0e | 66 | static unsigned int key_multicast_ports __read_mostly; |
83e3e75b JG |
67 | static unsigned int local_remote_ports __read_mostly; |
68 | static unsigned int remote_ports __read_mostly; | |
7d5735b3 | 69 | static unsigned int null_ports __read_mostly; |
bb635d0e | 70 | static unsigned int multicast_ports __read_mostly; |
d1eb60cc JG |
71 | |
72 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) | |
73 | #define rt_dst(rt) (rt->dst) | |
74 | #else | |
75 | #define rt_dst(rt) (rt->u.dst) | |
76 | #endif | |
77 | ||
6455100f | 78 | static struct vport *tnl_vport_to_vport(const struct tnl_vport *tnl_vport) |
d1eb60cc JG |
79 | { |
80 | return vport_from_priv(tnl_vport); | |
81 | } | |
82 | ||
842cf6f4 | 83 | static void free_config_rcu(struct rcu_head *rcu) |
d1eb60cc JG |
84 | { |
85 | struct tnl_mutable_config *c = container_of(rcu, struct tnl_mutable_config, rcu); | |
86 | kfree(c); | |
87 | } | |
88 | ||
b37e6334 BP |
89 | /* Frees the portion of 'mutable' that requires RTNL and thus can't happen |
90 | * within an RCU callback. Fortunately this part doesn't require waiting for | |
91 | * an RCU grace period. | |
92 | */ | |
93 | static void free_mutable_rtnl(struct tnl_mutable_config *mutable) | |
94 | { | |
95 | ASSERT_RTNL(); | |
96 | if (ipv4_is_multicast(mutable->key.daddr) && mutable->mlink) { | |
97 | struct in_device *in_dev; | |
2a4999f3 | 98 | in_dev = inetdev_by_index(port_key_get_net(&mutable->key), mutable->mlink); |
b37e6334 BP |
99 | if (in_dev) |
100 | ip_mc_dec_group(in_dev, mutable->key.daddr); | |
101 | } | |
102 | } | |
103 | ||
d1eb60cc JG |
104 | static void assign_config_rcu(struct vport *vport, |
105 | struct tnl_mutable_config *new_config) | |
106 | { | |
107 | struct tnl_vport *tnl_vport = tnl_vport_priv(vport); | |
108 | struct tnl_mutable_config *old_config; | |
109 | ||
ad919711 | 110 | old_config = rtnl_dereference(tnl_vport->mutable); |
d1eb60cc | 111 | rcu_assign_pointer(tnl_vport->mutable, new_config); |
b37e6334 BP |
112 | |
113 | free_mutable_rtnl(old_config); | |
842cf6f4 JG |
114 | call_rcu(&old_config->rcu, free_config_rcu); |
115 | } | |
116 | ||
d1eb60cc JG |
117 | static unsigned int *find_port_pool(const struct tnl_mutable_config *mutable) |
118 | { | |
bb635d0e JG |
119 | bool is_multicast = ipv4_is_multicast(mutable->key.daddr); |
120 | ||
c19e6535 | 121 | if (mutable->flags & TNL_F_IN_KEY_MATCH) { |
f686a33a | 122 | if (mutable->key.saddr) |
d1eb60cc | 123 | return &local_remote_ports; |
bb635d0e JG |
124 | else if (is_multicast) |
125 | return &multicast_ports; | |
d1eb60cc JG |
126 | else |
127 | return &remote_ports; | |
128 | } else { | |
f686a33a | 129 | if (mutable->key.saddr) |
d1eb60cc | 130 | return &key_local_remote_ports; |
bb635d0e JG |
131 | else if (is_multicast) |
132 | return &key_multicast_ports; | |
7d5735b3 | 133 | else if (mutable->key.daddr) |
d1eb60cc | 134 | return &key_remote_ports; |
7d5735b3 PS |
135 | else |
136 | return &null_ports; | |
d1eb60cc JG |
137 | } |
138 | } | |
139 | ||
f686a33a | 140 | static u32 port_hash(const struct port_lookup_key *key) |
d1eb60cc | 141 | { |
6455100f | 142 | return jhash2((u32 *)key, (PORT_KEY_LEN / sizeof(u32)), 0); |
d1eb60cc JG |
143 | } |
144 | ||
6455100f | 145 | static struct hlist_head *find_bucket(u32 hash) |
3544358a PS |
146 | { |
147 | return &port_table[(hash & (PORT_TABLE_SIZE - 1))]; | |
842cf6f4 JG |
148 | } |
149 | ||
3544358a | 150 | static void port_table_add_port(struct vport *vport) |
d1eb60cc JG |
151 | { |
152 | struct tnl_vport *tnl_vport = tnl_vport_priv(vport); | |
f686a33a PS |
153 | const struct tnl_mutable_config *mutable; |
154 | u32 hash; | |
d1eb60cc | 155 | |
f686a33a PS |
156 | mutable = rtnl_dereference(tnl_vport->mutable); |
157 | hash = port_hash(&mutable->key); | |
3544358a | 158 | hlist_add_head_rcu(&tnl_vport->hash_node, find_bucket(hash)); |
842cf6f4 | 159 | |
ad919711 | 160 | (*find_port_pool(rtnl_dereference(tnl_vport->mutable)))++; |
842cf6f4 JG |
161 | } |
162 | ||
3544358a PS |
163 | static void port_table_move_port(struct vport *vport, |
164 | struct tnl_mutable_config *new_mutable) | |
842cf6f4 | 165 | { |
842cf6f4 JG |
166 | struct tnl_vport *tnl_vport = tnl_vport_priv(vport); |
167 | u32 hash; | |
168 | ||
f686a33a | 169 | hash = port_hash(&new_mutable->key); |
3544358a PS |
170 | hlist_del_init_rcu(&tnl_vport->hash_node); |
171 | hlist_add_head_rcu(&tnl_vport->hash_node, find_bucket(hash)); | |
d1eb60cc | 172 | |
ad919711 | 173 | (*find_port_pool(rtnl_dereference(tnl_vport->mutable)))--; |
842cf6f4 | 174 | assign_config_rcu(vport, new_mutable); |
ad919711 | 175 | (*find_port_pool(rtnl_dereference(tnl_vport->mutable)))++; |
d1eb60cc JG |
176 | } |
177 | ||
3544358a | 178 | static void port_table_remove_port(struct vport *vport) |
d1eb60cc JG |
179 | { |
180 | struct tnl_vport *tnl_vport = tnl_vport_priv(vport); | |
d1eb60cc | 181 | |
3544358a PS |
182 | hlist_del_init_rcu(&tnl_vport->hash_node); |
183 | ||
ad919711 | 184 | (*find_port_pool(rtnl_dereference(tnl_vport->mutable)))--; |
3544358a | 185 | } |
d1eb60cc | 186 | |
681f040e BP |
187 | static struct vport *port_table_lookup(struct port_lookup_key *key, |
188 | const struct tnl_mutable_config **pmutable) | |
3544358a PS |
189 | { |
190 | struct hlist_node *n; | |
191 | struct hlist_head *bucket; | |
f686a33a | 192 | u32 hash = port_hash(key); |
6455100f | 193 | struct tnl_vport *tnl_vport; |
3544358a PS |
194 | |
195 | bucket = find_bucket(hash); | |
196 | ||
197 | hlist_for_each_entry_rcu(tnl_vport, n, bucket, hash_node) { | |
f686a33a PS |
198 | struct tnl_mutable_config *mutable; |
199 | ||
200 | mutable = rcu_dereference_rtnl(tnl_vport->mutable); | |
bd85a68f | 201 | if (!memcmp(&mutable->key, key, PORT_KEY_LEN)) { |
f686a33a | 202 | *pmutable = mutable; |
681f040e | 203 | return tnl_vport_to_vport(tnl_vport); |
f686a33a | 204 | } |
3544358a PS |
205 | } |
206 | ||
207 | return NULL; | |
d1eb60cc JG |
208 | } |
209 | ||
2a4999f3 PS |
210 | struct vport *ovs_tnl_find_port(struct net *net, __be32 saddr, __be32 daddr, |
211 | __be64 key, int tunnel_type, | |
850b6b3b | 212 | const struct tnl_mutable_config **mutable) |
d1eb60cc JG |
213 | { |
214 | struct port_lookup_key lookup; | |
681f040e | 215 | struct vport *vport; |
859ad376 | 216 | bool is_multicast = ipv4_is_multicast(saddr); |
b37e6334 | 217 | |
2a4999f3 | 218 | port_key_set_net(&lookup, net); |
4029c21a BP |
219 | lookup.saddr = saddr; |
220 | lookup.daddr = daddr; | |
d1eb60cc | 221 | |
085a41cb BP |
222 | /* First try for exact match on in_key. */ |
223 | lookup.in_key = key; | |
224 | lookup.tunnel_type = tunnel_type | TNL_T_KEY_EXACT; | |
859ad376 | 225 | if (!is_multicast && key_local_remote_ports) { |
085a41cb BP |
226 | vport = port_table_lookup(&lookup, mutable); |
227 | if (vport) | |
228 | return vport; | |
d1eb60cc | 229 | } |
085a41cb BP |
230 | if (key_remote_ports) { |
231 | lookup.saddr = 0; | |
232 | vport = port_table_lookup(&lookup, mutable); | |
233 | if (vport) | |
234 | return vport; | |
d1eb60cc | 235 | |
085a41cb BP |
236 | lookup.saddr = saddr; |
237 | } | |
d1eb60cc | 238 | |
085a41cb BP |
239 | /* Then try matches that wildcard in_key. */ |
240 | lookup.in_key = 0; | |
241 | lookup.tunnel_type = tunnel_type | TNL_T_KEY_MATCH; | |
859ad376 | 242 | if (!is_multicast && local_remote_ports) { |
085a41cb BP |
243 | vport = port_table_lookup(&lookup, mutable); |
244 | if (vport) | |
245 | return vport; | |
246 | } | |
247 | if (remote_ports) { | |
248 | lookup.saddr = 0; | |
249 | vport = port_table_lookup(&lookup, mutable); | |
250 | if (vport) | |
251 | return vport; | |
d1eb60cc JG |
252 | } |
253 | ||
859ad376 JG |
254 | if (is_multicast) { |
255 | lookup.saddr = 0; | |
256 | lookup.daddr = saddr; | |
bb635d0e | 257 | if (key_multicast_ports) { |
859ad376 JG |
258 | lookup.tunnel_type = tunnel_type | TNL_T_KEY_EXACT; |
259 | lookup.in_key = key; | |
260 | vport = port_table_lookup(&lookup, mutable); | |
261 | if (vport) | |
262 | return vport; | |
263 | } | |
bb635d0e | 264 | if (multicast_ports) { |
859ad376 JG |
265 | lookup.tunnel_type = tunnel_type | TNL_T_KEY_MATCH; |
266 | lookup.in_key = 0; | |
267 | vport = port_table_lookup(&lookup, mutable); | |
268 | if (vport) | |
269 | return vport; | |
270 | } | |
271 | } | |
272 | ||
7d5735b3 PS |
273 | if (null_ports) { |
274 | lookup.daddr = 0; | |
275 | lookup.saddr = 0; | |
48841e2d | 276 | lookup.in_key = 0; |
7d5735b3 PS |
277 | lookup.tunnel_type = tunnel_type; |
278 | vport = port_table_lookup(&lookup, mutable); | |
279 | if (vport) | |
280 | return vport; | |
281 | } | |
d1eb60cc | 282 | return NULL; |
d1eb60cc JG |
283 | } |
284 | ||
356af50b | 285 | static void ecn_decapsulate(struct sk_buff *skb) |
842cf6f4 | 286 | { |
356af50b | 287 | if (unlikely(INET_ECN_is_ce(OVS_CB(skb)->tun_key->ipv4_tos))) { |
842cf6f4 | 288 | __be16 protocol = skb->protocol; |
a2a96c04 JG |
289 | |
290 | skb_set_network_header(skb, ETH_HLEN); | |
842cf6f4 | 291 | |
aae369c7 | 292 | if (protocol == htons(ETH_P_8021Q)) { |
842cf6f4 JG |
293 | if (unlikely(!pskb_may_pull(skb, VLAN_ETH_HLEN))) |
294 | return; | |
295 | ||
296 | protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; | |
a2a96c04 | 297 | skb_set_network_header(skb, VLAN_ETH_HLEN); |
842cf6f4 JG |
298 | } |
299 | ||
300 | if (protocol == htons(ETH_P_IP)) { | |
a2a96c04 | 301 | if (unlikely(!pskb_may_pull(skb, skb_network_offset(skb) |
842cf6f4 JG |
302 | + sizeof(struct iphdr)))) |
303 | return; | |
304 | ||
a2a96c04 | 305 | IP_ECN_set_ce(ip_hdr(skb)); |
842cf6f4 JG |
306 | } |
307 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | |
308 | else if (protocol == htons(ETH_P_IPV6)) { | |
a2a96c04 | 309 | if (unlikely(!pskb_may_pull(skb, skb_network_offset(skb) |
842cf6f4 JG |
310 | + sizeof(struct ipv6hdr)))) |
311 | return; | |
312 | ||
a2a96c04 | 313 | IP6_ECN_set_ce(ipv6_hdr(skb)); |
842cf6f4 JG |
314 | } |
315 | #endif | |
316 | } | |
317 | } | |
318 | ||
aae369c7 | 319 | /** |
850b6b3b | 320 | * ovs_tnl_rcv - ingress point for generic tunnel code |
aae369c7 JG |
321 | * |
322 | * @vport: port this packet was received on | |
323 | * @skb: received packet | |
324 | * @tos: ToS from encapsulating IP packet, used to copy ECN bits | |
325 | * | |
326 | * Must be called with rcu_read_lock. | |
327 | * | |
328 | * Packets received by this function are in the following state: | |
329 | * - skb->data points to the inner Ethernet header. | |
330 | * - The inner Ethernet header is in the linear data area. | |
331 | * - skb->csum does not include the inner Ethernet header. | |
332 | * - The layer pointers are undefined. | |
333 | */ | |
356af50b | 334 | void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb) |
842cf6f4 | 335 | { |
aae369c7 | 336 | struct ethhdr *eh; |
9851dd67 | 337 | |
aae369c7 JG |
338 | skb_reset_mac_header(skb); |
339 | eh = eth_hdr(skb); | |
9851dd67 JG |
340 | |
341 | if (likely(ntohs(eh->h_proto) >= 1536)) | |
342 | skb->protocol = eh->h_proto; | |
343 | else | |
344 | skb->protocol = htons(ETH_P_802_2); | |
842cf6f4 JG |
345 | |
346 | skb_dst_drop(skb); | |
347 | nf_reset(skb); | |
a4a26436 | 348 | skb_clear_rxhash(skb); |
842cf6f4 | 349 | secpath_reset(skb); |
842cf6f4 | 350 | |
356af50b | 351 | ecn_decapsulate(skb); |
6ce39213 | 352 | vlan_set_tci(skb, 0); |
842cf6f4 | 353 | |
c3729ee4 JG |
354 | if (unlikely(compute_ip_summed(skb, false))) { |
355 | kfree_skb(skb); | |
356 | return; | |
357 | } | |
358 | ||
850b6b3b | 359 | ovs_vport_receive(vport, skb); |
842cf6f4 JG |
360 | } |
361 | ||
70cf679a PS |
362 | static struct rtable *find_route(struct net *net, |
363 | __be32 *saddr, __be32 daddr, u8 ipproto, | |
4b5fbf85 | 364 | u8 tos, u32 skb_mark) |
b37e6334 | 365 | { |
70cf679a | 366 | struct rtable *rt; |
749ae950 PS |
367 | /* Tunnel configuration keeps DSCP part of TOS bits, But Linux |
368 | * router expect RT_TOS bits only. */ | |
369 | ||
b37e6334 | 370 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) |
6455100f | 371 | struct flowi fl = { .nl_u = { .ip4_u = { |
356af50b | 372 | .daddr = daddr, |
70cf679a | 373 | .saddr = *saddr, |
4b5fbf85 AA |
374 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) |
375 | .fwmark = skb_mark, | |
376 | #endif | |
749ae950 | 377 | .tos = RT_TOS(tos) } }, |
4b5fbf85 AA |
378 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) |
379 | .mark = skb_mark, | |
380 | #endif | |
749ae950 | 381 | .proto = ipproto }; |
b37e6334 | 382 | |
70cf679a | 383 | if (unlikely(ip_route_output_key(net, &rt, &fl))) |
b37e6334 | 384 | return ERR_PTR(-EADDRNOTAVAIL); |
70cf679a | 385 | *saddr = fl.nl_u.ip4_u.saddr; |
b37e6334 BP |
386 | return rt; |
387 | #else | |
356af50b | 388 | struct flowi4 fl = { .daddr = daddr, |
70cf679a | 389 | .saddr = *saddr, |
749ae950 | 390 | .flowi4_tos = RT_TOS(tos), |
4b5fbf85 | 391 | .flowi4_mark = skb_mark, |
b37e6334 BP |
392 | .flowi4_proto = ipproto }; |
393 | ||
70cf679a PS |
394 | rt = ip_route_output_key(net, &fl); |
395 | *saddr = fl.saddr; | |
396 | return rt; | |
b37e6334 BP |
397 | #endif |
398 | } | |
399 | ||
6455100f | 400 | static bool need_linearize(const struct sk_buff *skb) |
d1eb60cc | 401 | { |
842cf6f4 JG |
402 | int i; |
403 | ||
404 | if (unlikely(skb_shinfo(skb)->frag_list)) | |
405 | return true; | |
406 | ||
407 | /* | |
408 | * Generally speaking we should linearize if there are paged frags. | |
409 | * However, if all of the refcounts are 1 we know nobody else can | |
410 | * change them from underneath us and we can skip the linearization. | |
411 | */ | |
412 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) | |
143af30e | 413 | if (unlikely(page_count(skb_frag_page(&skb_shinfo(skb)->frags[i])) > 1)) |
842cf6f4 JG |
414 | return true; |
415 | ||
416 | return false; | |
417 | } | |
418 | ||
419 | static struct sk_buff *handle_offloads(struct sk_buff *skb, | |
420 | const struct tnl_mutable_config *mutable, | |
356af50b KM |
421 | const struct rtable *rt, |
422 | int tunnel_hlen) | |
842cf6f4 JG |
423 | { |
424 | int min_headroom; | |
d1eb60cc | 425 | int err; |
d1eb60cc | 426 | |
842cf6f4 | 427 | min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len |
356af50b | 428 | + tunnel_hlen |
6ce39213 JG |
429 | + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0); |
430 | ||
bf16ba4a JG |
431 | if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) { |
432 | int head_delta = SKB_DATA_ALIGN(min_headroom - | |
433 | skb_headroom(skb) + | |
434 | 16); | |
435 | err = pskb_expand_head(skb, max_t(int, head_delta, 0), | |
436 | 0, GFP_ATOMIC); | |
437 | if (unlikely(err)) | |
438 | goto error_free; | |
6ce39213 | 439 | } |
d1eb60cc | 440 | |
c3729ee4 JG |
441 | forward_ip_summed(skb, true); |
442 | ||
842cf6f4 JG |
443 | if (skb_is_gso(skb)) { |
444 | struct sk_buff *nskb; | |
445 | ||
0aa52d88 | 446 | nskb = __skb_gso_segment(skb, 0, false); |
40796b34 | 447 | if (IS_ERR(nskb)) { |
5b95ab0e | 448 | kfree_skb(skb); |
842cf6f4 JG |
449 | err = PTR_ERR(nskb); |
450 | goto error; | |
451 | } | |
d1eb60cc | 452 | |
5b95ab0e | 453 | consume_skb(skb); |
842cf6f4 | 454 | skb = nskb; |
c3729ee4 | 455 | } else if (get_ip_summed(skb) == OVS_CSUM_PARTIAL) { |
6ce39213 JG |
456 | /* Pages aren't locked and could change at any time. |
457 | * If this happens after we compute the checksum, the | |
458 | * checksum will be wrong. We linearize now to avoid | |
459 | * this problem. | |
460 | */ | |
461 | if (unlikely(need_linearize(skb))) { | |
462 | err = __skb_linearize(skb); | |
842cf6f4 | 463 | if (unlikely(err)) |
d1eb60cc | 464 | goto error_free; |
6ce39213 JG |
465 | } |
466 | ||
467 | err = skb_checksum_help(skb); | |
468 | if (unlikely(err)) | |
469 | goto error_free; | |
c3729ee4 JG |
470 | } |
471 | ||
472 | set_ip_summed(skb, OVS_CSUM_NONE); | |
d1eb60cc | 473 | |
842cf6f4 | 474 | return skb; |
d1eb60cc | 475 | |
842cf6f4 JG |
476 | error_free: |
477 | kfree_skb(skb); | |
478 | error: | |
479 | return ERR_PTR(err); | |
480 | } | |
d1eb60cc | 481 | |
842cf6f4 | 482 | static int send_frags(struct sk_buff *skb, |
356af50b | 483 | int tunnel_hlen) |
842cf6f4 JG |
484 | { |
485 | int sent_len; | |
d1eb60cc | 486 | |
842cf6f4 | 487 | sent_len = 0; |
5214f5c4 JG |
488 | while (skb) { |
489 | struct sk_buff *next = skb->next; | |
356af50b | 490 | int frag_len = skb->len - tunnel_hlen; |
81158e4f | 491 | int err; |
d1eb60cc | 492 | |
5214f5c4 | 493 | skb->next = NULL; |
b1195d37 | 494 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); |
7da5c939 | 495 | |
5214f5c4 | 496 | err = ip_local_out(skb); |
5214f5c4 | 497 | skb = next; |
81158e4f BP |
498 | if (unlikely(net_xmit_eval(err))) |
499 | goto free_frags; | |
500 | sent_len += frag_len; | |
842cf6f4 | 501 | } |
5214f5c4 | 502 | |
842cf6f4 | 503 | return sent_len; |
d1eb60cc | 504 | |
5214f5c4 JG |
505 | free_frags: |
506 | /* | |
507 | * There's no point in continuing to send fragments once one has been | |
508 | * dropped so just free the rest. This may help improve the congestion | |
509 | * that caused the first packet to be dropped. | |
510 | */ | |
850b6b3b | 511 | ovs_tnl_free_linked_skbs(skb); |
842cf6f4 | 512 | return sent_len; |
d1eb60cc JG |
513 | } |
514 | ||
a6ae068b LJ |
515 | /* Compute source UDP port for outgoing packet. |
516 | * Currently we use the flow hash. | |
517 | */ | |
518 | u16 ovs_tnl_get_src_port(struct sk_buff *skb) | |
519 | { | |
520 | int low; | |
521 | int high; | |
522 | unsigned int range; | |
523 | u32 hash = OVS_CB(skb)->flow->hash; | |
524 | ||
525 | inet_get_local_port_range(&low, &high); | |
526 | range = (high - low) + 1; | |
527 | return (((u64) hash * range) >> 32) + low; | |
528 | } | |
529 | ||
850b6b3b | 530 | int ovs_tnl_send(struct vport *vport, struct sk_buff *skb) |
d1eb60cc JG |
531 | { |
532 | struct tnl_vport *tnl_vport = tnl_vport_priv(vport); | |
533 | const struct tnl_mutable_config *mutable = rcu_dereference(tnl_vport->mutable); | |
842cf6f4 | 534 | enum vport_err_type err = VPORT_E_TX_ERROR; |
d1eb60cc | 535 | struct rtable *rt; |
356af50b | 536 | struct ovs_key_ipv4_tunnel tun_key; |
842cf6f4 | 537 | int sent_len = 0; |
356af50b | 538 | int tunnel_hlen; |
78adaee1 | 539 | __be16 frag_off; |
356af50b KM |
540 | __be32 daddr; |
541 | __be32 saddr; | |
4b5fbf85 | 542 | u32 skb_mark; |
842cf6f4 | 543 | u8 ttl; |
842cf6f4 | 544 | u8 tos; |
d1eb60cc JG |
545 | |
546 | /* Validate the protocol headers before we try to use them. */ | |
6ce39213 JG |
547 | if (skb->protocol == htons(ETH_P_8021Q) && |
548 | !vlan_tx_tag_present(skb)) { | |
d1eb60cc JG |
549 | if (unlikely(!pskb_may_pull(skb, VLAN_ETH_HLEN))) |
550 | goto error_free; | |
551 | ||
552 | skb->protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; | |
553 | skb_set_network_header(skb, VLAN_ETH_HLEN); | |
554 | } | |
555 | ||
556 | if (skb->protocol == htons(ETH_P_IP)) { | |
842cf6f4 JG |
557 | if (unlikely(!pskb_may_pull(skb, skb_network_offset(skb) |
558 | + sizeof(struct iphdr)))) | |
d1eb60cc JG |
559 | skb->protocol = 0; |
560 | } | |
561 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | |
562 | else if (skb->protocol == htons(ETH_P_IPV6)) { | |
842cf6f4 JG |
563 | if (unlikely(!pskb_may_pull(skb, skb_network_offset(skb) |
564 | + sizeof(struct ipv6hdr)))) | |
d1eb60cc JG |
565 | skb->protocol = 0; |
566 | } | |
567 | #endif | |
d1eb60cc | 568 | |
356af50b KM |
569 | /* If OVS_CB(skb)->tun_key is NULL, point it at the local tun_key here, |
570 | * and zero it out. | |
571 | */ | |
572 | if (!OVS_CB(skb)->tun_key) { | |
573 | memset(&tun_key, 0, sizeof(tun_key)); | |
574 | OVS_CB(skb)->tun_key = &tun_key; | |
575 | } | |
576 | ||
577 | tunnel_hlen = tnl_vport->tnl_ops->hdr_len(mutable, OVS_CB(skb)->tun_key); | |
578 | if (unlikely(tunnel_hlen < 0)) { | |
579 | err = VPORT_E_TX_DROPPED; | |
580 | goto error_free; | |
581 | } | |
582 | tunnel_hlen += sizeof(struct iphdr); | |
583 | ||
584 | if (OVS_CB(skb)->tun_key->ipv4_dst) { | |
585 | daddr = OVS_CB(skb)->tun_key->ipv4_dst; | |
586 | saddr = OVS_CB(skb)->tun_key->ipv4_src; | |
587 | tos = OVS_CB(skb)->tun_key->ipv4_tos; | |
588 | ttl = OVS_CB(skb)->tun_key->ipv4_ttl; | |
78adaee1 JG |
589 | frag_off = OVS_CB(skb)->tun_key->tun_flags & |
590 | OVS_TNL_F_DONT_FRAGMENT ? htons(IP_DF) : 0; | |
356af50b KM |
591 | } else { |
592 | u8 inner_tos; | |
593 | daddr = mutable->key.daddr; | |
594 | saddr = mutable->key.saddr; | |
595 | ||
7d5735b3 PS |
596 | if (unlikely(!daddr)) { |
597 | /* Trying to sent packet from Null-port without | |
598 | * tunnel info? Drop this packet. */ | |
599 | err = VPORT_E_TX_DROPPED; | |
600 | goto error_free; | |
601 | } | |
602 | ||
356af50b KM |
603 | /* ToS */ |
604 | if (skb->protocol == htons(ETH_P_IP)) | |
605 | inner_tos = ip_hdr(skb)->tos; | |
d1eb60cc | 606 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
356af50b KM |
607 | else if (skb->protocol == htons(ETH_P_IPV6)) |
608 | inner_tos = ipv6_get_dsfield(ipv6_hdr(skb)); | |
d1eb60cc | 609 | #endif |
356af50b KM |
610 | else |
611 | inner_tos = 0; | |
d1eb60cc | 612 | |
356af50b KM |
613 | if (mutable->flags & TNL_F_TOS_INHERIT) |
614 | tos = inner_tos; | |
615 | else | |
616 | tos = mutable->tos; | |
617 | ||
618 | tos = INET_ECN_encapsulate(tos, inner_tos); | |
619 | ||
620 | /* TTL */ | |
621 | ttl = mutable->ttl; | |
622 | if (mutable->flags & TNL_F_TTL_INHERIT) { | |
623 | if (skb->protocol == htons(ETH_P_IP)) | |
624 | ttl = ip_hdr(skb)->ttl; | |
625 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | |
626 | else if (skb->protocol == htons(ETH_P_IPV6)) | |
627 | ttl = ipv6_hdr(skb)->hop_limit; | |
628 | #endif | |
629 | } | |
630 | ||
78adaee1 | 631 | frag_off = mutable->flags & TNL_F_DF_DEFAULT ? htons(IP_DF) : 0; |
356af50b | 632 | } |
d1eb60cc | 633 | |
842cf6f4 | 634 | /* Route lookup */ |
4b5fbf85 | 635 | skb_mark = skb_get_mark(skb); |
70cf679a | 636 | rt = find_route(port_key_get_net(&mutable->key), &saddr, daddr, |
4b5fbf85 | 637 | tnl_vport->tnl_ops->ipproto, tos, skb_mark); |
05a9d485 | 638 | if (IS_ERR(rt)) |
842cf6f4 | 639 | goto error_free; |
842cf6f4 JG |
640 | |
641 | /* Reset SKB */ | |
642 | nf_reset(skb); | |
643 | secpath_reset(skb); | |
644 | skb_dst_drop(skb); | |
a4a26436 | 645 | skb_clear_rxhash(skb); |
842cf6f4 JG |
646 | |
647 | /* Offloading */ | |
356af50b | 648 | skb = handle_offloads(skb, mutable, rt, tunnel_hlen); |
05a9d485 PS |
649 | if (IS_ERR(skb)) { |
650 | skb = NULL; | |
651 | goto err_free_rt; | |
652 | } | |
842cf6f4 | 653 | |
356af50b KM |
654 | /* TTL Fixup. */ |
655 | if (!OVS_CB(skb)->tun_key->ipv4_dst) { | |
656 | if (!(mutable->flags & TNL_F_TTL_INHERIT)) { | |
657 | if (!ttl) | |
658 | ttl = ip4_dst_hoplimit(&rt_dst(rt)); | |
659 | } | |
d1eb60cc | 660 | } |
d1eb60cc | 661 | |
842cf6f4 JG |
662 | while (skb) { |
663 | struct iphdr *iph; | |
664 | struct sk_buff *next_skb = skb->next; | |
665 | skb->next = NULL; | |
d1eb60cc | 666 | |
6ce39213 JG |
667 | if (unlikely(vlan_deaccel_tag(skb))) |
668 | goto next; | |
669 | ||
05a9d485 PS |
670 | skb_push(skb, tunnel_hlen); |
671 | skb_reset_network_header(skb); | |
672 | skb_set_transport_header(skb, sizeof(struct iphdr)); | |
d1eb60cc | 673 | |
05a9d485 PS |
674 | if (next_skb) |
675 | skb_dst_set(skb, dst_clone(&rt_dst(rt))); | |
676 | else | |
677 | skb_dst_set(skb, &rt_dst(rt)); | |
678 | ||
679 | /* Push IP header. */ | |
842cf6f4 | 680 | iph = ip_hdr(skb); |
05a9d485 PS |
681 | iph->version = 4; |
682 | iph->ihl = sizeof(struct iphdr) >> 2; | |
683 | iph->protocol = tnl_vport->tnl_ops->ipproto; | |
70cf679a PS |
684 | iph->daddr = daddr; |
685 | iph->saddr = saddr; | |
05a9d485 PS |
686 | iph->tos = tos; |
687 | iph->ttl = ttl; | |
688 | iph->frag_off = frag_off; | |
842cf6f4 | 689 | ip_select_ident(iph, &rt_dst(rt), NULL); |
d1eb60cc | 690 | |
05a9d485 PS |
691 | /* Push Tunnel header. */ |
692 | skb = tnl_vport->tnl_ops->build_header(vport, mutable, | |
356af50b | 693 | &rt_dst(rt), skb, tunnel_hlen); |
842cf6f4 JG |
694 | if (unlikely(!skb)) |
695 | goto next; | |
d1eb60cc | 696 | |
05a9d485 | 697 | sent_len += send_frags(skb, tunnel_hlen); |
842cf6f4 JG |
698 | |
699 | next: | |
d1eb60cc | 700 | skb = next_skb; |
842cf6f4 | 701 | } |
d1eb60cc | 702 | |
842cf6f4 | 703 | if (unlikely(sent_len == 0)) |
850b6b3b | 704 | ovs_vport_record_error(vport, VPORT_E_TX_DROPPED); |
5214f5c4 | 705 | |
05a9d485 | 706 | return sent_len; |
d1eb60cc | 707 | |
05a9d485 PS |
708 | err_free_rt: |
709 | ip_rt_put(rt); | |
d1eb60cc | 710 | error_free: |
850b6b3b | 711 | ovs_tnl_free_linked_skbs(skb); |
850b6b3b | 712 | ovs_vport_record_error(vport, err); |
842cf6f4 | 713 | return sent_len; |
d1eb60cc JG |
714 | } |
715 | ||
df2c07f4 JP |
716 | static const struct nla_policy tnl_policy[OVS_TUNNEL_ATTR_MAX + 1] = { |
717 | [OVS_TUNNEL_ATTR_FLAGS] = { .type = NLA_U32 }, | |
718 | [OVS_TUNNEL_ATTR_DST_IPV4] = { .type = NLA_U32 }, | |
719 | [OVS_TUNNEL_ATTR_SRC_IPV4] = { .type = NLA_U32 }, | |
720 | [OVS_TUNNEL_ATTR_OUT_KEY] = { .type = NLA_U64 }, | |
721 | [OVS_TUNNEL_ATTR_IN_KEY] = { .type = NLA_U64 }, | |
722 | [OVS_TUNNEL_ATTR_TOS] = { .type = NLA_U8 }, | |
723 | [OVS_TUNNEL_ATTR_TTL] = { .type = NLA_U8 }, | |
79f827fa | 724 | [OVS_TUNNEL_ATTR_DST_PORT] = { .type = NLA_U16 }, |
c19e6535 BP |
725 | }; |
726 | ||
6455100f PS |
727 | /* Sets OVS_TUNNEL_ATTR_* fields in 'mutable', which must initially be |
728 | * zeroed. */ | |
2a4999f3 PS |
729 | static int tnl_set_config(struct net *net, struct nlattr *options, |
730 | const struct tnl_ops *tnl_ops, | |
574f1fb5 BP |
731 | const struct vport *cur_vport, |
732 | struct tnl_mutable_config *mutable) | |
d1eb60cc JG |
733 | { |
734 | const struct vport *old_vport; | |
735 | const struct tnl_mutable_config *old_mutable; | |
df2c07f4 | 736 | struct nlattr *a[OVS_TUNNEL_ATTR_MAX + 1]; |
c19e6535 | 737 | int err; |
d1eb60cc | 738 | |
7d5735b3 PS |
739 | port_key_set_net(&mutable->key, net); |
740 | mutable->key.tunnel_type = tnl_ops->tunnel_type; | |
c19e6535 | 741 | if (!options) |
7d5735b3 | 742 | goto out; |
842cf6f4 | 743 | |
df2c07f4 | 744 | err = nla_parse_nested(a, OVS_TUNNEL_ATTR_MAX, options, tnl_policy); |
c19e6535 BP |
745 | if (err) |
746 | return err; | |
747 | ||
7f804ea5 JR |
748 | /* Process attributes possibly useful for null_ports first */ |
749 | if (a[OVS_TUNNEL_ATTR_DST_PORT]) | |
750 | mutable->dst_port = | |
751 | htons(nla_get_u16(a[OVS_TUNNEL_ATTR_DST_PORT])); | |
752 | ||
753 | if (a[OVS_TUNNEL_ATTR_DST_IPV4]) | |
754 | mutable->key.daddr = nla_get_be32(a[OVS_TUNNEL_ATTR_DST_IPV4]); | |
842cf6f4 | 755 | |
7f804ea5 JR |
756 | /* Skip the rest if configuring a null_port */ |
757 | if (!mutable->key.daddr) | |
758 | goto out; | |
759 | ||
760 | if (a[OVS_TUNNEL_ATTR_FLAGS]) | |
761 | mutable->flags = nla_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]) | |
762 | & TNL_F_PUBLIC; | |
7d5735b3 | 763 | |
b37e6334 BP |
764 | if (a[OVS_TUNNEL_ATTR_SRC_IPV4]) { |
765 | if (ipv4_is_multicast(mutable->key.daddr)) | |
766 | return -EINVAL; | |
767 | mutable->key.saddr = nla_get_be32(a[OVS_TUNNEL_ATTR_SRC_IPV4]); | |
768 | } | |
c19e6535 | 769 | |
df2c07f4 JP |
770 | if (a[OVS_TUNNEL_ATTR_TOS]) { |
771 | mutable->tos = nla_get_u8(a[OVS_TUNNEL_ATTR_TOS]); | |
749ae950 PS |
772 | /* Reject ToS config with ECN bits set. */ |
773 | if (mutable->tos & INET_ECN_MASK) | |
c19e6535 BP |
774 | return -EINVAL; |
775 | } | |
776 | ||
df2c07f4 JP |
777 | if (a[OVS_TUNNEL_ATTR_TTL]) |
778 | mutable->ttl = nla_get_u8(a[OVS_TUNNEL_ATTR_TTL]); | |
c19e6535 | 779 | |
df2c07f4 | 780 | if (!a[OVS_TUNNEL_ATTR_IN_KEY]) { |
f686a33a | 781 | mutable->key.tunnel_type |= TNL_T_KEY_MATCH; |
c19e6535 BP |
782 | mutable->flags |= TNL_F_IN_KEY_MATCH; |
783 | } else { | |
f686a33a PS |
784 | mutable->key.tunnel_type |= TNL_T_KEY_EXACT; |
785 | mutable->key.in_key = nla_get_be64(a[OVS_TUNNEL_ATTR_IN_KEY]); | |
c19e6535 BP |
786 | } |
787 | ||
df2c07f4 | 788 | if (!a[OVS_TUNNEL_ATTR_OUT_KEY]) |
c19e6535 BP |
789 | mutable->flags |= TNL_F_OUT_KEY_ACTION; |
790 | else | |
df2c07f4 | 791 | mutable->out_key = nla_get_be64(a[OVS_TUNNEL_ATTR_OUT_KEY]); |
d1eb60cc | 792 | |
b37e6334 BP |
793 | mutable->mlink = 0; |
794 | if (ipv4_is_multicast(mutable->key.daddr)) { | |
795 | struct net_device *dev; | |
796 | struct rtable *rt; | |
70cf679a | 797 | __be32 saddr = mutable->key.saddr; |
b37e6334 | 798 | |
70cf679a PS |
799 | rt = find_route(port_key_get_net(&mutable->key), |
800 | &saddr, mutable->key.daddr, | |
4b5fbf85 | 801 | tnl_ops->ipproto, mutable->tos, 0); |
b37e6334 BP |
802 | if (IS_ERR(rt)) |
803 | return -EADDRNOTAVAIL; | |
804 | dev = rt_dst(rt).dev; | |
805 | ip_rt_put(rt); | |
806 | if (__in_dev_get_rtnl(dev) == NULL) | |
807 | return -EADDRNOTAVAIL; | |
808 | mutable->mlink = dev->ifindex; | |
809 | ip_mc_inc_group(__in_dev_get_rtnl(dev), mutable->key.daddr); | |
810 | } | |
811 | ||
7d5735b3 PS |
812 | out: |
813 | old_vport = port_table_lookup(&mutable->key, &old_mutable); | |
814 | if (old_vport && old_vport != cur_vport) | |
815 | return -EEXIST; | |
816 | ||
d1eb60cc JG |
817 | return 0; |
818 | } | |
819 | ||
850b6b3b JG |
820 | struct vport *ovs_tnl_create(const struct vport_parms *parms, |
821 | const struct vport_ops *vport_ops, | |
822 | const struct tnl_ops *tnl_ops) | |
d1eb60cc JG |
823 | { |
824 | struct vport *vport; | |
825 | struct tnl_vport *tnl_vport; | |
13267549 | 826 | struct tnl_mutable_config *mutable; |
d1eb60cc JG |
827 | int err; |
828 | ||
850b6b3b | 829 | vport = ovs_vport_alloc(sizeof(struct tnl_vport), vport_ops, parms); |
d1eb60cc JG |
830 | if (IS_ERR(vport)) { |
831 | err = PTR_ERR(vport); | |
832 | goto error; | |
833 | } | |
834 | ||
835 | tnl_vport = tnl_vport_priv(vport); | |
836 | ||
94903c98 | 837 | strcpy(tnl_vport->name, parms->name); |
d1eb60cc JG |
838 | tnl_vport->tnl_ops = tnl_ops; |
839 | ||
13267549 JG |
840 | mutable = kzalloc(sizeof(struct tnl_mutable_config), GFP_KERNEL); |
841 | if (!mutable) { | |
d1eb60cc JG |
842 | err = -ENOMEM; |
843 | goto error_free_vport; | |
844 | } | |
845 | ||
2a4999f3 PS |
846 | err = tnl_set_config(ovs_dp_get_net(parms->dp), parms->options, tnl_ops, |
847 | NULL, mutable); | |
d1eb60cc JG |
848 | if (err) |
849 | goto error_free_mutable; | |
850 | ||
13267549 JG |
851 | rcu_assign_pointer(tnl_vport->mutable, mutable); |
852 | ||
3544358a | 853 | port_table_add_port(vport); |
d1eb60cc JG |
854 | return vport; |
855 | ||
856 | error_free_mutable: | |
b37e6334 | 857 | free_mutable_rtnl(mutable); |
13267549 | 858 | kfree(mutable); |
d1eb60cc | 859 | error_free_vport: |
850b6b3b | 860 | ovs_vport_free(vport); |
d1eb60cc JG |
861 | error: |
862 | return ERR_PTR(err); | |
863 | } | |
864 | ||
850b6b3b | 865 | int ovs_tnl_set_options(struct vport *vport, struct nlattr *options) |
d1eb60cc JG |
866 | { |
867 | struct tnl_vport *tnl_vport = tnl_vport_priv(vport); | |
c19e6535 | 868 | const struct tnl_mutable_config *old_mutable; |
d1eb60cc JG |
869 | struct tnl_mutable_config *mutable; |
870 | int err; | |
d1eb60cc | 871 | |
7d5735b3 PS |
872 | old_mutable = rtnl_dereference(tnl_vport->mutable); |
873 | if (!old_mutable->key.daddr) | |
874 | return -EINVAL; | |
875 | ||
c19e6535 | 876 | mutable = kzalloc(sizeof(struct tnl_mutable_config), GFP_KERNEL); |
d1eb60cc JG |
877 | if (!mutable) { |
878 | err = -ENOMEM; | |
879 | goto error; | |
880 | } | |
881 | ||
c19e6535 | 882 | /* Parse the others configured by userspace. */ |
2a4999f3 PS |
883 | err = tnl_set_config(ovs_dp_get_net(vport->dp), options, tnl_vport->tnl_ops, |
884 | vport, mutable); | |
d1eb60cc JG |
885 | if (err) |
886 | goto error_free; | |
887 | ||
f686a33a | 888 | if (port_hash(&mutable->key) != port_hash(&old_mutable->key)) |
3544358a | 889 | port_table_move_port(vport, mutable); |
b1184a78 BP |
890 | else |
891 | assign_config_rcu(vport, mutable); | |
d1eb60cc JG |
892 | |
893 | return 0; | |
894 | ||
895 | error_free: | |
b37e6334 | 896 | free_mutable_rtnl(mutable); |
d1eb60cc JG |
897 | kfree(mutable); |
898 | error: | |
899 | return err; | |
900 | } | |
901 | ||
850b6b3b | 902 | int ovs_tnl_get_options(const struct vport *vport, struct sk_buff *skb) |
c19e6535 BP |
903 | { |
904 | const struct tnl_vport *tnl_vport = tnl_vport_priv(vport); | |
905 | const struct tnl_mutable_config *mutable = rcu_dereference_rtnl(tnl_vport->mutable); | |
906 | ||
7f804ea5 JR |
907 | if (mutable->dst_port && nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, |
908 | ntohs(mutable->dst_port))) | |
c3cc8c03 DM |
909 | goto nla_put_failure; |
910 | ||
7f804ea5 JR |
911 | /* Skip the rest for null_ports */ |
912 | if (!mutable->key.daddr) | |
913 | return 0; | |
914 | ||
915 | if (nla_put_be32(skb, OVS_TUNNEL_ATTR_DST_IPV4, mutable->key.daddr)) | |
916 | goto nla_put_failure; | |
917 | if (nla_put_u32(skb, OVS_TUNNEL_ATTR_FLAGS, | |
918 | mutable->flags & TNL_F_PUBLIC)) | |
919 | goto nla_put_failure; | |
c3cc8c03 DM |
920 | if (!(mutable->flags & TNL_F_IN_KEY_MATCH) && |
921 | nla_put_be64(skb, OVS_TUNNEL_ATTR_IN_KEY, mutable->key.in_key)) | |
922 | goto nla_put_failure; | |
923 | if (!(mutable->flags & TNL_F_OUT_KEY_ACTION) && | |
924 | nla_put_be64(skb, OVS_TUNNEL_ATTR_OUT_KEY, mutable->out_key)) | |
925 | goto nla_put_failure; | |
926 | if (mutable->key.saddr && | |
927 | nla_put_be32(skb, OVS_TUNNEL_ATTR_SRC_IPV4, mutable->key.saddr)) | |
928 | goto nla_put_failure; | |
929 | if (mutable->tos && nla_put_u8(skb, OVS_TUNNEL_ATTR_TOS, mutable->tos)) | |
930 | goto nla_put_failure; | |
931 | if (mutable->ttl && nla_put_u8(skb, OVS_TUNNEL_ATTR_TTL, mutable->ttl)) | |
932 | goto nla_put_failure; | |
c19e6535 BP |
933 | |
934 | return 0; | |
935 | ||
936 | nla_put_failure: | |
937 | return -EMSGSIZE; | |
938 | } | |
939 | ||
842cf6f4 | 940 | static void free_port_rcu(struct rcu_head *rcu) |
d1eb60cc | 941 | { |
39872c70 JG |
942 | struct tnl_vport *tnl_vport = container_of(rcu, |
943 | struct tnl_vport, rcu); | |
d1eb60cc | 944 | |
39872c70 | 945 | kfree((struct tnl_mutable __force *)tnl_vport->mutable); |
850b6b3b | 946 | ovs_vport_free(tnl_vport_to_vport(tnl_vport)); |
d1eb60cc JG |
947 | } |
948 | ||
850b6b3b | 949 | void ovs_tnl_destroy(struct vport *vport) |
d1eb60cc JG |
950 | { |
951 | struct tnl_vport *tnl_vport = tnl_vport_priv(vport); | |
b37e6334 | 952 | struct tnl_mutable_config *mutable; |
f827d749 JG |
953 | |
954 | mutable = rtnl_dereference(tnl_vport->mutable); | |
3544358a | 955 | port_table_remove_port(vport); |
b37e6334 | 956 | free_mutable_rtnl(mutable); |
842cf6f4 | 957 | call_rcu(&tnl_vport->rcu, free_port_rcu); |
d1eb60cc JG |
958 | } |
959 | ||
850b6b3b | 960 | const char *ovs_tnl_get_name(const struct vport *vport) |
d1eb60cc JG |
961 | { |
962 | const struct tnl_vport *tnl_vport = tnl_vport_priv(vport); | |
963 | return tnl_vport->name; | |
964 | } | |
965 | ||
850b6b3b | 966 | void ovs_tnl_free_linked_skbs(struct sk_buff *skb) |
842cf6f4 | 967 | { |
842cf6f4 JG |
968 | while (skb) { |
969 | struct sk_buff *next = skb->next; | |
970 | kfree_skb(skb); | |
971 | skb = next; | |
972 | } | |
973 | } | |
3544358a | 974 | |
850b6b3b | 975 | int ovs_tnl_init(void) |
3544358a PS |
976 | { |
977 | int i; | |
978 | ||
979 | port_table = kmalloc(PORT_TABLE_SIZE * sizeof(struct hlist_head *), | |
2a4999f3 | 980 | GFP_KERNEL); |
3544358a PS |
981 | if (!port_table) |
982 | return -ENOMEM; | |
983 | ||
984 | for (i = 0; i < PORT_TABLE_SIZE; i++) | |
985 | INIT_HLIST_HEAD(&port_table[i]); | |
986 | ||
987 | return 0; | |
988 | } | |
989 | ||
850b6b3b | 990 | void ovs_tnl_exit(void) |
3544358a | 991 | { |
3544358a PS |
992 | kfree(port_table); |
993 | } |