]>
Commit | Line | Data |
---|---|---|
f094af7b | 1 | /* |
adcf00ba | 2 | * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. |
f094af7b SH |
3 | * Copyright (c) 2013 Simon Horman |
4 | * | |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | * you may not use this file except in compliance with the License. | |
7 | * You may obtain a copy of the License at: | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | */ | |
17 | ||
18 | #include <config.h> | |
19 | #include "odp-execute.h" | |
20 | #include <linux/openvswitch.h> | |
21 | #include <stdlib.h> | |
22 | #include <string.h> | |
23 | ||
758c456d | 24 | #include "dpif.h" |
f094af7b SH |
25 | #include "netlink.h" |
26 | #include "ofpbuf.h" | |
6c13071b | 27 | #include "odp-util.h" |
f094af7b | 28 | #include "packets.h" |
f6c8a6b1 | 29 | #include "unaligned.h" |
f094af7b SH |
30 | #include "util.h" |
31 | ||
32 | static void | |
09f9da0b JR |
33 | odp_eth_set_addrs(struct ofpbuf *packet, |
34 | const struct ovs_key_ethernet *eth_key) | |
f094af7b | 35 | { |
cf3b7538 | 36 | struct eth_header *eh = ofpbuf_l2(packet); |
f094af7b | 37 | |
cf3b7538 JR |
38 | if (eh) { |
39 | memcpy(eh->eth_src, eth_key->eth_src, sizeof eh->eth_src); | |
40 | memcpy(eh->eth_dst, eth_key->eth_dst, sizeof eh->eth_dst); | |
41 | } | |
f094af7b SH |
42 | } |
43 | ||
44 | static void | |
6c13071b SH |
45 | odp_set_tunnel_action(const struct nlattr *a, struct flow_tnl *tun_key) |
46 | { | |
47 | enum odp_key_fitness fitness; | |
48 | ||
49 | fitness = odp_tun_key_from_attr(a, tun_key); | |
50 | ovs_assert(fitness != ODP_FIT_ERROR); | |
51 | } | |
52 | ||
f6c8a6b1 BP |
53 | static void |
54 | set_arp(struct ofpbuf *packet, const struct ovs_key_arp *arp_key) | |
55 | { | |
6b8c377a | 56 | struct arp_eth_header *arp = ofpbuf_l3(packet); |
f6c8a6b1 BP |
57 | |
58 | arp->ar_op = arp_key->arp_op; | |
59 | memcpy(arp->ar_sha, arp_key->arp_sha, ETH_ADDR_LEN); | |
60 | put_16aligned_be32(&arp->ar_spa, arp_key->arp_sip); | |
61 | memcpy(arp->ar_tha, arp_key->arp_tha, ETH_ADDR_LEN); | |
62 | put_16aligned_be32(&arp->ar_tpa, arp_key->arp_tip); | |
63 | } | |
64 | ||
6c13071b SH |
65 | static void |
66 | odp_execute_set_action(struct ofpbuf *packet, const struct nlattr *a, | |
758c456d | 67 | struct pkt_metadata *md) |
f094af7b SH |
68 | { |
69 | enum ovs_key_attr type = nl_attr_type(a); | |
70 | const struct ovs_key_ipv4 *ipv4_key; | |
71 | const struct ovs_key_ipv6 *ipv6_key; | |
72 | const struct ovs_key_tcp *tcp_key; | |
73 | const struct ovs_key_udp *udp_key; | |
c6bcb685 | 74 | const struct ovs_key_sctp *sctp_key; |
f094af7b SH |
75 | |
76 | switch (type) { | |
77 | case OVS_KEY_ATTR_PRIORITY: | |
09f9da0b | 78 | md->skb_priority = nl_attr_get_u32(a); |
6c13071b SH |
79 | break; |
80 | ||
f094af7b | 81 | case OVS_KEY_ATTR_TUNNEL: |
09f9da0b | 82 | odp_set_tunnel_action(a, &md->tunnel); |
6c13071b SH |
83 | break; |
84 | ||
f094af7b | 85 | case OVS_KEY_ATTR_SKB_MARK: |
09f9da0b | 86 | md->pkt_mark = nl_attr_get_u32(a); |
f094af7b SH |
87 | break; |
88 | ||
89 | case OVS_KEY_ATTR_ETHERNET: | |
90 | odp_eth_set_addrs(packet, | |
91 | nl_attr_get_unspec(a, sizeof(struct ovs_key_ethernet))); | |
92 | break; | |
93 | ||
94 | case OVS_KEY_ATTR_IPV4: | |
95 | ipv4_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv4)); | |
96 | packet_set_ipv4(packet, ipv4_key->ipv4_src, ipv4_key->ipv4_dst, | |
97 | ipv4_key->ipv4_tos, ipv4_key->ipv4_ttl); | |
98 | break; | |
99 | ||
100 | case OVS_KEY_ATTR_IPV6: | |
101 | ipv6_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv6)); | |
102 | packet_set_ipv6(packet, ipv6_key->ipv6_proto, ipv6_key->ipv6_src, | |
103 | ipv6_key->ipv6_dst, ipv6_key->ipv6_tclass, | |
104 | ipv6_key->ipv6_label, ipv6_key->ipv6_hlimit); | |
105 | break; | |
106 | ||
107 | case OVS_KEY_ATTR_TCP: | |
108 | tcp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_tcp)); | |
109 | packet_set_tcp_port(packet, tcp_key->tcp_src, tcp_key->tcp_dst); | |
110 | break; | |
111 | ||
2b06df54 | 112 | case OVS_KEY_ATTR_UDP: |
f094af7b SH |
113 | udp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_udp)); |
114 | packet_set_udp_port(packet, udp_key->udp_src, udp_key->udp_dst); | |
115 | break; | |
116 | ||
c6bcb685 JS |
117 | case OVS_KEY_ATTR_SCTP: |
118 | sctp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_sctp)); | |
119 | packet_set_sctp_port(packet, sctp_key->sctp_src, sctp_key->sctp_dst); | |
120 | break; | |
121 | ||
2b06df54 | 122 | case OVS_KEY_ATTR_MPLS: |
f094af7b SH |
123 | set_mpls_lse(packet, nl_attr_get_be32(a)); |
124 | break; | |
125 | ||
f6c8a6b1 BP |
126 | case OVS_KEY_ATTR_ARP: |
127 | set_arp(packet, nl_attr_get_unspec(a, sizeof(struct ovs_key_arp))); | |
128 | break; | |
129 | ||
572f732a AZ |
130 | case OVS_KEY_ATTR_DP_HASH: |
131 | md->dp_hash = nl_attr_get_u32(a); | |
132 | break; | |
133 | ||
134 | case OVS_KEY_ATTR_RECIRC_ID: | |
135 | md->recirc_id = nl_attr_get_u32(a); | |
136 | break; | |
137 | ||
2b06df54 JS |
138 | case OVS_KEY_ATTR_UNSPEC: |
139 | case OVS_KEY_ATTR_ENCAP: | |
140 | case OVS_KEY_ATTR_ETHERTYPE: | |
141 | case OVS_KEY_ATTR_IN_PORT: | |
142 | case OVS_KEY_ATTR_VLAN: | |
143 | case OVS_KEY_ATTR_ICMP: | |
144 | case OVS_KEY_ATTR_ICMPV6: | |
2b06df54 | 145 | case OVS_KEY_ATTR_ND: |
dc235f7f | 146 | case OVS_KEY_ATTR_TCP_FLAGS: |
2b06df54 JS |
147 | case __OVS_KEY_ATTR_MAX: |
148 | default: | |
428b2edd | 149 | OVS_NOT_REACHED(); |
f094af7b SH |
150 | } |
151 | } | |
152 | ||
da546e07 | 153 | static void |
df1e5a3b PS |
154 | odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal, |
155 | struct pkt_metadata *, | |
da546e07 | 156 | const struct nlattr *actions, size_t actions_len, |
09f9da0b | 157 | odp_execute_cb dp_execute_action, bool more_actions); |
da546e07 | 158 | |
f094af7b | 159 | static void |
df1e5a3b PS |
160 | odp_execute_sample(void *dp, struct ofpbuf *packet, bool steal, |
161 | struct pkt_metadata *md, const struct nlattr *action, | |
09f9da0b | 162 | odp_execute_cb dp_execute_action, bool more_actions) |
f094af7b SH |
163 | { |
164 | const struct nlattr *subactions = NULL; | |
165 | const struct nlattr *a; | |
166 | size_t left; | |
167 | ||
168 | NL_NESTED_FOR_EACH_UNSAFE (a, left, action) { | |
169 | int type = nl_attr_type(a); | |
170 | ||
171 | switch ((enum ovs_sample_attr) type) { | |
172 | case OVS_SAMPLE_ATTR_PROBABILITY: | |
173 | if (random_uint32() >= nl_attr_get_u32(a)) { | |
174 | return; | |
175 | } | |
176 | break; | |
177 | ||
178 | case OVS_SAMPLE_ATTR_ACTIONS: | |
179 | subactions = a; | |
180 | break; | |
181 | ||
182 | case OVS_SAMPLE_ATTR_UNSPEC: | |
183 | case __OVS_SAMPLE_ATTR_MAX: | |
184 | default: | |
428b2edd | 185 | OVS_NOT_REACHED(); |
f094af7b SH |
186 | } |
187 | } | |
188 | ||
df1e5a3b | 189 | odp_execute_actions__(dp, packet, steal, md, nl_attr_get(subactions), |
09f9da0b | 190 | nl_attr_get_size(subactions), dp_execute_action, |
da546e07 | 191 | more_actions); |
f094af7b SH |
192 | } |
193 | ||
da546e07 | 194 | static void |
df1e5a3b PS |
195 | odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal, |
196 | struct pkt_metadata *md, | |
da546e07 | 197 | const struct nlattr *actions, size_t actions_len, |
09f9da0b | 198 | odp_execute_cb dp_execute_action, bool more_actions) |
f094af7b SH |
199 | { |
200 | const struct nlattr *a; | |
201 | unsigned int left; | |
202 | ||
203 | NL_ATTR_FOR_EACH_UNSAFE (a, left, actions, actions_len) { | |
204 | int type = nl_attr_type(a); | |
205 | ||
206 | switch ((enum ovs_action_attr) type) { | |
09f9da0b | 207 | /* These only make sense in the context of a datapath. */ |
f094af7b | 208 | case OVS_ACTION_ATTR_OUTPUT: |
09f9da0b | 209 | case OVS_ACTION_ATTR_USERSPACE: |
572f732a | 210 | case OVS_ACTION_ATTR_RECIRC: |
347bf289 | 211 | case OVS_ACTION_ATTR_HASH: |
09f9da0b JR |
212 | if (dp_execute_action) { |
213 | /* Allow 'dp_execute_action' to steal the packet data if we do | |
214 | * not need it any more. */ | |
adcf00ba AZ |
215 | bool may_steal = steal && (!more_actions |
216 | && left <= NLA_ALIGN(a->nla_len) | |
217 | && type != OVS_ACTION_ATTR_RECIRC); | |
df1e5a3b | 218 | dp_execute_action(dp, packet, md, a, may_steal); |
c51876c3 | 219 | } |
f094af7b | 220 | break; |
f094af7b SH |
221 | |
222 | case OVS_ACTION_ATTR_PUSH_VLAN: { | |
223 | const struct ovs_action_push_vlan *vlan = nl_attr_get(a); | |
1bf02876 | 224 | eth_push_vlan(packet, htons(ETH_TYPE_VLAN), vlan->vlan_tci); |
f094af7b SH |
225 | break; |
226 | } | |
227 | ||
228 | case OVS_ACTION_ATTR_POP_VLAN: | |
229 | eth_pop_vlan(packet); | |
230 | break; | |
231 | ||
232 | case OVS_ACTION_ATTR_PUSH_MPLS: { | |
233 | const struct ovs_action_push_mpls *mpls = nl_attr_get(a); | |
234 | push_mpls(packet, mpls->mpls_ethertype, mpls->mpls_lse); | |
235 | break; | |
236 | } | |
237 | ||
238 | case OVS_ACTION_ATTR_POP_MPLS: | |
239 | pop_mpls(packet, nl_attr_get_be16(a)); | |
240 | break; | |
241 | ||
242 | case OVS_ACTION_ATTR_SET: | |
09f9da0b | 243 | odp_execute_set_action(packet, nl_attr_get(a), md); |
f094af7b SH |
244 | break; |
245 | ||
246 | case OVS_ACTION_ATTR_SAMPLE: | |
df1e5a3b | 247 | odp_execute_sample(dp, packet, steal, md, a, dp_execute_action, |
da546e07 | 248 | more_actions || left > NLA_ALIGN(a->nla_len)); |
f094af7b SH |
249 | break; |
250 | ||
251 | case OVS_ACTION_ATTR_UNSPEC: | |
252 | case __OVS_ACTION_ATTR_MAX: | |
428b2edd | 253 | OVS_NOT_REACHED(); |
f094af7b SH |
254 | } |
255 | } | |
256 | } | |
da546e07 JR |
257 | |
258 | void | |
df1e5a3b PS |
259 | odp_execute_actions(void *dp, struct ofpbuf *packet, bool steal, |
260 | struct pkt_metadata *md, | |
da546e07 | 261 | const struct nlattr *actions, size_t actions_len, |
09f9da0b | 262 | odp_execute_cb dp_execute_action) |
da546e07 | 263 | { |
df1e5a3b | 264 | odp_execute_actions__(dp, packet, steal, md, actions, actions_len, |
09f9da0b | 265 | dp_execute_action, false); |
df1e5a3b PS |
266 | |
267 | if (!actions_len && steal) { | |
268 | /* Drop action. */ | |
269 | ofpbuf_delete(packet); | |
270 | } | |
da546e07 | 271 | } |