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 <pshe...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev