+
+static void sflow_sample(struct datapath *dp, struct sk_buff *skb,
+ const struct sw_flow_key *key,
+ const struct nlattr *a, u32 actions_len)
+{
+ 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.type = _ODPL_SFLOW_NR;
+ 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 sw_flow_key *key,
+ const struct nlattr *actions, u32 actions_len)
+{
+ if (dp->sflow_probability)
+ sflow_sample(dp, skb, key, actions, actions_len);
+
+ OVS_CB(skb)->tun_id = 0;
+
+ return do_execute_actions(dp, skb, key, actions, actions_len);
+}