]>
Commit | Line | Data |
---|---|---|
f094af7b SH |
1 | /* |
2 | * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc. | |
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 | ||
24 | #include "netlink.h" | |
25 | #include "ofpbuf.h" | |
6c13071b | 26 | #include "odp-util.h" |
f094af7b SH |
27 | #include "packets.h" |
28 | #include "util.h" | |
29 | ||
30 | static void | |
31 | odp_eth_set_addrs(struct ofpbuf *packet, const struct ovs_key_ethernet *eth_key) | |
32 | { | |
33 | struct eth_header *eh = packet->l2; | |
34 | ||
35 | memcpy(eh->eth_src, eth_key->eth_src, sizeof eh->eth_src); | |
36 | memcpy(eh->eth_dst, eth_key->eth_dst, sizeof eh->eth_dst); | |
37 | } | |
38 | ||
39 | static void | |
6c13071b SH |
40 | odp_set_tunnel_action(const struct nlattr *a, struct flow_tnl *tun_key) |
41 | { | |
42 | enum odp_key_fitness fitness; | |
43 | ||
44 | fitness = odp_tun_key_from_attr(a, tun_key); | |
45 | ovs_assert(fitness != ODP_FIT_ERROR); | |
46 | } | |
47 | ||
48 | static void | |
49 | odp_execute_set_action(struct ofpbuf *packet, const struct nlattr *a, | |
50 | struct flow *flow) | |
f094af7b SH |
51 | { |
52 | enum ovs_key_attr type = nl_attr_type(a); | |
53 | const struct ovs_key_ipv4 *ipv4_key; | |
54 | const struct ovs_key_ipv6 *ipv6_key; | |
55 | const struct ovs_key_tcp *tcp_key; | |
56 | const struct ovs_key_udp *udp_key; | |
57 | ||
58 | switch (type) { | |
59 | case OVS_KEY_ATTR_PRIORITY: | |
6c13071b SH |
60 | flow->skb_priority = nl_attr_get_u32(a); |
61 | break; | |
62 | ||
f094af7b | 63 | case OVS_KEY_ATTR_TUNNEL: |
6c13071b SH |
64 | odp_set_tunnel_action(a, &flow->tunnel); |
65 | break; | |
66 | ||
f094af7b | 67 | case OVS_KEY_ATTR_SKB_MARK: |
6c13071b | 68 | flow->skb_mark = nl_attr_get_u32(a); |
f094af7b SH |
69 | break; |
70 | ||
71 | case OVS_KEY_ATTR_ETHERNET: | |
72 | odp_eth_set_addrs(packet, | |
73 | nl_attr_get_unspec(a, sizeof(struct ovs_key_ethernet))); | |
74 | break; | |
75 | ||
76 | case OVS_KEY_ATTR_IPV4: | |
77 | ipv4_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv4)); | |
78 | packet_set_ipv4(packet, ipv4_key->ipv4_src, ipv4_key->ipv4_dst, | |
79 | ipv4_key->ipv4_tos, ipv4_key->ipv4_ttl); | |
80 | break; | |
81 | ||
82 | case OVS_KEY_ATTR_IPV6: | |
83 | ipv6_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv6)); | |
84 | packet_set_ipv6(packet, ipv6_key->ipv6_proto, ipv6_key->ipv6_src, | |
85 | ipv6_key->ipv6_dst, ipv6_key->ipv6_tclass, | |
86 | ipv6_key->ipv6_label, ipv6_key->ipv6_hlimit); | |
87 | break; | |
88 | ||
89 | case OVS_KEY_ATTR_TCP: | |
90 | tcp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_tcp)); | |
91 | packet_set_tcp_port(packet, tcp_key->tcp_src, tcp_key->tcp_dst); | |
92 | break; | |
93 | ||
94 | case OVS_KEY_ATTR_UDP: | |
95 | udp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_udp)); | |
96 | packet_set_udp_port(packet, udp_key->udp_src, udp_key->udp_dst); | |
97 | break; | |
98 | ||
99 | case OVS_KEY_ATTR_MPLS: | |
100 | set_mpls_lse(packet, nl_attr_get_be32(a)); | |
101 | break; | |
102 | ||
103 | case OVS_KEY_ATTR_UNSPEC: | |
104 | case OVS_KEY_ATTR_ENCAP: | |
105 | case OVS_KEY_ATTR_ETHERTYPE: | |
106 | case OVS_KEY_ATTR_IN_PORT: | |
107 | case OVS_KEY_ATTR_VLAN: | |
108 | case OVS_KEY_ATTR_ICMP: | |
109 | case OVS_KEY_ATTR_ICMPV6: | |
110 | case OVS_KEY_ATTR_ARP: | |
111 | case OVS_KEY_ATTR_ND: | |
112 | case __OVS_KEY_ATTR_MAX: | |
113 | default: | |
114 | NOT_REACHED(); | |
115 | } | |
116 | } | |
117 | ||
118 | static void | |
119 | odp_execute_sample(void *dp, struct ofpbuf *packet, struct flow *key, | |
120 | const struct nlattr *action, | |
121 | void (*output)(void *dp, struct ofpbuf *packet, | |
122 | uint32_t out_port), | |
123 | void (*userspace)(void *dp, struct ofpbuf *packet, | |
124 | const struct flow *key, | |
125 | const struct nlattr *a)) | |
126 | { | |
127 | const struct nlattr *subactions = NULL; | |
128 | const struct nlattr *a; | |
129 | size_t left; | |
130 | ||
131 | NL_NESTED_FOR_EACH_UNSAFE (a, left, action) { | |
132 | int type = nl_attr_type(a); | |
133 | ||
134 | switch ((enum ovs_sample_attr) type) { | |
135 | case OVS_SAMPLE_ATTR_PROBABILITY: | |
136 | if (random_uint32() >= nl_attr_get_u32(a)) { | |
137 | return; | |
138 | } | |
139 | break; | |
140 | ||
141 | case OVS_SAMPLE_ATTR_ACTIONS: | |
142 | subactions = a; | |
143 | break; | |
144 | ||
145 | case OVS_SAMPLE_ATTR_UNSPEC: | |
146 | case __OVS_SAMPLE_ATTR_MAX: | |
147 | default: | |
148 | NOT_REACHED(); | |
149 | } | |
150 | } | |
151 | ||
152 | odp_execute_actions(dp, packet, key, nl_attr_get(subactions), | |
153 | nl_attr_get_size(subactions), output, userspace); | |
154 | } | |
155 | ||
156 | void | |
157 | odp_execute_actions(void *dp, struct ofpbuf *packet, struct flow *key, | |
158 | const struct nlattr *actions, size_t actions_len, | |
159 | void (*output)(void *dp, struct ofpbuf *packet, | |
160 | uint32_t out_port), | |
161 | void (*userspace)(void *dp, struct ofpbuf *packet, | |
162 | const struct flow *key, | |
163 | const struct nlattr *a)) | |
164 | { | |
165 | const struct nlattr *a; | |
166 | unsigned int left; | |
167 | ||
168 | NL_ATTR_FOR_EACH_UNSAFE (a, left, actions, actions_len) { | |
169 | int type = nl_attr_type(a); | |
170 | ||
171 | switch ((enum ovs_action_attr) type) { | |
172 | case OVS_ACTION_ATTR_OUTPUT: | |
1ac7c9bd SH |
173 | if (output) { |
174 | output(dp, packet, nl_attr_get_u32(a)); | |
175 | } | |
f094af7b SH |
176 | break; |
177 | ||
178 | case OVS_ACTION_ATTR_USERSPACE: { | |
179 | const struct nlattr *userdata; | |
180 | ||
181 | userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA); | |
182 | userspace(dp, packet, key, userdata); | |
183 | break; | |
184 | } | |
185 | ||
186 | case OVS_ACTION_ATTR_PUSH_VLAN: { | |
187 | const struct ovs_action_push_vlan *vlan = nl_attr_get(a); | |
188 | eth_push_vlan(packet, vlan->vlan_tci); | |
189 | break; | |
190 | } | |
191 | ||
192 | case OVS_ACTION_ATTR_POP_VLAN: | |
193 | eth_pop_vlan(packet); | |
194 | break; | |
195 | ||
196 | case OVS_ACTION_ATTR_PUSH_MPLS: { | |
197 | const struct ovs_action_push_mpls *mpls = nl_attr_get(a); | |
198 | push_mpls(packet, mpls->mpls_ethertype, mpls->mpls_lse); | |
199 | break; | |
200 | } | |
201 | ||
202 | case OVS_ACTION_ATTR_POP_MPLS: | |
203 | pop_mpls(packet, nl_attr_get_be16(a)); | |
204 | break; | |
205 | ||
206 | case OVS_ACTION_ATTR_SET: | |
6c13071b | 207 | odp_execute_set_action(packet, nl_attr_get(a), key); |
f094af7b SH |
208 | break; |
209 | ||
210 | case OVS_ACTION_ATTR_SAMPLE: | |
211 | odp_execute_sample(dp, packet, key, a, output, userspace); | |
212 | break; | |
213 | ||
214 | case OVS_ACTION_ATTR_UNSPEC: | |
215 | case __OVS_ACTION_ATTR_MAX: | |
216 | NOT_REACHED(); | |
217 | } | |
218 | } | |
219 | } |