Blame view
net/openvswitch/actions.c
38.5 KB
c94229992 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
ccb1352e7 net: Add Open vSw... |
2 |
/* |
4572ef52a openvswitch: Refa... |
3 |
* Copyright (c) 2007-2017 Nicira, Inc. |
ccb1352e7 net: Add Open vSw... |
4 5 6 7 8 9 10 11 |
*/ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/skbuff.h> #include <linux/in.h> #include <linux/ip.h> #include <linux/openvswitch.h> |
a175a7233 openvswitch: Add ... |
12 |
#include <linux/sctp.h> |
ccb1352e7 net: Add Open vSw... |
13 14 15 16 17 |
#include <linux/tcp.h> #include <linux/udp.h> #include <linux/in6.h> #include <linux/if_arp.h> #include <linux/if_vlan.h> |
25cd9ba0a openvswitch: Add ... |
18 |
|
7f8a436ea openvswitch: Add ... |
19 |
#include <net/dst.h> |
ccb1352e7 net: Add Open vSw... |
20 |
#include <net/ip.h> |
3fdbd1ce1 openvswitch: add ... |
21 |
#include <net/ipv6.h> |
7b85b4dff openvswitch: Incl... |
22 |
#include <net/ip6_fib.h> |
ccb1352e7 net: Add Open vSw... |
23 24 |
#include <net/checksum.h> #include <net/dsfield.h> |
25cd9ba0a openvswitch: Add ... |
25 |
#include <net/mpls.h> |
a175a7233 openvswitch: Add ... |
26 |
#include <net/sctp/checksum.h> |
ccb1352e7 net: Add Open vSw... |
27 28 |
#include "datapath.h" |
971427f35 openvswitch: Add ... |
29 |
#include "flow.h" |
7f8a436ea openvswitch: Add ... |
30 |
#include "conntrack.h" |
ccb1352e7 net: Add Open vSw... |
31 |
#include "vport.h" |
b2d0f5d5d openvswitch: enab... |
32 |
#include "flow_netlink.h" |
ccb1352e7 net: Add Open vSw... |
33 |
|
971427f35 openvswitch: Add ... |
34 35 36 |
struct deferred_action { struct sk_buff *skb; const struct nlattr *actions; |
47c697aa2 openvswitch: Defe... |
37 |
int actions_len; |
971427f35 openvswitch: Add ... |
38 39 40 41 |
/* Store pkt_key clone when creating deferred action. */ struct sw_flow_key pkt_key; }; |
7f8a436ea openvswitch: Add ... |
42 43 44 45 46 47 |
#define MAX_L2_LEN (VLAN_ETH_HLEN + 3 * MPLS_HLEN) struct ovs_frag_data { unsigned long dst; struct vport *vport; struct ovs_skb_cb cb; __be16 inner_protocol; |
c66549ffd openvswitch: corr... |
48 49 |
u16 network_offset; /* valid only for MPLS */ u16 vlan_tci; |
7f8a436ea openvswitch: Add ... |
50 51 |
__be16 vlan_proto; unsigned int l2_len; |
e2d9d8358 openvswitch: pass... |
52 |
u8 mac_proto; |
7f8a436ea openvswitch: Add ... |
53 54 55 56 |
u8 l2_data[MAX_L2_LEN]; }; static DEFINE_PER_CPU(struct ovs_frag_data, ovs_frag_data_storage); |
971427f35 openvswitch: Add ... |
57 |
#define DEFERRED_ACTION_FIFO_SIZE 10 |
2679d0404 openvswitch: avoi... |
58 59 |
#define OVS_RECURSION_LIMIT 5 #define OVS_DEFERRED_ACTION_THRESHOLD (OVS_RECURSION_LIMIT - 2) |
971427f35 openvswitch: Add ... |
60 61 62 63 64 65 |
struct action_fifo { int head; int tail; /* Deferred action fifo queue storage. */ struct deferred_action fifo[DEFERRED_ACTION_FIFO_SIZE]; }; |
4572ef52a openvswitch: Refa... |
66 |
struct action_flow_keys { |
2679d0404 openvswitch: avoi... |
67 68 |
struct sw_flow_key key[OVS_DEFERRED_ACTION_THRESHOLD]; }; |
971427f35 openvswitch: Add ... |
69 |
static struct action_fifo __percpu *action_fifos; |
4572ef52a openvswitch: Refa... |
70 |
static struct action_flow_keys __percpu *flow_keys; |
971427f35 openvswitch: Add ... |
71 |
static DEFINE_PER_CPU(int, exec_actions_level); |
4572ef52a openvswitch: Refa... |
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
/* Make a clone of the 'key', using the pre-allocated percpu 'flow_keys' * space. Return NULL if out of key spaces. */ static struct sw_flow_key *clone_key(const struct sw_flow_key *key_) { struct action_flow_keys *keys = this_cpu_ptr(flow_keys); int level = this_cpu_read(exec_actions_level); struct sw_flow_key *key = NULL; if (level <= OVS_DEFERRED_ACTION_THRESHOLD) { key = &keys->key[level - 1]; *key = *key_; } return key; } |
971427f35 openvswitch: Add ... |
88 89 90 91 92 |
static void action_fifo_init(struct action_fifo *fifo) { fifo->head = 0; fifo->tail = 0; } |
12eb18f71 openvswitch: Cons... |
93 |
static bool action_fifo_is_empty(const struct action_fifo *fifo) |
971427f35 openvswitch: Add ... |
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
{ return (fifo->head == fifo->tail); } static struct deferred_action *action_fifo_get(struct action_fifo *fifo) { if (action_fifo_is_empty(fifo)) return NULL; return &fifo->fifo[fifo->tail++]; } static struct deferred_action *action_fifo_put(struct action_fifo *fifo) { if (fifo->head >= DEFERRED_ACTION_FIFO_SIZE - 1) return NULL; return &fifo->fifo[fifo->head++]; } /* Return true if fifo is not full */ static struct deferred_action *add_deferred_actions(struct sk_buff *skb, |
47c697aa2 openvswitch: Defe... |
116 117 118 |
const struct sw_flow_key *key, const struct nlattr *actions, const int actions_len) |
971427f35 openvswitch: Add ... |
119 120 121 122 123 124 125 126 |
{ struct action_fifo *fifo; struct deferred_action *da; fifo = this_cpu_ptr(action_fifos); da = action_fifo_put(fifo); if (da) { da->skb = skb; |
47c697aa2 openvswitch: Defe... |
127 128 |
da->actions = actions; da->actions_len = actions_len; |
971427f35 openvswitch: Add ... |
129 130 131 132 133 |
da->pkt_key = *key; } return da; } |
fff06c36a openvswitch: Opti... |
134 135 |
static void invalidate_flow_key(struct sw_flow_key *key) { |
329f45bc4 openvswitch: add ... |
136 |
key->mac_proto |= SW_FLOW_KEY_INVALID; |
fff06c36a openvswitch: Opti... |
137 138 139 140 |
} static bool is_flow_key_valid(const struct sw_flow_key *key) { |
329f45bc4 openvswitch: add ... |
141 |
return !(key->mac_proto & SW_FLOW_KEY_INVALID); |
fff06c36a openvswitch: Opti... |
142 |
} |
bef7f7567 Openvswitch: Refa... |
143 144 145 146 147 |
static int clone_execute(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, u32 recirc_id, const struct nlattr *actions, int len, bool last, bool clone_flow_key); |
4d5ec89fc net: openvswitch:... |
148 149 150 |
static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, const struct nlattr *attr, int len); |
fff06c36a openvswitch: Opti... |
151 |
static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key, |
f66b53fdb openvswitch: New ... |
152 |
__be32 mpls_lse, __be16 mpls_ethertype, __u16 mac_len) |
25cd9ba0a openvswitch: Add ... |
153 |
{ |
8822e270d net: core: move p... |
154 |
int err; |
25cd9ba0a openvswitch: Add ... |
155 |
|
f66b53fdb openvswitch: New ... |
156 |
err = skb_mpls_push(skb, mpls_lse, mpls_ethertype, mac_len, !!mac_len); |
8822e270d net: core: move p... |
157 158 |
if (err) return err; |
25cd9ba0a openvswitch: Add ... |
159 |
|
f66b53fdb openvswitch: New ... |
160 161 |
if (!mac_len) key->mac_proto = MAC_PROTO_NONE; |
fff06c36a openvswitch: Opti... |
162 |
invalidate_flow_key(key); |
25cd9ba0a openvswitch: Add ... |
163 164 |
return 0; } |
fff06c36a openvswitch: Opti... |
165 166 |
static int pop_mpls(struct sk_buff *skb, struct sw_flow_key *key, const __be16 ethertype) |
25cd9ba0a openvswitch: Add ... |
167 |
{ |
25cd9ba0a openvswitch: Add ... |
168 |
int err; |
040b5cfbc Fixed updating of... |
169 170 |
err = skb_mpls_pop(skb, ethertype, skb->mac_len, ovs_key_mac_proto(key) == MAC_PROTO_ETHERNET); |
ed246cee0 net: core: move p... |
171 |
if (err) |
25cd9ba0a openvswitch: Add ... |
172 |
return err; |
f66b53fdb openvswitch: New ... |
173 174 |
if (ethertype == htons(ETH_P_TEB)) key->mac_proto = MAC_PROTO_ETHERNET; |
fff06c36a openvswitch: Opti... |
175 |
invalidate_flow_key(key); |
25cd9ba0a openvswitch: Add ... |
176 177 |
return 0; } |
83d2b9ba1 net: openvswitch:... |
178 179 |
static int set_mpls(struct sk_buff *skb, struct sw_flow_key *flow_key, const __be32 *mpls_lse, const __be32 *mask) |
25cd9ba0a openvswitch: Add ... |
180 |
{ |
85de4a210 openvswitch: use ... |
181 |
struct mpls_shim_hdr *stack; |
83d2b9ba1 net: openvswitch:... |
182 |
__be32 lse; |
25cd9ba0a openvswitch: Add ... |
183 |
int err; |
43c13605b net: openvswitch:... |
184 185 |
if (!pskb_may_pull(skb, skb_network_offset(skb) + MPLS_HLEN)) return -ENOMEM; |
85de4a210 openvswitch: use ... |
186 187 |
stack = mpls_hdr(skb); lse = OVS_MASKED(stack->label_stack_entry, *mpls_lse, *mask); |
d27cf5c59 net: core: add MP... |
188 189 190 |
err = skb_mpls_update_lse(skb, lse); if (err) return err; |
25cd9ba0a openvswitch: Add ... |
191 |
|
fbdcdd78d Change in Openvsw... |
192 |
flow_key->mpls.lse[0] = lse; |
25cd9ba0a openvswitch: Add ... |
193 194 |
return 0; } |
fff06c36a openvswitch: Opti... |
195 |
static int pop_vlan(struct sk_buff *skb, struct sw_flow_key *key) |
ccb1352e7 net: Add Open vSw... |
196 |
{ |
ccb1352e7 net: Add Open vSw... |
197 |
int err; |
93515d53b net: move vlan po... |
198 |
err = skb_vlan_pop(skb); |
018c1dda5 openvswitch: 802.... |
199 |
if (skb_vlan_tag_present(skb)) { |
93515d53b net: move vlan po... |
200 |
invalidate_flow_key(key); |
018c1dda5 openvswitch: 802.... |
201 202 203 204 |
} else { key->eth.vlan.tci = 0; key->eth.vlan.tpid = 0; } |
93515d53b net: move vlan po... |
205 |
return err; |
ccb1352e7 net: Add Open vSw... |
206 |
} |
fff06c36a openvswitch: Opti... |
207 208 |
static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key, const struct ovs_action_push_vlan *vlan) |
ccb1352e7 net: Add Open vSw... |
209 |
{ |
018c1dda5 openvswitch: 802.... |
210 |
if (skb_vlan_tag_present(skb)) { |
fff06c36a openvswitch: Opti... |
211 |
invalidate_flow_key(key); |
018c1dda5 openvswitch: 802.... |
212 213 214 215 |
} else { key->eth.vlan.tci = vlan->vlan_tci; key->eth.vlan.tpid = vlan->vlan_tpid; } |
93515d53b net: move vlan po... |
216 |
return skb_vlan_push(skb, vlan->vlan_tpid, |
9df46aefa OVS: remove use o... |
217 |
ntohs(vlan->vlan_tci) & ~VLAN_CFI_MASK); |
ccb1352e7 net: Add Open vSw... |
218 |
} |
83d2b9ba1 net: openvswitch:... |
219 220 221 222 223 224 |
/* 'src' is already properly masked. */ static void ether_addr_copy_masked(u8 *dst_, const u8 *src_, const u8 *mask_) { u16 *dst = (u16 *)dst_; const u16 *src = (const u16 *)src_; const u16 *mask = (const u16 *)mask_; |
be26b9a88 openvswitch: Move... |
225 226 227 |
OVS_SET_MASKED(dst[0], src[0], mask[0]); OVS_SET_MASKED(dst[1], src[1], mask[1]); OVS_SET_MASKED(dst[2], src[2], mask[2]); |
83d2b9ba1 net: openvswitch:... |
228 229 230 231 232 |
} static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *flow_key, const struct ovs_key_ethernet *key, const struct ovs_key_ethernet *mask) |
ccb1352e7 net: Add Open vSw... |
233 234 |
{ int err; |
83d2b9ba1 net: openvswitch:... |
235 |
|
e21951212 net: move make_wr... |
236 |
err = skb_ensure_writable(skb, ETH_HLEN); |
ccb1352e7 net: Add Open vSw... |
237 238 |
if (unlikely(err)) return err; |
b34df5e80 openvswitch: make... |
239 |
skb_postpull_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2); |
83d2b9ba1 net: openvswitch:... |
240 241 242 243 |
ether_addr_copy_masked(eth_hdr(skb)->h_source, key->eth_src, mask->eth_src); ether_addr_copy_masked(eth_hdr(skb)->h_dest, key->eth_dst, mask->eth_dst); |
ccb1352e7 net: Add Open vSw... |
244 |
|
6b83d28a5 net: use skb_post... |
245 |
skb_postpush_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2); |
b34df5e80 openvswitch: make... |
246 |
|
83d2b9ba1 net: openvswitch:... |
247 248 |
ether_addr_copy(flow_key->eth.src, eth_hdr(skb)->h_source); ether_addr_copy(flow_key->eth.dst, eth_hdr(skb)->h_dest); |
ccb1352e7 net: Add Open vSw... |
249 250 |
return 0; } |
91820da6a openvswitch: add ... |
251 252 253 254 255 |
/* pop_eth does not support VLAN packets as this action is never called * for them. */ static int pop_eth(struct sk_buff *skb, struct sw_flow_key *key) { |
19fbcb36a net/sched: act_vl... |
256 257 258 259 260 |
int err; err = skb_eth_pop(skb); if (err) return err; |
91820da6a openvswitch: add ... |
261 262 263 264 265 266 267 268 269 270 |
/* safe right before invalidate_flow_key */ key->mac_proto = MAC_PROTO_NONE; invalidate_flow_key(key); return 0; } static int push_eth(struct sk_buff *skb, struct sw_flow_key *key, const struct ovs_action_push_eth *ethh) { |
19fbcb36a net/sched: act_vl... |
271 |
int err; |
91820da6a openvswitch: add ... |
272 |
|
19fbcb36a net/sched: act_vl... |
273 274 275 276 |
err = skb_eth_push(skb, ethh->addresses.eth_dst, ethh->addresses.eth_src); if (err) return err; |
91820da6a openvswitch: add ... |
277 278 279 280 281 282 |
/* safe right before invalidate_flow_key */ key->mac_proto = MAC_PROTO_ETHERNET; invalidate_flow_key(key); return 0; } |
b2d0f5d5d openvswitch: enab... |
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
static int push_nsh(struct sk_buff *skb, struct sw_flow_key *key, const struct nshhdr *nh) { int err; err = nsh_push(skb, nh); if (err) return err; /* safe right before invalidate_flow_key */ key->mac_proto = MAC_PROTO_NONE; invalidate_flow_key(key); return 0; } static int pop_nsh(struct sk_buff *skb, struct sw_flow_key *key) { int err; err = nsh_pop(skb); if (err) return err; /* safe right before invalidate_flow_key */ if (skb->protocol == htons(ETH_P_TEB)) key->mac_proto = MAC_PROTO_ETHERNET; else key->mac_proto = MAC_PROTO_NONE; invalidate_flow_key(key); return 0; } |
3576fd794 openvswitch: Fix ... |
314 315 |
static void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh, __be32 addr, __be32 new_addr) |
ccb1352e7 net: Add Open vSw... |
316 317 |
{ int transport_len = skb->len - skb_transport_offset(skb); |
3576fd794 openvswitch: Fix ... |
318 319 |
if (nh->frag_off & htons(IP_OFFSET)) return; |
ccb1352e7 net: Add Open vSw... |
320 321 322 |
if (nh->protocol == IPPROTO_TCP) { if (likely(transport_len >= sizeof(struct tcphdr))) inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb, |
4b048d6d9 net: Change pseud... |
323 |
addr, new_addr, true); |
ccb1352e7 net: Add Open vSw... |
324 |
} else if (nh->protocol == IPPROTO_UDP) { |
81e5d41d7 openvswitch: Fix ... |
325 326 327 328 329 |
if (likely(transport_len >= sizeof(struct udphdr))) { struct udphdr *uh = udp_hdr(skb); if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) { inet_proto_csum_replace4(&uh->check, skb, |
4b048d6d9 net: Change pseud... |
330 |
addr, new_addr, true); |
81e5d41d7 openvswitch: Fix ... |
331 332 333 334 |
if (!uh->check) uh->check = CSUM_MANGLED_0; } } |
ccb1352e7 net: Add Open vSw... |
335 |
} |
3576fd794 openvswitch: Fix ... |
336 |
} |
ccb1352e7 net: Add Open vSw... |
337 |
|
3576fd794 openvswitch: Fix ... |
338 339 340 341 |
static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh, __be32 *addr, __be32 new_addr) { update_ip_l4_checksum(skb, nh, *addr, new_addr); |
ccb1352e7 net: Add Open vSw... |
342 |
csum_replace4(&nh->check, *addr, new_addr); |
7539fadcb net: Add utility ... |
343 |
skb_clear_hash(skb); |
ccb1352e7 net: Add Open vSw... |
344 345 |
*addr = new_addr; } |
3fdbd1ce1 openvswitch: add ... |
346 347 348 349 |
static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto, __be32 addr[4], const __be32 new_addr[4]) { int transport_len = skb->len - skb_transport_offset(skb); |
856447d02 openvswitch: Fix ... |
350 |
if (l4_proto == NEXTHDR_TCP) { |
3fdbd1ce1 openvswitch: add ... |
351 352 |
if (likely(transport_len >= sizeof(struct tcphdr))) inet_proto_csum_replace16(&tcp_hdr(skb)->check, skb, |
4b048d6d9 net: Change pseud... |
353 |
addr, new_addr, true); |
856447d02 openvswitch: Fix ... |
354 |
} else if (l4_proto == NEXTHDR_UDP) { |
3fdbd1ce1 openvswitch: add ... |
355 356 357 358 359 |
if (likely(transport_len >= sizeof(struct udphdr))) { struct udphdr *uh = udp_hdr(skb); if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) { inet_proto_csum_replace16(&uh->check, skb, |
4b048d6d9 net: Change pseud... |
360 |
addr, new_addr, true); |
3fdbd1ce1 openvswitch: add ... |
361 362 363 364 |
if (!uh->check) uh->check = CSUM_MANGLED_0; } } |
856447d02 openvswitch: Fix ... |
365 366 367 |
} else if (l4_proto == NEXTHDR_ICMP) { if (likely(transport_len >= sizeof(struct icmp6hdr))) inet_proto_csum_replace16(&icmp6_hdr(skb)->icmp6_cksum, |
4b048d6d9 net: Change pseud... |
368 |
skb, addr, new_addr, true); |
3fdbd1ce1 openvswitch: add ... |
369 370 |
} } |
83d2b9ba1 net: openvswitch:... |
371 372 373 |
static void mask_ipv6_addr(const __be32 old[4], const __be32 addr[4], const __be32 mask[4], __be32 masked[4]) { |
be26b9a88 openvswitch: Move... |
374 375 376 377 |
masked[0] = OVS_MASKED(old[0], addr[0], mask[0]); masked[1] = OVS_MASKED(old[1], addr[1], mask[1]); masked[2] = OVS_MASKED(old[2], addr[2], mask[2]); masked[3] = OVS_MASKED(old[3], addr[3], mask[3]); |
83d2b9ba1 net: openvswitch:... |
378 |
} |
3fdbd1ce1 openvswitch: add ... |
379 380 381 382 383 384 |
static void set_ipv6_addr(struct sk_buff *skb, u8 l4_proto, __be32 addr[4], const __be32 new_addr[4], bool recalculate_csum) { if (recalculate_csum) update_ipv6_checksum(skb, l4_proto, addr, new_addr); |
7539fadcb net: Add utility ... |
385 |
skb_clear_hash(skb); |
3fdbd1ce1 openvswitch: add ... |
386 387 |
memcpy(addr, new_addr, sizeof(__be32[4])); } |
83d2b9ba1 net: openvswitch:... |
388 |
static void set_ipv6_fl(struct ipv6hdr *nh, u32 fl, u32 mask) |
3fdbd1ce1 openvswitch: add ... |
389 |
{ |
83d2b9ba1 net: openvswitch:... |
390 |
/* Bits 21-24 are always unmasked, so this retains their values. */ |
be26b9a88 openvswitch: Move... |
391 392 393 |
OVS_SET_MASKED(nh->flow_lbl[0], (u8)(fl >> 16), (u8)(mask >> 16)); OVS_SET_MASKED(nh->flow_lbl[1], (u8)(fl >> 8), (u8)(mask >> 8)); OVS_SET_MASKED(nh->flow_lbl[2], (u8)fl, (u8)mask); |
3fdbd1ce1 openvswitch: add ... |
394 |
} |
83d2b9ba1 net: openvswitch:... |
395 396 |
static void set_ip_ttl(struct sk_buff *skb, struct iphdr *nh, u8 new_ttl, u8 mask) |
3fdbd1ce1 openvswitch: add ... |
397 |
{ |
be26b9a88 openvswitch: Move... |
398 |
new_ttl = OVS_MASKED(nh->ttl, new_ttl, mask); |
3fdbd1ce1 openvswitch: add ... |
399 |
|
ccb1352e7 net: Add Open vSw... |
400 401 402 |
csum_replace2(&nh->check, htons(nh->ttl << 8), htons(new_ttl << 8)); nh->ttl = new_ttl; } |
83d2b9ba1 net: openvswitch:... |
403 404 405 |
static int set_ipv4(struct sk_buff *skb, struct sw_flow_key *flow_key, const struct ovs_key_ipv4 *key, const struct ovs_key_ipv4 *mask) |
ccb1352e7 net: Add Open vSw... |
406 407 |
{ struct iphdr *nh; |
83d2b9ba1 net: openvswitch:... |
408 |
__be32 new_addr; |
ccb1352e7 net: Add Open vSw... |
409 |
int err; |
e21951212 net: move make_wr... |
410 411 |
err = skb_ensure_writable(skb, skb_network_offset(skb) + sizeof(struct iphdr)); |
ccb1352e7 net: Add Open vSw... |
412 413 414 415 |
if (unlikely(err)) return err; nh = ip_hdr(skb); |
83d2b9ba1 net: openvswitch:... |
416 417 418 419 420 |
/* Setting an IP addresses is typically only a side effect of * matching on them in the current userspace implementation, so it * makes sense to check if the value actually changed. */ if (mask->ipv4_src) { |
be26b9a88 openvswitch: Move... |
421 |
new_addr = OVS_MASKED(nh->saddr, key->ipv4_src, mask->ipv4_src); |
ccb1352e7 net: Add Open vSw... |
422 |
|
83d2b9ba1 net: openvswitch:... |
423 424 425 426 |
if (unlikely(new_addr != nh->saddr)) { set_ip_addr(skb, nh, &nh->saddr, new_addr); flow_key->ipv4.addr.src = new_addr; } |
fff06c36a openvswitch: Opti... |
427 |
} |
83d2b9ba1 net: openvswitch:... |
428 |
if (mask->ipv4_dst) { |
be26b9a88 openvswitch: Move... |
429 |
new_addr = OVS_MASKED(nh->daddr, key->ipv4_dst, mask->ipv4_dst); |
ccb1352e7 net: Add Open vSw... |
430 |
|
83d2b9ba1 net: openvswitch:... |
431 432 433 434 |
if (unlikely(new_addr != nh->daddr)) { set_ip_addr(skb, nh, &nh->daddr, new_addr); flow_key->ipv4.addr.dst = new_addr; } |
fff06c36a openvswitch: Opti... |
435 |
} |
83d2b9ba1 net: openvswitch:... |
436 437 438 439 440 441 442 |
if (mask->ipv4_tos) { ipv4_change_dsfield(nh, ~mask->ipv4_tos, key->ipv4_tos); flow_key->ip.tos = nh->tos; } if (mask->ipv4_ttl) { set_ip_ttl(skb, nh, key->ipv4_ttl, mask->ipv4_ttl); flow_key->ip.ttl = nh->ttl; |
fff06c36a openvswitch: Opti... |
443 |
} |
ccb1352e7 net: Add Open vSw... |
444 445 446 |
return 0; } |
83d2b9ba1 net: openvswitch:... |
447 448 449 450 451 452 453 454 |
static bool is_ipv6_mask_nonzero(const __be32 addr[4]) { return !!(addr[0] | addr[1] | addr[2] | addr[3]); } static int set_ipv6(struct sk_buff *skb, struct sw_flow_key *flow_key, const struct ovs_key_ipv6 *key, const struct ovs_key_ipv6 *mask) |
3fdbd1ce1 openvswitch: add ... |
455 456 457 |
{ struct ipv6hdr *nh; int err; |
3fdbd1ce1 openvswitch: add ... |
458 |
|
e21951212 net: move make_wr... |
459 460 |
err = skb_ensure_writable(skb, skb_network_offset(skb) + sizeof(struct ipv6hdr)); |
3fdbd1ce1 openvswitch: add ... |
461 462 463 464 |
if (unlikely(err)) return err; nh = ipv6_hdr(skb); |
3fdbd1ce1 openvswitch: add ... |
465 |
|
83d2b9ba1 net: openvswitch:... |
466 467 468 469 470 471 472 473 474 475 476 |
/* Setting an IP addresses is typically only a side effect of * matching on them in the current userspace implementation, so it * makes sense to check if the value actually changed. */ if (is_ipv6_mask_nonzero(mask->ipv6_src)) { __be32 *saddr = (__be32 *)&nh->saddr; __be32 masked[4]; mask_ipv6_addr(saddr, key->ipv6_src, mask->ipv6_src, masked); if (unlikely(memcmp(saddr, masked, sizeof(masked)))) { |
b4f70527f openvswitch: use ... |
477 |
set_ipv6_addr(skb, flow_key->ip.proto, saddr, masked, |
83d2b9ba1 net: openvswitch:... |
478 479 480 481 482 483 |
true); memcpy(&flow_key->ipv6.addr.src, masked, sizeof(flow_key->ipv6.addr.src)); } } if (is_ipv6_mask_nonzero(mask->ipv6_dst)) { |
3fdbd1ce1 openvswitch: add ... |
484 485 486 |
unsigned int offset = 0; int flags = IP6_FH_F_SKIP_RH; bool recalc_csum = true; |
83d2b9ba1 net: openvswitch:... |
487 488 489 490 491 492 493 494 495 496 497 |
__be32 *daddr = (__be32 *)&nh->daddr; __be32 masked[4]; mask_ipv6_addr(daddr, key->ipv6_dst, mask->ipv6_dst, masked); if (unlikely(memcmp(daddr, masked, sizeof(masked)))) { if (ipv6_ext_hdr(nh->nexthdr)) recalc_csum = (ipv6_find_hdr(skb, &offset, NEXTHDR_ROUTING, NULL, &flags) != NEXTHDR_ROUTING); |
b4f70527f openvswitch: use ... |
498 |
set_ipv6_addr(skb, flow_key->ip.proto, daddr, masked, |
83d2b9ba1 net: openvswitch:... |
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 |
recalc_csum); memcpy(&flow_key->ipv6.addr.dst, masked, sizeof(flow_key->ipv6.addr.dst)); } } if (mask->ipv6_tclass) { ipv6_change_dsfield(nh, ~mask->ipv6_tclass, key->ipv6_tclass); flow_key->ip.tos = ipv6_get_dsfield(nh); } if (mask->ipv6_label) { set_ipv6_fl(nh, ntohl(key->ipv6_label), ntohl(mask->ipv6_label)); flow_key->ipv6.label = *(__be32 *)nh & htonl(IPV6_FLOWINFO_FLOWLABEL); } if (mask->ipv6_hlimit) { |
be26b9a88 openvswitch: Move... |
515 516 |
OVS_SET_MASKED(nh->hop_limit, key->ipv6_hlimit, mask->ipv6_hlimit); |
83d2b9ba1 net: openvswitch:... |
517 |
flow_key->ip.ttl = nh->hop_limit; |
3fdbd1ce1 openvswitch: add ... |
518 |
} |
3fdbd1ce1 openvswitch: add ... |
519 520 |
return 0; } |
b2d0f5d5d openvswitch: enab... |
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 |
static int set_nsh(struct sk_buff *skb, struct sw_flow_key *flow_key, const struct nlattr *a) { struct nshhdr *nh; size_t length; int err; u8 flags; u8 ttl; int i; struct ovs_key_nsh key; struct ovs_key_nsh mask; err = nsh_key_from_nlattr(a, &key, &mask); if (err) return err; /* Make sure the NSH base header is there */ if (!pskb_may_pull(skb, skb_network_offset(skb) + NSH_BASE_HDR_LEN)) return -ENOMEM; nh = nsh_hdr(skb); length = nsh_hdr_len(nh); /* Make sure the whole NSH header is there */ err = skb_ensure_writable(skb, skb_network_offset(skb) + length); if (unlikely(err)) return err; nh = nsh_hdr(skb); skb_postpull_rcsum(skb, nh, length); flags = nsh_get_flags(nh); flags = OVS_MASKED(flags, key.base.flags, mask.base.flags); flow_key->nsh.base.flags = flags; ttl = nsh_get_ttl(nh); ttl = OVS_MASKED(ttl, key.base.ttl, mask.base.ttl); flow_key->nsh.base.ttl = ttl; nsh_set_flags_and_ttl(nh, flags, ttl); nh->path_hdr = OVS_MASKED(nh->path_hdr, key.base.path_hdr, mask.base.path_hdr); flow_key->nsh.base.path_hdr = nh->path_hdr; switch (nh->mdtype) { case NSH_M_TYPE1: for (i = 0; i < NSH_MD1_CONTEXT_SIZE; i++) { nh->md1.context[i] = OVS_MASKED(nh->md1.context[i], key.context[i], mask.context[i]); } memcpy(flow_key->nsh.context, nh->md1.context, sizeof(nh->md1.context)); break; case NSH_M_TYPE2: memset(flow_key->nsh.context, 0, sizeof(flow_key->nsh.context)); break; default: return -EINVAL; } skb_postpush_rcsum(skb, nh, length); return 0; } |
e21951212 net: move make_wr... |
583 |
/* Must follow skb_ensure_writable() since that can move the skb data. */ |
ccb1352e7 net: Add Open vSw... |
584 |
static void set_tp_port(struct sk_buff *skb, __be16 *port, |
83d2b9ba1 net: openvswitch:... |
585 |
__be16 new_port, __sum16 *check) |
ccb1352e7 net: Add Open vSw... |
586 |
{ |
4b048d6d9 net: Change pseud... |
587 |
inet_proto_csum_replace2(check, skb, *port, new_port, false); |
ccb1352e7 net: Add Open vSw... |
588 |
*port = new_port; |
81e5d41d7 openvswitch: Fix ... |
589 |
} |
83d2b9ba1 net: openvswitch:... |
590 591 592 |
static int set_udp(struct sk_buff *skb, struct sw_flow_key *flow_key, const struct ovs_key_udp *key, const struct ovs_key_udp *mask) |
ccb1352e7 net: Add Open vSw... |
593 594 |
{ struct udphdr *uh; |
83d2b9ba1 net: openvswitch:... |
595 |
__be16 src, dst; |
ccb1352e7 net: Add Open vSw... |
596 |
int err; |
e21951212 net: move make_wr... |
597 598 |
err = skb_ensure_writable(skb, skb_transport_offset(skb) + sizeof(struct udphdr)); |
ccb1352e7 net: Add Open vSw... |
599 600 601 602 |
if (unlikely(err)) return err; uh = udp_hdr(skb); |
83d2b9ba1 net: openvswitch:... |
603 |
/* Either of the masks is non-zero, so do not bother checking them. */ |
be26b9a88 openvswitch: Move... |
604 605 |
src = OVS_MASKED(uh->source, key->udp_src, mask->udp_src); dst = OVS_MASKED(uh->dest, key->udp_dst, mask->udp_dst); |
ccb1352e7 net: Add Open vSw... |
606 |
|
83d2b9ba1 net: openvswitch:... |
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 |
if (uh->check && skb->ip_summed != CHECKSUM_PARTIAL) { if (likely(src != uh->source)) { set_tp_port(skb, &uh->source, src, &uh->check); flow_key->tp.src = src; } if (likely(dst != uh->dest)) { set_tp_port(skb, &uh->dest, dst, &uh->check); flow_key->tp.dst = dst; } if (unlikely(!uh->check)) uh->check = CSUM_MANGLED_0; } else { uh->source = src; uh->dest = dst; flow_key->tp.src = src; flow_key->tp.dst = dst; |
fff06c36a openvswitch: Opti... |
624 |
} |
ccb1352e7 net: Add Open vSw... |
625 |
|
83d2b9ba1 net: openvswitch:... |
626 |
skb_clear_hash(skb); |
ccb1352e7 net: Add Open vSw... |
627 628 |
return 0; } |
83d2b9ba1 net: openvswitch:... |
629 630 631 |
static int set_tcp(struct sk_buff *skb, struct sw_flow_key *flow_key, const struct ovs_key_tcp *key, const struct ovs_key_tcp *mask) |
ccb1352e7 net: Add Open vSw... |
632 633 |
{ struct tcphdr *th; |
83d2b9ba1 net: openvswitch:... |
634 |
__be16 src, dst; |
ccb1352e7 net: Add Open vSw... |
635 |
int err; |
e21951212 net: move make_wr... |
636 637 |
err = skb_ensure_writable(skb, skb_transport_offset(skb) + sizeof(struct tcphdr)); |
ccb1352e7 net: Add Open vSw... |
638 639 640 641 |
if (unlikely(err)) return err; th = tcp_hdr(skb); |
be26b9a88 openvswitch: Move... |
642 |
src = OVS_MASKED(th->source, key->tcp_src, mask->tcp_src); |
83d2b9ba1 net: openvswitch:... |
643 644 645 |
if (likely(src != th->source)) { set_tp_port(skb, &th->source, src, &th->check); flow_key->tp.src = src; |
fff06c36a openvswitch: Opti... |
646 |
} |
be26b9a88 openvswitch: Move... |
647 |
dst = OVS_MASKED(th->dest, key->tcp_dst, mask->tcp_dst); |
83d2b9ba1 net: openvswitch:... |
648 649 650 |
if (likely(dst != th->dest)) { set_tp_port(skb, &th->dest, dst, &th->check); flow_key->tp.dst = dst; |
fff06c36a openvswitch: Opti... |
651 |
} |
83d2b9ba1 net: openvswitch:... |
652 |
skb_clear_hash(skb); |
ccb1352e7 net: Add Open vSw... |
653 654 655 |
return 0; } |
83d2b9ba1 net: openvswitch:... |
656 657 658 |
static int set_sctp(struct sk_buff *skb, struct sw_flow_key *flow_key, const struct ovs_key_sctp *key, const struct ovs_key_sctp *mask) |
a175a7233 openvswitch: Add ... |
659 |
{ |
83d2b9ba1 net: openvswitch:... |
660 |
unsigned int sctphoff = skb_transport_offset(skb); |
a175a7233 openvswitch: Add ... |
661 |
struct sctphdr *sh; |
83d2b9ba1 net: openvswitch:... |
662 |
__le32 old_correct_csum, new_csum, old_csum; |
a175a7233 openvswitch: Add ... |
663 |
int err; |
a175a7233 openvswitch: Add ... |
664 |
|
e21951212 net: move make_wr... |
665 |
err = skb_ensure_writable(skb, sctphoff + sizeof(struct sctphdr)); |
a175a7233 openvswitch: Add ... |
666 667 668 669 |
if (unlikely(err)) return err; sh = sctp_hdr(skb); |
83d2b9ba1 net: openvswitch:... |
670 671 |
old_csum = sh->checksum; old_correct_csum = sctp_compute_cksum(skb, sctphoff); |
a175a7233 openvswitch: Add ... |
672 |
|
be26b9a88 openvswitch: Move... |
673 674 |
sh->source = OVS_MASKED(sh->source, key->sctp_src, mask->sctp_src); sh->dest = OVS_MASKED(sh->dest, key->sctp_dst, mask->sctp_dst); |
a175a7233 openvswitch: Add ... |
675 |
|
83d2b9ba1 net: openvswitch:... |
676 |
new_csum = sctp_compute_cksum(skb, sctphoff); |
a175a7233 openvswitch: Add ... |
677 |
|
83d2b9ba1 net: openvswitch:... |
678 679 |
/* Carry any checksum errors through. */ sh->checksum = old_csum ^ old_correct_csum ^ new_csum; |
a175a7233 openvswitch: Add ... |
680 |
|
83d2b9ba1 net: openvswitch:... |
681 682 683 |
skb_clear_hash(skb); flow_key->tp.src = sh->source; flow_key->tp.dst = sh->dest; |
a175a7233 openvswitch: Add ... |
684 685 686 |
return 0; } |
cf3266ad4 net: openvswitch:... |
687 688 |
static int ovs_vport_output(struct net *net, struct sock *sk, struct sk_buff *skb) |
7f8a436ea openvswitch: Add ... |
689 690 691 692 693 694 695 696 697 698 699 700 |
{ struct ovs_frag_data *data = this_cpu_ptr(&ovs_frag_data_storage); struct vport *vport = data->vport; if (skb_cow_head(skb, data->l2_len) < 0) { kfree_skb(skb); return -ENOMEM; } __skb_dst_copy(skb, data->dst); *OVS_CB(skb) = data->cb; skb->inner_protocol = data->inner_protocol; |
9df46aefa OVS: remove use o... |
701 702 703 704 |
if (data->vlan_tci & VLAN_CFI_MASK) __vlan_hwaccel_put_tag(skb, data->vlan_proto, data->vlan_tci & ~VLAN_CFI_MASK); else __vlan_hwaccel_clear_tag(skb); |
7f8a436ea openvswitch: Add ... |
705 706 707 708 |
/* Reconstruct the MAC header. */ skb_push(skb, data->l2_len); memcpy(skb->data, &data->l2_data, data->l2_len); |
6b83d28a5 net: use skb_post... |
709 |
skb_postpush_rcsum(skb, skb->data, data->l2_len); |
7f8a436ea openvswitch: Add ... |
710 |
skb_reset_mac_header(skb); |
c66549ffd openvswitch: corr... |
711 712 713 714 715 |
if (eth_p_mpls(skb->protocol)) { skb->inner_network_header = skb->network_header; skb_set_network_header(skb, data->network_offset); skb_reset_mac_len(skb); } |
e2d9d8358 openvswitch: pass... |
716 |
ovs_vport_send(vport, skb, data->mac_proto); |
7f8a436ea openvswitch: Add ... |
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 |
return 0; } static unsigned int ovs_dst_get_mtu(const struct dst_entry *dst) { return dst->dev->mtu; } static struct dst_ops ovs_dst_ops = { .family = AF_UNSPEC, .mtu = ovs_dst_get_mtu, }; /* prepare_frag() is called once per (larger-than-MTU) frame; its inverse is * ovs_vport_output(), which is called once per fragmented packet. */ |
c66549ffd openvswitch: corr... |
734 |
static void prepare_frag(struct vport *vport, struct sk_buff *skb, |
e2d9d8358 openvswitch: pass... |
735 |
u16 orig_network_offset, u8 mac_proto) |
7f8a436ea openvswitch: Add ... |
736 737 738 739 740 741 742 743 744 |
{ unsigned int hlen = skb_network_offset(skb); struct ovs_frag_data *data; data = this_cpu_ptr(&ovs_frag_data_storage); data->dst = skb->_skb_refdst; data->vport = vport; data->cb = *OVS_CB(skb); data->inner_protocol = skb->inner_protocol; |
c66549ffd openvswitch: corr... |
745 |
data->network_offset = orig_network_offset; |
9df46aefa OVS: remove use o... |
746 747 748 749 |
if (skb_vlan_tag_present(skb)) data->vlan_tci = skb_vlan_tag_get(skb) | VLAN_CFI_MASK; else data->vlan_tci = 0; |
7f8a436ea openvswitch: Add ... |
750 |
data->vlan_proto = skb->vlan_proto; |
e2d9d8358 openvswitch: pass... |
751 |
data->mac_proto = mac_proto; |
7f8a436ea openvswitch: Add ... |
752 753 754 755 756 757 |
data->l2_len = hlen; memcpy(&data->l2_data, skb->data, hlen); memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); skb_pull(skb, hlen); } |
c559cd3ad openvswitch: Pass... |
758 |
static void ovs_fragment(struct net *net, struct vport *vport, |
e2d9d8358 openvswitch: pass... |
759 760 |
struct sk_buff *skb, u16 mru, struct sw_flow_key *key) |
7f8a436ea openvswitch: Add ... |
761 |
{ |
c66549ffd openvswitch: corr... |
762 763 764 765 766 767 |
u16 orig_network_offset = 0; if (eth_p_mpls(skb->protocol)) { orig_network_offset = skb_network_offset(skb); skb->network_header = skb->inner_network_header; } |
7f8a436ea openvswitch: Add ... |
768 769 |
if (skb_network_offset(skb) > MAX_L2_LEN) { OVS_NLERR(1, "L2 header too long to fragment"); |
b8f225706 openvswitch: Fix ... |
770 |
goto err; |
7f8a436ea openvswitch: Add ... |
771 |
} |
e2d9d8358 openvswitch: pass... |
772 |
if (key->eth.type == htons(ETH_P_IP)) { |
7f8a436ea openvswitch: Add ... |
773 774 |
struct dst_entry ovs_dst; unsigned long orig_dst; |
e2d9d8358 openvswitch: pass... |
775 776 |
prepare_frag(vport, skb, orig_network_offset, ovs_key_mac_proto(key)); |
7f8a436ea openvswitch: Add ... |
777 778 779 780 781 782 783 |
dst_init(&ovs_dst, &ovs_dst_ops, NULL, 1, DST_OBSOLETE_NONE, DST_NOCOUNT); ovs_dst.dev = vport->dev; orig_dst = skb->_skb_refdst; skb_dst_set_noref(skb, &ovs_dst); IPCB(skb)->frag_max_size = mru; |
694869b3c ipv4: Pass struct... |
784 |
ip_do_fragment(net, skb->sk, skb, ovs_vport_output); |
7f8a436ea openvswitch: Add ... |
785 |
refdst_drop(orig_dst); |
e2d9d8358 openvswitch: pass... |
786 |
} else if (key->eth.type == htons(ETH_P_IPV6)) { |
7f8a436ea openvswitch: Add ... |
787 788 |
unsigned long orig_dst; struct rt6_info ovs_rt; |
e2d9d8358 openvswitch: pass... |
789 790 |
prepare_frag(vport, skb, orig_network_offset, ovs_key_mac_proto(key)); |
7f8a436ea openvswitch: Add ... |
791 792 793 794 795 796 797 798 |
memset(&ovs_rt, 0, sizeof(ovs_rt)); dst_init(&ovs_rt.dst, &ovs_dst_ops, NULL, 1, DST_OBSOLETE_NONE, DST_NOCOUNT); ovs_rt.dst.dev = vport->dev; orig_dst = skb->_skb_refdst; skb_dst_set_noref(skb, &ovs_rt.dst); IP6CB(skb)->frag_max_size = mru; |
a7c978c6c openvswitch: usin... |
799 |
ipv6_stub->ipv6_fragment(net, skb->sk, skb, ovs_vport_output); |
7f8a436ea openvswitch: Add ... |
800 801 802 |
refdst_drop(orig_dst); } else { WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.", |
e2d9d8358 openvswitch: pass... |
803 |
ovs_vport_name(vport), ntohs(key->eth.type), mru, |
7f8a436ea openvswitch: Add ... |
804 |
vport->dev->mtu); |
b8f225706 openvswitch: Fix ... |
805 |
goto err; |
7f8a436ea openvswitch: Add ... |
806 |
} |
b8f225706 openvswitch: Fix ... |
807 808 809 810 |
return; err: kfree_skb(skb); |
7f8a436ea openvswitch: Add ... |
811 812 813 814 |
} static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port, struct sw_flow_key *key) |
ccb1352e7 net: Add Open vSw... |
815 |
{ |
738967b8b openvswitch: refa... |
816 |
struct vport *vport = ovs_vport_rcu(dp, out_port); |
ccb1352e7 net: Add Open vSw... |
817 |
|
7f8a436ea openvswitch: Add ... |
818 819 |
if (likely(vport)) { u16 mru = OVS_CB(skb)->mru; |
f2a4d086e openvswitch: Add ... |
820 821 822 |
u32 cutlen = OVS_CB(skb)->cutlen; if (unlikely(cutlen > 0)) { |
e2d9d8358 openvswitch: pass... |
823 |
if (skb->len - cutlen > ovs_mac_header_len(key)) |
f2a4d086e openvswitch: Add ... |
824 825 |
pskb_trim(skb, skb->len - cutlen); else |
e2d9d8358 openvswitch: pass... |
826 |
pskb_trim(skb, ovs_mac_header_len(key)); |
f2a4d086e openvswitch: Add ... |
827 |
} |
7f8a436ea openvswitch: Add ... |
828 |
|
738314a08 openvswitch: use ... |
829 830 |
if (likely(!mru || (skb->len <= mru + vport->dev->hard_header_len))) { |
e2d9d8358 openvswitch: pass... |
831 |
ovs_vport_send(vport, skb, ovs_key_mac_proto(key)); |
7f8a436ea openvswitch: Add ... |
832 |
} else if (mru <= vport->dev->mtu) { |
c559cd3ad openvswitch: Pass... |
833 |
struct net *net = read_pnet(&dp->net); |
7f8a436ea openvswitch: Add ... |
834 |
|
e2d9d8358 openvswitch: pass... |
835 |
ovs_fragment(net, vport, skb, mru, key); |
7f8a436ea openvswitch: Add ... |
836 837 838 839 |
} else { kfree_skb(skb); } } else { |
ccb1352e7 net: Add Open vSw... |
840 |
kfree_skb(skb); |
7f8a436ea openvswitch: Add ... |
841 |
} |
ccb1352e7 net: Add Open vSw... |
842 843 844 |
} static int output_userspace(struct datapath *dp, struct sk_buff *skb, |
ccea74457 openvswitch: incl... |
845 |
struct sw_flow_key *key, const struct nlattr *attr, |
f2a4d086e openvswitch: Add ... |
846 847 |
const struct nlattr *actions, int actions_len, uint32_t cutlen) |
ccb1352e7 net: Add Open vSw... |
848 849 850 851 |
{ struct dp_upcall_info upcall; const struct nlattr *a; int rem; |
ccea74457 openvswitch: incl... |
852 |
memset(&upcall, 0, sizeof(upcall)); |
ccb1352e7 net: Add Open vSw... |
853 |
upcall.cmd = OVS_PACKET_CMD_ACTION; |
7f8a436ea openvswitch: Add ... |
854 |
upcall.mru = OVS_CB(skb)->mru; |
ccb1352e7 net: Add Open vSw... |
855 856 |
for (a = nla_data(attr), rem = nla_len(attr); rem > 0; |
cf3266ad4 net: openvswitch:... |
857 |
a = nla_next(a, &rem)) { |
ccb1352e7 net: Add Open vSw... |
858 859 860 861 862 863 |
switch (nla_type(a)) { case OVS_USERSPACE_ATTR_USERDATA: upcall.userdata = a; break; case OVS_USERSPACE_ATTR_PID: |
15e473046 netlink: Rename p... |
864 |
upcall.portid = nla_get_u32(a); |
ccb1352e7 net: Add Open vSw... |
865 |
break; |
8f0aad6f3 openvswitch: Exte... |
866 867 868 869 870 871 872 873 |
case OVS_USERSPACE_ATTR_EGRESS_TUN_PORT: { /* Get out tunnel info. */ struct vport *vport; vport = ovs_vport_rcu(dp, nla_get_u32(a)); if (vport) { int err; |
fc4099f17 openvswitch: Fix ... |
874 875 876 |
err = dev_fill_metadata_dst(vport->dev, skb); if (!err) upcall.egress_tun_info = skb_tunnel_info(skb); |
8f0aad6f3 openvswitch: Exte... |
877 |
} |
4c2227984 ip-tunnel: Use AP... |
878 |
|
8f0aad6f3 openvswitch: Exte... |
879 |
break; |
ccb1352e7 net: Add Open vSw... |
880 |
} |
8f0aad6f3 openvswitch: Exte... |
881 |
|
ccea74457 openvswitch: incl... |
882 883 884 885 886 887 |
case OVS_USERSPACE_ATTR_ACTIONS: { /* Include actions. */ upcall.actions = actions; upcall.actions_len = actions_len; break; } |
8f0aad6f3 openvswitch: Exte... |
888 |
} /* End of switch. */ |
ccb1352e7 net: Add Open vSw... |
889 |
} |
f2a4d086e openvswitch: Add ... |
890 |
return ovs_dp_upcall(dp, skb, key, &upcall, cutlen); |
ccb1352e7 net: Add Open vSw... |
891 |
} |
744676e77 openvswitch: add ... |
892 893 894 895 896 897 |
static int dec_ttl_exception_handler(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, const struct nlattr *attr, bool last) { /* The first action is always 'OVS_DEC_TTL_ATTR_ARG'. */ struct nlattr *dec_ttl_arg = nla_data(attr); |
744676e77 openvswitch: add ... |
898 899 |
if (nla_len(dec_ttl_arg)) { |
69929d4c4 net: openvswitch:... |
900 |
struct nlattr *actions = nla_data(dec_ttl_arg); |
744676e77 openvswitch: add ... |
901 902 |
if (actions) |
69929d4c4 net: openvswitch:... |
903 904 |
return clone_execute(dp, skb, key, 0, nla_data(actions), nla_len(actions), last, false); |
744676e77 openvswitch: add ... |
905 906 907 908 |
} consume_skb(skb); return 0; } |
798c16617 openvswitch: Opti... |
909 910 911 912 |
/* When 'last' is true, sample() should always consume the 'skb'. * Otherwise, sample() should keep 'skb' intact regardless what * actions are executed within sample(). */ |
ccb1352e7 net: Add Open vSw... |
913 |
static int sample(struct datapath *dp, struct sk_buff *skb, |
ccea74457 openvswitch: incl... |
914 |
struct sw_flow_key *key, const struct nlattr *attr, |
798c16617 openvswitch: Opti... |
915 |
bool last) |
ccb1352e7 net: Add Open vSw... |
916 |
{ |
798c16617 openvswitch: Opti... |
917 918 |
struct nlattr *actions; struct nlattr *sample_arg; |
798c16617 openvswitch: Opti... |
919 |
int rem = nla_len(attr); |
798c16617 openvswitch: Opti... |
920 |
const struct sample_arg *arg; |
bef7f7567 Openvswitch: Refa... |
921 |
bool clone_flow_key; |
ccb1352e7 net: Add Open vSw... |
922 |
|
798c16617 openvswitch: Opti... |
923 924 925 926 |
/* The first action is always 'OVS_SAMPLE_ATTR_ARG'. */ sample_arg = nla_data(attr); arg = nla_data(sample_arg); actions = nla_next(sample_arg, &rem); |
e05176a32 openvswitch: Make... |
927 |
|
798c16617 openvswitch: Opti... |
928 929 930 931 932 |
if ((arg->probability != U32_MAX) && (!arg->probability || prandom_u32() > arg->probability)) { if (last) consume_skb(skb); return 0; |
ccb1352e7 net: Add Open vSw... |
933 |
} |
bef7f7567 Openvswitch: Refa... |
934 935 936 |
clone_flow_key = !arg->exec; return clone_execute(dp, skb, key, 0, actions, rem, last, clone_flow_key); |
971427f35 openvswitch: Add ... |
937 |
} |
b23350403 openvswitch: kern... |
938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 |
/* When 'last' is true, clone() should always consume the 'skb'. * Otherwise, clone() should keep 'skb' intact regardless what * actions are executed within clone(). */ static int clone(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, const struct nlattr *attr, bool last) { struct nlattr *actions; struct nlattr *clone_arg; int rem = nla_len(attr); bool dont_clone_flow_key; /* The first action is always 'OVS_CLONE_ATTR_ARG'. */ clone_arg = nla_data(attr); dont_clone_flow_key = nla_get_u32(clone_arg); actions = nla_next(clone_arg, &rem); return clone_execute(dp, skb, key, 0, actions, rem, last, !dont_clone_flow_key); } |
971427f35 openvswitch: Add ... |
959 960 961 962 963 964 965 966 967 968 969 970 971 |
static void execute_hash(struct sk_buff *skb, struct sw_flow_key *key, const struct nlattr *attr) { struct ovs_action_hash *hash_act = nla_data(attr); u32 hash = 0; /* OVS_HASH_ALG_L4 is the only possible hash algorithm. */ hash = skb_get_hash(skb); hash = jhash_1word(hash, hash_act->hash_basis); if (!hash) hash = 0x1; key->ovs_flow_hash = hash; |
ccb1352e7 net: Add Open vSw... |
972 |
} |
83d2b9ba1 net: openvswitch:... |
973 974 975 976 977 978 |
static int execute_set_action(struct sk_buff *skb, struct sw_flow_key *flow_key, const struct nlattr *a) { /* Only tunnel set execution is supported without a mask. */ if (nla_type(a) == OVS_KEY_ATTR_TUNNEL_INFO) { |
34ae932a4 openvswitch: Make... |
979 980 981 982 983 |
struct ovs_tunnel_info *tun = nla_data(a); skb_dst_drop(skb); dst_hold((struct dst_entry *)tun->tun_dst); skb_dst_set(skb, (struct dst_entry *)tun->tun_dst); |
83d2b9ba1 net: openvswitch:... |
984 985 986 987 988 989 990 991 992 993 994 995 |
return 0; } return -EINVAL; } /* Mask is at the midpoint of the data. */ #define get_mask(a, type) ((const type)nla_data(a) + 1) static int execute_masked_set_action(struct sk_buff *skb, struct sw_flow_key *flow_key, const struct nlattr *a) |
ccb1352e7 net: Add Open vSw... |
996 997 |
{ int err = 0; |
83d2b9ba1 net: openvswitch:... |
998 |
switch (nla_type(a)) { |
ccb1352e7 net: Add Open vSw... |
999 |
case OVS_KEY_ATTR_PRIORITY: |
be26b9a88 openvswitch: Move... |
1000 1001 |
OVS_SET_MASKED(skb->priority, nla_get_u32(a), *get_mask(a, u32 *)); |
83d2b9ba1 net: openvswitch:... |
1002 |
flow_key->phy.priority = skb->priority; |
ccb1352e7 net: Add Open vSw... |
1003 |
break; |
39c7caebc openvswitch: add ... |
1004 |
case OVS_KEY_ATTR_SKB_MARK: |
be26b9a88 openvswitch: Move... |
1005 |
OVS_SET_MASKED(skb->mark, nla_get_u32(a), *get_mask(a, u32 *)); |
83d2b9ba1 net: openvswitch:... |
1006 |
flow_key->phy.skb_mark = skb->mark; |
39c7caebc openvswitch: add ... |
1007 |
break; |
f0b128c1e openvswitch: Wrap... |
1008 |
case OVS_KEY_ATTR_TUNNEL_INFO: |
83d2b9ba1 net: openvswitch:... |
1009 1010 |
/* Masked data not supported for tunnel. */ err = -EINVAL; |
7d5437c70 openvswitch: Add ... |
1011 |
break; |
ccb1352e7 net: Add Open vSw... |
1012 |
case OVS_KEY_ATTR_ETHERNET: |
83d2b9ba1 net: openvswitch:... |
1013 1014 |
err = set_eth_addr(skb, flow_key, nla_data(a), get_mask(a, struct ovs_key_ethernet *)); |
ccb1352e7 net: Add Open vSw... |
1015 |
break; |
b2d0f5d5d openvswitch: enab... |
1016 1017 1018 |
case OVS_KEY_ATTR_NSH: err = set_nsh(skb, flow_key, a); break; |
ccb1352e7 net: Add Open vSw... |
1019 |
case OVS_KEY_ATTR_IPV4: |
83d2b9ba1 net: openvswitch:... |
1020 1021 |
err = set_ipv4(skb, flow_key, nla_data(a), get_mask(a, struct ovs_key_ipv4 *)); |
ccb1352e7 net: Add Open vSw... |
1022 |
break; |
3fdbd1ce1 openvswitch: add ... |
1023 |
case OVS_KEY_ATTR_IPV6: |
83d2b9ba1 net: openvswitch:... |
1024 1025 |
err = set_ipv6(skb, flow_key, nla_data(a), get_mask(a, struct ovs_key_ipv6 *)); |
3fdbd1ce1 openvswitch: add ... |
1026 |
break; |
ccb1352e7 net: Add Open vSw... |
1027 |
case OVS_KEY_ATTR_TCP: |
83d2b9ba1 net: openvswitch:... |
1028 1029 |
err = set_tcp(skb, flow_key, nla_data(a), get_mask(a, struct ovs_key_tcp *)); |
ccb1352e7 net: Add Open vSw... |
1030 1031 1032 |
break; case OVS_KEY_ATTR_UDP: |
83d2b9ba1 net: openvswitch:... |
1033 1034 |
err = set_udp(skb, flow_key, nla_data(a), get_mask(a, struct ovs_key_udp *)); |
ccb1352e7 net: Add Open vSw... |
1035 |
break; |
a175a7233 openvswitch: Add ... |
1036 1037 |
case OVS_KEY_ATTR_SCTP: |
83d2b9ba1 net: openvswitch:... |
1038 1039 |
err = set_sctp(skb, flow_key, nla_data(a), get_mask(a, struct ovs_key_sctp *)); |
a175a7233 openvswitch: Add ... |
1040 |
break; |
25cd9ba0a openvswitch: Add ... |
1041 1042 |
case OVS_KEY_ATTR_MPLS: |
83d2b9ba1 net: openvswitch:... |
1043 1044 |
err = set_mpls(skb, flow_key, nla_data(a), get_mask(a, __be32 *)); |
25cd9ba0a openvswitch: Add ... |
1045 |
break; |
7f8a436ea openvswitch: Add ... |
1046 1047 1048 |
case OVS_KEY_ATTR_CT_STATE: case OVS_KEY_ATTR_CT_ZONE: |
182e3042e openvswitch: Allo... |
1049 |
case OVS_KEY_ATTR_CT_MARK: |
33db4125e openvswitch: Rena... |
1050 |
case OVS_KEY_ATTR_CT_LABELS: |
9dd7f8907 openvswitch: Add ... |
1051 1052 |
case OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4: case OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6: |
7f8a436ea openvswitch: Add ... |
1053 1054 |
err = -EINVAL; break; |
ccb1352e7 net: Add Open vSw... |
1055 1056 1057 1058 |
} return err; } |
971427f35 openvswitch: Add ... |
1059 1060 |
static int execute_recirc(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, |
bef7f7567 Openvswitch: Refa... |
1061 |
const struct nlattr *a, bool last) |
971427f35 openvswitch: Add ... |
1062 |
{ |
bef7f7567 Openvswitch: Refa... |
1063 |
u32 recirc_id; |
971427f35 openvswitch: Add ... |
1064 |
|
fff06c36a openvswitch: Opti... |
1065 1066 1067 1068 1069 1070 1071 1072 |
if (!is_flow_key_valid(key)) { int err; err = ovs_flow_key_update(skb, key); if (err) return err; } BUG_ON(!is_flow_key_valid(key)); |
971427f35 openvswitch: Add ... |
1073 |
|
bef7f7567 Openvswitch: Refa... |
1074 1075 |
recirc_id = nla_get_u32(a); return clone_execute(dp, skb, key, recirc_id, NULL, 0, last, true); |
971427f35 openvswitch: Add ... |
1076 |
} |
4d5ec89fc net: openvswitch:... |
1077 1078 1079 1080 |
static int execute_check_pkt_len(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, const struct nlattr *attr, bool last) { |
178436557 openvswitch: take... |
1081 |
struct ovs_skb_cb *ovs_cb = OVS_CB(skb); |
4d5ec89fc net: openvswitch:... |
1082 |
const struct nlattr *actions, *cpl_arg; |
178436557 openvswitch: take... |
1083 |
int len, max_len, rem = nla_len(attr); |
4d5ec89fc net: openvswitch:... |
1084 |
const struct check_pkt_len_arg *arg; |
4d5ec89fc net: openvswitch:... |
1085 1086 1087 1088 1089 1090 1091 |
bool clone_flow_key; /* The first netlink attribute in 'attr' is always * 'OVS_CHECK_PKT_LEN_ATTR_ARG'. */ cpl_arg = nla_data(attr); arg = nla_data(cpl_arg); |
178436557 openvswitch: take... |
1092 1093 1094 1095 1096 |
len = ovs_cb->mru ? ovs_cb->mru + skb->mac_len : skb->len; max_len = arg->pkt_len; if ((skb_is_gso(skb) && skb_gso_validate_mac_len(skb, max_len)) || len <= max_len) { |
4d5ec89fc net: openvswitch:... |
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 |
/* Second netlink attribute in 'attr' is always * 'OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL'. */ actions = nla_next(cpl_arg, &rem); clone_flow_key = !arg->exec_for_lesser_equal; } else { /* Third netlink attribute in 'attr' is always * 'OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER'. */ actions = nla_next(cpl_arg, &rem); actions = nla_next(actions, &rem); clone_flow_key = !arg->exec_for_greater; } return clone_execute(dp, skb, key, 0, nla_data(actions), nla_len(actions), last, clone_flow_key); } |
744676e77 openvswitch: add ... |
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 |
static int execute_dec_ttl(struct sk_buff *skb, struct sw_flow_key *key) { int err; if (skb->protocol == htons(ETH_P_IPV6)) { struct ipv6hdr *nh; err = skb_ensure_writable(skb, skb_network_offset(skb) + sizeof(*nh)); if (unlikely(err)) return err; nh = ipv6_hdr(skb); if (nh->hop_limit <= 1) return -EHOSTUNREACH; key->ip.ttl = --nh->hop_limit; } else { struct iphdr *nh; u8 old_ttl; err = skb_ensure_writable(skb, skb_network_offset(skb) + sizeof(*nh)); if (unlikely(err)) return err; nh = ip_hdr(skb); if (nh->ttl <= 1) return -EHOSTUNREACH; old_ttl = nh->ttl--; csum_replace2(&nh->check, htons(old_ttl << 8), htons(nh->ttl << 8)); key->ip.ttl = nh->ttl; } return 0; } |
ccb1352e7 net: Add Open vSw... |
1152 1153 |
/* Execute a list of actions against 'skb'. */ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, |
2ff3e4e48 openvswitch: Remo... |
1154 |
struct sw_flow_key *key, |
651887b0c openvswitch: Samp... |
1155 |
const struct nlattr *attr, int len) |
ccb1352e7 net: Add Open vSw... |
1156 |
{ |
ccb1352e7 net: Add Open vSw... |
1157 1158 1159 1160 1161 1162 |
const struct nlattr *a; int rem; for (a = attr, rem = len; rem > 0; a = nla_next(a, &rem)) { int err = 0; |
5b8784aaf openvswitch: Simp... |
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 |
switch (nla_type(a)) { case OVS_ACTION_ATTR_OUTPUT: { int port = nla_get_u32(a); struct sk_buff *clone; /* Every output action needs a separate clone * of 'skb', In case the output action is the * last action, cloning can be avoided. */ if (nla_is_last(a, rem)) { do_output(dp, skb, port, key); /* 'skb' has been used for output. */ return 0; } |
738967b8b openvswitch: refa... |
1178 |
|
5b8784aaf openvswitch: Simp... |
1179 1180 1181 |
clone = skb_clone(skb, GFP_ATOMIC); if (clone) do_output(dp, clone, port, key); |
f2a4d086e openvswitch: Add ... |
1182 |
OVS_CB(skb)->cutlen = 0; |
ccb1352e7 net: Add Open vSw... |
1183 |
break; |
5b8784aaf openvswitch: Simp... |
1184 |
} |
ccb1352e7 net: Add Open vSw... |
1185 |
|
f2a4d086e openvswitch: Add ... |
1186 1187 1188 1189 1190 1191 1192 |
case OVS_ACTION_ATTR_TRUNC: { struct ovs_action_trunc *trunc = nla_data(a); if (skb->len > trunc->max_len) OVS_CB(skb)->cutlen = skb->len - trunc->max_len; break; } |
ccb1352e7 net: Add Open vSw... |
1193 |
case OVS_ACTION_ATTR_USERSPACE: |
f2a4d086e openvswitch: Add ... |
1194 1195 1196 |
output_userspace(dp, skb, key, a, attr, len, OVS_CB(skb)->cutlen); OVS_CB(skb)->cutlen = 0; |
ccb1352e7 net: Add Open vSw... |
1197 |
break; |
971427f35 openvswitch: Add ... |
1198 1199 1200 |
case OVS_ACTION_ATTR_HASH: execute_hash(skb, key, a); break; |
f66b53fdb openvswitch: New ... |
1201 1202 1203 1204 1205 |
case OVS_ACTION_ATTR_PUSH_MPLS: { struct ovs_action_push_mpls *mpls = nla_data(a); err = push_mpls(skb, key, mpls->mpls_lse, mpls->mpls_ethertype, skb->mac_len); |
25cd9ba0a openvswitch: Add ... |
1206 |
break; |
f66b53fdb openvswitch: New ... |
1207 1208 1209 1210 1211 1212 1213 |
} case OVS_ACTION_ATTR_ADD_MPLS: { struct ovs_action_add_mpls *mpls = nla_data(a); __u16 mac_len = 0; if (mpls->tun_flags & OVS_MPLS_L3_TUNNEL_FLAG_MASK) mac_len = skb->mac_len; |
25cd9ba0a openvswitch: Add ... |
1214 |
|
f66b53fdb openvswitch: New ... |
1215 1216 1217 1218 |
err = push_mpls(skb, key, mpls->mpls_lse, mpls->mpls_ethertype, mac_len); break; } |
25cd9ba0a openvswitch: Add ... |
1219 |
case OVS_ACTION_ATTR_POP_MPLS: |
fff06c36a openvswitch: Opti... |
1220 |
err = pop_mpls(skb, key, nla_get_be16(a)); |
25cd9ba0a openvswitch: Add ... |
1221 |
break; |
ccb1352e7 net: Add Open vSw... |
1222 |
case OVS_ACTION_ATTR_PUSH_VLAN: |
fff06c36a openvswitch: Opti... |
1223 |
err = push_vlan(skb, key, nla_data(a)); |
ccb1352e7 net: Add Open vSw... |
1224 1225 1226 |
break; case OVS_ACTION_ATTR_POP_VLAN: |
fff06c36a openvswitch: Opti... |
1227 |
err = pop_vlan(skb, key); |
ccb1352e7 net: Add Open vSw... |
1228 |
break; |
bef7f7567 Openvswitch: Refa... |
1229 1230 1231 1232 1233 |
case OVS_ACTION_ATTR_RECIRC: { bool last = nla_is_last(a, rem); err = execute_recirc(dp, skb, key, a, last); if (last) { |
971427f35 openvswitch: Add ... |
1234 1235 1236 1237 1238 1239 1240 |
/* If this is the last action, the skb has * been consumed or freed. * Return immediately. */ return err; } break; |
bef7f7567 Openvswitch: Refa... |
1241 |
} |
971427f35 openvswitch: Add ... |
1242 |
|
ccb1352e7 net: Add Open vSw... |
1243 |
case OVS_ACTION_ATTR_SET: |
fff06c36a openvswitch: Opti... |
1244 |
err = execute_set_action(skb, key, nla_data(a)); |
ccb1352e7 net: Add Open vSw... |
1245 |
break; |
83d2b9ba1 net: openvswitch:... |
1246 1247 1248 1249 |
case OVS_ACTION_ATTR_SET_MASKED: case OVS_ACTION_ATTR_SET_TO_MASKED: err = execute_masked_set_action(skb, key, nla_data(a)); break; |
798c16617 openvswitch: Opti... |
1250 1251 1252 1253 1254 1255 |
case OVS_ACTION_ATTR_SAMPLE: { bool last = nla_is_last(a, rem); err = sample(dp, skb, key, a, last); if (last) return err; |
ccb1352e7 net: Add Open vSw... |
1256 |
break; |
798c16617 openvswitch: Opti... |
1257 |
} |
7f8a436ea openvswitch: Add ... |
1258 1259 |
case OVS_ACTION_ATTR_CT: |
ec0d043d0 openvswitch: Ensu... |
1260 1261 1262 1263 1264 |
if (!is_flow_key_valid(key)) { err = ovs_flow_key_update(skb, key); if (err) return err; } |
7f8a436ea openvswitch: Add ... |
1265 1266 1267 1268 |
err = ovs_ct_execute(ovs_dp_get_net(dp), skb, key, nla_data(a)); /* Hide stolen IP fragments from user space. */ |
74c166181 openvswitch: Fix ... |
1269 1270 |
if (err) return err == -EINPROGRESS ? 0 : err; |
7f8a436ea openvswitch: Add ... |
1271 |
break; |
91820da6a openvswitch: add ... |
1272 |
|
b8226962b openvswitch: add ... |
1273 1274 1275 |
case OVS_ACTION_ATTR_CT_CLEAR: err = ovs_ct_clear(skb, key); break; |
91820da6a openvswitch: add ... |
1276 1277 1278 1279 1280 1281 1282 |
case OVS_ACTION_ATTR_PUSH_ETH: err = push_eth(skb, key, nla_data(a)); break; case OVS_ACTION_ATTR_POP_ETH: err = pop_eth(skb, key); break; |
b2d0f5d5d openvswitch: enab... |
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 |
case OVS_ACTION_ATTR_PUSH_NSH: { u8 buffer[NSH_HDR_MAX_LEN]; struct nshhdr *nh = (struct nshhdr *)buffer; err = nsh_hdr_from_nlattr(nla_data(a), nh, NSH_HDR_MAX_LEN); if (unlikely(err)) break; err = push_nsh(skb, key, nh); break; } case OVS_ACTION_ATTR_POP_NSH: err = pop_nsh(skb, key); break; |
cd8a6c336 openvswitch: Add ... |
1299 1300 1301 1302 1303 1304 |
case OVS_ACTION_ATTR_METER: if (ovs_meter_execute(dp, skb, key, nla_get_u32(a))) { consume_skb(skb); return 0; } |
b23350403 openvswitch: kern... |
1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 |
break; case OVS_ACTION_ATTR_CLONE: { bool last = nla_is_last(a, rem); err = clone(dp, skb, key, a, last); if (last) return err; break; } |
4d5ec89fc net: openvswitch:... |
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 |
case OVS_ACTION_ATTR_CHECK_PKT_LEN: { bool last = nla_is_last(a, rem); err = execute_check_pkt_len(dp, skb, key, a, last); if (last) return err; break; } |
744676e77 openvswitch: add ... |
1326 1327 1328 1329 1330 1331 1332 1333 1334 |
case OVS_ACTION_ATTR_DEC_TTL: err = execute_dec_ttl(skb, key); if (err == -EHOSTUNREACH) { err = dec_ttl_exception_handler(dp, skb, key, a, true); return err; } break; |
ccb1352e7 net: Add Open vSw... |
1335 1336 1337 1338 1339 1340 1341 |
} if (unlikely(err)) { kfree_skb(skb); return err; } } |
5b8784aaf openvswitch: Simp... |
1342 |
consume_skb(skb); |
ccb1352e7 net: Add Open vSw... |
1343 1344 |
return 0; } |
bef7f7567 Openvswitch: Refa... |
1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 |
/* Execute the actions on the clone of the packet. The effect of the * execution does not affect the original 'skb' nor the original 'key'. * * The execution may be deferred in case the actions can not be executed * immediately. */ static int clone_execute(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, u32 recirc_id, const struct nlattr *actions, int len, bool last, bool clone_flow_key) { struct deferred_action *da; struct sw_flow_key *clone; skb = last ? skb : skb_clone(skb, GFP_ATOMIC); if (!skb) { /* Out of memory, skip this action. */ return 0; } /* When clone_flow_key is false, the 'key' will not be change * by the actions, then the 'key' can be used directly. * Otherwise, try to clone key from the next recursion level of * 'flow_keys'. If clone is successful, execute the actions * without deferring. */ clone = clone_flow_key ? clone_key(key) : key; if (clone) { int err = 0; if (actions) { /* Sample action */ if (clone_flow_key) __this_cpu_inc(exec_actions_level); err = do_execute_actions(dp, skb, clone, actions, len); if (clone_flow_key) __this_cpu_dec(exec_actions_level); } else { /* Recirc action */ clone->recirc_id = recirc_id; ovs_dp_process_packet(skb, clone); } return err; } /* Out of 'flow_keys' space. Defer actions */ da = add_deferred_actions(skb, key, actions, len); if (da) { if (!actions) { /* Recirc action */ key = &da->pkt_key; key->recirc_id = recirc_id; } } else { /* Out of per CPU action FIFO space. Drop the 'skb' and * log an error. */ kfree_skb(skb); if (net_ratelimit()) { if (actions) { /* Sample action */ pr_warn("%s: deferred action limit reached, drop sample action ", ovs_dp_name(dp)); } else { /* Recirc action */ pr_warn("%s: deferred action limit reached, drop recirc action ", ovs_dp_name(dp)); } } } return 0; } |
971427f35 openvswitch: Add ... |
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 |
static void process_deferred_actions(struct datapath *dp) { struct action_fifo *fifo = this_cpu_ptr(action_fifos); /* Do not touch the FIFO in case there is no deferred actions. */ if (action_fifo_is_empty(fifo)) return; /* Finishing executing all deferred actions. */ do { struct deferred_action *da = action_fifo_get(fifo); struct sk_buff *skb = da->skb; struct sw_flow_key *key = &da->pkt_key; const struct nlattr *actions = da->actions; |
47c697aa2 openvswitch: Defe... |
1433 |
int actions_len = da->actions_len; |
971427f35 openvswitch: Add ... |
1434 1435 |
if (actions) |
47c697aa2 openvswitch: Defe... |
1436 |
do_execute_actions(dp, skb, key, actions, actions_len); |
971427f35 openvswitch: Add ... |
1437 1438 1439 1440 1441 1442 1443 |
else ovs_dp_process_packet(skb, key); } while (!action_fifo_is_empty(fifo)); /* Reset FIFO for the next packet. */ action_fifo_init(fifo); } |
ccb1352e7 net: Add Open vSw... |
1444 |
/* Execute a list of actions against 'skb'. */ |
2ff3e4e48 openvswitch: Remo... |
1445 |
int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb, |
12eb18f71 openvswitch: Cons... |
1446 1447 |
const struct sw_flow_actions *acts, struct sw_flow_key *key) |
ccb1352e7 net: Add Open vSw... |
1448 |
{ |
b064d0d88 ovs: limit ovs re... |
1449 1450 1451 |
int err, level; level = __this_cpu_inc_return(exec_actions_level); |
2679d0404 openvswitch: avoi... |
1452 |
if (unlikely(level > OVS_RECURSION_LIMIT)) { |
b064d0d88 ovs: limit ovs re... |
1453 1454 1455 1456 1457 1458 1459 |
net_crit_ratelimited("ovs: recursion limit reached on datapath %s, probable configuration error ", ovs_dp_name(dp)); kfree_skb(skb); err = -ENETDOWN; goto out; } |
971427f35 openvswitch: Add ... |
1460 |
|
494bea39f openvswitch: fix ... |
1461 |
OVS_CB(skb)->acts_origlen = acts->orig_len; |
971427f35 openvswitch: Add ... |
1462 1463 |
err = do_execute_actions(dp, skb, key, acts->actions, acts->actions_len); |
b064d0d88 ovs: limit ovs re... |
1464 |
if (level == 1) |
971427f35 openvswitch: Add ... |
1465 |
process_deferred_actions(dp); |
b064d0d88 ovs: limit ovs re... |
1466 1467 |
out: __this_cpu_dec(exec_actions_level); |
971427f35 openvswitch: Add ... |
1468 1469 1470 1471 1472 1473 1474 1475 |
return err; } int action_fifos_init(void) { action_fifos = alloc_percpu(struct action_fifo); if (!action_fifos) return -ENOMEM; |
ccb1352e7 net: Add Open vSw... |
1476 |
|
4572ef52a openvswitch: Refa... |
1477 1478 |
flow_keys = alloc_percpu(struct action_flow_keys); if (!flow_keys) { |
2679d0404 openvswitch: avoi... |
1479 1480 1481 |
free_percpu(action_fifos); return -ENOMEM; } |
971427f35 openvswitch: Add ... |
1482 1483 1484 1485 1486 1487 |
return 0; } void action_fifos_exit(void) { free_percpu(action_fifos); |
4572ef52a openvswitch: Refa... |
1488 |
free_percpu(flow_keys); |
ccb1352e7 net: Add Open vSw... |
1489 |
} |