datapath: Add support for kernels 3.13
authorPravin Shelar <pshelar@nicira.com>
Wed, 2 Apr 2014 03:55:21 +0000 (20:55 -0700)
committerPravin B Shelar <pshelar@nicira.com>
Mon, 31 Mar 2014 14:38:38 +0000 (07:38 -0700)
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 <mestery@noironetworks.com>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Kyle Mestery <mestery@noironetworks.com>
15 files changed:
FAQ
NEWS
acinclude.m4
datapath/compat.h
datapath/datapath.c
datapath/datapath.h
datapath/dp_notify.c
datapath/linux/compat/genetlink-openvswitch.c
datapath/linux/compat/include/linux/u64_stats_sync.h
datapath/linux/compat/include/net/genetlink.h
datapath/linux/compat/include/net/ip.h
datapath/linux/compat/utils.c
datapath/vport-lisp.c
datapath/vport-vxlan.c
datapath/vport.c

diff --git a/FAQ b/FAQ
index eec2d4f..6b4be43 100644 (file)
--- 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
        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.
 
    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 9255778..7925598 100644 (file)
--- 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.
    - 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.
 
 
    - Added DPDK support.
 
 
index 1f52cf1..4269620 100644 (file)
@@ -134,10 +134,10 @@ AC_DEFUN([OVS_CHECK_LINUX], [
     AC_MSG_RESULT([$kversion])
 
     if test "$version" -ge 3; then
     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
           : # 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
        fi
     else
        if test "$version" -le 1 || test "$patchlevel" -le 5 || test "$sublevel" -le 31; then
index bc7e880..f8f0469 100644 (file)
@@ -32,10 +32,10 @@ static inline void skb_clear_rxhash(struct sk_buff *skb)
 #endif
 }
 
 #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
 #else
-#define SET_PARALLEL_OPS
+#define GROUP_ID(grp)  ((grp)->id)
 #endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
 #endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
index 52c76b4..c6d42db 100644 (file)
 
 int ovs_net_id __read_mostly;
 
 
 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 ||
 /* 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);
 }
 
        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)
 {
 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)
 {
 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))
 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)
        }
 
        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:
        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_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;
        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_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 {
                } 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;
 }
 
        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. */
 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),
        .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,
        .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)
 };
 
 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;
        }
 
                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) {
        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_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:
        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();
        __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:
        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();
        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:
        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;
 }
 
        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. */
 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),
        .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,
        .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. */
 };
 
 /* 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();
 
        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:
        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();
 
        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:
        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_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:
        return 0;
 
 exit_unlock_free:
@@ -1947,6 +1948,15 @@ out:
        return skb->len;
 }
 
        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. */
 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)
 };
 
 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++)
        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)
 {
 }
 
 static int dp_register_genl(void)
 {
-       int n_registered;
        int err;
        int i;
 
        int err;
        int i;
 
-       n_registered = 0;
        for (i = 0; i < ARRAY_SIZE(dp_genl_families); i++) {
        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;
                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:
        }
 
        return 0;
 
 error:
-       dp_unregister_genl(n_registered);
+       dp_unregister_genl(i);
        return err;
 }
 
        return err;
 }
 
index d81e05c..40e0f90 100644 (file)
@@ -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 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 *);
 extern struct genl_multicast_group ovs_dp_vport_multicast_group;
 
 void ovs_dp_process_received_packet(struct vport *, struct sk_buff *);
index 0b22d0c..f9a0375 100644 (file)
@@ -31,18 +31,18 @@ static void dp_detach_port_notify(struct vport *vport)
        struct datapath *dp;
 
        dp = vport->dp;
        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)) {
        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;
        }
 
                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);
 }
 
                                GFP_KERNEL);
 }
 
index 359f916..08f0fab 100644 (file)
@@ -1,12 +1,15 @@
 #include <net/genetlink.h>
 #include <linux/version.h>
 
 #include <net/genetlink.h>
 #include <linux/version.h>
 
-/* 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;
 
        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);
                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 */
index 45b617a..234fd91 100644 (file)
@@ -144,4 +144,15 @@ static inline bool u64_stats_fetch_retry_bh(const struct u64_stats_sync *syncp,
 }
 
 #endif /* Linux kernel < 2.6.36 */
 }
 
 #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 */
 #endif /* _LINUX_U64_STATS_SYNC_WRAPPER_H */
index 09ee23b..9f425e5 100644 (file)
 #define portid pid
 #endif
 
 #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,
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
 static inline struct sk_buff *genlmsg_new_unicast(size_t payload,
index 4193d32..c819e4d 100644 (file)
@@ -12,4 +12,14 @@ static inline bool ip_is_fragment(const struct iphdr *iph)
 }
 #endif
 
 }
 #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
 #endif
index dc4df2a..9404e20 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/mm.h>
 #include <linux/net.h>
 #include <net/checksum.h>
 #include <linux/mm.h>
 #include <linux/net.h>
 #include <net/checksum.h>
+#include <net/ip.h>
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/percpu.h>
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/percpu.h>
@@ -38,6 +39,7 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
 }
 #endif
 
 }
 #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)
 {
 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;
 }
 
        return true;
 }
+#endif
index e33cffe..8e3ff69 100644 (file)
@@ -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.
  */
 /* 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;
 {
        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);
        }
 
                            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;
 }
        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)
 {
 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;
        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));
 
        udph->check = 0;
        udph->len = htons(skb->len - skb_transport_offset(skb));
 
index d264785..cc9477d 100644 (file)
@@ -139,6 +139,7 @@ error:
 
 static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
 {
 
 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;
        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;
 
 
        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,
        src_port = vxlan_src_port(port_min, port_max, skb);
 
        err = vxlan_xmit_skb(vxlan_port->vs, rt, skb,
index 7f12acc..2673b81 100644 (file)
@@ -122,6 +122,7 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
 {
        struct vport *vport;
        size_t alloc_size;
 {
        struct vport *vport;
        size_t alloc_size;
+       int i;
 
        alloc_size = sizeof(struct vport);
        if (priv_size) {
 
        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);
        }
 
                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;
        spin_lock_init(&vport->stats_lock);
 
        return vport;