odp-execute: Consolidate callbacks.
[sliver-openvswitch.git] / lib / odp-execute.c
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"
26 #include "odp-util.h"
27 #include "packets.h"
28 #include "unaligned.h"
29 #include "util.h"
30
31 static void
32 odp_eth_set_addrs(struct ofpbuf *packet,
33                   const struct ovs_key_ethernet *eth_key)
34 {
35     struct eth_header *eh = packet->l2;
36
37     memcpy(eh->eth_src, eth_key->eth_src, sizeof eh->eth_src);
38     memcpy(eh->eth_dst, eth_key->eth_dst, sizeof eh->eth_dst);
39 }
40
41 static void
42 odp_set_tunnel_action(const struct nlattr *a, struct flow_tnl *tun_key)
43 {
44     enum odp_key_fitness fitness;
45
46     fitness = odp_tun_key_from_attr(a, tun_key);
47     ovs_assert(fitness != ODP_FIT_ERROR);
48 }
49
50 static void
51 set_arp(struct ofpbuf *packet, const struct ovs_key_arp *arp_key)
52 {
53     struct arp_eth_header *arp = packet->l3;
54
55     arp->ar_op = arp_key->arp_op;
56     memcpy(arp->ar_sha, arp_key->arp_sha, ETH_ADDR_LEN);
57     put_16aligned_be32(&arp->ar_spa, arp_key->arp_sip);
58     memcpy(arp->ar_tha, arp_key->arp_tha, ETH_ADDR_LEN);
59     put_16aligned_be32(&arp->ar_tpa, arp_key->arp_tip);
60 }
61
62 static void
63 odp_execute_set_action(struct ofpbuf *packet, const struct nlattr *a,
64                        struct flow *md)
65 {
66     enum ovs_key_attr type = nl_attr_type(a);
67     const struct ovs_key_ipv4 *ipv4_key;
68     const struct ovs_key_ipv6 *ipv6_key;
69     const struct ovs_key_tcp *tcp_key;
70     const struct ovs_key_udp *udp_key;
71     const struct ovs_key_sctp *sctp_key;
72
73     switch (type) {
74     case OVS_KEY_ATTR_PRIORITY:
75         md->skb_priority = nl_attr_get_u32(a);
76         break;
77
78     case OVS_KEY_ATTR_TUNNEL:
79         odp_set_tunnel_action(a, &md->tunnel);
80         break;
81
82     case OVS_KEY_ATTR_SKB_MARK:
83         md->pkt_mark = nl_attr_get_u32(a);
84         break;
85
86     case OVS_KEY_ATTR_ETHERNET:
87         odp_eth_set_addrs(packet,
88                           nl_attr_get_unspec(a, sizeof(struct ovs_key_ethernet)));
89         break;
90
91     case OVS_KEY_ATTR_IPV4:
92         ipv4_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv4));
93         packet_set_ipv4(packet, ipv4_key->ipv4_src, ipv4_key->ipv4_dst,
94                         ipv4_key->ipv4_tos, ipv4_key->ipv4_ttl);
95         break;
96
97     case OVS_KEY_ATTR_IPV6:
98         ipv6_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv6));
99         packet_set_ipv6(packet, ipv6_key->ipv6_proto, ipv6_key->ipv6_src,
100                         ipv6_key->ipv6_dst, ipv6_key->ipv6_tclass,
101                         ipv6_key->ipv6_label, ipv6_key->ipv6_hlimit);
102         break;
103
104     case OVS_KEY_ATTR_TCP:
105         tcp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_tcp));
106         packet_set_tcp_port(packet, tcp_key->tcp_src, tcp_key->tcp_dst);
107         break;
108
109     case OVS_KEY_ATTR_UDP:
110         udp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_udp));
111         packet_set_udp_port(packet, udp_key->udp_src, udp_key->udp_dst);
112         break;
113
114     case OVS_KEY_ATTR_SCTP:
115         sctp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_sctp));
116         packet_set_sctp_port(packet, sctp_key->sctp_src, sctp_key->sctp_dst);
117         break;
118
119     case OVS_KEY_ATTR_MPLS:
120          set_mpls_lse(packet, nl_attr_get_be32(a));
121          break;
122
123     case OVS_KEY_ATTR_ARP:
124         set_arp(packet, nl_attr_get_unspec(a, sizeof(struct ovs_key_arp)));
125         break;
126
127     case OVS_KEY_ATTR_UNSPEC:
128     case OVS_KEY_ATTR_ENCAP:
129     case OVS_KEY_ATTR_ETHERTYPE:
130     case OVS_KEY_ATTR_IN_PORT:
131     case OVS_KEY_ATTR_VLAN:
132     case OVS_KEY_ATTR_ICMP:
133     case OVS_KEY_ATTR_ICMPV6:
134     case OVS_KEY_ATTR_ND:
135     case OVS_KEY_ATTR_TCP_FLAGS:
136     case __OVS_KEY_ATTR_MAX:
137     default:
138         OVS_NOT_REACHED();
139     }
140 }
141
142 static void
143 odp_execute_actions__(void *dp, struct ofpbuf *packet, struct flow *key,
144                       const struct nlattr *actions, size_t actions_len,
145                       odp_execute_cb dp_execute_action, bool more_actions);
146
147 static void
148 odp_execute_sample(void *dp, struct ofpbuf *packet, struct flow *md,
149                    const struct nlattr *action,
150                    odp_execute_cb dp_execute_action, bool more_actions)
151 {
152     const struct nlattr *subactions = NULL;
153     const struct nlattr *a;
154     size_t left;
155
156     NL_NESTED_FOR_EACH_UNSAFE (a, left, action) {
157         int type = nl_attr_type(a);
158
159         switch ((enum ovs_sample_attr) type) {
160         case OVS_SAMPLE_ATTR_PROBABILITY:
161             if (random_uint32() >= nl_attr_get_u32(a)) {
162                 return;
163             }
164             break;
165
166         case OVS_SAMPLE_ATTR_ACTIONS:
167             subactions = a;
168             break;
169
170         case OVS_SAMPLE_ATTR_UNSPEC:
171         case __OVS_SAMPLE_ATTR_MAX:
172         default:
173             OVS_NOT_REACHED();
174         }
175     }
176
177     odp_execute_actions__(dp, packet, md, nl_attr_get(subactions),
178                           nl_attr_get_size(subactions), dp_execute_action,
179                           more_actions);
180 }
181
182 static void
183 odp_execute_actions__(void *dp, struct ofpbuf *packet, struct flow *md,
184                       const struct nlattr *actions, size_t actions_len,
185                       odp_execute_cb dp_execute_action, bool more_actions)
186 {
187     const struct nlattr *a;
188     unsigned int left;
189
190     NL_ATTR_FOR_EACH_UNSAFE (a, left, actions, actions_len) {
191         int type = nl_attr_type(a);
192
193         switch ((enum ovs_action_attr) type) {
194             /* These only make sense in the context of a datapath. */
195         case OVS_ACTION_ATTR_OUTPUT:
196         case OVS_ACTION_ATTR_USERSPACE:
197             if (dp_execute_action) {
198                 /* Allow 'dp_execute_action' to steal the packet data if we do
199                  * not need it any more. */
200                 bool steal = !more_actions && left <= NLA_ALIGN(a->nla_len);
201                 dp_execute_action(dp, packet, md, a, steal);
202             }
203             break;
204
205         case OVS_ACTION_ATTR_PUSH_VLAN: {
206             const struct ovs_action_push_vlan *vlan = nl_attr_get(a);
207             eth_push_vlan(packet, vlan->vlan_tci);
208             break;
209         }
210
211         case OVS_ACTION_ATTR_POP_VLAN:
212             eth_pop_vlan(packet);
213             break;
214
215         case OVS_ACTION_ATTR_PUSH_MPLS: {
216             const struct ovs_action_push_mpls *mpls = nl_attr_get(a);
217             push_mpls(packet, mpls->mpls_ethertype, mpls->mpls_lse);
218             break;
219          }
220
221         case OVS_ACTION_ATTR_POP_MPLS:
222             pop_mpls(packet, nl_attr_get_be16(a));
223             break;
224
225         case OVS_ACTION_ATTR_SET:
226             odp_execute_set_action(packet, nl_attr_get(a), md);
227             break;
228
229         case OVS_ACTION_ATTR_SAMPLE:
230             odp_execute_sample(dp, packet, md, a, dp_execute_action,
231                                more_actions || left > NLA_ALIGN(a->nla_len));
232             break;
233
234         case OVS_ACTION_ATTR_UNSPEC:
235         case __OVS_ACTION_ATTR_MAX:
236             OVS_NOT_REACHED();
237         }
238     }
239 }
240
241 void
242 odp_execute_actions(void *dp, struct ofpbuf *packet, struct flow *md,
243                     const struct nlattr *actions, size_t actions_len,
244                     odp_execute_cb dp_execute_action)
245 {
246     odp_execute_actions__(dp, packet, md, actions, actions_len,
247                           dp_execute_action, false);
248 }