]> git.proxmox.com Git - mirror_ovs.git/blobdiff - datapath/datapath.c
compat: Use nla_parse deprecated functions
[mirror_ovs.git] / datapath / datapath.c
index 32644453fd5fbbe241e05b05553a0619d38029b4..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 "vlan.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,44 +137,16 @@ 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 *,
                             const struct sw_flow_key *,
-                            const struct dp_upcall_info *);
+                            const struct dp_upcall_info *,
+                            uint32_t cutlen);
 static int queue_userspace_packet(struct datapath *dp, struct sk_buff *,
                                  const struct sw_flow_key *,
-                                 const struct dp_upcall_info *);
-
-/* 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;
-}
+                                 const struct dp_upcall_info *,
+                                 uint32_t cutlen);
 
 /* Must be called with rcu_read_lock or ovs_mutex. */
 const char *ovs_dp_name(const struct datapath *dp)
@@ -207,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);
 }
 
@@ -280,7 +254,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
                upcall.cmd = OVS_PACKET_CMD_MISS;
                upcall.portid = ovs_vport_find_upcall_portid(p, skb);
                upcall.mru = OVS_CB(skb)->mru;
-               error = ovs_dp_upcall(dp, skb, key, &upcall);
+               error = ovs_dp_upcall(dp, skb, key, &upcall, 0);
                if (unlikely(error))
                        kfree_skb(skb);
                else
@@ -305,7 +279,8 @@ out:
 
 int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
                  const struct sw_flow_key *key,
-                 const struct dp_upcall_info *upcall_info)
+                 const struct dp_upcall_info *upcall_info,
+                 uint32_t cutlen)
 {
        struct dp_stats_percpu *stats;
        int err;
@@ -316,9 +291,9 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
        }
 
        if (!skb_is_gso(skb))
-               err = queue_userspace_packet(dp, skb, key, upcall_info);
+               err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen);
        else
-               err = queue_gso_packets(dp, skb, key, upcall_info);
+               err = queue_gso_packets(dp, skb, key, upcall_info, cutlen);
        if (err)
                goto err;
 
@@ -336,10 +311,13 @@ err:
 
 static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
                             const struct sw_flow_key *key,
-                            const struct dp_upcall_info *upcall_info)
+                            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;
@@ -351,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
@@ -360,15 +338,16 @@ 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;
-
-               err = queue_userspace_packet(dp, skb, key, upcall_info);
+#endif
+               err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen);
                if (err)
                        break;
 
@@ -387,11 +366,12 @@ 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 */
-               + nla_total_size(ovs_key_attr_size()); /* OVS_PACKET_ATTR_KEY */
+               + nla_total_size(ovs_key_attr_size()) /* OVS_PACKET_ATTR_KEY */
+               + nla_total_size(sizeof(unsigned int)); /* OVS_PACKET_ATTR_LEN */
 
        /* OVS_PACKET_ATTR_USERDATA */
        if (upcall_info->userdata)
@@ -403,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)
@@ -418,24 +398,19 @@ 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);
        }
 }
 
 static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
                                  const struct sw_flow_key *key,
-                                 const struct dp_upcall_info *upcall_info)
+                                 const struct dp_upcall_info *upcall_info,
+                                 uint32_t cutlen)
 {
        struct ovs_header *upcall;
        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;
@@ -449,12 +424,10 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
                if (!nskb)
                        return -ENOMEM;
 
-               nskb = vlan_insert_tag_set_proto(nskb, nskb->vlan_proto, skb_vlan_tag_get(nskb));
+               nskb = __vlan_hwaccel_push_inside(nskb);
                if (!nskb)
                        return -ENOMEM;
 
-               vlan_set_tci(nskb, 0);
-
                skb = nskb;
        }
 
@@ -465,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
@@ -477,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);
-       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;
@@ -486,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);
@@ -498,16 +476,24 @@ 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);
-               err = ovs_nla_put_egress_tunnel_key(user_skb,
-                                                   upcall_info->egress_tun_info,
-                                                   upcall_info->egress_tun_opts);
+               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);
                nla_nest_end(user_skb, nla);
        }
 
        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);
@@ -527,6 +513,16 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
                pad_packet(dp, user_skb);
        }
 
+       /* Add OVS_PACKET_ATTR_LEN when packet is truncated */
+       if (cutlen > 0) {
+               if (nla_put_u32(user_skb, OVS_PACKET_ATTR_LEN,
+                               skb->len)) {
+                       err = -ENOBUFS;
+                       goto out;
+               }
+               pad_packet(dp, user_skb);
+       }
+
        /* Only reserve room for attribute header, packet data is added
         * in skb_zerocopy()
         */
@@ -534,9 +530,9 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
                err = -ENOBUFS;
                goto out;
        }
-       nla->nla_len = nla_attr_size(skb->len);
+       nla->nla_len = nla_attr_size(skb->len - cutlen);
 
-       err = skb_zerocopy(user_skb, skb, skb->len, hlen);
+       err = skb_zerocopy(user_skb, skb, skb->len - cutlen, hlen);
        if (err)
                goto out;
 
@@ -565,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;
@@ -586,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]);
@@ -611,8 +594,8 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        if (IS_ERR(flow))
                goto err_kfree_skb;
 
-       err = ovs_flow_key_extract_userspace(a[OVS_PACKET_ATTR_KEY], packet,
-                                            &flow->key, log);
+       err = ovs_flow_key_extract_userspace(net, a[OVS_PACKET_ATTR_KEY],
+                                            packet, &flow->key, log);
        if (err)
                goto err_flow_free;
 
@@ -670,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,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#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,
@@ -758,9 +749,9 @@ static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts,
                len += nla_total_size(acts->orig_len);
 
        return len
-               + nla_total_size(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */
+               + nla_total_size_64bit(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */
                + nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */
-               + nla_total_size(8); /* OVS_FLOW_ATTR_USED */
+               + nla_total_size_64bit(8); /* OVS_FLOW_ATTR_USED */
 }
 
 /* Called with ovs_mutex or RCU read lock. */
@@ -774,11 +765,14 @@ static int ovs_flow_cmd_fill_stats(const struct sw_flow *flow,
        ovs_flow_stats_get(flow, &stats, &used, &tcp_flags);
 
        if (used &&
-           nla_put_u64(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used)))
+           nla_put_u64_64bit(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used),
+                             OVS_FLOW_ATTR_PAD))
                return -EMSGSIZE;
 
        if (stats.n_packets &&
-           nla_put(skb, OVS_FLOW_ATTR_STATS, sizeof(struct ovs_flow_stats), &stats))
+           nla_put_64bit(skb, OVS_FLOW_ATTR_STATS,
+                         sizeof(struct ovs_flow_stats), &stats,
+                         OVS_FLOW_ATTR_PAD))
                return -EMSGSIZE;
 
        if ((u8)ntohs(tcp_flags) &&
@@ -805,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;
 
@@ -893,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);
 
@@ -930,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]);
@@ -958,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);
-       error = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY],
+       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);
@@ -998,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);
 
@@ -1082,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,
@@ -1103,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);
@@ -1110,40 +1161,29 @@ 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;
        struct sw_flow_match match;
        struct sw_flow_id sfid;
        u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
-       int error;
+       int error = 0;
        bool log = !a[OVS_FLOW_ATTR_PROBE];
        bool ufid_present;
 
-       /* Extract key. */
-       error = -EINVAL;
-       if (!a[OVS_FLOW_ATTR_KEY]) {
-               OVS_NLERR(log, "Flow key attribute not present in set flow.");
-               goto error;
+       ufid_present = ovs_nla_get_ufid(&sfid, a[OVS_FLOW_ATTR_UFID], log);
+       if (!a[OVS_FLOW_ATTR_KEY] && !ufid_present) {
+               OVS_NLERR(log,
+                         "Flow set message rejected, Key attribute missing.");
+               return -EINVAL;
        }
 
-       ufid_present = ovs_nla_get_ufid(&sfid, a[OVS_FLOW_ATTR_UFID], log);
-       ovs_match_init(&match, &key, &mask);
-       error = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY],
-                                 a[OVS_FLOW_ATTR_MASK], log);
+       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]) {
-               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);
@@ -1179,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))) {
@@ -1220,6 +1260,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr **a = info->attrs;
        struct ovs_header *ovs_header = info->userhdr;
+       struct net *net = sock_net(skb->sk);
        struct sw_flow_key key;
        struct sk_buff *reply;
        struct sw_flow *flow;
@@ -1233,8 +1274,8 @@ 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);
-               err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_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) {
                OVS_NLERR(log,
@@ -1261,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;
@@ -1278,6 +1319,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr **a = info->attrs;
        struct ovs_header *ovs_header = info->userhdr;
+       struct net *net = sock_net(skb->sk);
        struct sw_flow_key key;
        struct sk_buff *reply;
        struct sw_flow *flow = NULL;
@@ -1291,9 +1333,9 @@ 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);
-               err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL,
-                                       log);
+               ovs_match_init(&match, &key, true, NULL);
+               err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
+                                       NULL, log);
                if (unlikely(err))
                        return err;
        }
@@ -1359,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]);
@@ -1386,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;
@@ -1406,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,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#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,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#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,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#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)
@@ -1449,8 +1514,8 @@ static size_t ovs_dp_cmd_msg_size(void)
        size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header));
 
        msgsize += nla_total_size(IFNAMSIZ);
-       msgsize += nla_total_size(sizeof(struct ovs_dp_stats));
-       msgsize += nla_total_size(sizeof(struct ovs_dp_megaflow_stats));
+       msgsize += nla_total_size_64bit(sizeof(struct ovs_dp_stats));
+       msgsize += nla_total_size_64bit(sizeof(struct ovs_dp_megaflow_stats));
        msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_USER_FEATURES */
 
        return msgsize;
@@ -1477,13 +1542,13 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb,
                goto nla_put_failure;
 
        get_dp_stats(dp, &dp_stats, &dp_megaflow_stats);
-       if (nla_put(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats),
-                       &dp_stats))
+       if (nla_put_64bit(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats),
+                         &dp_stats, OVS_DP_ATTR_PAD))
                goto nla_put_failure;
 
-       if (nla_put(skb, OVS_DP_ATTR_MEGAFLOW_STATS,
-                       sizeof(struct ovs_dp_megaflow_stats),
-                       &dp_megaflow_stats))
+       if (nla_put_64bit(skb, OVS_DP_ATTR_MEGAFLOW_STATS,
+                         sizeof(struct ovs_dp_megaflow_stats),
+                         &dp_megaflow_stats, OVS_DP_ATTR_PAD))
                goto nla_put_failure;
 
        if (nla_put_u32(skb, OVS_DP_ATTR_USER_FEATURES, dp->user_features))
@@ -1498,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. */
@@ -1553,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;
 
@@ -1575,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;
@@ -1585,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;
@@ -1613,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,
@@ -1628,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);
@@ -1674,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;
 
@@ -1706,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;
 
@@ -1719,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();
@@ -1739,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;
 
@@ -1750,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();
 
@@ -1774,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++;
        }
@@ -1791,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,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#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,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#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,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#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;
@@ -1847,12 +1943,23 @@ 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(skb, OVS_VPORT_ATTR_STATS, sizeof(struct ovs_vport_stats),
-                   &vport_stats))
+       if (nla_put_64bit(skb, OVS_VPORT_ATTR_STATS,
+                         sizeof(struct ovs_vport_stats), &vport_stats,
+                         OVS_VPORT_ATTR_PAD))
                goto nla_put_failure;
 
        if (ovs_vport_get_upcall_portids(vport, skb))
@@ -1878,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;
@@ -1888,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;
@@ -1902,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)
@@ -1926,6 +2035,30 @@ static struct vport *lookup_vport(struct net *net,
                return vport;
        } else
                return ERR_PTR(-EINVAL);
+
+}
+
+/* Called with ovs_mutex */
+static void update_headroom(struct datapath *dp)
+{
+       unsigned dev_headroom, max_headroom = 0;
+       struct net_device *dev;
+       struct vport *vport;
+       int i;
+
+       for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
+               hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) {
+                       dev = vport->dev;
+                       dev_headroom = netdev_get_fwd_headroom(dev);
+                       if (dev_headroom > max_headroom)
+                               max_headroom = dev_headroom;
+               }
+       }
+
+       dp->max_headroom = max_headroom;
+       for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++)
+               hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node)
+                       netdev_set_rx_headroom(vport->dev, max_headroom);
 }
 
 static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
@@ -1942,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;
@@ -1991,9 +2126,16 @@ 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)
+               update_headroom(dp);
+       else
+               netdev_set_rx_headroom(vport->dev, dp->max_headroom);
+
        ovs_unlock();
 
        ovs_notify(&dp_vport_genl_family, &ovs_dp_vport_multicast_group, reply, info);
@@ -2042,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();
 
@@ -2058,8 +2201,10 @@ exit_unlock_free:
 
 static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
 {
+       bool must_update_headroom = false;
        struct nlattr **a = info->attrs;
        struct sk_buff *reply;
+       struct datapath *dp;
        struct vport *vport;
        int err;
 
@@ -2078,10 +2223,21 @@ 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 */
+       dp = vport->dp;
+       if (netdev_get_fwd_headroom(vport->dev) == dp->max_headroom)
+               must_update_headroom = true;
+       netdev_reset_rx_headroom(vport->dev);
        ovs_dp_detach_port(vport);
+
+       if (must_update_headroom)
+               update_headroom(dp);
+
        ovs_unlock();
 
        ovs_notify(&dp_vport_genl_family, &ovs_dp_vport_multicast_group, reply, info);
@@ -2110,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();
 
@@ -2143,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++;
@@ -2167,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,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#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,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#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,
-         .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
+#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[] = {
@@ -2214,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)
@@ -2224,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;
@@ -2249,7 +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);
-       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,
@@ -2284,14 +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) {
@@ -2311,23 +2511,18 @@ static struct pernet_operations ovs_net_ops = {
        .size = sizeof(struct ovs_net),
 };
 
-DEFINE_COMPAT_PNET_REG_FUNC(device);
-
 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)
@@ -2345,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;
@@ -2363,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:
@@ -2373,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;
 }
 
@@ -2384,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);
@@ -2399,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);