tests: Add test suite for packets.h.
[openvswitch] / datapath / actions.c
index 639b87078fbc37efbe31b86d57cb054c1d70587e..3223c65bd66b75680caf790ac470ff9f498e6d58 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Distributed under the terms of the GNU GPL version 2.
- * Copyright (c) 2007, 2008, 2009, 2010 Nicira Networks.
+ * Copyright (c) 2007, 2008, 2009, 2010, 2011 Nicira Networks.
  *
  * Significant portions of this file may be copied from parts of the Linux
  * kernel, by Linus Torvalds and others.
@@ -27,7 +27,7 @@
 #include "vport.h"
 
 static int do_execute_actions(struct datapath *, struct sk_buff *,
-                             const struct odp_flow_key *,
+                             const struct sw_flow_key *,
                              const struct nlattr *actions, u32 actions_len);
 
 static struct sk_buff *make_writable(struct sk_buff *skb, unsigned min_headroom)
@@ -76,7 +76,7 @@ static struct sk_buff *vlan_pull_tag(struct sk_buff *skb)
 }
 
 static struct sk_buff *modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
-                                      const struct odp_flow_key *key,
+                                      const struct sw_flow_key *key,
                                       const struct nlattr *a, u32 actions_len)
 {
        __be16 tci = nla_get_be16(a);
@@ -207,13 +207,13 @@ static struct sk_buff *strip_vlan(struct sk_buff *skb)
        return skb;
 }
 
-static bool is_ip(struct sk_buff *skb, const struct odp_flow_key *key)
+static bool is_ip(struct sk_buff *skb, const struct sw_flow_key *key)
 {
        return (key->dl_type == htons(ETH_P_IP) &&
                skb->transport_header > skb->network_header);
 }
 
-static __sum16 *get_l4_checksum(struct sk_buff *skb, const struct odp_flow_key *key)
+static __sum16 *get_l4_checksum(struct sk_buff *skb, const struct sw_flow_key *key)
 {
        int transport_len = skb->len - skb_transport_offset(skb);
        if (key->nw_proto == IPPROTO_TCP) {
@@ -227,7 +227,7 @@ static __sum16 *get_l4_checksum(struct sk_buff *skb, const struct odp_flow_key *
 }
 
 static struct sk_buff *set_nw_addr(struct sk_buff *skb,
-                                  const struct odp_flow_key *key,
+                                  const struct sw_flow_key *key,
                                   const struct nlattr *a)
 {
        __be32 new_nwaddr = nla_get_be32(a);
@@ -243,7 +243,7 @@ static struct sk_buff *set_nw_addr(struct sk_buff *skb,
                return NULL;
 
        nh = ip_hdr(skb);
-       nwaddr = nla_type(a) == ODPAT_SET_NW_SRC ? &nh->saddr : &nh->daddr;
+       nwaddr = nla_type(a) == ODP_ACTION_ATTR_SET_NW_SRC ? &nh->saddr : &nh->daddr;
 
        check = get_l4_checksum(skb, key);
        if (likely(check))
@@ -256,7 +256,7 @@ static struct sk_buff *set_nw_addr(struct sk_buff *skb,
 }
 
 static struct sk_buff *set_nw_tos(struct sk_buff *skb,
-                                 const struct odp_flow_key *key,
+                                 const struct sw_flow_key *key,
                                  u8 nw_tos)
 {
        if (unlikely(!is_ip(skb, key)))
@@ -279,7 +279,7 @@ static struct sk_buff *set_nw_tos(struct sk_buff *skb,
 }
 
 static struct sk_buff *set_tp_port(struct sk_buff *skb,
-                                  const struct odp_flow_key *key,
+                                  const struct sw_flow_key *key,
                                   const struct nlattr *a)
 {
        struct udphdr *th;
@@ -306,7 +306,7 @@ static struct sk_buff *set_tp_port(struct sk_buff *skb,
         * supports those protocols.
         */
        th = udp_hdr(skb);
-       port = nla_type(a) == ODPAT_SET_TP_SRC ? &th->source : &th->dest;
+       port = nla_type(a) == ODP_ACTION_ATTR_SET_TP_SRC ? &th->source : &th->dest;
        inet_proto_csum_replace2(check, skb, *port, nla_get_be16(a), 0);
        *port = nla_get_be16(a);
 
@@ -324,7 +324,7 @@ static struct sk_buff *set_tp_port(struct sk_buff *skb,
  * or truncated header fields or one whose inner and outer Ethernet address
  * differ.
  */
-static bool is_spoofed_arp(struct sk_buff *skb, const struct odp_flow_key *key)
+static bool is_spoofed_arp(struct sk_buff *skb, const struct sw_flow_key *key)
 {
        struct arp_eth_header *arp;
 
@@ -360,17 +360,27 @@ error:
        kfree_skb(skb);
 }
 
-static int output_control(struct datapath *dp, struct sk_buff *skb, u32 arg)
+static int output_control(struct datapath *dp, struct sk_buff *skb, u64 arg,
+                         const struct sw_flow_key *key)
 {
+       struct dp_upcall_info upcall;
+
        skb = skb_clone(skb, GFP_ATOMIC);
        if (!skb)
                return -ENOMEM;
-       return dp_output_control(dp, skb, _ODPL_ACTION_NR, arg);
+
+       upcall.cmd = ODP_PACKET_CMD_ACTION;
+       upcall.key = key;
+       upcall.userdata = arg;
+       upcall.sample_pool = 0;
+       upcall.actions = NULL;
+       upcall.actions_len = 0;
+       return dp_upcall(dp, skb, &upcall);
 }
 
 /* Execute a list of actions against 'skb'. */
 static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
-                             const struct odp_flow_key *key,
+                             const struct sw_flow_key *key,
                              const struct nlattr *actions, u32 actions_len)
 {
        /* Every output action needs a separate clone of 'skb', but the common
@@ -389,69 +399,69 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
                }
 
                switch (nla_type(a)) {
-               case ODPAT_OUTPUT:
+               case ODP_ACTION_ATTR_OUTPUT:
                        prev_port = nla_get_u32(a);
                        break;
 
-               case ODPAT_CONTROLLER:
-                       err = output_control(dp, skb, nla_get_u64(a));
+               case ODP_ACTION_ATTR_CONTROLLER:
+                       err = output_control(dp, skb, nla_get_u64(a), key);
                        if (err) {
                                kfree_skb(skb);
                                return err;
                        }
                        break;
 
-               case ODPAT_SET_TUNNEL:
+               case ODP_ACTION_ATTR_SET_TUNNEL:
                        OVS_CB(skb)->tun_id = nla_get_be64(a);
                        break;
 
-               case ODPAT_SET_DL_TCI:
+               case ODP_ACTION_ATTR_SET_DL_TCI:
                        skb = modify_vlan_tci(dp, skb, key, a, rem);
                        if (IS_ERR(skb))
                                return PTR_ERR(skb);
                        break;
 
-               case ODPAT_STRIP_VLAN:
+               case ODP_ACTION_ATTR_STRIP_VLAN:
                        skb = strip_vlan(skb);
                        break;
 
-               case ODPAT_SET_DL_SRC:
+               case ODP_ACTION_ATTR_SET_DL_SRC:
                        skb = make_writable(skb, 0);
                        if (!skb)
                                return -ENOMEM;
                        memcpy(eth_hdr(skb)->h_source, nla_data(a), ETH_ALEN);
                        break;
 
-               case ODPAT_SET_DL_DST:
+               case ODP_ACTION_ATTR_SET_DL_DST:
                        skb = make_writable(skb, 0);
                        if (!skb)
                                return -ENOMEM;
                        memcpy(eth_hdr(skb)->h_dest, nla_data(a), ETH_ALEN);
                        break;
 
-               case ODPAT_SET_NW_SRC:
-               case ODPAT_SET_NW_DST:
+               case ODP_ACTION_ATTR_SET_NW_SRC:
+               case ODP_ACTION_ATTR_SET_NW_DST:
                        skb = set_nw_addr(skb, key, a);
                        break;
 
-               case ODPAT_SET_NW_TOS:
+               case ODP_ACTION_ATTR_SET_NW_TOS:
                        skb = set_nw_tos(skb, key, nla_get_u8(a));
                        break;
 
-               case ODPAT_SET_TP_SRC:
-               case ODPAT_SET_TP_DST:
+               case ODP_ACTION_ATTR_SET_TP_SRC:
+               case ODP_ACTION_ATTR_SET_TP_DST:
                        skb = set_tp_port(skb, key, a);
                        break;
 
-               case ODPAT_SET_PRIORITY:
+               case ODP_ACTION_ATTR_SET_PRIORITY:
                        skb->priority = nla_get_u32(a);
                        break;
 
-               case ODPAT_POP_PRIORITY:
+               case ODP_ACTION_ATTR_POP_PRIORITY:
                        skb->priority = priority;
                        break;
 
-               case ODPAT_DROP_SPOOFED_ARP:
+               case ODP_ACTION_ATTR_DROP_SPOOFED_ARP:
                        if (unlikely(is_spoofed_arp(skb, key)))
                                goto exit;
                        break;
@@ -467,41 +477,41 @@ exit:
        return 0;
 }
 
-/* Send a copy of this packet up to the sFlow agent, along with extra
- * information about what happened to it. */
 static void sflow_sample(struct datapath *dp, struct sk_buff *skb,
-                        const struct nlattr *a, u32 actions_len,
-                        struct vport *vport)
+                        const struct sw_flow_key *key,
+                        const struct nlattr *a, u32 actions_len)
 {
-       struct odp_sflow_sample_header *hdr;
-       unsigned int hdrlen = sizeof(struct odp_sflow_sample_header);
        struct sk_buff *nskb;
+       struct vport *p = OVS_CB(skb)->vport;
+       struct dp_upcall_info upcall;
+
+       if (unlikely(!p))
+               return;
 
-       nskb = skb_copy_expand(skb, actions_len + hdrlen, 0, GFP_ATOMIC);
-       if (!nskb)
+       atomic_inc(&p->sflow_pool);
+       if (net_random() >= dp->sflow_probability)
                return;
 
-       memcpy(__skb_push(nskb, actions_len), a, actions_len);
-       hdr = (struct odp_sflow_sample_header*)__skb_push(nskb, hdrlen);
-       hdr->actions_len = actions_len;
-       hdr->sample_pool = atomic_read(&vport->sflow_pool);
-       dp_output_control(dp, nskb, _ODPL_SFLOW_NR, 0);
+       nskb = skb_clone(skb, GFP_ATOMIC);
+       if (unlikely(!nskb))
+               return;
+
+       upcall.cmd = ODP_PACKET_CMD_SAMPLE;
+       upcall.key = key;
+       upcall.userdata = 0;
+       upcall.sample_pool = atomic_read(&p->sflow_pool);
+       upcall.actions = a;
+       upcall.actions_len = actions_len;
+       dp_upcall(dp, nskb, &upcall);
 }
 
 /* Execute a list of actions against 'skb'. */
 int execute_actions(struct datapath *dp, struct sk_buff *skb,
-                   const struct odp_flow_key *key,
+                   const struct sw_flow_key *key,
                    const struct nlattr *actions, u32 actions_len)
 {
-       if (dp->sflow_probability) {
-               struct vport *p = OVS_CB(skb)->vport;
-               if (p) {
-                       atomic_inc(&p->sflow_pool);
-                       if (dp->sflow_probability == UINT_MAX ||
-                           net_random() < dp->sflow_probability)
-                               sflow_sample(dp, skb, actions, actions_len, p);
-               }
-       }
+       if (dp->sflow_probability)
+               sflow_sample(dp, skb, key, actions, actions_len);
 
        OVS_CB(skb)->tun_id = 0;