]> git.karo-electronics.de Git - linux-beck.git/blobdiff - net/openvswitch/datapath.c
Merge tag 'pm+acpi-4.6-rc1-3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[linux-beck.git] / net / openvswitch / datapath.c
index deadfdab1bc384c858642e176d690bcf62a103c0..0cc66a4e492deb8484781434d211fef5fa84b25c 100644 (file)
@@ -422,10 +422,6 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
        struct sk_buff *nskb = NULL;
        struct sk_buff *user_skb = NULL; /* to be queued to userspace */
        struct nlattr *nla;
-       struct genl_info info = {
-               .dst_sk = ovs_dp_get_net(dp)->genl_sock,
-               .snd_portid = upcall_info->portid,
-       };
        size_t len;
        unsigned int hlen;
        int err, dp_ifindex;
@@ -466,7 +462,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
                hlen = skb->len;
 
        len = upcall_msg_size(upcall_info, hlen);
-       user_skb = genlmsg_new_unicast(len, &info, GFP_ATOMIC);
+       user_skb = genlmsg_new(len, GFP_ATOMIC);
        if (!user_skb) {
                err = -ENOMEM;
                goto out;
@@ -654,7 +650,7 @@ static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
 
 static const struct genl_ops dp_packet_genl_ops[] = {
        { .cmd = OVS_PACKET_CMD_EXECUTE,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+         .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
          .policy = packet_policy,
          .doit = ovs_packet_cmd_execute
        }
@@ -876,7 +872,7 @@ static struct sk_buff *ovs_flow_cmd_alloc_info(const struct sw_flow_actions *act
                return NULL;
 
        len = ovs_flow_cmd_msg_size(acts, sfid, ufid_flags);
-       skb = genlmsg_new_unicast(len, info, GFP_KERNEL);
+       skb = genlmsg_new(len, GFP_KERNEL);
        if (!skb)
                return ERR_PTR(-ENOMEM);
 
@@ -1100,26 +1096,32 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
        struct sw_flow_match match;
        struct sw_flow_id sfid;
        u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
-       int error;
+       int error = 0;
        bool log = !a[OVS_FLOW_ATTR_PROBE];
        bool ufid_present;
 
-       /* Extract key. */
-       error = -EINVAL;
-       if (!a[OVS_FLOW_ATTR_KEY]) {
-               OVS_NLERR(log, "Flow key attribute not present in set flow.");
-               goto error;
-       }
-
        ufid_present = ovs_nla_get_ufid(&sfid, a[OVS_FLOW_ATTR_UFID], log);
-       ovs_match_init(&match, &key, &mask);
-       error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
-                                 a[OVS_FLOW_ATTR_MASK], log);
+       if (a[OVS_FLOW_ATTR_KEY]) {
+               ovs_match_init(&match, &key, &mask);
+               error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
+                                         a[OVS_FLOW_ATTR_MASK], log);
+       } else if (!ufid_present) {
+               OVS_NLERR(log,
+                         "Flow set message rejected, Key attribute missing.");
+               error = -EINVAL;
+       }
        if (error)
                goto error;
 
        /* Validate actions. */
        if (a[OVS_FLOW_ATTR_ACTIONS]) {
+               if (!a[OVS_FLOW_ATTR_KEY]) {
+                       OVS_NLERR(log,
+                                 "Flow key attribute not present in set flow.");
+                       error = -EINVAL;
+                       goto error;
+               }
+
                acts = get_flow_actions(net, a[OVS_FLOW_ATTR_ACTIONS], &key,
                                        &mask, log);
                if (IS_ERR(acts)) {
@@ -1391,12 +1393,12 @@ static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = {
 
 static const struct genl_ops dp_flow_genl_ops[] = {
        { .cmd = OVS_FLOW_CMD_NEW,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+         .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
          .policy = flow_policy,
          .doit = ovs_flow_cmd_new
        },
        { .cmd = OVS_FLOW_CMD_DEL,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+         .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
          .policy = flow_policy,
          .doit = ovs_flow_cmd_del
        },
@@ -1407,7 +1409,7 @@ static const struct genl_ops dp_flow_genl_ops[] = {
          .dumpit = ovs_flow_cmd_dump
        },
        { .cmd = OVS_FLOW_CMD_SET,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+         .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
          .policy = flow_policy,
          .doit = ovs_flow_cmd_set,
        },
@@ -1481,9 +1483,9 @@ error:
        return -EMSGSIZE;
 }
 
-static struct sk_buff *ovs_dp_cmd_alloc_info(struct genl_info *info)
+static struct sk_buff *ovs_dp_cmd_alloc_info(void)
 {
-       return genlmsg_new_unicast(ovs_dp_cmd_msg_size(), info, GFP_KERNEL);
+       return genlmsg_new(ovs_dp_cmd_msg_size(), GFP_KERNEL);
 }
 
 /* Called with rcu_read_lock or ovs_mutex. */
@@ -1536,7 +1538,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
        if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID])
                goto err;
 
-       reply = ovs_dp_cmd_alloc_info(info);
+       reply = ovs_dp_cmd_alloc_info();
        if (!reply)
                return -ENOMEM;
 
@@ -1657,7 +1659,7 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        int err;
 
-       reply = ovs_dp_cmd_alloc_info(info);
+       reply = ovs_dp_cmd_alloc_info();
        if (!reply)
                return -ENOMEM;
 
@@ -1690,7 +1692,7 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        int err;
 
-       reply = ovs_dp_cmd_alloc_info(info);
+       reply = ovs_dp_cmd_alloc_info();
        if (!reply)
                return -ENOMEM;
 
@@ -1723,7 +1725,7 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        int err;
 
-       reply = ovs_dp_cmd_alloc_info(info);
+       reply = ovs_dp_cmd_alloc_info();
        if (!reply)
                return -ENOMEM;
 
@@ -1777,12 +1779,12 @@ static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = {
 
 static const struct genl_ops dp_datapath_genl_ops[] = {
        { .cmd = OVS_DP_CMD_NEW,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+         .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
          .policy = datapath_policy,
          .doit = ovs_dp_cmd_new
        },
        { .cmd = OVS_DP_CMD_DEL,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+         .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
          .policy = datapath_policy,
          .doit = ovs_dp_cmd_del
        },
@@ -1793,7 +1795,7 @@ static const struct genl_ops dp_datapath_genl_ops[] = {
          .dumpit = ovs_dp_cmd_dump
        },
        { .cmd = OVS_DP_CMD_SET,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+         .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
          .policy = datapath_policy,
          .doit = ovs_dp_cmd_set,
        },
@@ -1912,6 +1914,29 @@ static struct vport *lookup_vport(struct net *net,
                return ERR_PTR(-EINVAL);
 }
 
+/* Called with ovs_mutex */
+static void update_headroom(struct datapath *dp)
+{
+       unsigned dev_headroom, max_headroom = 0;
+       struct net_device *dev;
+       struct vport *vport;
+       int i;
+
+       for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
+               hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) {
+                       dev = vport->dev;
+                       dev_headroom = netdev_get_fwd_headroom(dev);
+                       if (dev_headroom > max_headroom)
+                               max_headroom = dev_headroom;
+               }
+       }
+
+       dp->max_headroom = max_headroom;
+       for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++)
+               hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node)
+                       netdev_set_rx_headroom(vport->dev, max_headroom);
+}
+
 static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr **a = info->attrs;
@@ -1977,6 +2002,12 @@ restart:
 
        err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
                                      info->snd_seq, 0, OVS_VPORT_CMD_NEW);
+
+       if (netdev_get_fwd_headroom(vport->dev) > dp->max_headroom)
+               update_headroom(dp);
+       else
+               netdev_set_rx_headroom(vport->dev, dp->max_headroom);
+
        BUG_ON(err < 0);
        ovs_unlock();
 
@@ -2043,8 +2074,10 @@ exit_unlock_free:
 
 static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
 {
+       bool must_update_headroom = false;
        struct nlattr **a = info->attrs;
        struct sk_buff *reply;
+       struct datapath *dp;
        struct vport *vport;
        int err;
 
@@ -2066,7 +2099,16 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
        err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
                                      info->snd_seq, 0, OVS_VPORT_CMD_DEL);
        BUG_ON(err < 0);
+
+       /* the vport deletion may trigger dp headroom update */
+       dp = vport->dp;
+       if (netdev_get_fwd_headroom(vport->dev) == dp->max_headroom)
+               must_update_headroom = true;
+       netdev_reset_rx_headroom(vport->dev);
        ovs_dp_detach_port(vport);
+
+       if (must_update_headroom)
+               update_headroom(dp);
        ovs_unlock();
 
        ovs_notify(&dp_vport_genl_family, reply, info);
@@ -2158,12 +2200,12 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
 
 static const struct genl_ops dp_vport_genl_ops[] = {
        { .cmd = OVS_VPORT_CMD_NEW,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+         .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
          .policy = vport_policy,
          .doit = ovs_vport_cmd_new
        },
        { .cmd = OVS_VPORT_CMD_DEL,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+         .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
          .policy = vport_policy,
          .doit = ovs_vport_cmd_del
        },
@@ -2174,7 +2216,7 @@ static const struct genl_ops dp_vport_genl_ops[] = {
          .dumpit = ovs_vport_cmd_dump
        },
        { .cmd = OVS_VPORT_CMD_SET,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+         .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
          .policy = vport_policy,
          .doit = ovs_vport_cmd_set,
        },