[Devel,6/6] proc connector: switch logic on per-net basis

Submitted by Stanislav Kinsburskiy on Aug. 15, 2017, 12:42 p.m.

Details

Message ID 20170815124219.22445.84933.stgit@localhost.localdomain
State New
Series "proc connector: containerize on per-net basis"
Headers show

Commit Message

Stanislav Kinsburskiy Aug. 15, 2017, 12:42 p.m.
This patch enables per-net containerization for proc connector.

Note: check for cn_net_id when accessing listeners is required, because proc
connector helpers are called from the early beginning, i.e. before per-net
operations were initialized.

https://jira.sw.ru/browse/PSBM-60227

Signed-off-by: Stanislav Kinsburskiy <skinsbursky@virtuozzo.com>
---
 drivers/connector/cn_proc.c   |   49 ++++++++++++++++------------------------
 drivers/connector/connector.c |   50 +++++++----------------------------------
 2 files changed, 28 insertions(+), 71 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index 7117c4d..c5bd47b 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -52,33 +52,41 @@  static inline struct cn_msg *buffer_to_cn_msg(__u8 *buffer)
 	return (struct cn_msg *)(buffer + 4);
 }
 
-static atomic_t proc_event_num_listeners = ATOMIC_INIT(0);
 static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC };
 
-/* proc_event_counts is used as the sequence number of the netlink message */
-static DEFINE_PER_CPU(__u32, proc_event_counts) = { 0 };
-
 static inline void get_seq(struct net *net, __u32 *ts, int *cpu)
 {
+	struct cn_net *cnn = net_generic(net, cn_net_id);
+
 	preempt_disable();
-	*ts = __this_cpu_inc_return(proc_event_counts) - 1;
+	*ts = __this_cpu_inc_return(*cnn->proc_event_counts) - 1;
 	*cpu = smp_processor_id();
 	preempt_enable();
 }
 
 static int get_listeners(struct net *net)
 {
-	return atomic_read(&proc_event_num_listeners);
+	if (cn_net_id) {
+		struct cn_net *cnn = net_generic(net, cn_net_id);
+		return atomic_read(&cnn->proc_event_num_listeners);
+	}
+	return 0;
 }
 
 static void inc_listeners(struct net *net)
 {
-	atomic_inc(&proc_event_num_listeners);
+	if (cn_net_id) {
+		struct cn_net *cnn = net_generic(net, cn_net_id);
+		atomic_inc(&cnn->proc_event_num_listeners);
+	}
 }
 
 static void dec_listeners(struct net *net)
 {
-	atomic_dec(&proc_event_num_listeners);
+	if (cn_net_id) {
+		struct cn_net *cnn = net_generic(net, cn_net_id);
+		atomic_dec(&cnn->proc_event_num_listeners);
+	}
 }
 
 static struct net *task_net(struct task_struct *task)
@@ -397,12 +405,12 @@  static void cn_proc_mcast_ctl(struct cn_msg *msg,
 	 * and user namespaces so ignore requestors from
 	 * other namespaces.
 	 */
-	if ((current_user_ns() != &init_user_ns) ||
-	    (task_active_pid_ns(current) != &init_pid_ns))
+	if (!current_user_ns_initial() ||
+	    (task_active_pid_ns(current) != get_exec_env()->ve_ns->pid_ns))
 		return;
 
 	/* Can only change if privileged. */
-	if (!__netlink_ns_capable(nsp, &init_user_ns, CAP_NET_ADMIN)) {
+	if (!__netlink_ns_capable(nsp, ve_init_user_ns(), CAP_NET_ADMIN)) {
 		err = EPERM;
 		goto out;
 	}
@@ -456,22 +464,3 @@  void __net_exit cn_proc_exit_net(struct net *net)
 
 	free_percpu(cnn->proc_event_counts);
 }
-
-/*
- * cn_proc_init - initialization entry point
- *
- * Adds the connector callback to the connector driver.
- */
-static int __init cn_proc_init(void)
-{
-	int err = cn_add_callback(&cn_proc_event_id,
-				  "cn_proc",
-				  &cn_proc_mcast_ctl);
-	if (err) {
-		pr_warn("cn_proc failed to register\n");
-		return err;
-	}
-	return 0;
-}
-
-module_init(cn_proc_init);
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index e098d6f..9b2c537d 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -40,10 +40,6 @@  MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
 MODULE_DESCRIPTION("Generic userspace <-> kernelspace connector.");
 MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_CONNECTOR);
 
-static struct cn_dev cdev;
-
-static int cn_already_initialized;
-
 /*
  * msg->seq and msg->ack are used to determine message genealogy.
  * When someone sends message it puts there locally unique sequence
@@ -68,7 +64,10 @@  static int cn_already_initialized;
 
 static struct cn_dev *get_cdev(void)
 {
-	return &cdev;
+	struct net *net = get_exec_env()->ve_netns;
+	struct cn_net *cnn = net_generic(net, cn_net_id);
+
+	return cnn->cdev;
 }
 
 int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
@@ -189,7 +188,9 @@  static void cn_rx_skb(struct sk_buff *__skb)
 
 static int cn_initialized(struct net *net)
 {
-	return cn_already_initialized;
+	struct cn_net *cnn = net_generic(net, cn_net_id);
+
+	return cnn->cn_already_initialized;
 }
 
 /*
@@ -377,47 +378,14 @@  static struct pernet_operations cn_pernet_ops = {
        .size = sizeof(struct cn_net),
 };
 
-static struct cn_dev cdev = {
-	.input   = cn_rx_skb,
-};
-
 static int cn_init(void)
 {
-	struct cn_dev *dev = get_cdev();
-	struct netlink_kernel_cfg cfg = {
-		.groups	= CN_NETLINK_USERS + 0xf,
-		.input	= dev->input,
-	};
-
-	(void) cn_pernet_ops;
-
-	dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR, &cfg);
-	if (!dev->nls)
-		return -EIO;
-
-	dev->cbdev = cn_queue_alloc_dev("cqueue", dev->nls);
-	if (!dev->cbdev) {
-		netlink_kernel_release(dev->nls);
-		return -EINVAL;
-	}
-
-	cn_already_initialized = 1;
-
-	proc_create("connector", S_IRUGO, init_net.proc_net, &cn_file_ops);
-
-	return 0;
+	return register_pernet_subsys(&cn_pernet_ops);
 }
 
 static void cn_fini(void)
 {
-	struct cn_dev *dev = get_cdev();
-
-	cn_already_initialized = 0;
-
-	remove_proc_entry("connector", init_net.proc_net);
-
-	cn_queue_free_dev(dev->cbdev);
-	netlink_kernel_release(dev->nls);
+	return unregister_pernet_subsys(&cn_pernet_ops);
 }
 
 subsys_initcall(cn_init);