]> git.proxmox.com Git - mirror_ovs.git/blobdiff - datapath/datapath.c
compat: Use nla_parse deprecated functions
[mirror_ovs.git] / datapath / datapath.c
index 3d2385e208e1945e16f9690fdb9cebd382f02cd0..a7af7849a84bb05450c857db2436d3859cd2425c 100644 (file)
 #include <net/genetlink.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
+#include <net/nsh.h>
 
 #include "datapath.h"
 #include "conntrack.h"
 #include "flow.h"
 #include "flow_table.h"
 #include "flow_netlink.h"
+#include "meter.h"
 #include "gso.h"
 #include "vport-internal_dev.h"
 #include "vport-netdev.h"
 
-int ovs_net_id __read_mostly;
-EXPORT_SYMBOL_GPL(ovs_net_id);
+unsigned int ovs_net_id __read_mostly;
 
 static struct genl_family dp_packet_genl_family;
 static struct genl_family dp_flow_genl_family;
@@ -70,16 +71,16 @@ static struct genl_family dp_datapath_genl_family;
 
 static const struct nla_policy flow_policy[];
 
-static struct genl_multicast_group ovs_dp_flow_multicast_group = {
-       .name = OVS_FLOW_MCGROUP
+static const 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
+static const 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
+const struct genl_multicast_group ovs_dp_vport_multicast_group = {
+       .name = OVS_VPORT_MCGROUP,
 };
 
 /* Check if need to build a reply message.
@@ -92,11 +93,11 @@ static bool ovs_must_notify(struct genl_family *family, struct genl_info *info,
               genl_has_listeners(family, genl_info_net(info), group);
 }
 
-static void ovs_notify(struct genl_family *family, struct genl_multicast_group *grp,
+static void ovs_notify(struct genl_family *family,
+                      const struct genl_multicast_group *grp,
                       struct sk_buff *skb, struct genl_info *info)
 {
-       genl_notify(family, skb, genl_info_net(info),
-                   info->snd_portid, GROUP_ID(grp), info->nlhdr, GFP_KERNEL);
+       genl_notify(family, skb, info, GROUP_ID(grp), GFP_KERNEL);
 }
 
 /**
@@ -136,7 +137,6 @@ int lockdep_ovsl_is_held(void)
        else
                return 1;
 }
-EXPORT_SYMBOL_GPL(lockdep_ovsl_is_held);
 #endif
 
 static int queue_gso_packets(struct datapath *dp, struct sk_buff *,
@@ -148,35 +148,6 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *,
                                  const struct dp_upcall_info *,
                                  uint32_t cutlen);
 
-/* Must be called with rcu_read_lock. */
-static struct datapath *get_dp_rcu(struct net *net, int dp_ifindex)
-{
-       struct net_device *dev = dev_get_by_index_rcu(net, dp_ifindex);
-
-       if (dev) {
-               struct vport *vport = ovs_internal_dev_get_vport(dev);
-               if (vport)
-                       return vport->dp;
-       }
-
-       return NULL;
-}
-
-/* The caller must hold either ovs_mutex or rcu_read_lock to keep the
- * returned dp pointer valid.
- */
-static inline struct datapath *get_dp(struct net *net, int dp_ifindex)
-{
-       struct datapath *dp;
-
-       WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_ovsl_is_held());
-       rcu_read_lock();
-       dp = get_dp_rcu(net, dp_ifindex);
-       rcu_read_unlock();
-
-       return dp;
-}
-
 /* Must be called with rcu_read_lock or ovs_mutex. */
 const char *ovs_dp_name(const struct datapath *dp)
 {
@@ -209,6 +180,7 @@ static void destroy_dp_rcu(struct rcu_head *rcu)
        ovs_flow_tbl_destroy(&dp->table);
        free_percpu(dp->stats_percpu);
        kfree(dp->ports);
+       ovs_meters_exit(dp);
        kfree(dp);
 }
 
@@ -342,8 +314,10 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
                             const struct dp_upcall_info *upcall_info,
                                 uint32_t cutlen)
 {
-       unsigned short gso_type = skb_shinfo(skb)->gso_type;
+#ifdef HAVE_SKB_GSO_UDP
+       unsigned int gso_type = skb_shinfo(skb)->gso_type;
        struct sw_flow_key later_key;
+#endif
        struct sk_buff *segs, *nskb;
        struct ovs_skb_cb ovs_cb;
        int err;
@@ -355,7 +329,7 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
                return PTR_ERR(segs);
        if (segs == NULL)
                return -EINVAL;
-
+#ifdef HAVE_SKB_GSO_UDP
        if (gso_type & SKB_GSO_UDP) {
                /* The initial flow key extracted by ovs_flow_key_extract()
                 * in this case is for a first fragment, so we need to
@@ -364,14 +338,15 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
                later_key = *key;
                later_key.ip.frag = OVS_FRAG_TYPE_LATER;
        }
-
+#endif
        /* Queue all of the segments. */
        skb = segs;
        do {
                *OVS_CB(skb) = ovs_cb;
+#ifdef HAVE_SKB_GSO_UDP
                if (gso_type & SKB_GSO_UDP && skb != segs)
                        key = &later_key;
-
+#endif
                err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen);
                if (err)
                        break;
@@ -391,7 +366,7 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
 }
 
 static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info,
-                             unsigned int hdrlen)
+                             unsigned int hdrlen, int actions_attrlen)
 {
        size_t size = NLMSG_ALIGN(sizeof(struct ovs_header))
                + nla_total_size(hdrlen) /* OVS_PACKET_ATTR_PACKET */
@@ -408,7 +383,7 @@ static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info,
 
        /* OVS_PACKET_ATTR_ACTIONS */
        if (upcall_info->actions_len)
-               size += nla_total_size(upcall_info->actions_len);
+               size += nla_total_size(actions_attrlen);
 
        /* OVS_PACKET_ATTR_MRU */
        if (upcall_info->mru)
@@ -423,7 +398,7 @@ static void pad_packet(struct datapath *dp, struct sk_buff *skb)
                size_t plen = NLA_ALIGN(skb->len) - skb->len;
 
                if (plen > 0)
-                       memset(skb_put(skb, plen), 0, plen);
+                       skb_put_zero(skb, plen);
        }
 }
 
@@ -436,12 +411,6 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
        struct sk_buff *nskb = NULL;
        struct sk_buff *user_skb = NULL; /* to be queued to userspace */
        struct nlattr *nla;
-       struct genl_info info = {
-#ifdef HAVE_GENLMSG_NEW_UNICAST
-               .dst_sk = ovs_dp_get_net(dp)->genl_sock,
-#endif
-               .snd_portid = upcall_info->portid,
-       };
        size_t len;
        unsigned int hlen;
        int err, dp_ifindex;
@@ -469,7 +438,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
 
        /* Complete checksum if needed */
        if (skb->ip_summed == CHECKSUM_PARTIAL &&
-           (err = skb_checksum_help(skb)))
+           (err = skb_csum_hwoffload_help(skb, 0)))
                goto out;
 
        /* Older versions of OVS user space enforce alignment of the last
@@ -481,8 +450,9 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
        else
                hlen = skb->len;
 
-       len = upcall_msg_size(upcall_info, hlen - cutlen);
-       user_skb = genlmsg_new_unicast(len, &info, GFP_ATOMIC);
+       len = upcall_msg_size(upcall_info, hlen - cutlen,
+                             OVS_CB(skb)->acts_origlen);
+       user_skb = genlmsg_new(len, GFP_ATOMIC);
        if (!user_skb) {
                err = -ENOMEM;
                goto out;
@@ -490,6 +460,10 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
 
        upcall = genlmsg_put(user_skb, 0, 0, &dp_packet_genl_family,
                             0, upcall_info->cmd);
+       if (!upcall) {
+               err = -EINVAL;
+               goto out;
+       }
        upcall->dp_ifindex = dp_ifindex;
 
        err = ovs_nla_put_key(key, key, OVS_PACKET_ATTR_KEY, false, user_skb);
@@ -502,7 +476,12 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
 
 
        if (upcall_info->egress_tun_info) {
-               nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_EGRESS_TUN_KEY);
+               nla = nla_nest_start_noflag(user_skb,
+                                           OVS_PACKET_ATTR_EGRESS_TUN_KEY);
+               if (!nla) {
+                       err = -EMSGSIZE;
+                       goto out;
+               }
                err = ovs_nla_put_tunnel_info(user_skb,
                                              upcall_info->egress_tun_info);
                BUG_ON(err);
@@ -510,7 +489,11 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
        }
 
        if (upcall_info->actions_len) {
-               nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_ACTIONS);
+               nla = nla_nest_start_noflag(user_skb, OVS_PACKET_ATTR_ACTIONS);
+               if (!nla) {
+                       err = -EMSGSIZE;
+                       goto out;
+               }
                err = ovs_nla_put_actions(upcall_info->actions,
                                          upcall_info->actions_len,
                                          user_skb);
@@ -578,7 +561,6 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        struct sw_flow *flow;
        struct sw_flow_actions *sf_acts;
        struct datapath *dp;
-       struct ethhdr *eth;
        struct vport *input_vport;
        u16 mru = 0;
        int len;
@@ -599,18 +581,6 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
 
        nla_memcpy(__skb_put(packet, len), a[OVS_PACKET_ATTR_PACKET], len);
 
-       skb_reset_mac_header(packet);
-       eth = eth_hdr(packet);
-
-       /* Normally, setting the skb 'protocol' field would be handled by a
-        * call to eth_type_trans(), but it assumes there's a sending
-        * device, which we may not have.
-        */
-       if (eth_proto_is_802_3(eth->h_proto))
-               packet->protocol = eth->h_proto;
-       else
-               packet->protocol = htons(ETH_P_802_2);
-
        /* Set packet's mru */
        if (a[OVS_PACKET_ATTR_MRU]) {
                mru = nla_get_u16(a[OVS_PACKET_ATTR_MRU]);
@@ -683,22 +653,30 @@ static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
 
 static struct genl_ops dp_packet_genl_ops[] = {
        { .cmd = OVS_PACKET_CMD_EXECUTE,
+#ifdef HAVE_GENL_VALIDATE_FLAGS
+         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+#endif
          .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#ifdef HAVE_GENL_OPS_POLICY
          .policy = packet_policy,
+#endif
          .doit = ovs_packet_cmd_execute
        }
 };
 
-static struct genl_family dp_packet_genl_family = {
-       .id = GENL_ID_GENERATE,
+static struct genl_family dp_packet_genl_family __ro_after_init = {
        .hdrsize = sizeof(struct ovs_header),
        .name = OVS_PACKET_FAMILY,
        .version = OVS_PACKET_VERSION,
        .maxattr = OVS_PACKET_ATTR_MAX,
+#ifndef HAVE_GENL_OPS_POLICY
+       .policy = packet_policy,
+#endif
        .netnsok = true,
        .parallel_ops = true,
        .ops = dp_packet_genl_ops,
        .n_ops = ARRAY_SIZE(dp_packet_genl_ops),
+       .module = THIS_MODULE,
 };
 
 static void get_dp_stats(const struct datapath *dp, struct ovs_dp_stats *stats,
@@ -821,7 +799,7 @@ static int ovs_flow_cmd_fill_actions(const struct sw_flow *flow,
         * This can only fail for dump operations because the skb is always
         * properly sized for single flows.
         */
-       start = nla_nest_start(skb, OVS_FLOW_ATTR_ACTIONS);
+       start = nla_nest_start_noflag(skb, OVS_FLOW_ATTR_ACTIONS);
        if (start) {
                const struct sw_flow_actions *sf_acts;
 
@@ -909,7 +887,7 @@ static struct sk_buff *ovs_flow_cmd_alloc_info(const struct sw_flow_actions *act
                return NULL;
 
        len = ovs_flow_cmd_msg_size(acts, sfid, ufid_flags);
-       skb = genlmsg_new_unicast(len, info, GFP_KERNEL);
+       skb = genlmsg_new(len, GFP_KERNEL);
        if (!skb)
                return ERR_PTR(-ENOMEM);
 
@@ -946,7 +924,6 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
        struct sw_flow_mask mask;
        struct sk_buff *reply;
        struct datapath *dp;
-       struct sw_flow_key key;
        struct sw_flow_actions *acts;
        struct sw_flow_match match;
        u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
@@ -974,20 +951,24 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
        }
 
        /* Extract key. */
-       ovs_match_init(&match, &key, &mask);
+       ovs_match_init(&match, &new_flow->key, false, &mask);
        error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
                                  a[OVS_FLOW_ATTR_MASK], log);
        if (error)
                goto err_kfree_flow;
 
-       ovs_flow_mask_key(&new_flow->key, &key, true, &mask);
-
        /* Extract flow identifier. */
        error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],
-                                      &key, log);
+                                      &new_flow->key, log);
        if (error)
                goto err_kfree_flow;
 
+       /* unmasked key is needed to match when ufid is not used. */
+       if (ovs_identifier_is_key(&new_flow->id))
+               match.key = new_flow->id.unmasked_key;
+
+       ovs_flow_mask_key(&new_flow->key, &new_flow->key, true, &mask);
+
        /* Validate actions. */
        error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS],
                                     &new_flow->key, &acts, log);
@@ -1014,7 +995,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
        if (ovs_identifier_is_ufid(&new_flow->id))
                flow = ovs_flow_tbl_lookup_ufid(&dp->table, &new_flow->id);
        if (!flow)
-               flow = ovs_flow_tbl_lookup(&dp->table, &key);
+               flow = ovs_flow_tbl_lookup(&dp->table, &new_flow->key);
        if (likely(!flow)) {
                rcu_assign_pointer(new_flow->sf_acts, acts);
 
@@ -1098,7 +1079,7 @@ error:
 }
 
 /* Factor out action copy to avoid "Wframe-larger-than=1024" warning. */
-static struct sw_flow_actions *get_flow_actions(struct net *net,
+static noinline_for_stack struct sw_flow_actions *get_flow_actions(struct net *net,
                                                const struct nlattr *a,
                                                const struct sw_flow_key *key,
                                                const struct sw_flow_mask *mask,
@@ -1119,6 +1100,60 @@ static struct sw_flow_actions *get_flow_actions(struct net *net,
        return acts;
 }
 
+/* Factor out match-init and action-copy to avoid
+ * "Wframe-larger-than=1024" warning. Because mask is only
+ * used to get actions, we new a function to save some
+ * stack space.
+ *
+ * If there are not key and action attrs, we return 0
+ * directly. In the case, the caller will also not use the
+ * match as before. If there is action attr, we try to get
+ * actions and save them to *acts. Before returning from
+ * the function, we reset the match->mask pointer. Because
+ * we should not to return match object with dangling reference
+ * to mask.
+ * */
+static noinline_for_stack int
+ovs_nla_init_match_and_action(struct net *net,
+                             struct sw_flow_match *match,
+                             struct sw_flow_key *key,
+                             struct nlattr **a,
+                             struct sw_flow_actions **acts,
+                             bool log)
+{
+       struct sw_flow_mask mask;
+       int error = 0;
+
+       if (a[OVS_FLOW_ATTR_KEY]) {
+               ovs_match_init(match, key, true, &mask);
+               error = ovs_nla_get_match(net, match, a[OVS_FLOW_ATTR_KEY],
+                                         a[OVS_FLOW_ATTR_MASK], log);
+               if (error)
+                       goto error;
+       }
+
+       if (a[OVS_FLOW_ATTR_ACTIONS]) {
+               if (!a[OVS_FLOW_ATTR_KEY]) {
+                       OVS_NLERR(log,
+                                 "Flow key attribute not present in set flow.");
+                       error = -EINVAL;
+                       goto error;
+               }
+
+               *acts = get_flow_actions(net, a[OVS_FLOW_ATTR_ACTIONS], key,
+                                        &mask, log);
+               if (IS_ERR(*acts)) {
+                       error = PTR_ERR(*acts);
+                       goto error;
+               }
+       }
+
+       /* On success, error is 0. */
+error:
+       match->mask = NULL;
+       return error;
+}
+
 static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
 {
        struct net *net = sock_net(skb->sk);
@@ -1126,7 +1161,6 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
        struct ovs_header *ovs_header = info->userhdr;
        struct sw_flow_key key;
        struct sw_flow *flow;
-       struct sw_flow_mask mask;
        struct sk_buff *reply = NULL;
        struct datapath *dp;
        struct sw_flow_actions *old_acts = NULL, *acts = NULL;
@@ -1138,34 +1172,18 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
        bool ufid_present;
 
        ufid_present = ovs_nla_get_ufid(&sfid, a[OVS_FLOW_ATTR_UFID], log);
-       if (a[OVS_FLOW_ATTR_KEY]) {
-               ovs_match_init(&match, &key, &mask);
-               error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
-                                         a[OVS_FLOW_ATTR_MASK], log);
-       } else if (!ufid_present) {
+       if (!a[OVS_FLOW_ATTR_KEY] && !ufid_present) {
                OVS_NLERR(log,
                          "Flow set message rejected, Key attribute missing.");
-               error = -EINVAL;
+               return -EINVAL;
        }
+
+       error = ovs_nla_init_match_and_action(net, &match, &key, a,
+                                             &acts, log);
        if (error)
                goto error;
 
-       /* Validate actions. */
-       if (a[OVS_FLOW_ATTR_ACTIONS]) {
-               if (!a[OVS_FLOW_ATTR_KEY]) {
-                       OVS_NLERR(log,
-                                 "Flow key attribute not present in set flow.");
-                       error = -EINVAL;
-                       goto error;
-               }
-
-               acts = get_flow_actions(net, a[OVS_FLOW_ATTR_ACTIONS], &key,
-                                       &mask, log);
-               if (IS_ERR(acts)) {
-                       error = PTR_ERR(acts);
-                       goto error;
-               }
-
+       if (acts) {
                /* Can allocate before locking if have acts. */
                reply = ovs_flow_cmd_alloc_info(acts, &sfid, info, false,
                                                ufid_flags);
@@ -1201,14 +1219,14 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
                                                       ovs_header->dp_ifindex,
                                                       reply, info->snd_portid,
                                                       info->snd_seq, 0,
-                                                      OVS_FLOW_CMD_NEW,
+                                                      OVS_FLOW_CMD_SET,
                                                       ufid_flags);
                        BUG_ON(error < 0);
                }
        } else {
                /* Could not alloc without acts before locking. */
                reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex,
-                                               info, OVS_FLOW_CMD_NEW, false,
+                                               info, OVS_FLOW_CMD_SET, false,
                                                ufid_flags);
 
                if (unlikely(IS_ERR(reply))) {
@@ -1256,7 +1274,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
 
        ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log);
        if (a[OVS_FLOW_ATTR_KEY]) {
-               ovs_match_init(&match, &key, NULL);
+               ovs_match_init(&match, &key, true, NULL);
                err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY], NULL,
                                        log);
        } else if (!ufid_present) {
@@ -1284,7 +1302,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
        }
 
        reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, info,
-                                       OVS_FLOW_CMD_NEW, true, ufid_flags);
+                                       OVS_FLOW_CMD_GET, true, ufid_flags);
        if (IS_ERR(reply)) {
                err = PTR_ERR(reply);
                goto unlock;
@@ -1315,7 +1333,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
 
        ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log);
        if (a[OVS_FLOW_ATTR_KEY]) {
-               ovs_match_init(&match, &key, NULL);
+               ovs_match_init(&match, &key, true, NULL);
                err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
                                        NULL, log);
                if (unlikely(err))
@@ -1383,8 +1401,8 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
        u32 ufid_flags;
        int err;
 
-       err = genlmsg_parse(cb->nlh, &dp_flow_genl_family, a,
-                           OVS_FLOW_ATTR_MAX, flow_policy);
+       err = genlmsg_parse_deprecated(cb->nlh, &dp_flow_genl_family, a,
+                                      OVS_FLOW_ATTR_MAX, flow_policy, NULL);
        if (err)
                return err;
        ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
@@ -1410,7 +1428,7 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
                if (ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, skb,
                                           NETLINK_CB(cb->skb).portid,
                                           cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                                          OVS_FLOW_CMD_NEW, ufid_flags) < 0)
+                                          OVS_FLOW_CMD_GET, ufid_flags) < 0)
                        break;
 
                cb->args[0] = bucket;
@@ -1430,42 +1448,65 @@ static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = {
        [OVS_FLOW_ATTR_UFID_FLAGS] = { .type = NLA_U32 },
 };
 
-static struct genl_ops dp_flow_genl_ops[] = {
+static const struct genl_ops dp_flow_genl_ops[] = {
        { .cmd = OVS_FLOW_CMD_NEW,
+#ifdef HAVE_GENL_VALIDATE_FLAGS
+         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+#endif
          .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#ifdef HAVE_GENL_OPS_POLICY
          .policy = flow_policy,
+#endif
          .doit = ovs_flow_cmd_new
        },
        { .cmd = OVS_FLOW_CMD_DEL,
+#ifdef HAVE_GENL_VALIDATE_FLAGS
+         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+#endif
          .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#ifdef HAVE_GENL_OPS_POLICY
          .policy = flow_policy,
+#endif
          .doit = ovs_flow_cmd_del
        },
        { .cmd = OVS_FLOW_CMD_GET,
+#ifdef HAVE_GENL_VALIDATE_FLAGS
+         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+#endif
          .flags = 0,               /* OK for unprivileged users. */
+#ifdef HAVE_GENL_OPS_POLICY
          .policy = flow_policy,
+#endif
          .doit = ovs_flow_cmd_get,
          .dumpit = ovs_flow_cmd_dump
        },
        { .cmd = OVS_FLOW_CMD_SET,
+#ifdef HAVE_GENL_VALIDATE_FLAGS
+         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+#endif
          .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#ifdef HAVE_GENL_OPS_POLICY
          .policy = flow_policy,
+#endif
          .doit = ovs_flow_cmd_set,
        },
 };
 
-static struct genl_family dp_flow_genl_family = {
-       .id = GENL_ID_GENERATE,
+static struct genl_family dp_flow_genl_family __ro_after_init = {
        .hdrsize = sizeof(struct ovs_header),
        .name = OVS_FLOW_FAMILY,
        .version = OVS_FLOW_VERSION,
        .maxattr = OVS_FLOW_ATTR_MAX,
+#ifndef HAVE_GENL_OPS_POLICY
+       .policy = flow_policy,
+#endif
        .netnsok = true,
        .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,
+       .module = THIS_MODULE,
 };
 
 static size_t ovs_dp_cmd_msg_size(void)
@@ -1522,9 +1563,9 @@ error:
        return -EMSGSIZE;
 }
 
-static struct sk_buff *ovs_dp_cmd_alloc_info(struct genl_info *info)
+static struct sk_buff *ovs_dp_cmd_alloc_info(void)
 {
-       return genlmsg_new_unicast(ovs_dp_cmd_msg_size(), info, GFP_KERNEL);
+       return genlmsg_new(ovs_dp_cmd_msg_size(), GFP_KERNEL);
 }
 
 /* Called with rcu_read_lock or ovs_mutex. */
@@ -1577,7 +1618,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
        if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID])
                goto err;
 
-       reply = ovs_dp_cmd_alloc_info(info);
+       reply = ovs_dp_cmd_alloc_info();
        if (!reply)
                return -ENOMEM;
 
@@ -1599,8 +1640,9 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
                goto err_destroy_table;
        }
 
-       dp->ports = kmalloc(DP_VPORT_HASH_BUCKETS * sizeof(struct hlist_head),
-                           GFP_KERNEL);
+       dp->ports = kmalloc_array(DP_VPORT_HASH_BUCKETS,
+                                 sizeof(struct hlist_head),
+                                 GFP_KERNEL);
        if (!dp->ports) {
                err = -ENOMEM;
                goto err_destroy_percpu;
@@ -1609,6 +1651,10 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
        for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++)
                INIT_HLIST_HEAD(&dp->ports[i]);
 
+       err = ovs_meters_init(dp);
+       if (err)
+               goto err_destroy_ports_array;
+
        /* Set up our datapath device. */
        parms.name = nla_data(a[OVS_DP_ATTR_NAME]);
        parms.type = OVS_VPORT_TYPE_INTERNAL;
@@ -1637,7 +1683,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
                                ovs_dp_reset_user_features(skb, info);
                }
 
-               goto err_destroy_ports_array;
+               goto err_destroy_meters;
        }
 
        err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
@@ -1652,8 +1698,10 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
        ovs_notify(&dp_datapath_genl_family, &ovs_dp_datapath_multicast_group, reply, info);
        return 0;
 
-err_destroy_ports_array:
+err_destroy_meters:
        ovs_unlock();
+       ovs_meters_exit(dp);
+err_destroy_ports_array:
        kfree(dp->ports);
 err_destroy_percpu:
        free_percpu(dp->stats_percpu);
@@ -1698,7 +1746,7 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        int err;
 
-       reply = ovs_dp_cmd_alloc_info(info);
+       reply = ovs_dp_cmd_alloc_info();
        if (!reply)
                return -ENOMEM;
 
@@ -1730,7 +1778,7 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        int err;
 
-       reply = ovs_dp_cmd_alloc_info(info);
+       reply = ovs_dp_cmd_alloc_info();
        if (!reply)
                return -ENOMEM;
 
@@ -1743,7 +1791,7 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
        ovs_dp_change(dp, info->attrs);
 
        err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
-                                  info->snd_seq, 0, OVS_DP_CMD_NEW);
+                                  info->snd_seq, 0, OVS_DP_CMD_GET);
        BUG_ON(err < 0);
 
        ovs_unlock();
@@ -1763,7 +1811,7 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        int err;
 
-       reply = ovs_dp_cmd_alloc_info(info);
+       reply = ovs_dp_cmd_alloc_info();
        if (!reply)
                return -ENOMEM;
 
@@ -1774,7 +1822,7 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
                goto err_unlock_free;
        }
        err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
-                                  info->snd_seq, 0, OVS_DP_CMD_NEW);
+                                  info->snd_seq, 0, OVS_DP_CMD_GET);
        BUG_ON(err < 0);
        ovs_unlock();
 
@@ -1798,7 +1846,7 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
                if (i >= skip &&
                    ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).portid,
                                         cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                                        OVS_DP_CMD_NEW) < 0)
+                                        OVS_DP_CMD_GET) < 0)
                        break;
                i++;
        }
@@ -1815,47 +1863,71 @@ static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = {
        [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 },
 };
 
-static struct genl_ops dp_datapath_genl_ops[] = {
+static const struct genl_ops dp_datapath_genl_ops[] = {
        { .cmd = OVS_DP_CMD_NEW,
+#ifdef HAVE_GENL_VALIDATE_FLAGS
+         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+#endif
          .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#ifdef HAVE_GENL_OPS_POLICY
          .policy = datapath_policy,
+#endif
          .doit = ovs_dp_cmd_new
        },
        { .cmd = OVS_DP_CMD_DEL,
+#ifdef HAVE_GENL_VALIDATE_FLAGS
+         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+#endif
          .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#ifdef HAVE_GENL_OPS_POLICY
          .policy = datapath_policy,
+#endif
          .doit = ovs_dp_cmd_del
        },
        { .cmd = OVS_DP_CMD_GET,
+#ifdef HAVE_GENL_VALIDATE_FLAGS
+         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+#endif
          .flags = 0,               /* OK for unprivileged users. */
+#ifdef HAVE_GENL_OPS_POLICY
          .policy = datapath_policy,
+#endif
          .doit = ovs_dp_cmd_get,
          .dumpit = ovs_dp_cmd_dump
        },
        { .cmd = OVS_DP_CMD_SET,
+#ifdef HAVE_GENL_VALIDATE_FLAGS
+         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+#endif
          .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#ifdef HAVE_GENL_OPS_POLICY
          .policy = datapath_policy,
+#endif
          .doit = ovs_dp_cmd_set,
        },
 };
 
-static struct genl_family dp_datapath_genl_family = {
-       .id = GENL_ID_GENERATE,
+static struct genl_family dp_datapath_genl_family __ro_after_init = {
        .hdrsize = sizeof(struct ovs_header),
        .name = OVS_DATAPATH_FAMILY,
        .version = OVS_DATAPATH_VERSION,
        .maxattr = OVS_DP_ATTR_MAX,
+#ifndef HAVE_GENL_OPS_POLICY
+       .policy = datapath_policy,
+#endif
        .netnsok = true,
        .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,
+       .module = THIS_MODULE,
 };
 
 /* Called with ovs_mutex or RCU read lock. */
 static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
-                                  u32 portid, u32 seq, u32 flags, u8 cmd)
+                                  struct net *net, u32 portid, u32 seq,
+                                  u32 flags, u8 cmd)
 {
        struct ovs_header *ovs_header;
        struct ovs_vport_stats vport_stats;
@@ -1871,9 +1943,19 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
        if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) ||
            nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) ||
            nla_put_string(skb, OVS_VPORT_ATTR_NAME,
-                          ovs_vport_name(vport)))
+                          ovs_vport_name(vport)) ||
+           nla_put_u32(skb, OVS_VPORT_ATTR_IFINDEX, vport->dev->ifindex))
                goto nla_put_failure;
 
+#ifdef HAVE_PEERNET2ID_ALLOC
+       if (!net_eq(net, dev_net(vport->dev))) {
+               int id = peernet2id_alloc(net, dev_net(vport->dev));
+
+               if (nla_put_s32(skb, OVS_VPORT_ATTR_NETNSID, id))
+                       goto nla_put_failure;
+       }
+
+#endif
        ovs_vport_get_stats(vport, &vport_stats);
        if (nla_put_64bit(skb, OVS_VPORT_ATTR_STATS,
                          sizeof(struct ovs_vport_stats), &vport_stats,
@@ -1903,8 +1985,8 @@ static struct sk_buff *ovs_vport_cmd_alloc_info(void)
 }
 
 /* Called with ovs_mutex, only via ovs_dp_notify_wq(). */
-struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid,
-                                        u32 seq, u8 cmd)
+struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net,
+                                        u32 portid, u32 seq, u8 cmd)
 {
        struct sk_buff *skb;
        int retval;
@@ -1913,7 +1995,7 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid,
        if (!skb)
                return ERR_PTR(-ENOMEM);
 
-       retval = ovs_vport_cmd_fill_info(vport, skb, portid, seq, 0, cmd);
+       retval = ovs_vport_cmd_fill_info(vport, skb, net, portid, seq, 0, cmd);
        BUG_ON(retval < 0);
 
        return skb;
@@ -1927,6 +2009,8 @@ static struct vport *lookup_vport(struct net *net,
        struct datapath *dp;
        struct vport *vport;
 
+       if (a[OVS_VPORT_ATTR_IFINDEX])
+               return ERR_PTR(-EOPNOTSUPP);
        if (a[OVS_VPORT_ATTR_NAME]) {
                vport = ovs_vport_locate(net, nla_data(a[OVS_VPORT_ATTR_NAME]));
                if (!vport)
@@ -1951,6 +2035,7 @@ static struct vport *lookup_vport(struct net *net,
                return vport;
        } else
                return ERR_PTR(-EINVAL);
+
 }
 
 /* Called with ovs_mutex */
@@ -1990,6 +2075,8 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
        if (!a[OVS_VPORT_ATTR_NAME] || !a[OVS_VPORT_ATTR_TYPE] ||
            !a[OVS_VPORT_ATTR_UPCALL_PID])
                return -EINVAL;
+       if (a[OVS_VPORT_ATTR_IFINDEX])
+               return -EOPNOTSUPP;
 
        port_no = a[OVS_VPORT_ATTR_PORT_NO]
                ? nla_get_u32(a[OVS_VPORT_ATTR_PORT_NO]) : 0;
@@ -2039,8 +2126,9 @@ restart:
                goto exit_unlock_free;
        }
 
-       err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
-                                     info->snd_seq, 0, OVS_VPORT_CMD_NEW);
+       err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
+                                     info->snd_portid, info->snd_seq, 0,
+                                     OVS_VPORT_CMD_NEW);
        BUG_ON(err < 0);
 
        if (netdev_get_fwd_headroom(vport->dev) > dp->max_headroom)
@@ -2096,8 +2184,9 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
                        goto exit_unlock_free;
        }
 
-       err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
-                                     info->snd_seq, 0, OVS_VPORT_CMD_NEW);
+       err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
+                                     info->snd_portid, info->snd_seq, 0,
+                                     OVS_VPORT_CMD_SET);
        BUG_ON(err < 0);
        ovs_unlock();
 
@@ -2134,8 +2223,9 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
                goto exit_unlock_free;
        }
 
-       err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
-                                     info->snd_seq, 0, OVS_VPORT_CMD_DEL);
+       err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
+                                     info->snd_portid, info->snd_seq, 0,
+                                     OVS_VPORT_CMD_DEL);
        BUG_ON(err < 0);
 
        /* the vport deletion may trigger dp headroom update */
@@ -2176,8 +2266,9 @@ static int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info)
        err = PTR_ERR(vport);
        if (IS_ERR(vport))
                goto exit_unlock_free;
-       err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
-                                     info->snd_seq, 0, OVS_VPORT_CMD_NEW);
+       err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
+                                     info->snd_portid, info->snd_seq, 0,
+                                     OVS_VPORT_CMD_GET);
        BUG_ON(err < 0);
        rcu_read_unlock();
 
@@ -2209,10 +2300,11 @@ static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
                hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) {
                        if (j >= skip &&
                            ovs_vport_cmd_fill_info(vport, skb,
+                                                   sock_net(skb->sk),
                                                    NETLINK_CB(cb->skb).portid,
                                                    cb->nlh->nlmsg_seq,
                                                    NLM_F_MULTI,
-                                                   OVS_VPORT_CMD_NEW) < 0)
+                                                   OVS_VPORT_CMD_GET) < 0)
                                goto out;
 
                        j++;
@@ -2233,46 +2325,71 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 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_UPCALL_PID] = { .type = NLA_UNSPEC },
        [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED },
+       [OVS_VPORT_ATTR_IFINDEX] = { .type = NLA_U32 },
+       [OVS_VPORT_ATTR_NETNSID] = { .type = NLA_S32 },
 };
 
-static struct genl_ops dp_vport_genl_ops[] = {
+static const struct genl_ops dp_vport_genl_ops[] = {
        { .cmd = OVS_VPORT_CMD_NEW,
+#ifdef HAVE_GENL_VALIDATE_FLAGS
+         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+#endif
          .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#ifdef HAVE_GENL_OPS_POLICY
          .policy = vport_policy,
+#endif
          .doit = ovs_vport_cmd_new
        },
        { .cmd = OVS_VPORT_CMD_DEL,
+#ifdef HAVE_GENL_VALIDATE_FLAGS
+         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+#endif
          .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#ifdef HAVE_GENL_OPS_POLICY
          .policy = vport_policy,
+#endif
          .doit = ovs_vport_cmd_del
        },
        { .cmd = OVS_VPORT_CMD_GET,
+#ifdef HAVE_GENL_VALIDATE_FLAGS
+         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+#endif
          .flags = 0,               /* OK for unprivileged users. */
+#ifdef HAVE_GENL_OPS_POLICY
          .policy = vport_policy,
+#endif
          .doit = ovs_vport_cmd_get,
          .dumpit = ovs_vport_cmd_dump
        },
        { .cmd = OVS_VPORT_CMD_SET,
+#ifdef HAVE_GENL_VALIDATE_FLAGS
+         .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+#endif
          .flags = GENL_UNS_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#ifdef HAVE_GENL_OPS_POLICY
          .policy = vport_policy,
+#endif
          .doit = ovs_vport_cmd_set,
        },
 };
 
-struct genl_family dp_vport_genl_family = {
-       .id = GENL_ID_GENERATE,
+struct genl_family dp_vport_genl_family __ro_after_init = {
        .hdrsize = sizeof(struct ovs_header),
        .name = OVS_VPORT_FAMILY,
        .version = OVS_VPORT_VERSION,
        .maxattr = OVS_VPORT_ATTR_MAX,
+#ifndef HAVE_GENL_OPS_POLICY
+       .policy = vport_policy,
+#endif
        .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,
+       .module = THIS_MODULE,
 };
 
 static struct genl_family *dp_genl_families[] = {
@@ -2280,6 +2397,10 @@ static struct genl_family *dp_genl_families[] = {
        &dp_vport_genl_family,
        &dp_flow_genl_family,
        &dp_packet_genl_family,
+       &dp_meter_genl_family,
+#if    IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT)
+       &dp_ct_limit_genl_family,
+#endif
 };
 
 static void dp_unregister_genl(int n_families)
@@ -2290,7 +2411,7 @@ static void dp_unregister_genl(int n_families)
                genl_unregister_family(dp_genl_families[i]);
 }
 
-static int dp_register_genl(void)
+static int __init dp_register_genl(void)
 {
        int err;
        int i;
@@ -2315,8 +2436,9 @@ static int __net_init ovs_init_net(struct net *net)
 
        INIT_LIST_HEAD(&ovs_net->dps);
        INIT_WORK(&ovs_net->dp_notify_work, ovs_dp_notify_wq);
-       ovs_ct_init(net);
-       return 0;
+       ovs_netns_frags_init(net);
+       ovs_netns_frags6_init(net);
+       return ovs_ct_init(net);
 }
 
 static void __net_exit list_vports_from_net(struct net *net, struct net *dnet,
@@ -2351,15 +2473,25 @@ static void __net_exit ovs_exit_net(struct net *dnet)
        struct net *net;
        LIST_HEAD(head);
 
+       ovs_netns_frags6_exit(dnet);
+       ovs_netns_frags_exit(dnet);
        ovs_ct_exit(dnet);
        ovs_lock();
        list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node)
                __dp_destroy(dp);
 
+#ifdef HAVE_NET_RWSEM
+       down_read(&net_rwsem);
+#else
        rtnl_lock();
+#endif
        for_each_net(net)
                list_vports_from_net(net, dnet, &head);
+#ifdef HAVE_NET_RWSEM
+       up_read(&net_rwsem);
+#else
        rtnl_unlock();
+#endif
 
        /* Detach all vports from given namespace. */
        list_for_each_entry_safe(vport, vport_next, &head, detach_list) {
@@ -2383,17 +2515,14 @@ static int __init dp_init(void)
 {
        int err;
 
-       BUILD_BUG_ON(sizeof(struct ovs_skb_cb) > FIELD_SIZEOF(struct sk_buff, cb));
+       BUILD_BUG_ON(sizeof(struct ovs_skb_cb) > sizeof_field(struct sk_buff, cb));
 
        pr_info("Open vSwitch switching datapath %s\n", VERSION);
 
-       err = compat_init();
-       if (err)
-               goto error;
-
+       ovs_nsh_init();
        err = action_fifos_init();
        if (err)
-               goto error_compat_exit;
+               goto error;
 
        err = ovs_internal_dev_rtnl_link_register();
        if (err)
@@ -2411,10 +2540,14 @@ static int __init dp_init(void)
        if (err)
                goto error_vport_exit;
 
-       err = register_netdevice_notifier(&ovs_dp_device_notifier);
+       err = compat_init();
        if (err)
                goto error_netns_exit;
 
+       err = register_netdevice_notifier(&ovs_dp_device_notifier);
+       if (err)
+               goto error_compat_exit;
+
        err = ovs_netdev_init();
        if (err)
                goto error_unreg_notifier;
@@ -2429,6 +2562,8 @@ error_unreg_netdev:
        ovs_netdev_exit();
 error_unreg_notifier:
        unregister_netdevice_notifier(&ovs_dp_device_notifier);
+error_compat_exit:
+       compat_exit();
 error_netns_exit:
        unregister_pernet_device(&ovs_net_ops);
 error_vport_exit:
@@ -2439,9 +2574,8 @@ error_unreg_rtnl_link:
        ovs_internal_dev_rtnl_link_unregister();
 error_action_fifos_exit:
        action_fifos_exit();
-error_compat_exit:
-       compat_exit();
 error:
+       ovs_nsh_cleanup();
        return err;
 }
 
@@ -2450,13 +2584,14 @@ static void dp_cleanup(void)
        dp_unregister_genl(ARRAY_SIZE(dp_genl_families));
        ovs_netdev_exit();
        unregister_netdevice_notifier(&ovs_dp_device_notifier);
+       compat_exit();
        unregister_pernet_device(&ovs_net_ops);
        rcu_barrier();
        ovs_vport_exit();
        ovs_flow_exit();
        ovs_internal_dev_rtnl_link_unregister();
        action_fifos_exit();
-       compat_exit();
+       ovs_nsh_cleanup();
 }
 
 module_init(dp_init);
@@ -2465,3 +2600,9 @@ module_exit(dp_cleanup);
 MODULE_DESCRIPTION("Open vSwitch switching datapath");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(VERSION);
+MODULE_ALIAS_GENL_FAMILY(OVS_DATAPATH_FAMILY);
+MODULE_ALIAS_GENL_FAMILY(OVS_VPORT_FAMILY);
+MODULE_ALIAS_GENL_FAMILY(OVS_FLOW_FAMILY);
+MODULE_ALIAS_GENL_FAMILY(OVS_PACKET_FAMILY);
+MODULE_ALIAS_GENL_FAMILY(OVS_METER_FAMILY);
+MODULE_ALIAS_GENL_FAMILY(OVS_CT_LIMIT_FAMILY);