+
+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 = ODP_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)
+{
+ struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
+ struct loop_counter *loop;
+ int error;
+
+ /* Check whether we've looped too much. */
+ loop = loop_get_counter();
+ if (unlikely(++loop->count > MAX_LOOPS))
+ loop->looping = true;
+ if (unlikely(loop->looping)) {
+ error = loop_suppress(dp, acts);
+ kfree_skb(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);
+
+ /* Check whether sub-actions looped too much. */
+ if (unlikely(loop->looping))
+ error = loop_suppress(dp, acts);
+
+out_loop:
+ /* Decrement loop counter. */
+ if (!--loop->count)
+ loop->looping = false;
+ loop_put_counter();
+
+ return error;
+}