+ err = genlmsg_unicast(&init_net, user_skb, pid);
+ if (err)
+ goto err_kfree_skbs;
+
+ consume_skb(skb);
+ skb = nskb;
+ } while (skb);
+ return 0;
+
+err_kfree_skbs:
+ kfree_skb(skb);
+ while ((skb = nskb) != NULL) {
+ nskb = skb->next;
+ kfree_skb(skb);
+ }
+ return err;
+}
+
+/* Called with genl_mutex. */
+static int flush_flows(int dp_ifindex)
+{
+ struct flow_table *old_table;
+ struct flow_table *new_table;
+ struct datapath *dp;
+
+ dp = get_dp(dp_ifindex);
+ if (!dp)
+ return -ENODEV;
+
+ old_table = get_table_protected(dp);
+ new_table = flow_tbl_alloc(TBL_MIN_BUCKETS);
+ if (!new_table)
+ return -ENOMEM;
+
+ rcu_assign_pointer(dp->table, new_table);
+
+ flow_tbl_deferred_destroy(old_table);
+ return 0;
+}
+
+static int validate_actions(const struct nlattr *attr)
+{
+ const struct nlattr *a;
+ int rem;
+
+ nla_for_each_nested(a, attr, rem) {
+ static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = {
+ [OVS_ACTION_ATTR_OUTPUT] = 4,
+ [OVS_ACTION_ATTR_USERSPACE] = 8,
+ [OVS_ACTION_ATTR_PUSH_VLAN] = 2,
+ [OVS_ACTION_ATTR_POP_VLAN] = 0,
+ [OVS_ACTION_ATTR_SET_DL_SRC] = ETH_ALEN,
+ [OVS_ACTION_ATTR_SET_DL_DST] = ETH_ALEN,
+ [OVS_ACTION_ATTR_SET_NW_SRC] = 4,
+ [OVS_ACTION_ATTR_SET_NW_DST] = 4,
+ [OVS_ACTION_ATTR_SET_NW_TOS] = 1,
+ [OVS_ACTION_ATTR_SET_TP_SRC] = 2,
+ [OVS_ACTION_ATTR_SET_TP_DST] = 2,
+ [OVS_ACTION_ATTR_SET_TUNNEL] = 8,
+ [OVS_ACTION_ATTR_SET_PRIORITY] = 4,
+ [OVS_ACTION_ATTR_POP_PRIORITY] = 0,
+ };
+ int type = nla_type(a);
+
+ if (type > OVS_ACTION_ATTR_MAX || nla_len(a) != action_lens[type])
+ return -EINVAL;
+
+ switch (type) {
+ case OVS_ACTION_ATTR_UNSPEC:
+ return -EINVAL;
+
+ case OVS_ACTION_ATTR_USERSPACE:
+ case OVS_ACTION_ATTR_POP_VLAN:
+ case OVS_ACTION_ATTR_SET_DL_SRC:
+ case OVS_ACTION_ATTR_SET_DL_DST:
+ case OVS_ACTION_ATTR_SET_NW_SRC:
+ case OVS_ACTION_ATTR_SET_NW_DST:
+ case OVS_ACTION_ATTR_SET_TP_SRC:
+ case OVS_ACTION_ATTR_SET_TP_DST:
+ case OVS_ACTION_ATTR_SET_TUNNEL:
+ case OVS_ACTION_ATTR_SET_PRIORITY:
+ case OVS_ACTION_ATTR_POP_PRIORITY:
+ /* No validation needed. */
+ break;
+
+ case OVS_ACTION_ATTR_OUTPUT:
+ if (nla_get_u32(a) >= DP_MAX_PORTS)
+ return -EINVAL;
+ break;
+
+ case OVS_ACTION_ATTR_PUSH_VLAN:
+ if (nla_get_be16(a) & htons(VLAN_CFI_MASK))
+ return -EINVAL;
+ break;
+
+ case OVS_ACTION_ATTR_SET_NW_TOS:
+ if (nla_get_u8(a) & INET_ECN_MASK)
+ return -EINVAL;
+ break;