datapath: genlmsg_new_unicast to genlmsg_new
[cascardo/ovs.git] / datapath / datapath.c
index 56bb86d..6e0d911 100644 (file)
@@ -436,12 +436,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 = {
-#ifdef HAVE_GENLMSG_NEW_UNICAST
-               .dst_sk = ovs_dp_get_net(dp)->genl_sock,
-#endif
-               .snd_portid = upcall_info->portid,
-       };
        size_t len;
        unsigned int hlen;
        int err, dp_ifindex;
@@ -482,7 +476,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
                hlen = skb->len;
 
        len = upcall_msg_size(upcall_info, hlen - cutlen);
-       user_skb = genlmsg_new_unicast(len, &info, GFP_ATOMIC);
+       user_skb = genlmsg_new(len, GFP_ATOMIC);
        if (!user_skb) {
                err = -ENOMEM;
                goto out;
@@ -771,9 +765,9 @@ static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts,
                len += nla_total_size(acts->orig_len);
 
        return len
-               + nla_total_size(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */
+               + nla_total_size_64bit(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */
                + nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */
-               + nla_total_size(8); /* OVS_FLOW_ATTR_USED */
+               + nla_total_size_64bit(8); /* OVS_FLOW_ATTR_USED */
 }
 
 /* Called with ovs_mutex or RCU read lock. */
@@ -787,11 +781,14 @@ static int ovs_flow_cmd_fill_stats(const struct sw_flow *flow,
        ovs_flow_stats_get(flow, &stats, &used, &tcp_flags);
 
        if (used &&
-           nla_put_u64(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used)))
+           nla_put_u64_64bit(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used),
+                             OVS_FLOW_ATTR_PAD))
                return -EMSGSIZE;
 
        if (stats.n_packets &&
-           nla_put(skb, OVS_FLOW_ATTR_STATS, sizeof(struct ovs_flow_stats), &stats))
+           nla_put_64bit(skb, OVS_FLOW_ATTR_STATS,
+                         sizeof(struct ovs_flow_stats), &stats,
+                         OVS_FLOW_ATTR_PAD))
                return -EMSGSIZE;
 
        if ((u8)ntohs(tcp_flags) &&
@@ -906,7 +903,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);
 
@@ -1130,26 +1127,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)) {
@@ -1464,8 +1467,8 @@ static size_t ovs_dp_cmd_msg_size(void)
        size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header));
 
        msgsize += nla_total_size(IFNAMSIZ);
-       msgsize += nla_total_size(sizeof(struct ovs_dp_stats));
-       msgsize += nla_total_size(sizeof(struct ovs_dp_megaflow_stats));
+       msgsize += nla_total_size_64bit(sizeof(struct ovs_dp_stats));
+       msgsize += nla_total_size_64bit(sizeof(struct ovs_dp_megaflow_stats));
        msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_USER_FEATURES */
 
        return msgsize;
@@ -1492,13 +1495,13 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb,
                goto nla_put_failure;
 
        get_dp_stats(dp, &dp_stats, &dp_megaflow_stats);
-       if (nla_put(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats),
-                       &dp_stats))
+       if (nla_put_64bit(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats),
+                         &dp_stats, OVS_DP_ATTR_PAD))
                goto nla_put_failure;
 
-       if (nla_put(skb, OVS_DP_ATTR_MEGAFLOW_STATS,
-                       sizeof(struct ovs_dp_megaflow_stats),
-                       &dp_megaflow_stats))
+       if (nla_put_64bit(skb, OVS_DP_ATTR_MEGAFLOW_STATS,
+                         sizeof(struct ovs_dp_megaflow_stats),
+                         &dp_megaflow_stats, OVS_DP_ATTR_PAD))
                goto nla_put_failure;
 
        if (nla_put_u32(skb, OVS_DP_ATTR_USER_FEATURES, dp->user_features))
@@ -1513,9 +1516,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. */
@@ -1568,7 +1571,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;
 
@@ -1689,7 +1692,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;
 
@@ -1721,7 +1724,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;
 
@@ -1754,7 +1757,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;
 
@@ -1866,8 +1869,9 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
                goto nla_put_failure;
 
        ovs_vport_get_stats(vport, &vport_stats);
-       if (nla_put(skb, OVS_VPORT_ATTR_STATS, sizeof(struct ovs_vport_stats),
-                   &vport_stats))
+       if (nla_put_64bit(skb, OVS_VPORT_ATTR_STATS,
+                         sizeof(struct ovs_vport_stats), &vport_stats,
+                         OVS_VPORT_ATTR_PAD))
                goto nla_put_failure;
 
        if (ovs_vport_get_upcall_portids(vport, skb))
@@ -1943,6 +1947,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;
@@ -2009,6 +2036,12 @@ restart:
        err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
                                      info->snd_seq, 0, OVS_VPORT_CMD_NEW);
        BUG_ON(err < 0);
+
+       if (netdev_get_fwd_headroom(vport->dev) > dp->max_headroom)
+               update_headroom(dp);
+       else
+               netdev_set_rx_headroom(vport->dev, dp->max_headroom);
+
        ovs_unlock();
 
        ovs_notify(&dp_vport_genl_family, &ovs_dp_vport_multicast_group, reply, info);
@@ -2073,8 +2106,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;
 
@@ -2096,7 +2131,17 @@ 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, &ovs_dp_vport_multicast_group, reply, info);