[ovs-dev] [PATCH 1/3] datapath: Add genl_exec().

Pravin B Shelar pshelar at nicira.com
Thu Dec 22 04:28:13 UTC 2011


Resending this patch as net-namespace patches depends on it.

--8<--------------------------cut here-------------------------->8-

genl_lock is not exported from older kernel. Following patch add
genl_exec() which can run any function (passed as arg) with
genl_lock held.

Signed-off-by: Pravin B Shelar <pshelar at nicira.com>
---
 acinclude.m4                                  |    2 +
 datapath/datapath.c                           |    9 ++-
 datapath/linux/compat/genetlink.inc           |  126 +++++++++++++++++++++++++
 datapath/linux/compat/include/linux/skbuff.h  |    6 +
 datapath/linux/compat/include/net/genetlink.h |    6 +
 5 files changed, 148 insertions(+), 1 deletions(-)

diff --git a/acinclude.m4 b/acinclude.m4
index 648132a..4c1b065 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -230,6 +230,8 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
                   [OVS_DEFINE([HAVE_SKB_DST_ACCESSOR_FUNCS])])
   OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], 
                   [skb_copy_from_linear_data_offset])
+  OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h],
+                  [skb_reset_tail_pointer])
   OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [skb_cow_head])
   OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [skb_transport_header],
                   [OVS_DEFINE([HAVE_SKBUFF_HEADER_HELPERS])])
diff --git a/datapath/datapath.c b/datapath/datapath.c
index c86c20b..025d932 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -2049,10 +2049,14 @@ static int __init dp_init(void)
 	pr_info("Open vSwitch switching datapath %s, built "__DATE__" "__TIME__"\n",
 		VERSION BUILDNR);
 
-	err = ovs_tnl_init();
+	err = genl_exec_init();
 	if (err)
 		goto error;
 
+	err = ovs_tnl_init();
+	if (err)
+		goto error_genl_exec;
+
 	err = ovs_flow_init();
 	if (err)
 		goto error_tnl_exit;
@@ -2079,6 +2083,8 @@ error_flow_exit:
 	ovs_flow_exit();
 error_tnl_exit:
 	ovs_tnl_exit();
+error_genl_exec:
+	genl_exec_exit();
 error:
 	return err;
 }
@@ -2091,6 +2097,7 @@ static void dp_cleanup(void)
 	ovs_vport_exit();
 	ovs_flow_exit();
 	ovs_tnl_exit();
+	genl_exec_exit();
 }
 
 module_init(dp_init);
diff --git a/datapath/linux/compat/genetlink.inc b/datapath/linux/compat/genetlink.inc
index bf96980..1301006 100644
--- a/datapath/linux/compat/genetlink.inc
+++ b/datapath/linux/compat/genetlink.inc
@@ -146,3 +146,129 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
 {
 }
 #endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+
+static DEFINE_MUTEX(genl_exec_lock);
+
+static genl_exec_func_t	 genl_exec_function;
+static int		 genl_exec_function_ret;
+static void		*genl_exec_data;
+static struct completion done;
+
+
+static int genl_exec_cmd(struct sk_buff *dummy, struct genl_info *dummy2)
+{
+	genl_exec_function_ret = genl_exec_function(genl_exec_data);
+	complete(&done);
+	return 0;
+}
+
+enum exec_cmd {
+	GENL_EXEC_UNSPEC,
+	GENL_EXEC_RUN,
+};
+
+static struct genl_family genl_exec_family = {
+	.id = GENL_ID_GENERATE,
+	.name = "ovs_genl_exec",
+	.version = 1,
+};
+
+static struct genl_ops genl_exec_ops[] = {
+	{
+	 .cmd = GENL_EXEC_RUN,
+	 .doit = genl_exec_cmd,
+	 .flags = CAP_NET_ADMIN,
+	},
+};
+
+static struct sk_buff *genlmsg_skb;
+
+int genl_exec_init(void)
+{
+	int err;
+
+	err = genl_register_family_with_ops(&genl_exec_family,
+			genl_exec_ops,
+			ARRAY_SIZE(genl_exec_ops));
+
+	if (err)
+		return err;
+
+	genlmsg_skb = genlmsg_new( NLMSG_HDRLEN, GFP_KERNEL);
+	if (!genlmsg_skb) {
+		genl_unregister_family(&genl_exec_family);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+void genl_exec_exit(void)
+{
+	genl_unregister_family(&genl_exec_family);
+	mutex_lock(&genl_exec_lock);
+	kfree_skb(genlmsg_skb);
+	genlmsg_skb = NULL;
+	mutex_unlock(&genl_exec_lock);
+}
+
+/* genl_lock() is not exported from older kernel.
+ * Following function allows any function to be executed with
+ * genl_mutex held. */
+
+int genl_exec(genl_exec_func_t func, void *data)
+{
+	int ret;
+	struct nlmsghdr *nlh;
+
+	mutex_lock(&genl_exec_lock);
+	if (!genlmsg_skb) {
+		ret = -ESHUTDOWN;
+		goto out;
+	}
+
+	skb_get(genlmsg_skb);
+
+	nlh = genlmsg_put(genlmsg_skb, 0, 0, &genl_exec_family, NLM_F_REQUEST, GENL_EXEC_RUN);
+	genl_exec_function = func;
+	genl_exec_data = data;
+	init_completion(&done);
+
+	ret = genlmsg_unicast(&init_net, genlmsg_skb, 0);
+	if (!ret) {
+		wait_for_completion(&done);
+		ret = genl_exec_function_ret;
+	} else
+		printk(KERN_ERR "[%s] Msg send error %d\n",__func__, ret);
+
+	genlmsg_skb->data = genlmsg_skb->head;
+	skb_reset_tail_pointer(genlmsg_skb);
+
+out:
+	mutex_unlock(&genl_exec_lock);
+
+	return ret;
+}
+
+#else
+
+int genl_exec(genl_exec_func_t func, void *data)
+{
+	int ret;
+
+	genl_lock();
+	ret = func(data);
+	genl_unlock();
+	return ret;
+}
+
+int genl_exec_init(void)
+{
+	return 0;
+}
+
+void genl_exec_exit(void)
+{
+}
+#endif
diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h
index 96d8012..01e524e 100644
--- a/datapath/linux/compat/include/linux/skbuff.h
+++ b/datapath/linux/compat/include/linux/skbuff.h
@@ -34,6 +34,12 @@ static inline void skb_copy_to_linear_data_offset(struct sk_buff *skb,
 
 #endif	/* !HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET */
 
+#ifndef HAVE_SKB_RESET_TAIL_POINTER
+static inline void skb_reset_tail_pointer(struct sk_buff *skb)
+{
+	skb->tail = skb->data;
+}
+#endif
 /*
  * The networking layer reserves some headroom in skb data (via
  * dev_alloc_skb). This is used to avoid having to reallocate skb data when
diff --git a/datapath/linux/compat/include/net/genetlink.h b/datapath/linux/compat/include/net/genetlink.h
index a1ff7c1..1bbb559 100644
--- a/datapath/linux/compat/include/net/genetlink.h
+++ b/datapath/linux/compat/include/net/genetlink.h
@@ -170,4 +170,10 @@ static inline struct net *genl_info_net(struct genl_info *info)
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
 #define genlmsg_unicast(ignore_net, skb, pid)   genlmsg_unicast(skb, pid)
 #endif
+
+typedef int (*genl_exec_func_t)(void *data);
+int genl_exec(genl_exec_func_t func, void *data);
+int genl_exec_init(void);
+void genl_exec_exit(void);
+
 #endif /* genetlink.h */
-- 
1.7.1




More information about the dev mailing list