From: Pravin Shelar Date: Wed, 2 Apr 2014 03:55:21 +0000 (-0700) Subject: datapath: Add support for kernels 3.13 X-Git-Tag: sliver-openvswitch-2.2.90-1~5^2~48 X-Git-Url: http://git.onelab.eu/?p=sliver-openvswitch.git;a=commitdiff_plain;h=cb25142c50cd3a92e779ca1ce6f61380ffc75927 datapath: Add support for kernels 3.13 Add support for building the in-tree kernel datapath for Linux kernels up to 3.13. There were some changes in the netlink area which required adding new compatibility code for this layer. Also, some new per-cpu stats initialization code was added. Based on patch from Kyle Mestery. Signed-off-by: Kyle Mestery Signed-off-by: Pravin B Shelar Acked-by: Kyle Mestery --- diff --git a/FAQ b/FAQ index eec2d4f37..6b4be439d 100644 --- a/FAQ +++ b/FAQ @@ -149,7 +149,7 @@ A: The following table lists the Linux kernel versions against which the 1.11.x 2.6.18 to 3.8 2.0.x 2.6.32 to 3.10 2.1.x 2.6.32 to 3.11 - 2.2.x 2.6.32 to 3.12 + 2.2.x 2.6.32 to 3.13 Open vSwitch userspace should also work with the Linux kernel module built into Linux 3.3 and later. diff --git a/NEWS b/NEWS index 92557785d..79255980d 100644 --- a/NEWS +++ b/NEWS @@ -13,8 +13,8 @@ Post-v2.1.0 - Upon the receipt of a SIGHUP signal, ovs-vswitchd no longer reopens its log file (it will terminate instead). Please use 'ovs-appctl vlog/reopen' instead. - - Support for Linux kernels up to 3.12. On Kernel 3.12 OVS uses tunnel - API for GRE and VXLAN. + - Support for Linux kernels up to 3.13. From Kernel 3.12 onwards OVS uses + tunnel API for GRE and VXLAN. - Added DPDK support. diff --git a/acinclude.m4 b/acinclude.m4 index 1f52cf142..4269620a0 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -134,10 +134,10 @@ AC_DEFUN([OVS_CHECK_LINUX], [ AC_MSG_RESULT([$kversion]) if test "$version" -ge 3; then - if test "$version" = 3 && test "$patchlevel" -le 12; then + if test "$version" = 3 && test "$patchlevel" -le 13; then : # Linux 3.x else - AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version newer than 3.12.x is not supported]) + AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version newer than 3.13.x is not supported]) fi else if test "$version" -le 1 || test "$patchlevel" -le 5 || test "$sublevel" -le 31; then diff --git a/datapath/compat.h b/datapath/compat.h index bc7e88055..f8f04697c 100644 --- a/datapath/compat.h +++ b/datapath/compat.h @@ -32,10 +32,10 @@ static inline void skb_clear_rxhash(struct sk_buff *skb) #endif } -#ifdef HAVE_PARALLEL_OPS -#define SET_PARALLEL_OPS .parallel_ops = true, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0) +#define GROUP_ID(grp) 0 #else -#define SET_PARALLEL_OPS +#define GROUP_ID(grp) ((grp)->id) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) diff --git a/datapath/datapath.c b/datapath/datapath.c index 52c76b413..c6d42db38 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -64,20 +64,36 @@ int ovs_net_id __read_mostly; +static struct genl_family dp_packet_genl_family; +static struct genl_family dp_flow_genl_family; +static struct genl_family dp_datapath_genl_family; + +static struct genl_multicast_group ovs_dp_flow_multicast_group = { + .name = OVS_FLOW_MCGROUP +}; + +static struct genl_multicast_group ovs_dp_datapath_multicast_group = { + .name = OVS_DATAPATH_MCGROUP +}; + +struct genl_multicast_group ovs_dp_vport_multicast_group = { + .name = OVS_VPORT_MCGROUP +}; + /* Check if need to build a reply message. * OVS userspace sets the NLM_F_ECHO flag if it needs the reply. */ static bool ovs_must_notify(struct genl_info *info, const struct genl_multicast_group *grp) { return info->nlhdr->nlmsg_flags & NLM_F_ECHO || - netlink_has_listeners(genl_info_net(info)->genl_sock, grp->id); + netlink_has_listeners(genl_info_net(info)->genl_sock, GROUP_ID(grp)); } -static void ovs_notify(struct sk_buff *skb, struct genl_info *info, - struct genl_multicast_group *grp) +static void ovs_notify(struct genl_family *family, struct genl_multicast_group *grp, + struct sk_buff *skb, struct genl_info *info) { - genl_notify(skb, genl_info_net(info), info->snd_portid, - grp->id, info->nlhdr, GFP_KERNEL); + genl_notify(family, skb, genl_info_net(info), + info->snd_portid, GROUP_ID(grp), info->nlhdr, GFP_KERNEL); } /** @@ -274,16 +290,6 @@ out: u64_stats_update_end(&stats->sync); } -static struct genl_family dp_packet_genl_family = { - .id = GENL_ID_GENERATE, - .hdrsize = sizeof(struct ovs_header), - .name = OVS_PACKET_FAMILY, - .version = OVS_PACKET_VERSION, - .maxattr = OVS_PACKET_ATTR_MAX, - .netnsok = true, - SET_PARALLEL_OPS -}; - int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb, const struct dp_upcall_info *upcall_info) { @@ -601,6 +607,18 @@ static struct genl_ops dp_packet_genl_ops[] = { } }; +static struct genl_family dp_packet_genl_family = { + .id = GENL_ID_GENERATE, + .hdrsize = sizeof(struct ovs_header), + .name = OVS_PACKET_FAMILY, + .version = OVS_PACKET_VERSION, + .maxattr = OVS_PACKET_ATTR_MAX, + .netnsok = true, + .parallel_ops = true, + .ops = dp_packet_genl_ops, + .n_ops = ARRAY_SIZE(dp_packet_genl_ops), +}; + static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats, struct ovs_dp_megaflow_stats *mega_stats) { @@ -632,26 +650,6 @@ static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats, } } -static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = { - [OVS_FLOW_ATTR_KEY] = { .type = NLA_NESTED }, - [OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED }, - [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG }, -}; - -static struct genl_family dp_flow_genl_family = { - .id = GENL_ID_GENERATE, - .hdrsize = sizeof(struct ovs_header), - .name = OVS_FLOW_FAMILY, - .version = OVS_FLOW_VERSION, - .maxattr = OVS_FLOW_ATTR_MAX, - .netnsok = true, - SET_PARALLEL_OPS -}; - -static struct genl_multicast_group ovs_dp_flow_multicast_group = { - .name = OVS_FLOW_MCGROUP -}; - static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts) { return NLMSG_ALIGN(sizeof(struct ovs_header)) @@ -914,7 +912,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) } if (reply) - ovs_notify(reply, info, &ovs_dp_flow_multicast_group); + ovs_notify(&dp_flow_genl_family, &ovs_dp_flow_multicast_group, reply, info); return 0; err_unlock_ovs: @@ -1023,7 +1021,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) ovs_unlock(); if (reply) - ovs_notify(reply, info, &ovs_dp_flow_multicast_group); + ovs_notify(&dp_flow_genl_family, &ovs_dp_flow_multicast_group, reply, info); if (old_acts) ovs_nla_free_flow_actions(old_acts); return 0; @@ -1135,11 +1133,11 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) OVS_FLOW_CMD_DEL); rcu_read_unlock(); BUG_ON(err < 0); - ovs_notify(reply, info, &ovs_dp_flow_multicast_group); + ovs_notify(&dp_flow_genl_family, &ovs_dp_flow_multicast_group, reply, info); } else { - netlink_set_err(sock_net(skb->sk)->genl_sock, 0, - ovs_dp_flow_multicast_group.id, - PTR_ERR(reply)); + genl_set_err(&dp_flow_genl_family, sock_net(skb->sk), 0, + GROUP_ID(&ovs_dp_flow_multicast_group), PTR_ERR(reply)); + } } @@ -1187,6 +1185,12 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) return skb->len; } +static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = { + [OVS_FLOW_ATTR_KEY] = { .type = NLA_NESTED }, + [OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED }, + [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG }, +}; + static struct genl_ops dp_flow_genl_ops[] = { { .cmd = OVS_FLOW_CMD_NEW, .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ @@ -1211,24 +1215,18 @@ static struct genl_ops dp_flow_genl_ops[] = { }, }; -static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = { - [OVS_DP_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, - [OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 }, - [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 }, -}; - -static struct genl_family dp_datapath_genl_family = { +static struct genl_family dp_flow_genl_family = { .id = GENL_ID_GENERATE, .hdrsize = sizeof(struct ovs_header), - .name = OVS_DATAPATH_FAMILY, - .version = OVS_DATAPATH_VERSION, - .maxattr = OVS_DP_ATTR_MAX, + .name = OVS_FLOW_FAMILY, + .version = OVS_FLOW_VERSION, + .maxattr = OVS_FLOW_ATTR_MAX, .netnsok = true, - SET_PARALLEL_OPS -}; - -static struct genl_multicast_group ovs_dp_datapath_multicast_group = { - .name = OVS_DATAPATH_MCGROUP + .parallel_ops = true, + .ops = dp_flow_genl_ops, + .n_ops = ARRAY_SIZE(dp_flow_genl_ops), + .mcgrps = &ovs_dp_flow_multicast_group, + .n_mcgrps = 1, }; static size_t ovs_dp_cmd_msg_size(void) @@ -1361,6 +1359,12 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) goto err_destroy_table; } + for_each_possible_cpu(i) { + struct dp_stats_percpu *dpath_stats; + dpath_stats = per_cpu_ptr(dp->stats_percpu, i); + u64_stats_init(&dpath_stats->sync); + } + dp->ports = kmalloc(DP_VPORT_HASH_BUCKETS * sizeof(struct hlist_head), GFP_KERNEL); if (!dp->ports) { @@ -1411,7 +1415,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_datapath_multicast_group); + ovs_notify(&dp_datapath_genl_family, &ovs_dp_datapath_multicast_group, reply, info); return 0; err_destroy_ports_array: @@ -1480,7 +1484,7 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info) __dp_destroy(dp); ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_datapath_multicast_group); + ovs_notify(&dp_datapath_genl_family, &ovs_dp_datapath_multicast_group, reply, info); return 0; err_unlock_free: @@ -1512,7 +1516,7 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info) BUG_ON(err < 0); ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_datapath_multicast_group); + ovs_notify(&dp_datapath_genl_family, &ovs_dp_datapath_multicast_group, reply, info); return 0; err_unlock_free: @@ -1573,6 +1577,12 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) return skb->len; } +static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = { + [OVS_DP_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, + [OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 }, + [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 }, +}; + static struct genl_ops dp_datapath_genl_ops[] = { { .cmd = OVS_DP_CMD_NEW, .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ @@ -1597,27 +1607,18 @@ static struct genl_ops dp_datapath_genl_ops[] = { }, }; -static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = { - [OVS_VPORT_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, - [OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct ovs_vport_stats) }, - [OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 }, - [OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 }, - [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_U32 }, - [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, -}; - -static struct genl_family dp_vport_genl_family = { +static struct genl_family dp_datapath_genl_family = { .id = GENL_ID_GENERATE, .hdrsize = sizeof(struct ovs_header), - .name = OVS_VPORT_FAMILY, - .version = OVS_VPORT_VERSION, - .maxattr = OVS_VPORT_ATTR_MAX, + .name = OVS_DATAPATH_FAMILY, + .version = OVS_DATAPATH_VERSION, + .maxattr = OVS_DP_ATTR_MAX, .netnsok = true, - SET_PARALLEL_OPS -}; - -struct genl_multicast_group ovs_dp_vport_multicast_group = { - .name = OVS_VPORT_MCGROUP + .parallel_ops = true, + .ops = dp_datapath_genl_ops, + .n_ops = ARRAY_SIZE(dp_datapath_genl_ops), + .mcgrps = &ovs_dp_datapath_multicast_group, + .n_mcgrps = 1, }; /* Called with ovs_mutex or RCU read lock. */ @@ -1783,7 +1784,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) BUG_ON(err < 0); ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_vport_multicast_group); + ovs_notify(&dp_vport_genl_family, &ovs_dp_vport_multicast_group, reply, info); return 0; exit_unlock_free: @@ -1832,7 +1833,7 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info) BUG_ON(err < 0); ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_vport_multicast_group); + ovs_notify(&dp_vport_genl_family, &ovs_dp_vport_multicast_group, reply, info); return 0; exit_unlock_free: @@ -1869,7 +1870,7 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info) ovs_dp_detach_port(vport); ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_vport_multicast_group); + ovs_notify(&dp_vport_genl_family, &ovs_dp_vport_multicast_group, reply, info); return 0; exit_unlock_free: @@ -1947,6 +1948,15 @@ out: return skb->len; } +static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = { + [OVS_VPORT_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, + [OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct ovs_vport_stats) }, + [OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 }, + [OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 }, + [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_U32 }, + [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, +}; + static struct genl_ops dp_vport_genl_ops[] = { { .cmd = OVS_VPORT_CMD_NEW, .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */ @@ -1971,26 +1981,25 @@ static struct genl_ops dp_vport_genl_ops[] = { }, }; -struct genl_family_and_ops { - struct genl_family *family; - struct genl_ops *ops; - int n_ops; - struct genl_multicast_group *group; +struct genl_family dp_vport_genl_family = { + .id = GENL_ID_GENERATE, + .hdrsize = sizeof(struct ovs_header), + .name = OVS_VPORT_FAMILY, + .version = OVS_VPORT_VERSION, + .maxattr = OVS_VPORT_ATTR_MAX, + .netnsok = true, + .parallel_ops = true, + .ops = dp_vport_genl_ops, + .n_ops = ARRAY_SIZE(dp_vport_genl_ops), + .mcgrps = &ovs_dp_vport_multicast_group, + .n_mcgrps = 1, }; -static const struct genl_family_and_ops dp_genl_families[] = { - { &dp_datapath_genl_family, - dp_datapath_genl_ops, ARRAY_SIZE(dp_datapath_genl_ops), - &ovs_dp_datapath_multicast_group }, - { &dp_vport_genl_family, - dp_vport_genl_ops, ARRAY_SIZE(dp_vport_genl_ops), - &ovs_dp_vport_multicast_group }, - { &dp_flow_genl_family, - dp_flow_genl_ops, ARRAY_SIZE(dp_flow_genl_ops), - &ovs_dp_flow_multicast_group }, - { &dp_packet_genl_family, - dp_packet_genl_ops, ARRAY_SIZE(dp_packet_genl_ops), - NULL }, +static struct genl_family *dp_genl_families[] = { + &dp_datapath_genl_family, + &dp_vport_genl_family, + &dp_flow_genl_family, + &dp_packet_genl_family, }; static void dp_unregister_genl(int n_families) @@ -1998,36 +2007,25 @@ static void dp_unregister_genl(int n_families) int i; for (i = 0; i < n_families; i++) - genl_unregister_family(dp_genl_families[i].family); + genl_unregister_family(dp_genl_families[i]); } static int dp_register_genl(void) { - int n_registered; int err; int i; - n_registered = 0; for (i = 0; i < ARRAY_SIZE(dp_genl_families); i++) { - const struct genl_family_and_ops *f = &dp_genl_families[i]; - err = genl_register_family_with_ops(f->family, f->ops, - f->n_ops); + err = genl_register_family(dp_genl_families[i]); if (err) goto error; - n_registered++; - - if (f->group) { - err = genl_register_mc_group(f->family, f->group); - if (err) - goto error; - } } return 0; error: - dp_unregister_genl(n_registered); + dp_unregister_genl(i); return err; } diff --git a/datapath/datapath.h b/datapath/datapath.h index d81e05c59..40e0f90b8 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h @@ -184,6 +184,7 @@ static inline struct vport *ovs_vport_ovsl(const struct datapath *dp, int port_n } extern struct notifier_block ovs_dp_device_notifier; +extern struct genl_family dp_vport_genl_family; extern struct genl_multicast_group ovs_dp_vport_multicast_group; void ovs_dp_process_received_packet(struct vport *, struct sk_buff *); diff --git a/datapath/dp_notify.c b/datapath/dp_notify.c index 0b22d0c19..f9a037510 100644 --- a/datapath/dp_notify.c +++ b/datapath/dp_notify.c @@ -31,18 +31,18 @@ static void dp_detach_port_notify(struct vport *vport) struct datapath *dp; dp = vport->dp; - notify = ovs_vport_cmd_build_info(vport, 0, 0, - OVS_VPORT_CMD_DEL); + notify = ovs_vport_cmd_build_info(vport, 0, 0, OVS_VPORT_CMD_DEL); ovs_dp_detach_port(vport); if (IS_ERR(notify)) { - netlink_set_err(ovs_dp_get_net(dp)->genl_sock, 0, - ovs_dp_vport_multicast_group.id, - PTR_ERR(notify)); + genl_set_err(&dp_vport_genl_family, ovs_dp_get_net(dp), 0, + GROUP_ID(&ovs_dp_vport_multicast_group), + PTR_ERR(notify)); return; } - genlmsg_multicast_netns(ovs_dp_get_net(dp), notify, 0, - ovs_dp_vport_multicast_group.id, + genlmsg_multicast_netns(&dp_vport_genl_family, + ovs_dp_get_net(dp), notify, 0, + GROUP_ID(&ovs_dp_vport_multicast_group), GFP_KERNEL); } diff --git a/datapath/linux/compat/genetlink-openvswitch.c b/datapath/linux/compat/genetlink-openvswitch.c index 359f916dc..08f0fab8b 100644 --- a/datapath/linux/compat/genetlink-openvswitch.c +++ b/datapath/linux/compat/genetlink-openvswitch.c @@ -1,12 +1,15 @@ #include #include -/* This is analogous to rtnl_notify() but uses genl_sock instead of rtnl. - * - * This is not (yet) in any upstream kernel. */ -void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, u32 group, - struct nlmsghdr *nlh, gfp_t flags) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) + +#undef genl_notify + +void rpl_genl_notify(struct rpl_genl_family *family, struct sk_buff *skb, + struct net *net, u32 portid, u32 group, + struct nlmsghdr *nlh, gfp_t flags) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) struct sock *sk = net->genl_sock; int report = 0; @@ -14,4 +17,39 @@ void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, u32 group, report = nlmsg_report(nlh); nlmsg_notify(sk, skb, portid, group, report, flags); +#else + genl_notify(skb, net, portid, group, nlh, flags); +#endif +} + +int rpl___genl_register_family(struct rpl_genl_family *f) +{ + int err; + + f->compat_family.id = f->id; + f->compat_family.hdrsize = f->hdrsize; + strncpy(f->compat_family.name, f->name, GENL_NAMSIZ); + f->compat_family.version = f->version; + f->compat_family.maxattr = f->maxattr; + f->compat_family.netnsok = f->netnsok; +#ifdef HAVE_PARALLEL_OPS + f->compat_family.parallel_ops = f->parallel_ops; +#endif + err = genl_register_family_with_ops(&f->compat_family, + (struct genl_ops *) f->ops, f->n_ops); + if (err) + goto error; + + if (f->mcgrps) { + /* Need to Fix GROUP_ID() for more than one group. */ + BUG_ON(f->n_mcgrps > 1); + err = genl_register_mc_group(&f->compat_family, + (struct genl_multicast_group *) f->mcgrps); + if (err) + goto error; + } +error: + return err; + } +#endif /* kernel version < 3.13.0 */ diff --git a/datapath/linux/compat/include/linux/u64_stats_sync.h b/datapath/linux/compat/include/linux/u64_stats_sync.h index 45b617a29..234fd9156 100644 --- a/datapath/linux/compat/include/linux/u64_stats_sync.h +++ b/datapath/linux/compat/include/linux/u64_stats_sync.h @@ -144,4 +144,15 @@ static inline bool u64_stats_fetch_retry_bh(const struct u64_stats_sync *syncp, } #endif /* Linux kernel < 2.6.36 */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) + +#if BITS_PER_LONG == 32 && defined(CONFIG_SMP) +# define u64_stats_init(syncp) seqcount_init(syncp.seq) +#else +# define u64_stats_init(syncp) do { } while (0) +#endif + +#endif + #endif /* _LINUX_U64_STATS_SYNC_WRAPPER_H */ diff --git a/datapath/linux/compat/include/net/genetlink.h b/datapath/linux/compat/include/net/genetlink.h index 09ee23bdd..9f425e5ff 100644 --- a/datapath/linux/compat/include/net/genetlink.h +++ b/datapath/linux/compat/include/net/genetlink.h @@ -17,8 +17,84 @@ #define portid pid #endif -extern void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, - u32 group, struct nlmsghdr *nlh, gfp_t flags); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) +struct rpl_genl_family { + struct genl_family compat_family; + unsigned int id; + unsigned int hdrsize; + char name[GENL_NAMSIZ]; + unsigned int version; + unsigned int maxattr; + bool netnsok; + bool parallel_ops; + int (*pre_doit)(const struct genl_ops *ops, + struct sk_buff *skb, + struct genl_info *info); + void (*post_doit)(const struct genl_ops *ops, + struct sk_buff *skb, + struct genl_info *info); + struct nlattr ** attrbuf; /* private */ + const struct genl_ops * ops; /* private */ + const struct genl_multicast_group *mcgrps; /* private */ + unsigned int n_ops; /* private */ + unsigned int n_mcgrps; /* private */ + unsigned int mcgrp_offset; /* private */ + struct list_head family_list; /* private */ + struct module *module; +}; + +#define genl_family rpl_genl_family +#define genl_notify rpl_genl_notify +void genl_notify(struct genl_family *family, + struct sk_buff *skb, struct net *net, u32 portid, u32 group, + struct nlmsghdr *nlh, gfp_t flags); + +static inline void *rpl_genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, + struct genl_family *family, int flags, u8 cmd) +{ + return genlmsg_put(skb, portid, seq, &family->compat_family, flags, cmd); +} + +#define genlmsg_put rpl_genlmsg_put + +static inline int rpl_genl_unregister_family(struct genl_family *family) +{ + return genl_unregister_family(&family->compat_family); +} +#define genl_unregister_family rpl_genl_unregister_family + +#define genl_set_err rpl_genl_set_err +static inline int genl_set_err(struct genl_family *family, struct net *net, + u32 portid, u32 group, int code) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) + netlink_set_err(net->genl_sock, portid, group, code); + return 0; +#else + return netlink_set_err(net->genl_sock, portid, group, code); +#endif +} + +#define genlmsg_multicast_netns rpl_genlmsg_multicast_netns +static inline int genlmsg_multicast_netns(struct genl_family *family, + struct net *net, struct sk_buff *skb, + u32 portid, unsigned int group, gfp_t flags) +{ + return nlmsg_multicast(net->genl_sock, skb, portid, group, flags); +} + + +#define __genl_register_family rpl___genl_register_family +int rpl___genl_register_family(struct genl_family *family); + +#define genl_register_family rpl_genl_register_family +static inline int rpl_genl_register_family(struct genl_family *family) +{ + family->module = THIS_MODULE; + return rpl___genl_register_family(family); +} + +#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0) static inline struct sk_buff *genlmsg_new_unicast(size_t payload, diff --git a/datapath/linux/compat/include/net/ip.h b/datapath/linux/compat/include/net/ip.h index 4193d3290..c819e4d99 100644 --- a/datapath/linux/compat/include/net/ip.h +++ b/datapath/linux/compat/include/net/ip.h @@ -12,4 +12,14 @@ static inline bool ip_is_fragment(const struct iphdr *iph) } #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) +static inline void rpl_inet_get_local_port_range(struct net *net, int *low, + int *high) +{ + inet_get_local_port_range(low, high); +} +#define inet_get_local_port_range rpl_inet_get_local_port_range + +#endif + #endif diff --git a/datapath/linux/compat/utils.c b/datapath/linux/compat/utils.c index dc4df2aaa..9404e20f4 100644 --- a/datapath/linux/compat/utils.c +++ b/datapath/linux/compat/utils.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb, } #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) bool __net_get_random_once(void *buf, int nbytes, bool *done, atomic_t *done_key) { @@ -58,3 +60,4 @@ bool __net_get_random_once(void *buf, int nbytes, bool *done, return true; } +#endif diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c index e33cffea2..8e3ff6928 100644 --- a/datapath/vport-lisp.c +++ b/datapath/vport-lisp.c @@ -163,7 +163,7 @@ static __be64 instance_id_to_tunnel_id(__u8 *iid) /* Compute source UDP port for outgoing packet. * Currently we use the flow hash. */ -static u16 get_src_port(struct sk_buff *skb) +static u16 get_src_port(struct net *net, struct sk_buff *skb) { u32 hash = skb_get_rxhash(skb); unsigned int range; @@ -177,7 +177,7 @@ static u16 get_src_port(struct sk_buff *skb) sizeof(*pkt_key) / sizeof(u32), 0); } - inet_get_local_port_range(&low, &high); + inet_get_local_port_range(net, &low, &high); range = (high - low) + 1; return (((u64) hash * range) >> 32) + low; } @@ -185,13 +185,14 @@ static u16 get_src_port(struct sk_buff *skb) static void lisp_build_header(const struct vport *vport, struct sk_buff *skb) { + struct net *net = ovs_dp_get_net(vport->dp); struct lisp_port *lisp_port = lisp_vport(vport); struct udphdr *udph = udp_hdr(skb); struct lisphdr *lisph = (struct lisphdr *)(udph + 1); const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key; udph->dest = lisp_port->dst_port; - udph->source = htons(get_src_port(skb)); + udph->source = htons(get_src_port(net, skb)); udph->check = 0; udph->len = htons(skb->len - skb_transport_offset(skb)); diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c index d26478535..cc9477dd1 100644 --- a/datapath/vport-vxlan.c +++ b/datapath/vport-vxlan.c @@ -139,6 +139,7 @@ error: static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) { + struct net *net = ovs_dp_get_net(vport->dp); struct vxlan_port *vxlan_port = vxlan_vport(vport); __be16 dst_port = inet_sport(vxlan_port->vs->sock->sk); struct rtable *rt; @@ -172,7 +173,7 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) skb->local_df = 1; - inet_get_local_port_range(&port_min, &port_max); + inet_get_local_port_range(net, &port_min, &port_max); src_port = vxlan_src_port(port_min, port_max, skb); err = vxlan_xmit_skb(vxlan_port->vs, rt, skb, diff --git a/datapath/vport.c b/datapath/vport.c index 7f12acccb..2673b8178 100644 --- a/datapath/vport.c +++ b/datapath/vport.c @@ -122,6 +122,7 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops, { struct vport *vport; size_t alloc_size; + int i; alloc_size = sizeof(struct vport); if (priv_size) { @@ -145,6 +146,12 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops, return ERR_PTR(-ENOMEM); } + for_each_possible_cpu(i) { + struct pcpu_tstats *vport_stats; + vport_stats = per_cpu_ptr(vport->percpu_stats, i); + u64_stats_init(&vport_stats->syncp); + } + spin_lock_init(&vport->stats_lock); return vport;