Fix "make dist" by adding forgotten files to sources lists.
[sliver-openvswitch.git] / switch / dp_act.c
1 /* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
2  * Junior University
3  * 
4  * We are making the OpenFlow specification and associated documentation
5  * (Software) available for public use and benefit with the expectation
6  * that others will use, modify and enhance the Software and contribute
7  * those enhancements back to the community. However, since we would
8  * like to make the Software available for broadest use, with as few
9  * restrictions as possible permission is hereby granted, free of
10  * charge, to any person obtaining a copy of this Software to deal in
11  * the Software under the copyrights without restriction, including
12  * without limitation the rights to use, copy, modify, merge, publish,
13  * distribute, sublicense, and/or sell copies of the Software, and to
14  * permit persons to whom the Software is furnished to do so, subject to
15  * the following conditions:
16  * 
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  * 
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE.
28  * 
29  * The name and trademarks of copyright holder(s) may NOT be used in
30  * advertising or publicity pertaining to the Software or any
31  * derivatives without specific, written prior permission.
32  */
33
34 /* Functions for executing OpenFlow actions. */
35
36 #include <arpa/inet.h>
37 #include "csum.h"
38 #include "packets.h"
39 #include "dp_act.h"
40 #include "openflow/nicira-ext.h"
41 #include "nx_act.h"
42
43
44 static uint16_t
45 validate_output(struct datapath *dp, const struct sw_flow_key *key, 
46         const struct ofp_action_header *ah) 
47 {
48     struct ofp_action_output *oa = (struct ofp_action_output *)ah;
49
50     /* To prevent loops, make sure there's no action to send to the
51      * OFP_TABLE virtual port.
52      */
53     if (oa->port == htons(OFPP_NONE) || oa->port == key->flow.in_port) {
54         return OFPBAC_BAD_OUT_PORT;
55     }
56     return ACT_VALIDATION_OK;
57 }
58
59 static void
60 do_output(struct datapath *dp, struct ofpbuf *buffer, int in_port,
61           size_t max_len, int out_port, bool ignore_no_fwd)
62 {
63     if (out_port != OFPP_CONTROLLER) {
64         dp_output_port(dp, buffer, in_port, out_port, ignore_no_fwd);
65     } else {
66         dp_output_control(dp, buffer, in_port, max_len, OFPR_ACTION);
67     }
68 }
69
70 /* Modify vlan tag control information (TCI).  Only sets the TCI bits
71  * indicated by 'mask'.  If no vlan tag is present, one is added.
72  */
73 static void
74 modify_vlan_tci(struct ofpbuf *buffer, struct sw_flow_key *key,
75         uint16_t tci, uint16_t mask)
76 {
77     struct vlan_eth_header *veh;
78
79     if (key->flow.dl_vlan != htons(OFP_VLAN_NONE)) {
80         /* Modify vlan id, but maintain other TCI values */
81         veh = buffer->l2;
82         veh->veth_tci &= ~htons(mask);
83         veh->veth_tci |= htons(tci);
84     } else {
85         /* Insert new vlan id. */
86         struct eth_header *eh = buffer->l2;
87         struct vlan_eth_header tmp;
88         memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN);
89         memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN);
90         tmp.veth_type = htons(ETH_TYPE_VLAN);
91         tmp.veth_tci = htons(tci);
92         tmp.veth_next_type = eh->eth_type;
93
94         veh = ofpbuf_push_uninit(buffer, VLAN_HEADER_LEN);
95         memcpy(veh, &tmp, sizeof tmp);
96         buffer->l2 = (char*)buffer->l2 - VLAN_HEADER_LEN;
97     }
98
99     key->flow.dl_vlan = veh->veth_tci & htons(VLAN_VID_MASK);
100 }
101
102
103 /* Remove an existing vlan header if it exists. */
104 static void
105 vlan_pull_tag(struct ofpbuf *buffer)
106 {
107     struct vlan_eth_header *veh = buffer->l2;
108
109     if (veh->veth_type == htons(ETH_TYPE_VLAN)) {
110         struct eth_header tmp;
111
112         memcpy(tmp.eth_dst, veh->veth_dst, ETH_ADDR_LEN);
113         memcpy(tmp.eth_src, veh->veth_src, ETH_ADDR_LEN);
114         tmp.eth_type = veh->veth_next_type;
115
116         buffer->size -= VLAN_HEADER_LEN;
117         buffer->data = (char*)buffer->data + VLAN_HEADER_LEN;
118         buffer->l2 = (char*)buffer->l2 + VLAN_HEADER_LEN;
119         memcpy(buffer->data, &tmp, sizeof tmp);
120     }
121 }
122
123 static void
124 set_vlan_vid(struct ofpbuf *buffer, struct sw_flow_key *key, 
125         const struct ofp_action_header *ah)
126 {
127     struct ofp_action_vlan_vid *va = (struct ofp_action_vlan_vid *)ah;
128     uint16_t tci = ntohs(va->vlan_vid);
129
130     modify_vlan_tci(buffer, key, tci, VLAN_VID_MASK);
131 }
132
133 static void
134 set_vlan_pcp(struct ofpbuf *buffer, struct sw_flow_key *key, 
135         const struct ofp_action_header *ah)
136 {
137     struct ofp_action_vlan_pcp *va = (struct ofp_action_vlan_pcp *)ah;
138     uint16_t tci = (uint16_t)va->vlan_pcp << 13;
139
140     modify_vlan_tci(buffer, key, tci, VLAN_PCP_MASK);
141 }
142
143 static void
144 strip_vlan(struct ofpbuf *buffer, struct sw_flow_key *key, 
145         const struct ofp_action_header *ah)
146 {
147     vlan_pull_tag(buffer);
148     key->flow.dl_vlan = htons(OFP_VLAN_NONE);
149 }
150
151 static void
152 set_dl_addr(struct ofpbuf *buffer, struct sw_flow_key *key, 
153         const struct ofp_action_header *ah)
154 {
155     struct ofp_action_dl_addr *da = (struct ofp_action_dl_addr *)ah;
156     struct eth_header *eh = buffer->l2;
157
158     if (da->type == htons(OFPAT_SET_DL_SRC)) {
159         memcpy(eh->eth_src, da->dl_addr, sizeof eh->eth_src);
160     } else {
161         memcpy(eh->eth_dst, da->dl_addr, sizeof eh->eth_dst);
162     }
163 }
164
165 static void
166 set_nw_addr(struct ofpbuf *buffer, struct sw_flow_key *key, 
167         const struct ofp_action_header *ah)
168 {
169     struct ofp_action_nw_addr *na = (struct ofp_action_nw_addr *)ah;
170     uint16_t eth_proto = ntohs(key->flow.dl_type);
171
172     if (eth_proto == ETH_TYPE_IP) {
173         struct ip_header *nh = buffer->l3;
174         uint8_t nw_proto = key->flow.nw_proto;
175         uint32_t new, *field;
176
177         new = na->nw_addr;
178         field = na->type == OFPAT_SET_NW_SRC ? &nh->ip_src : &nh->ip_dst;
179         if (nw_proto == IP_TYPE_TCP) {
180             struct tcp_header *th = buffer->l4;
181             th->tcp_csum = recalc_csum32(th->tcp_csum, *field, new);
182         } else if (nw_proto == IP_TYPE_UDP) {
183             struct udp_header *th = buffer->l4;
184             if (th->udp_csum) {
185                 th->udp_csum = recalc_csum32(th->udp_csum, *field, new);
186                 if (!th->udp_csum) {
187                     th->udp_csum = 0xffff;
188                 }
189             }
190         }
191         nh->ip_csum = recalc_csum32(nh->ip_csum, *field, new);
192         *field = new;
193     }
194 }
195
196 static void
197 set_tp_port(struct ofpbuf *buffer, struct sw_flow_key *key, 
198         const struct ofp_action_header *ah)
199 {
200     struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah;
201     uint16_t eth_proto = ntohs(key->flow.dl_type);
202
203     if (eth_proto == ETH_TYPE_IP) {
204         uint8_t nw_proto = key->flow.nw_proto;
205         uint16_t new, *field;
206
207         new = ta->tp_port;
208         if (nw_proto == IP_TYPE_TCP) {
209             struct tcp_header *th = buffer->l4;
210             field = ta->type == OFPAT_SET_TP_SRC ? &th->tcp_src : &th->tcp_dst;
211             th->tcp_csum = recalc_csum16(th->tcp_csum, *field, new);
212             *field = new;
213         } else if (nw_proto == IP_TYPE_UDP) {
214             struct udp_header *th = buffer->l4;
215             field = ta->type == OFPAT_SET_TP_SRC ? &th->udp_src : &th->udp_dst;
216             th->udp_csum = recalc_csum16(th->udp_csum, *field, new);
217             *field = new;
218         }
219     }
220 }
221
222 struct openflow_action {
223     size_t min_size;
224     size_t max_size;
225     uint16_t (*validate)(struct datapath *dp, 
226             const struct sw_flow_key *key,
227             const struct ofp_action_header *ah);
228     void (*execute)(struct ofpbuf *buffer,
229             struct sw_flow_key *key, 
230             const struct ofp_action_header *ah);
231 };
232
233 static const struct openflow_action of_actions[] = {
234     [OFPAT_OUTPUT] = {
235         sizeof(struct ofp_action_output),
236         sizeof(struct ofp_action_output),
237         validate_output,
238         NULL                   /* This is optimized into execute_actions */
239     },
240     [OFPAT_SET_VLAN_VID] = {
241         sizeof(struct ofp_action_vlan_vid),
242         sizeof(struct ofp_action_vlan_vid),
243         NULL,
244         set_vlan_vid
245     },
246     [OFPAT_SET_VLAN_PCP] = {
247         sizeof(struct ofp_action_vlan_pcp),
248         sizeof(struct ofp_action_vlan_pcp),
249         NULL,
250         set_vlan_pcp
251     },
252     [OFPAT_STRIP_VLAN] = {
253         sizeof(struct ofp_action_header),
254         sizeof(struct ofp_action_header),
255         NULL,
256         strip_vlan
257     },
258     [OFPAT_SET_DL_SRC] = {
259         sizeof(struct ofp_action_dl_addr),
260         sizeof(struct ofp_action_dl_addr),
261         NULL,
262         set_dl_addr
263     },
264     [OFPAT_SET_DL_DST] = {
265         sizeof(struct ofp_action_dl_addr),
266         sizeof(struct ofp_action_dl_addr),
267         NULL,
268         set_dl_addr
269     },
270     [OFPAT_SET_NW_SRC] = {
271         sizeof(struct ofp_action_nw_addr),
272         sizeof(struct ofp_action_nw_addr),
273         NULL,
274         set_nw_addr
275     },
276     [OFPAT_SET_NW_DST] = {
277         sizeof(struct ofp_action_nw_addr),
278         sizeof(struct ofp_action_nw_addr),
279         NULL,
280         set_nw_addr
281     },
282     [OFPAT_SET_TP_SRC] = {
283         sizeof(struct ofp_action_tp_port),
284         sizeof(struct ofp_action_tp_port),
285         NULL,
286         set_tp_port
287     },
288     [OFPAT_SET_TP_DST] = {
289         sizeof(struct ofp_action_tp_port),
290         sizeof(struct ofp_action_tp_port),
291         NULL,
292         set_tp_port
293     }
294     /* OFPAT_VENDOR is not here, since it would blow up the array size. */
295 };
296
297 /* Validate built-in OpenFlow actions.  Either returns ACT_VALIDATION_OK
298  * or an OFPET_BAD_ACTION error code. */
299 static uint16_t 
300 validate_ofpat(struct datapath *dp, const struct sw_flow_key *key, 
301         const struct ofp_action_header *ah, uint16_t type, uint16_t len)
302 {
303     int ret = ACT_VALIDATION_OK;
304     const struct openflow_action *act = &of_actions[type];
305
306     if ((len < act->min_size) || (len > act->max_size)) {
307         return OFPBAC_BAD_LEN;
308     }
309
310     if (act->validate) {
311         ret = act->validate(dp, key, ah);
312     }
313
314     return ret;
315 }
316
317 /* Validate vendor-defined actions.  Either returns ACT_VALIDATION_OK
318  * or an OFPET_BAD_ACTION error code. */
319 static uint16_t 
320 validate_vendor(struct datapath *dp, const struct sw_flow_key *key, 
321         const struct ofp_action_header *ah, uint16_t len)
322 {
323     struct ofp_action_vendor_header *avh;
324     int ret = ACT_VALIDATION_OK;
325
326     if (len < sizeof(struct ofp_action_vendor_header)) {
327         return OFPBAC_BAD_LEN;
328     }
329
330     avh = (struct ofp_action_vendor_header *)ah;
331
332     switch(ntohl(avh->vendor)) {
333     case NX_VENDOR_ID: 
334         ret = nx_validate_act(dp, key, avh, len);
335         break;
336
337     default:
338         return OFPBAC_BAD_VENDOR;
339     }
340
341     return ret;
342 }
343
344 /* Validates a list of actions.  If a problem is found, a code for the
345  * OFPET_BAD_ACTION error type is returned.  If the action list validates, 
346  * ACT_VALIDATION_OK is returned. */
347 uint16_t 
348 validate_actions(struct datapath *dp, const struct sw_flow_key *key,
349         const struct ofp_action_header *actions, size_t actions_len)
350 {
351     uint8_t *p = (uint8_t *)actions;
352     int err;
353
354     while (actions_len >= sizeof(struct ofp_action_header)) {
355         struct ofp_action_header *ah = (struct ofp_action_header *)p;
356         size_t len = ntohs(ah->len);
357         uint16_t type;
358
359         /* Make there's enough remaining data for the specified length
360          * and that the action length is a multiple of 64 bits. */
361         if ((actions_len < len) || (len % 8) != 0) {
362             return OFPBAC_BAD_LEN;
363         }
364
365         type = ntohs(ah->type);
366         if (type < ARRAY_SIZE(of_actions)) {
367             err = validate_ofpat(dp, key, ah, type, len);
368             if (err != ACT_VALIDATION_OK) {
369                 return err;
370             }
371         } else if (type == OFPAT_VENDOR) {
372             err = validate_vendor(dp, key, ah, len);
373             if (err != ACT_VALIDATION_OK) {
374                 return err;
375             }
376         } else {
377             return OFPBAC_BAD_TYPE;
378         }
379
380         p += len;
381         actions_len -= len;
382     }
383
384     /* Check if there's any trailing garbage. */
385     if (actions_len != 0) {
386         return OFPBAC_BAD_LEN;
387     }
388
389     return ACT_VALIDATION_OK;
390 }
391
392 /* Execute a built-in OpenFlow action against 'buffer'. */
393 static void
394 execute_ofpat(struct ofpbuf *buffer, struct sw_flow_key *key, 
395         const struct ofp_action_header *ah, uint16_t type)
396 {
397     const struct openflow_action *act = &of_actions[type];
398
399     if (act->execute) {
400         act->execute(buffer, key, ah);
401     }
402 }
403
404 /* Execute a vendor-defined action against 'buffer'. */
405 static void
406 execute_vendor(struct ofpbuf *buffer, const struct sw_flow_key *key, 
407         const struct ofp_action_header *ah)
408 {
409     struct ofp_action_vendor_header *avh 
410             = (struct ofp_action_vendor_header *)ah;
411
412     switch(ntohl(avh->vendor)) {
413     case NX_VENDOR_ID: 
414         nx_execute_act(buffer, key, avh);
415         break;
416
417     default:
418         /* This should not be possible due to prior validation. */
419         printf("attempt to execute action with unknown vendor: %#x\n", 
420                 ntohl(avh->vendor));
421         break;
422     }
423 }
424
425 /* Execute a list of actions against 'buffer'. */
426 void execute_actions(struct datapath *dp, struct ofpbuf *buffer,
427              struct sw_flow_key *key,
428              const struct ofp_action_header *actions, size_t actions_len,
429              int ignore_no_fwd)
430 {
431     /* Every output action needs a separate clone of 'buffer', but the common
432      * case is just a single output action, so that doing a clone and then
433      * freeing the original buffer is wasteful.  So the following code is
434      * slightly obscure just to avoid that. */
435     int prev_port;
436     size_t max_len=0;     /* Initialze to make compiler happy */
437     uint16_t in_port = ntohs(key->flow.in_port);
438     uint8_t *p = (uint8_t *)actions;
439
440     prev_port = -1;
441
442     /* The action list was already validated, so we can be a bit looser
443      * in our sanity-checking. */
444     while (actions_len > 0) {
445         struct ofp_action_header *ah = (struct ofp_action_header *)p;
446         size_t len = htons(ah->len);
447
448         if (prev_port != -1) {
449             do_output(dp, ofpbuf_clone(buffer), in_port, max_len, 
450                     prev_port, ignore_no_fwd);
451             prev_port = -1;
452         }
453
454         if (ah->type == htons(OFPAT_OUTPUT)) {
455             struct ofp_action_output *oa = (struct ofp_action_output *)p;
456             prev_port = ntohs(oa->port);
457             max_len = ntohs(oa->max_len);
458         } else {
459             uint16_t type = ntohs(ah->type);
460
461             if (type < ARRAY_SIZE(of_actions)) {
462                 execute_ofpat(buffer, key, ah, type);
463             } else if (type == OFPAT_VENDOR) {
464                 execute_vendor(buffer, key, ah);
465             }
466         }
467
468         p += len;
469         actions_len -= len;
470     }
471     if (prev_port != -1) {
472         do_output(dp, buffer, in_port, max_len, prev_port, ignore_no_fwd);
473     } else {
474         ofpbuf_delete(buffer);
475     }
476 }