[RFC V3 PATCH 02/26] net/netpolicy: init NET policy
From: kan . liang
Date: Mon Sep 12 2016 - 11:04:34 EST
From: Kan Liang <kan.liang@xxxxxxxxx>
This patch tries to initialize NET policy for all the devices in the
system. However, not all device drivers have NET policy support. For
those drivers who does not have NET policy support, the node will not be
showed in /proc/net/netpolicy/.
The device driver who has NET policy support must implement the
interface ndo_netpolicy_init, which is used to do necessory
initialization and collect information (E.g. supported policies) from
driver.
The user can check /proc/net/netpolicy/ and
/proc/net/netpolicy/$DEV/policy to know the available device and its
supported policy.
np_lock is also introduced to protect the state of NET policy.
Device hotplug will be handled later in this series.
Signed-off-by: Kan Liang <kan.liang@xxxxxxxxx>
---
include/linux/netdevice.h | 12 +++++++
include/linux/netpolicy.h | 31 ++++++++++++++++
net/core/netpolicy.c | 91 +++++++++++++++++++++++++++++++++++++++++------
3 files changed, 123 insertions(+), 11 deletions(-)
create mode 100644 include/linux/netpolicy.h
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 435573c..876293d 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -53,6 +53,7 @@
#include <uapi/linux/if_bonding.h>
#include <uapi/linux/pkt_cls.h>
#include <linux/hashtable.h>
+#include <linux/netpolicy.h>
struct netpoll_info;
struct device;
@@ -1121,6 +1122,9 @@ struct netdev_xdp {
* int (*ndo_xdp)(struct net_device *dev, struct netdev_xdp *xdp);
* This function is used to set or query state related to XDP on the
* netdevice. See definition of enum xdp_netdev_command for details.
+ * int(*ndo_netpolicy_init)(struct net_device *dev,
+ * struct netpolicy_info *info);
+ * This function is used to init and get supported policy.
*
*/
struct net_device_ops {
@@ -1307,6 +1311,10 @@ struct net_device_ops {
int needed_headroom);
int (*ndo_xdp)(struct net_device *dev,
struct netdev_xdp *xdp);
+#ifdef CONFIG_NETPOLICY
+ int (*ndo_netpolicy_init)(struct net_device *dev,
+ struct netpolicy_info *info);
+#endif /* CONFIG_NETPOLICY */
};
/**
@@ -1619,6 +1627,8 @@ enum netdev_priv_flags {
* switch port.
*
* @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
*
* FIXME: cleanup struct net_device such that network protocol info
* moves out.
@@ -1891,6 +1901,8 @@ struct net_device {
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_dev;
#endif /* CONFIG_PROC_FS */
+ struct netpolicy_info *netpolicy;
+ spinlock_t np_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
new file mode 100644
index 0000000..ca1f131
--- /dev/null
+++ b/include/linux/netpolicy.h
@@ -0,0 +1,31 @@
+/*
+ * netpolicy.h: Net policy support
+ * Copyright (c) 2016, Intel Corporation.
+ * Author: Kan Liang (kan.liang@xxxxxxxxx)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+#ifndef __LINUX_NETPOLICY_H
+#define __LINUX_NETPOLICY_H
+
+enum netpolicy_name {
+ NET_POLICY_NONE = 0,
+ NET_POLICY_MAX,
+};
+
+extern const char *policy_name[];
+
+struct netpolicy_info {
+ enum netpolicy_name cur_policy;
+ unsigned long avail_policy[BITS_TO_LONGS(NET_POLICY_MAX)];
+};
+
+#endif /*__LINUX_NETPOLICY_H*/
diff --git a/net/core/netpolicy.c b/net/core/netpolicy.c
index faabfe7..c1c0dc0 100644
--- a/net/core/netpolicy.c
+++ b/net/core/netpolicy.c
@@ -34,14 +34,31 @@
#include <linux/uaccess.h>
#include <linux/netdevice.h>
#include <net/net_namespace.h>
+#include <net/rtnetlink.h>
+const char *policy_name[NET_POLICY_MAX] = {
+ "NONE"
+};
#ifdef CONFIG_PROC_FS
static int net_policy_proc_show(struct seq_file *m, void *v)
{
struct net_device *dev = (struct net_device *)m->private;
-
- seq_printf(m, "%s doesn't support net policy manager\n", dev->name);
+ int i;
+
+ if (WARN_ON(!dev->netpolicy))
+ return -EINVAL;
+
+ if (dev->netpolicy->cur_policy == NET_POLICY_NONE) {
+ seq_printf(m, "%s: There is no policy applied\n", dev->name);
+ seq_printf(m, "%s: The available policy include:", dev->name);
+ for_each_set_bit(i, dev->netpolicy->avail_policy, NET_POLICY_MAX)
+ seq_printf(m, " %s", policy_name[i]);
+ seq_printf(m, "\n");
+ } else {
+ seq_printf(m, "%s: POLICY %s is running on the system\n",
+ dev->name, policy_name[dev->netpolicy->cur_policy]);
+ }
return 0;
}
@@ -73,33 +90,85 @@ static int netpolicy_proc_dev_init(struct net *net, struct net_device *dev)
}
return 0;
}
+#endif /* CONFIG_PROC_FS */
+
+int init_netpolicy(struct net_device *dev)
+{
+ int ret;
+
+ spin_lock(&dev->np_lock);
+ ret = 0;
+
+ if (!dev->netdev_ops->ndo_netpolicy_init) {
+ ret = -ENOTSUPP;
+ goto unlock;
+ }
+
+ if (dev->netpolicy)
+ goto unlock;
+
+ dev->netpolicy = kzalloc(sizeof(*dev->netpolicy), GFP_ATOMIC);
+ if (!dev->netpolicy) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ ret = dev->netdev_ops->ndo_netpolicy_init(dev, dev->netpolicy);
+ if (ret) {
+ kfree(dev->netpolicy);
+ dev->netpolicy = NULL;
+ }
+
+unlock:
+ spin_unlock(&dev->np_lock);
+ return ret;
+}
+
+void uninit_netpolicy(struct net_device *dev)
+{
+ spin_lock(&dev->np_lock);
+ if (dev->netpolicy) {
+ kfree(dev->netpolicy);
+ dev->netpolicy = NULL;
+ }
+ spin_unlock(&dev->np_lock);
+}
static int __net_init netpolicy_net_init(struct net *net)
{
struct net_device *dev, *aux;
+#ifdef CONFIG_PROC_FS
net->proc_netpolicy = proc_net_mkdir(net, "netpolicy",
net->proc_net);
if (!net->proc_netpolicy)
return -ENOMEM;
+#endif /* CONFIG_PROC_FS */
+ rtnl_lock();
for_each_netdev_safe(net, dev, aux) {
- netpolicy_proc_dev_init(net, dev);
+ if (!init_netpolicy(dev)) {
+#ifdef CONFIG_PROC_FS
+ if (netpolicy_proc_dev_init(net, dev))
+ uninit_netpolicy(dev);
+ else
+#endif /* CONFIG_PROC_FS */
+ pr_info("NETPOLICY: Init net policy for %s\n", dev->name);
+ }
}
+ rtnl_unlock();
return 0;
}
-#else /* CONFIG_PROC_FS */
-
-static int __net_init netpolicy_net_init(struct net *net)
-{
- return 0;
-}
-#endif /* CONFIG_PROC_FS */
-
static void __net_exit netpolicy_net_exit(struct net *net)
{
+ struct net_device *dev, *aux;
+
+ rtnl_lock();
+ for_each_netdev_safe(net, dev, aux)
+ uninit_netpolicy(dev);
+ rtnl_unlock();
#ifdef CONFIG_PROC_FS
remove_proc_subtree("netpolicy", net->proc_net);
#endif /* CONFIG_PROC_FS */
--
2.5.5