+ upcall.userdata = NULL;
+ upcall.pid = 0;
+
+ for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
+ a = nla_next(a, &rem)) {
+ switch (nla_type(a)) {
+ case OVS_USERSPACE_ATTR_USERDATA:
+ upcall.userdata = a;
+ break;
+
+ case OVS_USERSPACE_ATTR_PID:
+ upcall.pid = nla_get_u32(a);
+ break;
+ }
+ }
+
+ return ovs_dp_upcall(dp, skb, &upcall);
+}
+
+static int sample(struct datapath *dp, struct sk_buff *skb,
+ const struct nlattr *attr,
+ struct ovs_key_ipv4_tunnel *tun_key)
+{
+ 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), tun_key, true);
+}
+
+static int execute_set_action(struct sk_buff *skb,
+ const struct nlattr *nested_attr,
+ struct ovs_key_ipv4_tunnel *tun_key)
+{
+ int err = 0;
+
+ switch (nla_type(nested_attr)) {
+ case OVS_KEY_ATTR_PRIORITY:
+ skb->priority = nla_get_u32(nested_attr);
+ break;
+
+ case OVS_KEY_ATTR_SKB_MARK:
+ skb_set_mark(skb, nla_get_u32(nested_attr));
+ break;
+
+ case OVS_KEY_ATTR_TUN_ID:
+ /* If we're only using the TUN_ID action, store the value in a
+ * temporary instance of struct ovs_key_ipv4_tunnel on the stack.
+ * If both IPV4_TUNNEL and TUN_ID are being used together we
+ * can't write into the IPV4_TUNNEL action, so make a copy and
+ * write into that version.
+ */
+ if (!OVS_CB(skb)->tun_key)
+ memset(tun_key, 0, sizeof(*tun_key));
+ else if (OVS_CB(skb)->tun_key != tun_key)
+ memcpy(tun_key, OVS_CB(skb)->tun_key, sizeof(*tun_key));
+ OVS_CB(skb)->tun_key = tun_key;
+
+ OVS_CB(skb)->tun_key->tun_id = nla_get_be64(nested_attr);
+ break;
+
+ case OVS_KEY_ATTR_IPV4_TUNNEL:
+ OVS_CB(skb)->tun_key = nla_data(nested_attr);
+ break;
+
+ case OVS_KEY_ATTR_ETHERNET:
+ err = set_eth_addr(skb, nla_data(nested_attr));
+ break;
+
+ case OVS_KEY_ATTR_IPV4:
+ err = set_ipv4(skb, nla_data(nested_attr));
+ break;
+
+ case OVS_KEY_ATTR_IPV6:
+ err = set_ipv6(skb, nla_data(nested_attr));
+ break;
+
+ case OVS_KEY_ATTR_TCP:
+ err = set_tcp(skb, nla_data(nested_attr));
+ break;
+
+ case OVS_KEY_ATTR_UDP:
+ err = set_udp(skb, nla_data(nested_attr));
+ break;
+ }
+
+ return err;