[PATCH] RFC containerized syslog and iptable log dispatching (working stage)

Jean-Marc Pigeon jmp at safe.ca
Tue Feb 23 13:01:19 PST 2010


	Capability to redirect iptable log, in the right containerized
	syslog_ns, is now fully working.

	Tried my best to have a very minimal foot-print.

	BEWARE: patch not done for IPV6 (I can't test it),
	you are welcome to do it.

Signed-off-by:  Jean-Marc Pigeon        <jmp at safe.ca>
---
 include/linux/netdevice.h    |    2 +
 include/linux/syslog.h       |    8 +++
 kernel/syslog.c              |  140 +++++++++++++++++++++++++++++++++++++++---
 net/core/rtnetlink.c         |    3 +
 net/ipv4/netfilter/ipt_LOG.c |   11 +++
 5 files changed, 154 insertions(+), 10 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index a3fccc8..c323463 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -918,6 +918,8 @@ struct net_device {
 	/* Network namespace this network device is inside */
 	struct net		*nd_net;
 #endif
+	/* to assign a syslog chanel according device ownership	*/
+	pid_t			syslog_ns_pid;
 
 	/* mid-layer private */
 	void			*ml_priv;
diff --git a/include/linux/syslog.h b/include/linux/syslog.h
index 9fbe190..2188f09 100644
--- a/include/linux/syslog.h
+++ b/include/linux/syslog.h
@@ -44,15 +44,23 @@ static inline void put_syslog_ns(struct syslog_ns *ns)
 #ifdef	CONFIG_PRINTK
 extern struct syslog_ns *current_syslog_ns(void);
 extern struct syslog_ns *switch_syslog_ns(struct syslog_ns *syslog_ns);
+extern struct syslog_ns *find_syslog_ns_bypid(pid_t pid);
 #else
 static inline syslog_ns *current_syslog_ns(void)
 {
 	return 0;
 }
+
 static inline struct syslog_ns *switch_syslog_ns(struct syslog_ns *syslog_ns)
 {
 	return syslog_ns;
 }
+
+static inline syslog_ns *find_syslog_ns_bypid(pid_t pid)
+
+{
+	return 0;
+}
 #endif
 
 #endif /* _LINUX_SYSLOG_H */
diff --git a/kernel/syslog.c b/kernel/syslog.c
index 9873c06..1ab9bdc 100644
--- a/kernel/syslog.c
+++ b/kernel/syslog.c
@@ -18,7 +18,8 @@
  *  where container kernel data are redirected, kept and
  *  managed.
  *
- *  Containerized syslog is activated by CLONE_SYSLOG
+ *  Containerized syslog is activated if CLONE_SYSLOG
+ *  condition is true.
  *
  */
 
@@ -47,23 +48,99 @@ struct syslog_ns init_kernel_syslog_ns = {
 	.buf_len = __LOG_BUF_LEN,
 	.buf = __log_buf
 };
-
 struct syslog_ns init_kernel_syslog_ns;
 EXPORT_SYMBOL_GPL(init_kernel_syslog_ns);
 
 /*
+ * List of all syslog ns currently allocated
+ * first member of this list (kernel syslog)
+ * can't be removed.
+ */
+struct	log_list	{
+	spinlock_t list_lock;		/*make sure about list access	*/
+	struct log_list *next;		/*next syslog_ns in the list	*/
+	struct syslog_ns *syslog_ns;
+	}  log_list = {
+		.list_lock = __SPIN_LOCK_INITIALIZER(list_lock),
+		.next = (struct log_list *)0,
+		.syslog_ns = &init_kernel_syslog_ns
+		};
+/*
+ * removing a syslog reference from the list
+ *
+ */
+static void removing_syslog_ns(struct syslog_ns *syslog_ns)
+
+{
+	int done;
+	struct log_list	*start;
+
+	done = false;
+	start = &log_list;
+	while (start->next != (struct log_list *)0) {
+		struct log_list	*check;
+		unsigned long flags;
+
+		spin_lock_irqsave(&(start->next->list_lock), flags);
+		check = start->next;
+		if (check->syslog_ns == syslog_ns) {
+			start->next = check->next;
+			done = true;
+			}
+		spin_unlock_irqrestore(&(check->list_lock), flags);
+		if (done == true) {
+			kfree(check);
+			break;
+			}
+		start = start->next;
+		}
+}
+
+/*
+ * adding a syslog_ns to the list of known syslog
+ *
+ */
+static void adding_syslog_ns(struct syslog_ns *syslog_ns)
+
+{
+	int done;
+	struct log_list	*start;
+
+	done = false;
+	start = &log_list;
+	while ((done == false) && (start != (struct log_list *)0)) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&(start->list_lock), flags);
+		if (start->next == (struct log_list *)0) {
+			struct log_list *next;
+
+			next = kzalloc(sizeof(struct log_list), GFP_KERNEL);
+			BUG_ON(!next);
+			spin_lock_init(&(next->list_lock));
+			next->syslog_ns = syslog_ns;
+			start->next = next;
+			done = true;
+			}
+		spin_unlock_irqrestore(&(start->list_lock), flags);
+		start = start->next;
+		}
+}
+
+/*
  * Procedure to free all ressources tied to syslog
  *
  */
-static struct syslog_ns *free_all_syslog_ns(struct syslog_ns *syslog)
+static struct syslog_ns *free_all_syslog_ns(struct syslog_ns *syslog_ns)
 
 {
-	if (syslog != (struct syslog_ns *)0) {
-		(void) kfree(syslog->buf);
-		(void) kfree(syslog);
-		syslog = (struct syslog_ns *)0;
+	if (syslog_ns != (struct syslog_ns *)0) {
+		(void) removing_syslog_ns(syslog_ns);
+		(void) kfree(syslog_ns->buf);
+		(void) kfree(syslog_ns);
+		syslog_ns = (struct syslog_ns *)0;
 		}
-	return syslog;
+	return syslog_ns;
 }
 
 /*
@@ -93,9 +170,28 @@ static struct syslog_ns *malloc_syslog_ns(unsigned container_buf_len)
 	ns->handle = current->pid;
 	ns->buf_len = container_buf_len;
 	ns->buf = buf;
+	(void) adding_syslog_ns(ns);
 	return ns;
 }
 /*
+ * Procedure to locate and return a syslog_ns with same handle as pid submitted.
+ * return a NULL pointer if not found;
+ *
+ */
+static struct syslog_ns *find_its_syslog_ns(pid_t pid)
+
+{
+	struct log_list	*start;
+
+	start = &log_list;
+	while (start != (struct log_list *)0) {
+		if (start->syslog_ns->handle == pid)
+			return start->syslog_ns;
+		start = start->next;
+		}
+	return 0;
+}
+/*
  * Procedure to ONLY increase syslog buffer size
  * If syslog_ns is NULL, assign a brand new syslog_ns
  *
@@ -193,7 +289,7 @@ void free_syslog_ns(struct kref *kref)
 /*
  * Procedure to get the current syslog area linked to a
  * container (by CLONE_SYSLOG).
- * if trouble, pin down the problem before it propagate.
+ * if trouble, report host kernel own syslog_ns.
  *
  */
 struct syslog_ns *current_syslog_ns(void)
@@ -222,7 +318,31 @@ struct syslog_ns *switch_syslog_ns(struct syslog_ns *syslog_ns)
 
 	spin_lock_irqsave(&(current_syslog_ns()->logbuf_lock), flags);
 	old = current_syslog_ns();
-	current->nsproxy->syslog_ns = syslog_ns;
+	if (syslog_ns)
+		current->nsproxy->syslog_ns = syslog_ns;
 	spin_unlock_irqrestore(&(old->logbuf_lock), flags);
 	return old;
 }
+/*
+ * Procedure to locate the syslog handle own by a given
+ * pid or one of its parents lineage.
+ *
+ */
+struct syslog_ns *find_syslog_ns_bypid(pid_t pid)
+
+{
+	while (pid > 1) {
+		struct syslog_ns *its_ns;
+		struct task_struct *ns_task;
+
+		its_ns = find_its_syslog_ns(pid);
+		if (its_ns)
+			return its_ns;
+		ns_task = find_task_by_vpid(pid);
+		if ((ns_task) && (ns_task->real_parent))
+			pid = ns_task->real_parent->pid;
+		else
+			break;
+		}
+	return log_list.syslog_ns;
+}
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 794bcb8..e41bc93 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -775,6 +775,9 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
 			err = PTR_ERR(net);
 			goto errout;
 		}
+		if (dev)
+			dev->syslog_ns_pid = nla_get_u32(tb[IFLA_NET_NS_PID]);
+
 		err = dev_change_net_namespace(dev, net, ifname);
 		put_net(net);
 		if (err)
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index ee128ef..7e1467d 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -14,6 +14,7 @@
 #include <linux/spinlock.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
+#include <linux/syslog.h>
 #include <net/icmp.h>
 #include <net/udp.h>
 #include <net/tcp.h>
@@ -382,6 +383,15 @@ ipt_log_packet(u_int8_t pf,
 	       const struct nf_loginfo *loginfo,
 	       const char *prefix)
 {
+
+	struct syslog_ns	*syslog_ns;
+
+
+	syslog_ns = (struct syslog_ns *)0;
+	if (skb->dev) 	/*another syslog_ns possible?	*/
+		syslog_ns = find_syslog_ns_bypid(skb->dev->syslog_ns_pid);
+	syslog_ns = switch_syslog_ns(syslog_ns);
+
 	if (!loginfo)
 		loginfo = &default_loginfo;
 
@@ -422,6 +432,7 @@ ipt_log_packet(u_int8_t pf,
 	dump_packet(loginfo, skb, 0);
 	printk("\n");
 	spin_unlock_bh(&log_lock);
+	(void) switch_syslog_ns(syslog_ns);
 }
 
 static unsigned int
-- 
1.6.6




More information about the Containers mailing list