From: kan.liang@intel.com
To: davem@davemloft.net, linux-kernel@vger.kernel.org,
netdev@vger.kernel.org
Cc: jeffrey.t.kirsher@intel.com, mingo@redhat.com,
peterz@infradead.org, kuznet@ms2.inr.ac.ru, jmorris@namei.org,
yoshfuji@linux-ipv6.org, kaber@trash.net,
akpm@linux-foundation.org, keescook@chromium.org,
viro@zeniv.linux.org.uk, gorcunov@openvz.org,
john.stultz@linaro.org, aduyck@mirantis.com, ben@decadent.org.uk,
decot@googlers.com, fw@strlen.de, alexander.duyck@gmail.com,
daniel@iogearbox.net, tom@herbertland.com, rdunlap@infradead.org,
xiyou.wangcong@gmail.com, hannes@stressinduktion.org,
stephen@networkplumber.org, alexei.starovoitov@gmail.com,
jesse.brandeburg@intel.com, andi@firstfloor.org,
Kan Liang <kan.liang@intel.com>
Subject: [RFC V3 PATCH 08/26] net/netpolicy: introduce NET policy object
Date: Mon, 12 Sep 2016 07:55:41 -0700 [thread overview]
Message-ID: <1473692159-4017-9-git-send-email-kan.liang@intel.com> (raw)
In-Reply-To: <1473692159-4017-1-git-send-email-kan.liang@intel.com>
From: Kan Liang <kan.liang@intel.com>
This patch introduces the concept of NET policy object and policy object
list.
The NET policy object is the instance of CPU/queue mapping. The object
can be shared between different tasks/sockets. So besides CPU and queue
information, the object also maintains a reference counter.
Each policy will have a dedicated object list. If the policy is set as
device policy, all objects will be inserted into the related policy
object list. The user will search and pickup the available objects from
the list later.
The network performance for objects could be different because of the
queue and CPU topology. To generate a proper object list, dev location,
HT and CPU topology have to be considered. The high performance objects
are in the front of the list.
The object lists will be regenerated if sys mapping changes or device
net policy changes.
Lock np_ob_list_lock is used to protect the object list.
Signed-off-by: Kan Liang <kan.liang@intel.com>
---
include/linux/netdevice.h | 2 +
include/linux/netpolicy.h | 15 +++
net/core/netpolicy.c | 238 +++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 254 insertions(+), 1 deletion(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index e1b5685..8fcea13 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1634,6 +1634,7 @@ enum netdev_priv_flags {
* @proc_dev: device node in proc to configure device net policy
* @netpolicy: NET policy related information of net device
* @np_lock: protect the state of NET policy
+ * @np_ob_list_lock: protect the net policy object list
*
* FIXME: cleanup struct net_device such that network protocol info
* moves out.
@@ -1908,6 +1909,7 @@ struct net_device {
#endif /* CONFIG_PROC_FS */
struct netpolicy_info *netpolicy;
spinlock_t np_lock;
+ spinlock_t np_ob_list_lock;
#endif /* CONFIG_NETPOLICY */
};
#define to_net_dev(d) container_of(d, struct net_device, dev)
diff --git a/include/linux/netpolicy.h b/include/linux/netpolicy.h
index bfab7b8..1c89dda 100644
--- a/include/linux/netpolicy.h
+++ b/include/linux/netpolicy.h
@@ -21,6 +21,12 @@ enum netpolicy_name {
NET_POLICY_MAX,
};
+enum netpolicy_traffic {
+ NETPOLICY_RX = 0,
+ NETPOLICY_TX,
+ NETPOLICY_RXTX,
+};
+
extern const char *policy_name[];
struct netpolicy_dev_info {
@@ -46,12 +52,21 @@ struct netpolicy_sys_info {
struct netpolicy_sys_map *tx;
};
+struct netpolicy_object {
+ struct list_head list;
+ u32 cpu;
+ u32 queue;
+ atomic_t refcnt;
+};
+
struct netpolicy_info {
enum netpolicy_name cur_policy;
unsigned long avail_policy[BITS_TO_LONGS(NET_POLICY_MAX)];
bool irq_affinity;
/* cpu and queue mapping information */
struct netpolicy_sys_info sys_info;
+ /* List of policy objects 0 rx 1 tx */
+ struct list_head obj_list[NETPOLICY_RXTX][NET_POLICY_MAX];
};
#endif /*__LINUX_NETPOLICY_H*/
diff --git a/net/core/netpolicy.c b/net/core/netpolicy.c
index a6e240f..b330cf3 100644
--- a/net/core/netpolicy.c
+++ b/net/core/netpolicy.c
@@ -36,6 +36,7 @@
#include <linux/netdevice.h>
#include <net/net_namespace.h>
#include <net/rtnetlink.h>
+#include <linux/sort.h>
static int netpolicy_get_dev_info(struct net_device *dev,
struct netpolicy_dev_info *d_info)
@@ -162,11 +163,31 @@ static void netpolicy_set_affinity(struct net_device *dev)
}
}
+static void netpolicy_free_obj_list(struct net_device *dev)
+{
+ int i, j;
+ struct netpolicy_object *obj, *tmp;
+
+ spin_lock(&dev->np_ob_list_lock);
+ for (i = 0; i < NETPOLICY_RXTX; i++) {
+ for (j = NET_POLICY_NONE; j < NET_POLICY_MAX; j++) {
+ if (list_empty(&dev->netpolicy->obj_list[i][j]))
+ continue;
+ list_for_each_entry_safe(obj, tmp, &dev->netpolicy->obj_list[i][j], list) {
+ list_del(&obj->list);
+ kfree(obj);
+ }
+ }
+ }
+ spin_unlock(&dev->np_ob_list_lock);
+}
+
static int netpolicy_disable(struct net_device *dev)
{
if (dev->netpolicy->irq_affinity)
netpolicy_clear_affinity(dev);
netpolicy_free_sys_map(dev);
+ netpolicy_free_obj_list(dev);
return 0;
}
@@ -206,6 +227,213 @@ static int netpolicy_enable(struct net_device *dev)
const char *policy_name[NET_POLICY_MAX] = {
"NONE"
};
+
+static u32 cpu_to_queue(struct net_device *dev,
+ u32 cpu, bool is_rx)
+{
+ struct netpolicy_sys_info *s_info = &dev->netpolicy->sys_info;
+ int i;
+
+ if (is_rx) {
+ for (i = 0; i < s_info->avail_rx_num; i++) {
+ if (s_info->rx[i].cpu == cpu)
+ return s_info->rx[i].queue;
+ }
+ } else {
+ for (i = 0; i < s_info->avail_tx_num; i++) {
+ if (s_info->tx[i].cpu == cpu)
+ return s_info->tx[i].queue;
+ }
+ }
+
+ return ~0;
+}
+
+static int netpolicy_add_obj(struct net_device *dev,
+ u32 cpu, bool is_rx,
+ enum netpolicy_name policy)
+{
+ struct netpolicy_object *obj;
+ int dir = is_rx ? NETPOLICY_RX : NETPOLICY_TX;
+
+ obj = kzalloc(sizeof(*obj), GFP_ATOMIC);
+ if (!obj)
+ return -ENOMEM;
+ obj->cpu = cpu;
+ obj->queue = cpu_to_queue(dev, cpu, is_rx);
+ list_add_tail(&obj->list, &dev->netpolicy->obj_list[dir][policy]);
+
+ return 0;
+}
+
+struct sort_node {
+ int node;
+ int distance;
+};
+
+static inline int node_distance_cmp(const void *a, const void *b)
+{
+ const struct sort_node *_a = a;
+ const struct sort_node *_b = b;
+
+ return _a->distance - _b->distance;
+}
+
+static int _netpolicy_gen_obj_list(struct net_device *dev, bool is_rx,
+ enum netpolicy_name policy,
+ struct sort_node *nodes, int num_node,
+ struct cpumask *node_avail_cpumask)
+{
+ cpumask_var_t node_tmp_cpumask, sibling_tmp_cpumask;
+ struct cpumask *node_assigned_cpumask;
+ int i, ret = -ENOMEM;
+ u32 cpu;
+
+ if (!alloc_cpumask_var(&node_tmp_cpumask, GFP_ATOMIC))
+ return ret;
+ if (!alloc_cpumask_var(&sibling_tmp_cpumask, GFP_ATOMIC))
+ goto alloc_fail1;
+
+ node_assigned_cpumask = kcalloc(num_node, sizeof(struct cpumask), GFP_ATOMIC);
+ if (!node_assigned_cpumask)
+ goto alloc_fail2;
+
+ /* Don't share physical core */
+ for (i = 0; i < num_node; i++) {
+ if (cpumask_weight(&node_avail_cpumask[nodes[i].node]) == 0)
+ continue;
+ spin_lock(&dev->np_ob_list_lock);
+ cpumask_copy(node_tmp_cpumask, &node_avail_cpumask[nodes[i].node]);
+ while (cpumask_weight(node_tmp_cpumask)) {
+ cpu = cpumask_first(node_tmp_cpumask);
+
+ /* push to obj list */
+ ret = netpolicy_add_obj(dev, cpu, is_rx, policy);
+ if (ret) {
+ spin_unlock(&dev->np_ob_list_lock);
+ goto err;
+ }
+
+ cpumask_set_cpu(cpu, &node_assigned_cpumask[nodes[i].node]);
+ cpumask_and(sibling_tmp_cpumask, node_tmp_cpumask, topology_sibling_cpumask(cpu));
+ cpumask_xor(node_tmp_cpumask, node_tmp_cpumask, sibling_tmp_cpumask);
+ }
+ spin_unlock(&dev->np_ob_list_lock);
+ }
+
+ for (i = 0; i < num_node; i++) {
+ cpumask_xor(node_tmp_cpumask, &node_avail_cpumask[nodes[i].node], &node_assigned_cpumask[nodes[i].node]);
+ if (cpumask_weight(node_tmp_cpumask) == 0)
+ continue;
+ spin_lock(&dev->np_ob_list_lock);
+ for_each_cpu(cpu, node_tmp_cpumask) {
+ /* push to obj list */
+ ret = netpolicy_add_obj(dev, cpu, is_rx, policy);
+ if (ret) {
+ spin_unlock(&dev->np_ob_list_lock);
+ goto err;
+ }
+ cpumask_set_cpu(cpu, &node_assigned_cpumask[nodes[i].node]);
+ }
+ spin_unlock(&dev->np_ob_list_lock);
+ }
+
+err:
+ kfree(node_assigned_cpumask);
+alloc_fail2:
+ free_cpumask_var(sibling_tmp_cpumask);
+alloc_fail1:
+ free_cpumask_var(node_tmp_cpumask);
+
+ return ret;
+}
+
+static int netpolicy_gen_obj_list(struct net_device *dev,
+ enum netpolicy_name policy)
+{
+ struct netpolicy_sys_info *s_info = &dev->netpolicy->sys_info;
+ struct cpumask *node_avail_cpumask;
+ struct sort_node *nodes;
+ int i, ret, node = 0;
+ int num_nodes = 1;
+ u32 cpu;
+#ifdef CONFIG_NUMA
+ int dev_node = 0;
+ int val;
+#endif
+ /* The network performance for objects could be different
+ * because of the queue and cpu topology.
+ * The objects will be ordered accordingly,
+ * and put high performance object in the front.
+ *
+ * The priority rules as below,
+ * - The local object. (Local means cpu and queue are in the same node.)
+ * - The cpu in the object is the only logical core in physical core.
+ * The sibiling core's object has not been added in the object list yet.
+ * - The rest of objects
+ *
+ * So the order of object list is as below:
+ * 1. Local core + the only logical core
+ * 2. Remote core + the only logical core
+ * 3. Local core + the core's sibling is already in the object list
+ * 4. Remote core + the core's sibling is already in the object list
+ */
+#ifdef CONFIG_NUMA
+ dev_node = dev_to_node(dev->dev.parent);
+ num_nodes = num_online_nodes();
+#endif
+
+ nodes = kcalloc(num_nodes, sizeof(*nodes), GFP_ATOMIC);
+ if (!nodes)
+ return -ENOMEM;
+
+ node_avail_cpumask = kcalloc(num_nodes, sizeof(struct cpumask), GFP_ATOMIC);
+ if (!node_avail_cpumask) {
+ kfree(nodes);
+ return -ENOMEM;
+ }
+
+#ifdef CONFIG_NUMA
+ /* order the node from near to far */
+ for_each_node_mask(i, node_online_map) {
+ val = node_distance(dev_node, i);
+ nodes[node].node = i;
+ nodes[node].distance = val;
+ node++;
+ }
+ sort(nodes, num_nodes, sizeof(*nodes),
+ node_distance_cmp, NULL);
+#else
+ nodes[0].node = 0;
+#endif
+
+ for (i = 0; i < s_info->avail_rx_num; i++) {
+ cpu = s_info->rx[i].cpu;
+ cpumask_set_cpu(cpu, &node_avail_cpumask[cpu_to_node(cpu)]);
+ }
+ ret = _netpolicy_gen_obj_list(dev, true, policy, nodes,
+ node, node_avail_cpumask);
+ if (ret)
+ goto err;
+
+ for (i = 0; i < node; i++)
+ cpumask_clear(&node_avail_cpumask[nodes[i].node]);
+
+ for (i = 0; i < s_info->avail_tx_num; i++) {
+ cpu = s_info->tx[i].cpu;
+ cpumask_set_cpu(cpu, &node_avail_cpumask[cpu_to_node(cpu)]);
+ }
+ ret = _netpolicy_gen_obj_list(dev, false, policy, nodes,
+ node, node_avail_cpumask);
+ if (ret)
+ goto err;
+
+err:
+ kfree(nodes);
+ kfree(node_avail_cpumask);
+ return ret;
+}
+
#ifdef CONFIG_PROC_FS
static int net_policy_proc_show(struct seq_file *m, void *v)
@@ -261,7 +489,7 @@ static int netpolicy_proc_dev_init(struct net *net, struct net_device *dev)
int init_netpolicy(struct net_device *dev)
{
- int ret;
+ int ret, i, j;
spin_lock(&dev->np_lock);
ret = 0;
@@ -284,7 +512,15 @@ int init_netpolicy(struct net_device *dev)
if (ret) {
kfree(dev->netpolicy);
dev->netpolicy = NULL;
+ goto unlock;
+ }
+
+ spin_lock(&dev->np_ob_list_lock);
+ for (i = 0; i < NETPOLICY_RXTX; i++) {
+ for (j = NET_POLICY_NONE; j < NET_POLICY_MAX; j++)
+ INIT_LIST_HEAD(&dev->netpolicy->obj_list[i][j]);
}
+ spin_unlock(&dev->np_ob_list_lock);
unlock:
spin_unlock(&dev->np_lock);
--
2.5.5
next prev parent reply other threads:[~2016-09-12 14:55 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-09-12 14:55 [RFC V3 PATCH 00/26] Kernel NET policy kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 01/26] net: introduce " kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 02/26] net/netpolicy: init " kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 03/26] net/netpolicy: get device queue irq information kan.liang
2016-09-12 16:48 ` Sergei Shtylyov
2016-09-13 12:23 ` Liang, Kan
2016-09-13 13:14 ` Alexander Duyck
2016-09-13 13:22 ` Liang, Kan
2016-09-12 14:55 ` [RFC V3 PATCH 04/26] net/netpolicy: get CPU information kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 05/26] net/netpolicy: create CPU and queue mapping kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 06/26] net/netpolicy: set and remove IRQ affinity kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 07/26] net/netpolicy: enable and disable NET policy kan.liang
2016-09-12 14:55 ` kan.liang [this message]
2016-09-12 14:55 ` [RFC V3 PATCH 09/26] net/netpolicy: set NET policy by policy name kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 10/26] net/netpolicy: add three new NET policies kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 11/26] net/netpolicy: add MIX policy kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 12/26] net/netpolicy: NET device hotplug kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 13/26] net/netpolicy: support CPU hotplug kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 14/26] net/netpolicy: handle channel changes kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 15/26] net/netpolicy: implement netpolicy register kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 16/26] net/netpolicy: introduce per socket netpolicy kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 17/26] net/netpolicy: introduce netpolicy_pick_queue kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 18/26] net/netpolicy: set tx queues according to policy kan.liang
2016-09-12 20:23 ` Tom Herbert
2016-09-13 12:22 ` Liang, Kan
2016-09-12 14:55 ` [RFC V3 PATCH 19/26] net/netpolicy: tc bpf extension to pick Tx queue kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 20/26] net/netpolicy: set Rx queues according to policy kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 21/26] net/netpolicy: introduce per task net policy kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 22/26] net/netpolicy: set per task policy by proc kan.liang
2016-09-12 17:01 ` Sergei Shtylyov
2016-09-12 14:55 ` [RFC V3 PATCH 23/26] net/netpolicy: fast path for finding the queues kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 24/26] net/netpolicy: optimize for queue pair kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 25/26] net/netpolicy: limit the total record number kan.liang
2016-09-12 14:55 ` [RFC V3 PATCH 26/26] Documentation/networking: Document NET policy kan.liang
2016-09-12 15:38 ` [RFC V3 PATCH 00/26] Kernel " Florian Westphal
2016-09-12 17:21 ` Cong Wang
2016-09-12 15:52 ` Eric Dumazet
2016-09-19 20:39 ` Stephen Hemminger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1473692159-4017-9-git-send-email-kan.liang@intel.com \
--to=kan.liang@intel.com \
--cc=aduyck@mirantis.com \
--cc=akpm@linux-foundation.org \
--cc=alexander.duyck@gmail.com \
--cc=alexei.starovoitov@gmail.com \
--cc=andi@firstfloor.org \
--cc=ben@decadent.org.uk \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=decot@googlers.com \
--cc=fw@strlen.de \
--cc=gorcunov@openvz.org \
--cc=hannes@stressinduktion.org \
--cc=jeffrey.t.kirsher@intel.com \
--cc=jesse.brandeburg@intel.com \
--cc=jmorris@namei.org \
--cc=john.stultz@linaro.org \
--cc=kaber@trash.net \
--cc=keescook@chromium.org \
--cc=kuznet@ms2.inr.ac.ru \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=peterz@infradead.org \
--cc=rdunlap@infradead.org \
--cc=stephen@networkplumber.org \
--cc=tom@herbertland.com \
--cc=viro@zeniv.linux.org.uk \
--cc=xiyou.wangcong@gmail.com \
--cc=yoshfuji@linux-ipv6.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).