From b9c15df93753b640008f879315e26833c2e95468 Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Wed, 4 Jan 2012 17:20:08 -0800 Subject: [PATCH] datapath: Add genl_exec(). 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 Acked-by: Jesse Gross --- acinclude.m4 | 2 + datapath/Modules.mk | 2 + datapath/datapath.c | 10 +- datapath/genl_exec.c | 144 +++++++++++++++++++ datapath/genl_exec.h | 27 ++++ datapath/linux/compat/include/linux/skbuff.h | 6 + 6 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 datapath/genl_exec.c create mode 100644 datapath/genl_exec.h diff --git a/acinclude.m4 b/acinclude.m4 index 648132a2..4c1b0654 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/Modules.mk b/datapath/Modules.mk index e015a9dd..4d17568e 100644 --- a/datapath/Modules.mk +++ b/datapath/Modules.mk @@ -17,6 +17,7 @@ openvswitch_sources = \ dp_sysfs_dp.c \ dp_sysfs_if.c \ flow.c \ + genl_exec.c \ tunnel.c \ vlan.c \ vport.c \ @@ -33,6 +34,7 @@ openvswitch_headers = \ datapath.h \ dp_sysfs.h \ flow.h \ + genl_exec.h \ tunnel.h \ vlan.h \ vport.h \ diff --git a/datapath/datapath.c b/datapath/datapath.c index c86c20bc..281e86bf 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -54,6 +54,7 @@ #include "checksum.h" #include "datapath.h" #include "flow.h" +#include "genl_exec.h" #include "vlan.h" #include "tunnel.h" #include "vport-internal_dev.h" @@ -2049,10 +2050,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 +2084,8 @@ error_flow_exit: ovs_flow_exit(); error_tnl_exit: ovs_tnl_exit(); +error_genl_exec: + genl_exec_exit(); error: return err; } @@ -2091,6 +2098,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/genl_exec.c b/datapath/genl_exec.c new file mode 100644 index 00000000..e5795294 --- /dev/null +++ b/datapath/genl_exec.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2007-2012 Nicira Networks. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include "genl_exec.h" + +#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 struct sk_buff *genlmsg_skb; + +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, + }, +}; + +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(0, GFP_KERNEL); + if (!genlmsg_skb) { + genl_unregister_family(&genl_exec_family); + return -ENOMEM; + } + return 0; +} + +void genl_exec_exit(void) +{ + kfree_skb(genlmsg_skb); + genl_unregister_family(&genl_exec_family); +} + +/* 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; + + mutex_lock(&genl_exec_lock); + + init_completion(&done); + skb_get(genlmsg_skb); + genlmsg_put(genlmsg_skb, 0, 0, &genl_exec_family, + NLM_F_REQUEST, GENL_EXEC_RUN); + + genl_exec_function = func; + genl_exec_data = data; + ret = genlmsg_unicast(&init_net, genlmsg_skb, 0); + + if (!ret) { + wait_for_completion(&done); + ret = genl_exec_function_ret; + } else { + pr_err("genl_exec send error %d\n", ret); + } + + /* Wait for genetlink to kfree skb. */ + while (skb_shared(genlmsg_skb)) + cpu_relax(); + + genlmsg_skb->data = genlmsg_skb->head; + skb_reset_tail_pointer(genlmsg_skb); + + 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/genl_exec.h b/datapath/genl_exec.h new file mode 100644 index 00000000..251aa0a2 --- /dev/null +++ b/datapath/genl_exec.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2007-2012 Nicira Networks. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef GENL_EXEC_H +#define GENL_EXEC_H 1 + +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 /* genl_exec.h */ diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h index 96d80124..01e524ef 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 -- 2.30.2