vconn: Remove unnecessary forward declarations and #includes from header.
[openvswitch] / datapath / actions.c
index 83b531adfff3143fc29e59f2515527aea804c732..36437a4baa4fee411a116cd2f578af0885b864bc 100644 (file)
@@ -28,8 +28,8 @@
 #include "vlan.h"
 #include "vport.h"
 
-static int do_execute_actions(struct datapath *, struct sk_buff *,
-                             struct sw_flow_actions *acts);
+static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
+                       const struct nlattr *attr, int len, bool keep_skb);
 
 static int make_writable(struct sk_buff *skb, int write_len)
 {
@@ -227,44 +227,61 @@ static int set_tp_port(struct sk_buff *skb, const struct nlattr *a)
        return 0;
 }
 
-static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
+static int do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
 {
-       struct vport *p;
-
-       if (!skb)
-               goto error;
+       struct vport *vport;
 
-       p = rcu_dereference(dp->ports[out_port]);
-       if (!p)
-               goto error;
+       if (unlikely(!skb))
+               return -ENOMEM;
 
-       vport_send(p, skb);
-       return;
+       vport = rcu_dereference(dp->ports[out_port]);
+       if (unlikely(!vport)) {
+               kfree_skb(skb);
+               return -ENODEV;
+       }
 
-error:
-       kfree_skb(skb);
+       vport_send(vport, skb);
+       return 0;
 }
 
 static int output_userspace(struct datapath *dp, struct sk_buff *skb, u64 arg)
 {
        struct dp_upcall_info upcall;
 
-       skb = skb_clone(skb, GFP_ATOMIC);
-       if (!skb)
-               return -ENOMEM;
-
        upcall.cmd = OVS_PACKET_CMD_ACTION;
        upcall.key = &OVS_CB(skb)->flow->key;
        upcall.userdata = arg;
-       upcall.sample_pool = 0;
-       upcall.actions = NULL;
-       upcall.actions_len = 0;
        return dp_upcall(dp, skb, &upcall);
 }
 
+static int sample(struct datapath *dp, struct sk_buff *skb,
+                 const struct nlattr *attr)
+{
+       const struct nlattr *acts_list = NULL;
+       const struct nlattr *a;
+       int rem;
+
+       for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
+                a = nla_next(a, &rem)) {
+               switch (nla_type(a)) {
+               case OVS_SAMPLE_ATTR_PROBABILITY:
+                       if (net_random() >= nla_get_u32(a))
+                               return 0;
+                       break;
+
+               case OVS_SAMPLE_ATTR_ACTIONS:
+                       acts_list = a;
+                       break;
+               }
+       }
+
+       return do_execute_actions(dp, skb, nla_data(acts_list),
+                                                nla_len(acts_list), true);
+}
+
 /* Execute a list of actions against 'skb'. */
 static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
-                             struct sw_flow_actions *acts)
+                       const struct nlattr *attr, int len, bool keep_skb)
 {
        /* Every output action needs a separate clone of 'skb', but the common
         * case is just a single output action, so that doing a clone and
@@ -275,7 +292,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
        const struct nlattr *a;
        int rem;
 
-       for (a = acts->actions, rem = acts->actions_len; rem > 0;
+       for (a = attr, rem = len; rem > 0;
             a = nla_next(a, &rem)) {
                int err = 0;
 
@@ -290,7 +307,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
                        break;
 
                case OVS_ACTION_ATTR_USERSPACE:
-                       err = output_userspace(dp, skb, nla_get_u64(a));
+                       output_userspace(dp, skb, nla_get_u64(a));
                        break;
 
                case OVS_ACTION_ATTR_SET_TUNNEL:
@@ -340,49 +357,29 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
                case OVS_ACTION_ATTR_POP_PRIORITY:
                        skb->priority = priority;
                        break;
-               }
 
+               case OVS_ACTION_ATTR_SAMPLE:
+                       err = sample(dp, skb, a);
+                       break;
+
+               }
                if (unlikely(err)) {
                        kfree_skb(skb);
                        return err;
                }
        }
 
-       if (prev_port != -1)
+       if (prev_port != -1) {
+               if (keep_skb)
+                       skb = skb_clone(skb, GFP_ATOMIC);
+
                do_output(dp, skb, prev_port);
-       else
+       } else if (!keep_skb)
                consume_skb(skb);
 
        return 0;
 }
 
-static void sflow_sample(struct datapath *dp, struct sk_buff *skb,
-                        struct sw_flow_actions *acts)
-{
-       struct sk_buff *nskb;
-       struct vport *p = OVS_CB(skb)->vport;
-       struct dp_upcall_info upcall;
-
-       if (unlikely(!p))
-               return;
-
-       atomic_inc(&p->sflow_pool);
-       if (net_random() >= dp->sflow_probability)
-               return;
-
-       nskb = skb_clone(skb, GFP_ATOMIC);
-       if (unlikely(!nskb))
-               return;
-
-       upcall.cmd = OVS_PACKET_CMD_SAMPLE;
-       upcall.key = &OVS_CB(skb)->flow->key;
-       upcall.userdata = 0;
-       upcall.sample_pool = atomic_read(&p->sflow_pool);
-       upcall.actions = acts->actions;
-       upcall.actions_len = acts->actions_len;
-       dp_upcall(dp, nskb, &upcall);
-}
-
 /* Execute a list of actions against 'skb'. */
 int execute_actions(struct datapath *dp, struct sk_buff *skb)
 {
@@ -400,11 +397,9 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb)
                goto out_loop;
        }
 
-       /* Really execute actions. */
-       if (dp->sflow_probability)
-               sflow_sample(dp, skb, acts);
        OVS_CB(skb)->tun_id = 0;
-       error = do_execute_actions(dp, skb, acts);
+       error = do_execute_actions(dp, skb, acts->actions,
+                                        acts->actions_len, false);
 
        /* Check whether sub-actions looped too much. */
        if (unlikely(loop->looping))