commit:     774c18b6c2321e3e6969d0ce021d2ae461e350c6
Author:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
AuthorDate: Wed Dec 18 19:30:14 2019 +0000
Commit:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
CommitDate: Wed Dec 18 19:30:14 2019 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=774c18b6

Linux patch 5.4.5

Signed-off-by: Mike Pagano <mpagano <AT> gentoo.org>

 0000_README            |    4 +
 1004_linux-5.4.5.patch | 2510 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 2514 insertions(+)

diff --git a/0000_README b/0000_README
index d56f066..7a19811 100644
--- a/0000_README
+++ b/0000_README
@@ -59,6 +59,10 @@ Patch:  1003_linux-5.4.4.patch
 From:   http://www.kernel.org
 Desc:   Linux 5.4.4
 
+Patch:  1004_linux-5.4.5.patch
+From:   http://www.kernel.org
+Desc:   Linux 5.4.5
+
 Patch:  1500_XATTR_USER_PREFIX.patch
 From:   https://bugs.gentoo.org/show_bug.cgi?id=470644
 Desc:   Support for namespace user.pax.* on tmpfs.

diff --git a/1004_linux-5.4.5.patch b/1004_linux-5.4.5.patch
new file mode 100644
index 0000000..491146c
--- /dev/null
+++ b/1004_linux-5.4.5.patch
@@ -0,0 +1,2510 @@
+diff --git a/Makefile b/Makefile
+index 144daf02c78a..0f6e72d5e4f1 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 5
+ PATCHLEVEL = 4
+-SUBLEVEL = 4
++SUBLEVEL = 5
+ EXTRAVERSION =
+ NAME = Kleptomaniac Octopus
+ 
+diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
+index 6d7ec371e7b2..606fa6d86685 100644
+--- a/drivers/infiniband/core/addr.c
++++ b/drivers/infiniband/core/addr.c
+@@ -421,16 +421,15 @@ static int addr6_resolve(struct sockaddr *src_sock,
+                               (const struct sockaddr_in6 *)dst_sock;
+       struct flowi6 fl6;
+       struct dst_entry *dst;
+-      int ret;
+ 
+       memset(&fl6, 0, sizeof fl6);
+       fl6.daddr = dst_in->sin6_addr;
+       fl6.saddr = src_in->sin6_addr;
+       fl6.flowi6_oif = addr->bound_dev_if;
+ 
+-      ret = ipv6_stub->ipv6_dst_lookup(addr->net, NULL, &dst, &fl6);
+-      if (ret < 0)
+-              return ret;
++      dst = ipv6_stub->ipv6_dst_lookup_flow(addr->net, NULL, &fl6, NULL);
++      if (IS_ERR(dst))
++              return PTR_ERR(dst);
+ 
+       if (ipv6_addr_any(&src_in->sin6_addr))
+               src_in->sin6_addr = fl6.saddr;
+diff --git a/drivers/infiniband/sw/rxe/rxe_net.c 
b/drivers/infiniband/sw/rxe/rxe_net.c
+index 5a3474f9351b..312c2fc961c0 100644
+--- a/drivers/infiniband/sw/rxe/rxe_net.c
++++ b/drivers/infiniband/sw/rxe/rxe_net.c
+@@ -117,10 +117,12 @@ static struct dst_entry *rxe_find_route6(struct 
net_device *ndev,
+       memcpy(&fl6.daddr, daddr, sizeof(*daddr));
+       fl6.flowi6_proto = IPPROTO_UDP;
+ 
+-      if (unlikely(ipv6_stub->ipv6_dst_lookup(sock_net(recv_sockets.sk6->sk),
+-                                              recv_sockets.sk6->sk, &ndst, 
&fl6))) {
++      ndst = ipv6_stub->ipv6_dst_lookup_flow(sock_net(recv_sockets.sk6->sk),
++                                             recv_sockets.sk6->sk, &fl6,
++                                             NULL);
++      if (unlikely(IS_ERR(ndst))) {
+               pr_err_ratelimited("no route to %pI6\n", daddr);
+-              goto put;
++              return NULL;
+       }
+ 
+       if (unlikely(ndst->error)) {
+diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c 
b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+index acb016834f04..6cc100e7d5c0 100644
+--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
++++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+@@ -1115,7 +1115,7 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid)
+                                      phy_interface_mode(lmac->lmac_type)))
+                       return -ENODEV;
+ 
+-              phy_start_aneg(lmac->phydev);
++              phy_start(lmac->phydev);
+               return 0;
+       }
+ 
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h 
b/drivers/net/ethernet/mellanox/mlx5/core/en.h
+index f1a7bc46f1c0..2c16add0b642 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
+@@ -816,7 +816,7 @@ struct mlx5e_xsk {
+ struct mlx5e_priv {
+       /* priv data path fields - start */
+       struct mlx5e_txqsq *txq2sq[MLX5E_MAX_NUM_CHANNELS * MLX5E_MAX_NUM_TC];
+-      int channel_tc2txq[MLX5E_MAX_NUM_CHANNELS][MLX5E_MAX_NUM_TC];
++      int channel_tc2realtxq[MLX5E_MAX_NUM_CHANNELS][MLX5E_MAX_NUM_TC];
+ #ifdef CONFIG_MLX5_CORE_EN_DCB
+       struct mlx5e_dcbx_dp       dcbx_dp;
+ #endif
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
+index f777994f3005..fce6eccdcf8b 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port.c
+@@ -73,6 +73,7 @@ static const u32 
mlx5e_ext_link_speed[MLX5E_EXT_LINK_MODES_NUMBER] = {
+       [MLX5E_50GAUI_2_LAUI_2_50GBASE_CR2_KR2] = 50000,
+       [MLX5E_50GAUI_1_LAUI_1_50GBASE_CR_KR]   = 50000,
+       [MLX5E_CAUI_4_100GBASE_CR4_KR4]         = 100000,
++      [MLX5E_100GAUI_2_100GBASE_CR2_KR2]      = 100000,
+       [MLX5E_200GAUI_4_200GBASE_CR4_KR4]      = 200000,
+       [MLX5E_400GAUI_8]                       = 400000,
+ };
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c
+index 633b117eb13e..99c7cdd0404a 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c
+@@ -155,8 +155,11 @@ static int update_xoff_threshold(struct mlx5e_port_buffer 
*port_buffer,
+               }
+ 
+               if (port_buffer->buffer[i].size <
+-                  (xoff + max_mtu + (1 << MLX5E_BUFFER_CELL_SHIFT)))
++                  (xoff + max_mtu + (1 << MLX5E_BUFFER_CELL_SHIFT))) {
++                      pr_err("buffer_size[%d]=%d is not enough for lossless 
buffer\n",
++                             i, port_buffer->buffer[i].size);
+                       return -ENOMEM;
++              }
+ 
+               port_buffer->buffer[i].xoff = port_buffer->buffer[i].size - 
xoff;
+               port_buffer->buffer[i].xon  =
+@@ -232,6 +235,26 @@ static int update_buffer_lossy(unsigned int max_mtu,
+       return 0;
+ }
+ 
++static int fill_pfc_en(struct mlx5_core_dev *mdev, u8 *pfc_en)
++{
++      u32 g_rx_pause, g_tx_pause;
++      int err;
++
++      err = mlx5_query_port_pause(mdev, &g_rx_pause, &g_tx_pause);
++      if (err)
++              return err;
++
++      /* If global pause enabled, set all active buffers to lossless.
++       * Otherwise, check PFC setting.
++       */
++      if (g_rx_pause || g_tx_pause)
++              *pfc_en = 0xff;
++      else
++              err = mlx5_query_port_pfc(mdev, pfc_en, NULL);
++
++      return err;
++}
++
+ #define MINIMUM_MAX_MTU 9216
+ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv,
+                                   u32 change, unsigned int mtu,
+@@ -277,7 +300,7 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv 
*priv,
+ 
+       if (change & MLX5E_PORT_BUFFER_PRIO2BUFFER) {
+               update_prio2buffer = true;
+-              err = mlx5_query_port_pfc(priv->mdev, &curr_pfc_en, NULL);
++              err = fill_pfc_en(priv->mdev, &curr_pfc_en);
+               if (err)
+                       return err;
+ 
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
+index 745ab6cd7c30..362f01bc8372 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
+@@ -144,10 +144,10 @@ static int mlx5e_route_lookup_ipv6(struct mlx5e_priv 
*priv,
+ #if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6)
+       int ret;
+ 
+-      ret = ipv6_stub->ipv6_dst_lookup(dev_net(mirred_dev), NULL, &dst,
+-                                       fl6);
+-      if (ret < 0)
+-              return ret;
++      dst = ipv6_stub->ipv6_dst_lookup_flow(dev_net(mirred_dev), NULL, fl6,
++                                            NULL);
++      if (IS_ERR(dst))
++              return PTR_ERR(dst);
+ 
+       if (!(*out_ttl))
+               *out_ttl = ip6_dst_hoplimit(dst);
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+index 95601269fa2e..c6776f308d5e 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+@@ -1027,18 +1027,11 @@ static bool ext_link_mode_requested(const unsigned 
long *adver)
+       return bitmap_intersects(modes, adver, __ETHTOOL_LINK_MODE_MASK_NBITS);
+ }
+ 
+-static bool ext_speed_requested(u32 speed)
+-{
+-#define MLX5E_MAX_PTYS_LEGACY_SPEED 100000
+-      return !!(speed > MLX5E_MAX_PTYS_LEGACY_SPEED);
+-}
+-
+-static bool ext_requested(u8 autoneg, const unsigned long *adver, u32 speed)
++static bool ext_requested(u8 autoneg, const unsigned long *adver, bool 
ext_supported)
+ {
+       bool ext_link_mode = ext_link_mode_requested(adver);
+-      bool ext_speed = ext_speed_requested(speed);
+ 
+-      return  autoneg == AUTONEG_ENABLE ? ext_link_mode : ext_speed;
++      return  autoneg == AUTONEG_ENABLE ? ext_link_mode : ext_supported;
+ }
+ 
+ int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,
+@@ -1065,8 +1058,8 @@ int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv 
*priv,
+       autoneg = link_ksettings->base.autoneg;
+       speed = link_ksettings->base.speed;
+ 
+-      ext = ext_requested(autoneg, adver, speed),
+       ext_supported = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
++      ext = ext_requested(autoneg, adver, ext_supported);
+       if (!ext_supported && ext)
+               return -EOPNOTSUPP;
+ 
+@@ -1643,7 +1636,7 @@ static int mlx5e_get_module_info(struct net_device 
*netdev,
+               break;
+       case MLX5_MODULE_ID_SFP:
+               modinfo->type       = ETH_MODULE_SFF_8472;
+-              modinfo->eeprom_len = MLX5_EEPROM_PAGE_LENGTH;
++              modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+               break;
+       default:
+               netdev_err(priv->netdev, "%s: cable type not recognized:0x%x\n",
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index 2a56e66f58d8..6abd4ed5b69b 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -1693,11 +1693,10 @@ static int mlx5e_open_sqs(struct mlx5e_channel *c,
+                         struct mlx5e_params *params,
+                         struct mlx5e_channel_param *cparam)
+ {
+-      struct mlx5e_priv *priv = c->priv;
+       int err, tc;
+ 
+       for (tc = 0; tc < params->num_tc; tc++) {
+-              int txq_ix = c->ix + tc * priv->max_nch;
++              int txq_ix = c->ix + tc * params->num_channels;
+ 
+               err = mlx5e_open_txqsq(c, c->priv->tisn[c->lag_port][tc], 
txq_ix,
+                                      params, &cparam->sq, &c->sq[tc], tc);
+@@ -2878,26 +2877,21 @@ static void mlx5e_netdev_set_tcs(struct net_device 
*netdev)
+               netdev_set_tc_queue(netdev, tc, nch, 0);
+ }
+ 
+-static void mlx5e_build_tc2txq_maps(struct mlx5e_priv *priv)
++static void mlx5e_build_txq_maps(struct mlx5e_priv *priv)
+ {
+-      int i, tc;
++      int i, ch;
+ 
+-      for (i = 0; i < priv->max_nch; i++)
+-              for (tc = 0; tc < priv->profile->max_tc; tc++)
+-                      priv->channel_tc2txq[i][tc] = i + tc * priv->max_nch;
+-}
++      ch = priv->channels.num;
+ 
+-static void mlx5e_build_tx2sq_maps(struct mlx5e_priv *priv)
+-{
+-      struct mlx5e_channel *c;
+-      struct mlx5e_txqsq *sq;
+-      int i, tc;
++      for (i = 0; i < ch; i++) {
++              int tc;
++
++              for (tc = 0; tc < priv->channels.params.num_tc; tc++) {
++                      struct mlx5e_channel *c = priv->channels.c[i];
++                      struct mlx5e_txqsq *sq = &c->sq[tc];
+ 
+-      for (i = 0; i < priv->channels.num; i++) {
+-              c = priv->channels.c[i];
+-              for (tc = 0; tc < c->num_tc; tc++) {
+-                      sq = &c->sq[tc];
+                       priv->txq2sq[sq->txq_ix] = sq;
++                      priv->channel_tc2realtxq[i][tc] = i + tc * ch;
+               }
+       }
+ }
+@@ -2912,7 +2906,7 @@ void mlx5e_activate_priv_channels(struct mlx5e_priv 
*priv)
+       netif_set_real_num_tx_queues(netdev, num_txqs);
+       netif_set_real_num_rx_queues(netdev, num_rxqs);
+ 
+-      mlx5e_build_tx2sq_maps(priv);
++      mlx5e_build_txq_maps(priv);
+       mlx5e_activate_channels(&priv->channels);
+       mlx5e_xdp_tx_enable(priv);
+       netif_tx_start_all_queues(priv->netdev);
+@@ -5028,7 +5022,6 @@ static int mlx5e_nic_init(struct mlx5_core_dev *mdev,
+       if (err)
+               mlx5_core_err(mdev, "TLS initialization failed, %d\n", err);
+       mlx5e_build_nic_netdev(netdev);
+-      mlx5e_build_tc2txq_maps(priv);
+       mlx5e_health_create_reporters(priv);
+ 
+       return 0;
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
+index 7e6ebd0505cc..9f09253f9f46 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
+@@ -1601,7 +1601,7 @@ static int mlx5e_grp_channels_fill_strings(struct 
mlx5e_priv *priv, u8 *data,
+                       for (j = 0; j < NUM_SQ_STATS; j++)
+                               sprintf(data + (idx++) * ETH_GSTRING_LEN,
+                                       sq_stats_desc[j].format,
+-                                      priv->channel_tc2txq[i][tc]);
++                                      i + tc * max_nch);
+ 
+       for (i = 0; i < max_nch; i++) {
+               for (j = 0; j < NUM_XSKSQ_STATS * is_xsk; j++)
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+index f90a9f8e0fc6..c2c7f214a56a 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+@@ -1616,7 +1616,7 @@ static void __mlx5e_tc_del_fdb_peer_flow(struct 
mlx5e_tc_flow *flow)
+       flow_flag_clear(flow, DUP);
+ 
+       mlx5e_tc_del_fdb_flow(flow->peer_flow->priv, flow->peer_flow);
+-      kvfree(flow->peer_flow);
++      kfree(flow->peer_flow);
+       flow->peer_flow = NULL;
+ }
+ 
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c 
b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+index 67dc4f0921b6..dee12f17f9c2 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+@@ -93,7 +93,7 @@ u16 mlx5e_select_queue(struct net_device *dev, struct 
sk_buff *skb,
+       if (txq_ix >= num_channels)
+               txq_ix = priv->txq2sq[txq_ix]->ch_ix;
+ 
+-      return priv->channel_tc2txq[txq_ix][up];
++      return priv->channel_tc2realtxq[txq_ix][up];
+ }
+ 
+ static inline int mlx5e_skb_l2_header_offset(struct sk_buff *skb)
+diff --git a/drivers/net/ethernet/mscc/ocelot.c 
b/drivers/net/ethernet/mscc/ocelot.c
+index 672ea1342add..da1fd0e08c36 100644
+--- a/drivers/net/ethernet/mscc/ocelot.c
++++ b/drivers/net/ethernet/mscc/ocelot.c
+@@ -1979,14 +1979,18 @@ static struct ptp_clock_info ocelot_ptp_clock_info = {
+ 
+ static int ocelot_init_timestamp(struct ocelot *ocelot)
+ {
++      struct ptp_clock *ptp_clock;
++
+       ocelot->ptp_info = ocelot_ptp_clock_info;
+-      ocelot->ptp_clock = ptp_clock_register(&ocelot->ptp_info, ocelot->dev);
+-      if (IS_ERR(ocelot->ptp_clock))
+-              return PTR_ERR(ocelot->ptp_clock);
++      ptp_clock = ptp_clock_register(&ocelot->ptp_info, ocelot->dev);
++      if (IS_ERR(ptp_clock))
++              return PTR_ERR(ptp_clock);
+       /* Check if PHC support is missing at the configuration level */
+-      if (!ocelot->ptp_clock)
++      if (!ptp_clock)
+               return 0;
+ 
++      ocelot->ptp_clock = ptp_clock;
++
+       ocelot_write(ocelot, SYS_PTP_CFG_PTP_STAMP_WID(30), SYS_PTP_CFG);
+       ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_LOW);
+       ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_HIGH);
+@@ -2213,6 +2217,8 @@ void ocelot_deinit(struct ocelot *ocelot)
+       destroy_workqueue(ocelot->stats_queue);
+       mutex_destroy(&ocelot->stats_lock);
+       ocelot_ace_deinit();
++      if (ocelot->ptp_clock)
++              ptp_clock_unregister(ocelot->ptp_clock);
+ 
+       for (i = 0; i < ocelot->num_phys_ports; i++) {
+               port = ocelot->ports[i];
+diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c 
b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+index 20faa8d24c9f..134640412d7b 100644
+--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
++++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+@@ -1364,12 +1364,9 @@ int ionic_lif_rss_config(struct ionic_lif *lif, const 
u16 types,
+ 
+ static int ionic_lif_rss_init(struct ionic_lif *lif)
+ {
+-      u8 rss_key[IONIC_RSS_HASH_KEY_SIZE];
+       unsigned int tbl_sz;
+       unsigned int i;
+ 
+-      netdev_rss_key_fill(rss_key, IONIC_RSS_HASH_KEY_SIZE);
+-
+       lif->rss_types = IONIC_RSS_TYPE_IPV4     |
+                        IONIC_RSS_TYPE_IPV4_TCP |
+                        IONIC_RSS_TYPE_IPV4_UDP |
+@@ -1382,12 +1379,18 @@ static int ionic_lif_rss_init(struct ionic_lif *lif)
+       for (i = 0; i < tbl_sz; i++)
+               lif->rss_ind_tbl[i] = ethtool_rxfh_indir_default(i, lif->nxqs);
+ 
+-      return ionic_lif_rss_config(lif, lif->rss_types, rss_key, NULL);
++      return ionic_lif_rss_config(lif, lif->rss_types, NULL, NULL);
+ }
+ 
+-static int ionic_lif_rss_deinit(struct ionic_lif *lif)
++static void ionic_lif_rss_deinit(struct ionic_lif *lif)
+ {
+-      return ionic_lif_rss_config(lif, 0x0, NULL, NULL);
++      int tbl_sz;
++
++      tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
++      memset(lif->rss_ind_tbl, 0, tbl_sz);
++      memset(lif->rss_hash_key, 0, IONIC_RSS_HASH_KEY_SIZE);
++
++      ionic_lif_rss_config(lif, 0x0, NULL, NULL);
+ }
+ 
+ static void ionic_txrx_disable(struct ionic_lif *lif)
+@@ -1710,6 +1713,7 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic 
*ionic, unsigned int index
+               dev_err(dev, "Failed to allocate rss indirection table, 
aborting\n");
+               goto err_out_free_qcqs;
+       }
++      netdev_rss_key_fill(lif->rss_hash_key, IONIC_RSS_HASH_KEY_SIZE);
+ 
+       list_add_tail(&lif->list, &ionic->lifs);
+ 
+diff --git a/drivers/net/ethernet/realtek/r8169_main.c 
b/drivers/net/ethernet/realtek/r8169_main.c
+index 235d51ea4d39..4fe0977d01fa 100644
+--- a/drivers/net/ethernet/realtek/r8169_main.c
++++ b/drivers/net/ethernet/realtek/r8169_main.c
+@@ -3920,7 +3920,7 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private 
*tp)
+       case RTL_GIGA_MAC_VER_32:
+       case RTL_GIGA_MAC_VER_33:
+       case RTL_GIGA_MAC_VER_34:
+-      case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_51:
++      case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_61:
+               RTL_W32(tp, RxConfig, RTL_R32(tp, RxConfig) |
+                       AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
+               break;
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 
b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index f826365c979d..271a00f24f45 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -1502,10 +1502,8 @@ static void free_dma_rx_desc_resources(struct 
stmmac_priv *priv)
+                                         rx_q->dma_erx, rx_q->dma_rx_phy);
+ 
+               kfree(rx_q->buf_pool);
+-              if (rx_q->page_pool) {
+-                      page_pool_request_shutdown(rx_q->page_pool);
++              if (rx_q->page_pool)
+                       page_pool_destroy(rx_q->page_pool);
+-              }
+       }
+ }
+ 
+diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
+index f298d714efd6..d7a953c647b4 100644
+--- a/drivers/net/ethernet/ti/cpsw.c
++++ b/drivers/net/ethernet/ti/cpsw.c
+@@ -890,8 +890,8 @@ static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id)
+ {
+       struct cpsw_common *cpsw = dev_id;
+ 
+-      cpdma_ctlr_eoi(cpsw->dma, CPDMA_EOI_RX);
+       writel(0, &cpsw->wr_regs->rx_en);
++      cpdma_ctlr_eoi(cpsw->dma, CPDMA_EOI_RX);
+ 
+       if (cpsw->quirk_irq) {
+               disable_irq_nosync(cpsw->irqs_table[0]);
+diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
+index 3ab24fdccd3b..5c6b7fc04ea6 100644
+--- a/drivers/net/geneve.c
++++ b/drivers/net/geneve.c
+@@ -853,7 +853,9 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff 
*skb,
+               if (dst)
+                       return dst;
+       }
+-      if (ipv6_stub->ipv6_dst_lookup(geneve->net, gs6->sock->sk, &dst, fl6)) {
++      dst = ipv6_stub->ipv6_dst_lookup_flow(geneve->net, gs6->sock->sk, fl6,
++                                            NULL);
++      if (IS_ERR(dst)) {
+               netdev_dbg(dev, "no route to %pI6\n", &fl6->daddr);
+               return ERR_PTR(-ENETUNREACH);
+       }
+diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
+index 8869154fad88..404ac3a0d1c3 100644
+--- a/drivers/net/vxlan.c
++++ b/drivers/net/vxlan.c
+@@ -2276,7 +2276,6 @@ static struct dst_entry *vxlan6_get_route(struct 
vxlan_dev *vxlan,
+       bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
+       struct dst_entry *ndst;
+       struct flowi6 fl6;
+-      int err;
+ 
+       if (!sock6)
+               return ERR_PTR(-EIO);
+@@ -2299,10 +2298,9 @@ static struct dst_entry *vxlan6_get_route(struct 
vxlan_dev *vxlan,
+       fl6.fl6_dport = dport;
+       fl6.fl6_sport = sport;
+ 
+-      err = ipv6_stub->ipv6_dst_lookup(vxlan->net,
+-                                       sock6->sock->sk,
+-                                       &ndst, &fl6);
+-      if (unlikely(err < 0)) {
++      ndst = ipv6_stub->ipv6_dst_lookup_flow(vxlan->net, sock6->sock->sk,
++                                             &fl6, NULL);
++      if (unlikely(IS_ERR(ndst))) {
+               netdev_dbg(dev, "no route to %pI6\n", daddr);
+               return ERR_PTR(-ENETUNREACH);
+       }
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index c20f190b4c18..76d952aeb0fc 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1867,6 +1867,11 @@ struct net_device {
+       unsigned char           if_port;
+       unsigned char           dma;
+ 
++      /* Note : dev->mtu is often read without holding a lock.
++       * Writers usually hold RTNL.
++       * It is recommended to use READ_ONCE() to annotate the reads,
++       * and to use WRITE_ONCE() to annotate the writes.
++       */
+       unsigned int            mtu;
+       unsigned int            min_mtu;
+       unsigned int            max_mtu;
+diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
+index 8688f7adfda7..1ba6e2cc2725 100644
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -3527,8 +3527,9 @@ int __skb_vlan_pop(struct sk_buff *skb, u16 *vlan_tci);
+ int skb_vlan_pop(struct sk_buff *skb);
+ int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci);
+ int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto,
+-                int mac_len);
+-int skb_mpls_pop(struct sk_buff *skb, __be16 next_proto, int mac_len);
++                int mac_len, bool ethernet);
++int skb_mpls_pop(struct sk_buff *skb, __be16 next_proto, int mac_len,
++               bool ethernet);
+ int skb_mpls_update_lse(struct sk_buff *skb, __be32 mpls_lse);
+ int skb_mpls_dec_ttl(struct sk_buff *skb);
+ struct sk_buff *pskb_extract(struct sk_buff *skb, int off, int to_copy,
+diff --git a/include/linux/time.h b/include/linux/time.h
+index 27d83fd2ae61..5f3e49978837 100644
+--- a/include/linux/time.h
++++ b/include/linux/time.h
+@@ -96,4 +96,17 @@ static inline bool itimerspec64_valid(const struct 
itimerspec64 *its)
+  */
+ #define time_after32(a, b)    ((s32)((u32)(b) - (u32)(a)) < 0)
+ #define time_before32(b, a)   time_after32(a, b)
++
++/**
++ * time_between32 - check if a 32-bit timestamp is within a given time range
++ * @t:        the time which may be within [l,h]
++ * @l:        the lower bound of the range
++ * @h:        the higher bound of the range
++ *
++ * time_before32(t, l, h) returns true if @l <= @t <= @h. All operands are
++ * treated as 32-bit integers.
++ *
++ * Equivalent to !(time_before32(@t, @l) || time_after32(@t, @h)).
++ */
++#define time_between32(t, l, h) ((u32)(h) - (u32)(l) >= (u32)(t) - (u32)(l))
+ #endif
+diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h
+index 5cd12276ae21..e5fc8db1f783 100644
+--- a/include/net/flow_dissector.h
++++ b/include/net/flow_dissector.h
+@@ -229,6 +229,7 @@ enum flow_dissector_key_id {
+       FLOW_DISSECTOR_KEY_IPV4_ADDRS, /* struct flow_dissector_key_ipv4_addrs 
*/
+       FLOW_DISSECTOR_KEY_IPV6_ADDRS, /* struct flow_dissector_key_ipv6_addrs 
*/
+       FLOW_DISSECTOR_KEY_PORTS, /* struct flow_dissector_key_ports */
++      FLOW_DISSECTOR_KEY_PORTS_RANGE, /* struct flow_dissector_key_ports */
+       FLOW_DISSECTOR_KEY_ICMP, /* struct flow_dissector_key_icmp */
+       FLOW_DISSECTOR_KEY_ETH_ADDRS, /* struct flow_dissector_key_eth_addrs */
+       FLOW_DISSECTOR_KEY_TIPC, /* struct flow_dissector_key_tipc */
+diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
+index 86c567f531f3..c6f7bd22db60 100644
+--- a/include/net/flow_offload.h
++++ b/include/net/flow_offload.h
+@@ -380,19 +380,18 @@ static inline void flow_block_init(struct flow_block 
*flow_block)
+ typedef int flow_indr_block_bind_cb_t(struct net_device *dev, void *cb_priv,
+                                     enum tc_setup_type type, void *type_data);
+ 
+-typedef void flow_indr_block_ing_cmd_t(struct net_device *dev,
+-                                      flow_indr_block_bind_cb_t *cb,
+-                                      void *cb_priv,
+-                                      enum flow_block_command command);
++typedef void flow_indr_block_cmd_t(struct net_device *dev,
++                                 flow_indr_block_bind_cb_t *cb, void *cb_priv,
++                                 enum flow_block_command command);
+ 
+-struct flow_indr_block_ing_entry {
+-      flow_indr_block_ing_cmd_t *cb;
++struct flow_indr_block_entry {
++      flow_indr_block_cmd_t *cb;
+       struct list_head        list;
+ };
+ 
+-void flow_indr_add_block_ing_cb(struct flow_indr_block_ing_entry *entry);
++void flow_indr_add_block_cb(struct flow_indr_block_entry *entry);
+ 
+-void flow_indr_del_block_ing_cb(struct flow_indr_block_ing_entry *entry);
++void flow_indr_del_block_cb(struct flow_indr_block_entry *entry);
+ 
+ int __flow_indr_block_cb_register(struct net_device *dev, void *cb_priv,
+                                 flow_indr_block_bind_cb_t *cb,
+diff --git a/include/net/ip.h b/include/net/ip.h
+index a2c61c36dc4a..4b15cc1c224c 100644
+--- a/include/net/ip.h
++++ b/include/net/ip.h
+@@ -760,4 +760,9 @@ int ip_misc_proc_init(void);
+ int rtm_getroute_parse_ip_proto(struct nlattr *attr, u8 *ip_proto, u8 family,
+                               struct netlink_ext_ack *extack);
+ 
++static inline bool inetdev_valid_mtu(unsigned int mtu)
++{
++      return likely(mtu >= IPV4_MIN_MTU);
++}
++
+ #endif        /* _IP_H */
+diff --git a/include/net/ipv6.h b/include/net/ipv6.h
+index 009605c56f20..b59b3dae0f71 100644
+--- a/include/net/ipv6.h
++++ b/include/net/ipv6.h
+@@ -1017,7 +1017,7 @@ static inline struct sk_buff *ip6_finish_skb(struct sock 
*sk)
+ 
+ int ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst,
+                  struct flowi6 *fl6);
+-struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 
*fl6,
++struct dst_entry *ip6_dst_lookup_flow(struct net *net, const struct sock *sk, 
struct flowi6 *fl6,
+                                     const struct in6_addr *final_dst);
+ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
+                                        const struct in6_addr *final_dst,
+diff --git a/include/net/ipv6_stubs.h b/include/net/ipv6_stubs.h
+index 5c93e942c50b..3e7d2c0e79ca 100644
+--- a/include/net/ipv6_stubs.h
++++ b/include/net/ipv6_stubs.h
+@@ -24,8 +24,10 @@ struct ipv6_stub {
+                                const struct in6_addr *addr);
+       int (*ipv6_sock_mc_drop)(struct sock *sk, int ifindex,
+                                const struct in6_addr *addr);
+-      int (*ipv6_dst_lookup)(struct net *net, struct sock *sk,
+-                             struct dst_entry **dst, struct flowi6 *fl6);
++      struct dst_entry *(*ipv6_dst_lookup_flow)(struct net *net,
++                                                const struct sock *sk,
++                                                struct flowi6 *fl6,
++                                                const struct in6_addr 
*final_dst);
+       int (*ipv6_route_input)(struct sk_buff *skb);
+ 
+       struct fib6_table *(*fib6_get_table)(struct net *net, u32 id);
+diff --git a/include/net/page_pool.h b/include/net/page_pool.h
+index 2cbcdbdec254..1121faa99c12 100644
+--- a/include/net/page_pool.h
++++ b/include/net/page_pool.h
+@@ -70,7 +70,12 @@ struct page_pool_params {
+ struct page_pool {
+       struct page_pool_params p;
+ 
+-        u32 pages_state_hold_cnt;
++      struct delayed_work release_dw;
++      void (*disconnect)(void *);
++      unsigned long defer_start;
++      unsigned long defer_warn;
++
++      u32 pages_state_hold_cnt;
+ 
+       /*
+        * Data structure for allocation side
+@@ -129,25 +134,19 @@ inline enum dma_data_direction 
page_pool_get_dma_dir(struct page_pool *pool)
+ 
+ struct page_pool *page_pool_create(const struct page_pool_params *params);
+ 
+-void __page_pool_free(struct page_pool *pool);
+-static inline void page_pool_free(struct page_pool *pool)
+-{
+-      /* When page_pool isn't compiled-in, net/core/xdp.c doesn't
+-       * allow registering MEM_TYPE_PAGE_POOL, but shield linker.
+-       */
+ #ifdef CONFIG_PAGE_POOL
+-      __page_pool_free(pool);
+-#endif
+-}
+-
+-/* Drivers use this instead of page_pool_free */
++void page_pool_destroy(struct page_pool *pool);
++void page_pool_use_xdp_mem(struct page_pool *pool, void (*disconnect)(void 
*));
++#else
+ static inline void page_pool_destroy(struct page_pool *pool)
+ {
+-      if (!pool)
+-              return;
++}
+ 
+-      page_pool_free(pool);
++static inline void page_pool_use_xdp_mem(struct page_pool *pool,
++                                       void (*disconnect)(void *))
++{
+ }
++#endif
+ 
+ /* Never call this directly, use helpers below */
+ void __page_pool_put_page(struct page_pool *pool,
+@@ -170,24 +169,6 @@ static inline void page_pool_recycle_direct(struct 
page_pool *pool,
+       __page_pool_put_page(pool, page, true);
+ }
+ 
+-/* API user MUST have disconnected alloc-side (not allowed to call
+- * page_pool_alloc_pages()) before calling this.  The free-side can
+- * still run concurrently, to handle in-flight packet-pages.
+- *
+- * A request to shutdown can fail (with false) if there are still
+- * in-flight packet-pages.
+- */
+-bool __page_pool_request_shutdown(struct page_pool *pool);
+-static inline bool page_pool_request_shutdown(struct page_pool *pool)
+-{
+-      bool safe_to_remove = false;
+-
+-#ifdef CONFIG_PAGE_POOL
+-      safe_to_remove = __page_pool_request_shutdown(pool);
+-#endif
+-      return safe_to_remove;
+-}
+-
+ /* Disconnects a page (from a page_pool).  API users can have a need
+  * to disconnect a page (from a page_pool), to allow it to be used as
+  * a regular page (that will eventually be returned to the normal
+@@ -216,11 +197,6 @@ static inline bool is_page_pool_compiled_in(void)
+ #endif
+ }
+ 
+-static inline void page_pool_get(struct page_pool *pool)
+-{
+-      refcount_inc(&pool->user_cnt);
+-}
+-
+ static inline bool page_pool_put(struct page_pool *pool)
+ {
+       return refcount_dec_and_test(&pool->user_cnt);
+diff --git a/include/net/tcp.h b/include/net/tcp.h
+index ab4eb5eb5d07..b2367cfe0bda 100644
+--- a/include/net/tcp.h
++++ b/include/net/tcp.h
+@@ -494,15 +494,16 @@ static inline void tcp_synq_overflow(const struct sock 
*sk)
+               reuse = rcu_dereference(sk->sk_reuseport_cb);
+               if (likely(reuse)) {
+                       last_overflow = READ_ONCE(reuse->synq_overflow_ts);
+-                      if (time_after32(now, last_overflow + HZ))
++                      if (!time_between32(now, last_overflow,
++                                          last_overflow + HZ))
+                               WRITE_ONCE(reuse->synq_overflow_ts, now);
+                       return;
+               }
+       }
+ 
+-      last_overflow = tcp_sk(sk)->rx_opt.ts_recent_stamp;
+-      if (time_after32(now, last_overflow + HZ))
+-              tcp_sk(sk)->rx_opt.ts_recent_stamp = now;
++      last_overflow = READ_ONCE(tcp_sk(sk)->rx_opt.ts_recent_stamp);
++      if (!time_between32(now, last_overflow, last_overflow + HZ))
++              WRITE_ONCE(tcp_sk(sk)->rx_opt.ts_recent_stamp, now);
+ }
+ 
+ /* syncookies: no recent synqueue overflow on this listening socket? */
+@@ -517,13 +518,23 @@ static inline bool tcp_synq_no_recent_overflow(const 
struct sock *sk)
+               reuse = rcu_dereference(sk->sk_reuseport_cb);
+               if (likely(reuse)) {
+                       last_overflow = READ_ONCE(reuse->synq_overflow_ts);
+-                      return time_after32(now, last_overflow +
+-                                          TCP_SYNCOOKIE_VALID);
++                      return !time_between32(now, last_overflow - HZ,
++                                             last_overflow +
++                                             TCP_SYNCOOKIE_VALID);
+               }
+       }
+ 
+-      last_overflow = tcp_sk(sk)->rx_opt.ts_recent_stamp;
+-      return time_after32(now, last_overflow + TCP_SYNCOOKIE_VALID);
++      last_overflow = READ_ONCE(tcp_sk(sk)->rx_opt.ts_recent_stamp);
++
++      /* If last_overflow <= jiffies <= last_overflow + TCP_SYNCOOKIE_VALID,
++       * then we're under synflood. However, we have to use
++       * 'last_overflow - HZ' as lower bound. That's because a concurrent
++       * tcp_synq_overflow() could update .ts_recent_stamp after we read
++       * jiffies but before we store .ts_recent_stamp into last_overflow,
++       * which could lead to rejecting a valid syncookie.
++       */
++      return !time_between32(now, last_overflow - HZ,
++                             last_overflow + TCP_SYNCOOKIE_VALID);
+ }
+ 
+ static inline u32 tcp_cookie_time(void)
+diff --git a/include/net/xdp_priv.h b/include/net/xdp_priv.h
+index 6a8cba6ea79a..a9d5b7603b89 100644
+--- a/include/net/xdp_priv.h
++++ b/include/net/xdp_priv.h
+@@ -12,12 +12,8 @@ struct xdp_mem_allocator {
+               struct page_pool *page_pool;
+               struct zero_copy_allocator *zc_alloc;
+       };
+-      int disconnect_cnt;
+-      unsigned long defer_start;
+       struct rhash_head node;
+       struct rcu_head rcu;
+-      struct delayed_work defer_wq;
+-      unsigned long defer_warn;
+ };
+ 
+ #endif /* __LINUX_NET_XDP_PRIV_H__ */
+diff --git a/include/trace/events/xdp.h b/include/trace/events/xdp.h
+index 8c8420230a10..c79943e82a54 100644
+--- a/include/trace/events/xdp.h
++++ b/include/trace/events/xdp.h
+@@ -317,19 +317,15 @@ __MEM_TYPE_MAP(__MEM_TYPE_TP_FN)
+ 
+ TRACE_EVENT(mem_disconnect,
+ 
+-      TP_PROTO(const struct xdp_mem_allocator *xa,
+-               bool safe_to_remove, bool force),
++      TP_PROTO(const struct xdp_mem_allocator *xa),
+ 
+-      TP_ARGS(xa, safe_to_remove, force),
++      TP_ARGS(xa),
+ 
+       TP_STRUCT__entry(
+               __field(const struct xdp_mem_allocator *,       xa)
+               __field(u32,            mem_id)
+               __field(u32,            mem_type)
+               __field(const void *,   allocator)
+-              __field(bool,           safe_to_remove)
+-              __field(bool,           force)
+-              __field(int,            disconnect_cnt)
+       ),
+ 
+       TP_fast_assign(
+@@ -337,19 +333,12 @@ TRACE_EVENT(mem_disconnect,
+               __entry->mem_id         = xa->mem.id;
+               __entry->mem_type       = xa->mem.type;
+               __entry->allocator      = xa->allocator;
+-              __entry->safe_to_remove = safe_to_remove;
+-              __entry->force          = force;
+-              __entry->disconnect_cnt = xa->disconnect_cnt;
+       ),
+ 
+-      TP_printk("mem_id=%d mem_type=%s allocator=%p"
+-                " safe_to_remove=%s force=%s disconnect_cnt=%d",
++      TP_printk("mem_id=%d mem_type=%s allocator=%p",
+                 __entry->mem_id,
+                 __print_symbolic(__entry->mem_type, __MEM_TYPE_SYM_TAB),
+-                __entry->allocator,
+-                __entry->safe_to_remove ? "true" : "false",
+-                __entry->force ? "true" : "false",
+-                __entry->disconnect_cnt
++                __entry->allocator
+       )
+ );
+ 
+diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
+index e804a3016902..022dc6e504c4 100644
+--- a/net/bridge/br_device.c
++++ b/net/bridge/br_device.c
+@@ -245,6 +245,12 @@ static int br_set_mac_address(struct net_device *dev, 
void *p)
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+ 
++      /* dev_set_mac_addr() can be called by a master device on bridge's
++       * NETDEV_UNREGISTER, but since it's being destroyed do nothing
++       */
++      if (dev->reg_state != NETREG_REGISTERED)
++              return -EBUSY;
++
+       spin_lock_bh(&br->lock);
+       if (!ether_addr_equal(dev->dev_addr, addr->sa_data)) {
+               /* Mac address will be changed in br_stp_change_bridge_id(). */
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 99ac84ff398f..046307445ece 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -7967,7 +7967,8 @@ int __dev_set_mtu(struct net_device *dev, int new_mtu)
+       if (ops->ndo_change_mtu)
+               return ops->ndo_change_mtu(dev, new_mtu);
+ 
+-      dev->mtu = new_mtu;
++      /* Pairs with all the lockless reads of dev->mtu in the stack */
++      WRITE_ONCE(dev->mtu, new_mtu);
+       return 0;
+ }
+ EXPORT_SYMBOL(__dev_set_mtu);
+diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
+index 68eda10d0680..1292f3f0f93f 100644
+--- a/net/core/flow_dissector.c
++++ b/net/core/flow_dissector.c
+@@ -683,6 +683,31 @@ __skb_flow_dissect_tcp(const struct sk_buff *skb,
+       key_tcp->flags = (*(__be16 *) &tcp_flag_word(th) & htons(0x0FFF));
+ }
+ 
++static void
++__skb_flow_dissect_ports(const struct sk_buff *skb,
++                       struct flow_dissector *flow_dissector,
++                       void *target_container, void *data, int nhoff,
++                       u8 ip_proto, int hlen)
++{
++      enum flow_dissector_key_id dissector_ports = FLOW_DISSECTOR_KEY_MAX;
++      struct flow_dissector_key_ports *key_ports;
++
++      if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS))
++              dissector_ports = FLOW_DISSECTOR_KEY_PORTS;
++      else if (dissector_uses_key(flow_dissector,
++                                  FLOW_DISSECTOR_KEY_PORTS_RANGE))
++              dissector_ports = FLOW_DISSECTOR_KEY_PORTS_RANGE;
++
++      if (dissector_ports == FLOW_DISSECTOR_KEY_MAX)
++              return;
++
++      key_ports = skb_flow_dissector_target(flow_dissector,
++                                            dissector_ports,
++                                            target_container);
++      key_ports->ports = __skb_flow_get_ports(skb, nhoff, ip_proto,
++                                              data, hlen);
++}
++
+ static void
+ __skb_flow_dissect_ipv4(const struct sk_buff *skb,
+                       struct flow_dissector *flow_dissector,
+@@ -852,7 +877,6 @@ bool __skb_flow_dissect(const struct net *net,
+       struct flow_dissector_key_control *key_control;
+       struct flow_dissector_key_basic *key_basic;
+       struct flow_dissector_key_addrs *key_addrs;
+-      struct flow_dissector_key_ports *key_ports;
+       struct flow_dissector_key_icmp *key_icmp;
+       struct flow_dissector_key_tags *key_tags;
+       struct flow_dissector_key_vlan *key_vlan;
+@@ -870,9 +894,10 @@ bool __skb_flow_dissect(const struct net *net,
+               nhoff = skb_network_offset(skb);
+               hlen = skb_headlen(skb);
+ #if IS_ENABLED(CONFIG_NET_DSA)
+-              if (unlikely(skb->dev && netdev_uses_dsa(skb->dev))) {
++              if (unlikely(skb->dev && netdev_uses_dsa(skb->dev) &&
++                           proto == htons(ETH_P_XDSA))) {
+                       const struct dsa_device_ops *ops;
+-                      int offset;
++                      int offset = 0;
+ 
+                       ops = skb->dev->dsa_ptr->tag_ops;
+                       if (ops->flow_dissect &&
+@@ -1299,14 +1324,9 @@ ip_proto_again:
+               break;
+       }
+ 
+-      if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS) &&
+-          !(key_control->flags & FLOW_DIS_IS_FRAGMENT)) {
+-              key_ports = skb_flow_dissector_target(flow_dissector,
+-                                                    FLOW_DISSECTOR_KEY_PORTS,
+-                                                    target_container);
+-              key_ports->ports = __skb_flow_get_ports(skb, nhoff, ip_proto,
+-                                                      data, hlen);
+-      }
++      if (!(key_control->flags & FLOW_DIS_IS_FRAGMENT))
++              __skb_flow_dissect_ports(skb, flow_dissector, target_container,
++                                       data, nhoff, ip_proto, hlen);
+ 
+       if (dissector_uses_key(flow_dissector,
+                              FLOW_DISSECTOR_KEY_ICMP)) {
+diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
+index cf52d9c422fa..45b6a59ac124 100644
+--- a/net/core/flow_offload.c
++++ b/net/core/flow_offload.c
+@@ -283,7 +283,7 @@ int flow_block_cb_setup_simple(struct flow_block_offload 
*f,
+ }
+ EXPORT_SYMBOL(flow_block_cb_setup_simple);
+ 
+-static LIST_HEAD(block_ing_cb_list);
++static LIST_HEAD(block_cb_list);
+ 
+ static struct rhashtable indr_setup_block_ht;
+ 
+@@ -391,20 +391,19 @@ static void flow_indr_block_cb_del(struct 
flow_indr_block_cb *indr_block_cb)
+       kfree(indr_block_cb);
+ }
+ 
+-static DEFINE_MUTEX(flow_indr_block_ing_cb_lock);
++static DEFINE_MUTEX(flow_indr_block_cb_lock);
+ 
+-static void flow_block_ing_cmd(struct net_device *dev,
+-                             flow_indr_block_bind_cb_t *cb,
+-                             void *cb_priv,
+-                             enum flow_block_command command)
++static void flow_block_cmd(struct net_device *dev,
++                         flow_indr_block_bind_cb_t *cb, void *cb_priv,
++                         enum flow_block_command command)
+ {
+-      struct flow_indr_block_ing_entry *entry;
++      struct flow_indr_block_entry *entry;
+ 
+-      mutex_lock(&flow_indr_block_ing_cb_lock);
+-      list_for_each_entry(entry, &block_ing_cb_list, list) {
++      mutex_lock(&flow_indr_block_cb_lock);
++      list_for_each_entry(entry, &block_cb_list, list) {
+               entry->cb(dev, cb, cb_priv, command);
+       }
+-      mutex_unlock(&flow_indr_block_ing_cb_lock);
++      mutex_unlock(&flow_indr_block_cb_lock);
+ }
+ 
+ int __flow_indr_block_cb_register(struct net_device *dev, void *cb_priv,
+@@ -424,8 +423,8 @@ int __flow_indr_block_cb_register(struct net_device *dev, 
void *cb_priv,
+       if (err)
+               goto err_dev_put;
+ 
+-      flow_block_ing_cmd(dev, indr_block_cb->cb, indr_block_cb->cb_priv,
+-                         FLOW_BLOCK_BIND);
++      flow_block_cmd(dev, indr_block_cb->cb, indr_block_cb->cb_priv,
++                     FLOW_BLOCK_BIND);
+ 
+       return 0;
+ 
+@@ -464,8 +463,8 @@ void __flow_indr_block_cb_unregister(struct net_device 
*dev,
+       if (!indr_block_cb)
+               return;
+ 
+-      flow_block_ing_cmd(dev, indr_block_cb->cb, indr_block_cb->cb_priv,
+-                         FLOW_BLOCK_UNBIND);
++      flow_block_cmd(dev, indr_block_cb->cb, indr_block_cb->cb_priv,
++                     FLOW_BLOCK_UNBIND);
+ 
+       flow_indr_block_cb_del(indr_block_cb);
+       flow_indr_block_dev_put(indr_dev);
+@@ -499,21 +498,21 @@ void flow_indr_block_call(struct net_device *dev,
+ }
+ EXPORT_SYMBOL_GPL(flow_indr_block_call);
+ 
+-void flow_indr_add_block_ing_cb(struct flow_indr_block_ing_entry *entry)
++void flow_indr_add_block_cb(struct flow_indr_block_entry *entry)
+ {
+-      mutex_lock(&flow_indr_block_ing_cb_lock);
+-      list_add_tail(&entry->list, &block_ing_cb_list);
+-      mutex_unlock(&flow_indr_block_ing_cb_lock);
++      mutex_lock(&flow_indr_block_cb_lock);
++      list_add_tail(&entry->list, &block_cb_list);
++      mutex_unlock(&flow_indr_block_cb_lock);
+ }
+-EXPORT_SYMBOL_GPL(flow_indr_add_block_ing_cb);
++EXPORT_SYMBOL_GPL(flow_indr_add_block_cb);
+ 
+-void flow_indr_del_block_ing_cb(struct flow_indr_block_ing_entry *entry)
++void flow_indr_del_block_cb(struct flow_indr_block_entry *entry)
+ {
+-      mutex_lock(&flow_indr_block_ing_cb_lock);
++      mutex_lock(&flow_indr_block_cb_lock);
+       list_del(&entry->list);
+-      mutex_unlock(&flow_indr_block_ing_cb_lock);
++      mutex_unlock(&flow_indr_block_cb_lock);
+ }
+-EXPORT_SYMBOL_GPL(flow_indr_del_block_ing_cb);
++EXPORT_SYMBOL_GPL(flow_indr_del_block_cb);
+ 
+ static int __init init_flow_indr_rhashtable(void)
+ {
+diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c
+index 74cfb8b5ab33..99a6de52b21d 100644
+--- a/net/core/lwt_bpf.c
++++ b/net/core/lwt_bpf.c
+@@ -230,9 +230,7 @@ static int bpf_lwt_xmit_reroute(struct sk_buff *skb)
+               fl6.daddr = iph6->daddr;
+               fl6.saddr = iph6->saddr;
+ 
+-              err = ipv6_stub->ipv6_dst_lookup(net, skb->sk, &dst, &fl6);
+-              if (unlikely(err))
+-                      goto err;
++              dst = ipv6_stub->ipv6_dst_lookup_flow(net, skb->sk, &fl6, NULL);
+               if (IS_ERR(dst)) {
+                       err = PTR_ERR(dst);
+                       goto err;
+diff --git a/net/core/page_pool.c b/net/core/page_pool.c
+index 5bc65587f1c4..dfc2501c35d9 100644
+--- a/net/core/page_pool.c
++++ b/net/core/page_pool.c
+@@ -18,6 +18,9 @@
+ 
+ #include <trace/events/page_pool.h>
+ 
++#define DEFER_TIME (msecs_to_jiffies(1000))
++#define DEFER_WARN_INTERVAL (60 * HZ)
++
+ static int page_pool_init(struct page_pool *pool,
+                         const struct page_pool_params *params)
+ {
+@@ -193,22 +196,14 @@ static s32 page_pool_inflight(struct page_pool *pool)
+ {
+       u32 release_cnt = atomic_read(&pool->pages_state_release_cnt);
+       u32 hold_cnt = READ_ONCE(pool->pages_state_hold_cnt);
+-      s32 distance;
+-
+-      distance = _distance(hold_cnt, release_cnt);
+-
+-      trace_page_pool_inflight(pool, distance, hold_cnt, release_cnt);
+-      return distance;
+-}
++      s32 inflight;
+ 
+-static bool __page_pool_safe_to_destroy(struct page_pool *pool)
+-{
+-      s32 inflight = page_pool_inflight(pool);
++      inflight = _distance(hold_cnt, release_cnt);
+ 
+-      /* The distance should not be able to become negative */
++      trace_page_pool_inflight(pool, inflight, hold_cnt, release_cnt);
+       WARN(inflight < 0, "Negative(%d) inflight packet-pages", inflight);
+ 
+-      return (inflight == 0);
++      return inflight;
+ }
+ 
+ /* Cleanup page_pool state from page */
+@@ -216,6 +211,7 @@ static void __page_pool_clean_page(struct page_pool *pool,
+                                  struct page *page)
+ {
+       dma_addr_t dma;
++      int count;
+ 
+       if (!(pool->p.flags & PP_FLAG_DMA_MAP))
+               goto skip_dma_unmap;
+@@ -227,9 +223,11 @@ static void __page_pool_clean_page(struct page_pool *pool,
+                            DMA_ATTR_SKIP_CPU_SYNC);
+       page->dma_addr = 0;
+ skip_dma_unmap:
+-      atomic_inc(&pool->pages_state_release_cnt);
+-      trace_page_pool_state_release(pool, page,
+-                            atomic_read(&pool->pages_state_release_cnt));
++      /* This may be the last page returned, releasing the pool, so
++       * it is not safe to reference pool afterwards.
++       */
++      count = atomic_inc_return(&pool->pages_state_release_cnt);
++      trace_page_pool_state_release(pool, page, count);
+ }
+ 
+ /* unmap the page and clean our state */
+@@ -338,31 +336,10 @@ static void __page_pool_empty_ring(struct page_pool 
*pool)
+       }
+ }
+ 
+-static void __warn_in_flight(struct page_pool *pool)
++static void page_pool_free(struct page_pool *pool)
+ {
+-      u32 release_cnt = atomic_read(&pool->pages_state_release_cnt);
+-      u32 hold_cnt = READ_ONCE(pool->pages_state_hold_cnt);
+-      s32 distance;
+-
+-      distance = _distance(hold_cnt, release_cnt);
+-
+-      /* Drivers should fix this, but only problematic when DMA is used */
+-      WARN(1, "Still in-flight pages:%d hold:%u released:%u",
+-           distance, hold_cnt, release_cnt);
+-}
+-
+-void __page_pool_free(struct page_pool *pool)
+-{
+-      /* Only last user actually free/release resources */
+-      if (!page_pool_put(pool))
+-              return;
+-
+-      WARN(pool->alloc.count, "API usage violation");
+-      WARN(!ptr_ring_empty(&pool->ring), "ptr_ring is not empty");
+-
+-      /* Can happen due to forced shutdown */
+-      if (!__page_pool_safe_to_destroy(pool))
+-              __warn_in_flight(pool);
++      if (pool->disconnect)
++              pool->disconnect(pool);
+ 
+       ptr_ring_cleanup(&pool->ring, NULL);
+ 
+@@ -371,12 +348,8 @@ void __page_pool_free(struct page_pool *pool)
+ 
+       kfree(pool);
+ }
+-EXPORT_SYMBOL(__page_pool_free);
+ 
+-/* Request to shutdown: release pages cached by page_pool, and check
+- * for in-flight pages
+- */
+-bool __page_pool_request_shutdown(struct page_pool *pool)
++static void page_pool_scrub(struct page_pool *pool)
+ {
+       struct page *page;
+ 
+@@ -393,7 +366,64 @@ bool __page_pool_request_shutdown(struct page_pool *pool)
+        * be in-flight.
+        */
+       __page_pool_empty_ring(pool);
++}
++
++static int page_pool_release(struct page_pool *pool)
++{
++      int inflight;
++
++      page_pool_scrub(pool);
++      inflight = page_pool_inflight(pool);
++      if (!inflight)
++              page_pool_free(pool);
++
++      return inflight;
++}
++
++static void page_pool_release_retry(struct work_struct *wq)
++{
++      struct delayed_work *dwq = to_delayed_work(wq);
++      struct page_pool *pool = container_of(dwq, typeof(*pool), release_dw);
++      int inflight;
++
++      inflight = page_pool_release(pool);
++      if (!inflight)
++              return;
++
++      /* Periodic warning */
++      if (time_after_eq(jiffies, pool->defer_warn)) {
++              int sec = (s32)((u32)jiffies - (u32)pool->defer_start) / HZ;
++
++              pr_warn("%s() stalled pool shutdown %d inflight %d sec\n",
++                      __func__, inflight, sec);
++              pool->defer_warn = jiffies + DEFER_WARN_INTERVAL;
++      }
++
++      /* Still not ready to be disconnected, retry later */
++      schedule_delayed_work(&pool->release_dw, DEFER_TIME);
++}
++
++void page_pool_use_xdp_mem(struct page_pool *pool, void (*disconnect)(void *))
++{
++      refcount_inc(&pool->user_cnt);
++      pool->disconnect = disconnect;
++}
++
++void page_pool_destroy(struct page_pool *pool)
++{
++      if (!pool)
++              return;
++
++      if (!page_pool_put(pool))
++              return;
++
++      if (!page_pool_release(pool))
++              return;
++
++      pool->defer_start = jiffies;
++      pool->defer_warn  = jiffies + DEFER_WARN_INTERVAL;
+ 
+-      return __page_pool_safe_to_destroy(pool);
++      INIT_DELAYED_WORK(&pool->release_dw, page_pool_release_retry);
++      schedule_delayed_work(&pool->release_dw, DEFER_TIME);
+ }
+-EXPORT_SYMBOL(__page_pool_request_shutdown);
++EXPORT_SYMBOL(page_pool_destroy);
+diff --git a/net/core/skbuff.c b/net/core/skbuff.c
+index 867e61df00db..973a71f4bc89 100644
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -5484,7 +5484,7 @@ static void skb_mod_eth_type(struct sk_buff *skb, struct 
ethhdr *hdr,
+  * Returns 0 on success, -errno otherwise.
+  */
+ int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto,
+-                int mac_len)
++                int mac_len, bool ethernet)
+ {
+       struct mpls_shim_hdr *lse;
+       int err;
+@@ -5515,7 +5515,7 @@ int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, 
__be16 mpls_proto,
+       lse->label_stack_entry = mpls_lse;
+       skb_postpush_rcsum(skb, lse, MPLS_HLEN);
+ 
+-      if (skb->dev && skb->dev->type == ARPHRD_ETHER)
++      if (ethernet)
+               skb_mod_eth_type(skb, eth_hdr(skb), mpls_proto);
+       skb->protocol = mpls_proto;
+ 
+@@ -5529,12 +5529,14 @@ EXPORT_SYMBOL_GPL(skb_mpls_push);
+  * @skb: buffer
+  * @next_proto: ethertype of header after popped MPLS header
+  * @mac_len: length of the MAC header
++ * @ethernet: flag to indicate if ethernet header is present in packet
+  *
+  * Expects skb->data at mac header.
+  *
+  * Returns 0 on success, -errno otherwise.
+  */
+-int skb_mpls_pop(struct sk_buff *skb, __be16 next_proto, int mac_len)
++int skb_mpls_pop(struct sk_buff *skb, __be16 next_proto, int mac_len,
++               bool ethernet)
+ {
+       int err;
+ 
+@@ -5553,7 +5555,7 @@ int skb_mpls_pop(struct sk_buff *skb, __be16 next_proto, 
int mac_len)
+       skb_reset_mac_header(skb);
+       skb_set_network_header(skb, mac_len);
+ 
+-      if (skb->dev && skb->dev->type == ARPHRD_ETHER) {
++      if (ethernet) {
+               struct ethhdr *hdr;
+ 
+               /* use mpls_hdr() to get ethertype to account for VLANs. */
+diff --git a/net/core/xdp.c b/net/core/xdp.c
+index d7bf62ffbb5e..b3f463c6543f 100644
+--- a/net/core/xdp.c
++++ b/net/core/xdp.c
+@@ -70,10 +70,6 @@ static void __xdp_mem_allocator_rcu_free(struct rcu_head 
*rcu)
+ 
+       xa = container_of(rcu, struct xdp_mem_allocator, rcu);
+ 
+-      /* Allocator have indicated safe to remove before this is called */
+-      if (xa->mem.type == MEM_TYPE_PAGE_POOL)
+-              page_pool_free(xa->page_pool);
+-
+       /* Allow this ID to be reused */
+       ida_simple_remove(&mem_id_pool, xa->mem.id);
+ 
+@@ -85,62 +81,57 @@ static void __xdp_mem_allocator_rcu_free(struct rcu_head 
*rcu)
+       kfree(xa);
+ }
+ 
+-static bool __mem_id_disconnect(int id, bool force)
++static void mem_xa_remove(struct xdp_mem_allocator *xa)
++{
++      trace_mem_disconnect(xa);
++
++      if (!rhashtable_remove_fast(mem_id_ht, &xa->node, mem_id_rht_params))
++              call_rcu(&xa->rcu, __xdp_mem_allocator_rcu_free);
++}
++
++static void mem_allocator_disconnect(void *allocator)
+ {
+       struct xdp_mem_allocator *xa;
+-      bool safe_to_remove = true;
++      struct rhashtable_iter iter;
+ 
+       mutex_lock(&mem_id_lock);
+ 
+-      xa = rhashtable_lookup_fast(mem_id_ht, &id, mem_id_rht_params);
+-      if (!xa) {
+-              mutex_unlock(&mem_id_lock);
+-              WARN(1, "Request remove non-existing id(%d), driver bug?", id);
+-              return true;
+-      }
+-      xa->disconnect_cnt++;
++      rhashtable_walk_enter(mem_id_ht, &iter);
++      do {
++              rhashtable_walk_start(&iter);
+ 
+-      /* Detects in-flight packet-pages for page_pool */
+-      if (xa->mem.type == MEM_TYPE_PAGE_POOL)
+-              safe_to_remove = page_pool_request_shutdown(xa->page_pool);
++              while ((xa = rhashtable_walk_next(&iter)) && !IS_ERR(xa)) {
++                      if (xa->allocator == allocator)
++                              mem_xa_remove(xa);
++              }
+ 
+-      trace_mem_disconnect(xa, safe_to_remove, force);
++              rhashtable_walk_stop(&iter);
+ 
+-      if ((safe_to_remove || force) &&
+-          !rhashtable_remove_fast(mem_id_ht, &xa->node, mem_id_rht_params))
+-              call_rcu(&xa->rcu, __xdp_mem_allocator_rcu_free);
++      } while (xa == ERR_PTR(-EAGAIN));
++      rhashtable_walk_exit(&iter);
+ 
+       mutex_unlock(&mem_id_lock);
+-      return (safe_to_remove|force);
+ }
+ 
+-#define DEFER_TIME (msecs_to_jiffies(1000))
+-#define DEFER_WARN_INTERVAL (30 * HZ)
+-#define DEFER_MAX_RETRIES 120
+-
+-static void mem_id_disconnect_defer_retry(struct work_struct *wq)
++static void mem_id_disconnect(int id)
+ {
+-      struct delayed_work *dwq = to_delayed_work(wq);
+-      struct xdp_mem_allocator *xa = container_of(dwq, typeof(*xa), defer_wq);
+-      bool force = false;
++      struct xdp_mem_allocator *xa;
+ 
+-      if (xa->disconnect_cnt > DEFER_MAX_RETRIES)
+-              force = true;
++      mutex_lock(&mem_id_lock);
+ 
+-      if (__mem_id_disconnect(xa->mem.id, force))
++      xa = rhashtable_lookup_fast(mem_id_ht, &id, mem_id_rht_params);
++      if (!xa) {
++              mutex_unlock(&mem_id_lock);
++              WARN(1, "Request remove non-existing id(%d), driver bug?", id);
+               return;
++      }
+ 
+-      /* Periodic warning */
+-      if (time_after_eq(jiffies, xa->defer_warn)) {
+-              int sec = (s32)((u32)jiffies - (u32)xa->defer_start) / HZ;
++      trace_mem_disconnect(xa);
+ 
+-              pr_warn("%s() stalled mem.id=%u shutdown %d attempts %d sec\n",
+-                      __func__, xa->mem.id, xa->disconnect_cnt, sec);
+-              xa->defer_warn = jiffies + DEFER_WARN_INTERVAL;
+-      }
++      if (!rhashtable_remove_fast(mem_id_ht, &xa->node, mem_id_rht_params))
++              call_rcu(&xa->rcu, __xdp_mem_allocator_rcu_free);
+ 
+-      /* Still not ready to be disconnected, retry later */
+-      schedule_delayed_work(&xa->defer_wq, DEFER_TIME);
++      mutex_unlock(&mem_id_lock);
+ }
+ 
+ void xdp_rxq_info_unreg_mem_model(struct xdp_rxq_info *xdp_rxq)
+@@ -153,38 +144,21 @@ void xdp_rxq_info_unreg_mem_model(struct xdp_rxq_info 
*xdp_rxq)
+               return;
+       }
+ 
+-      if (xdp_rxq->mem.type != MEM_TYPE_PAGE_POOL &&
+-          xdp_rxq->mem.type != MEM_TYPE_ZERO_COPY) {
+-              return;
+-      }
+-
+       if (id == 0)
+               return;
+ 
+-      if (__mem_id_disconnect(id, false))
+-              return;
+-
+-      /* Could not disconnect, defer new disconnect attempt to later */
+-      mutex_lock(&mem_id_lock);
++      if (xdp_rxq->mem.type == MEM_TYPE_ZERO_COPY)
++              return mem_id_disconnect(id);
+ 
+-      xa = rhashtable_lookup_fast(mem_id_ht, &id, mem_id_rht_params);
+-      if (!xa) {
+-              mutex_unlock(&mem_id_lock);
+-              return;
++      if (xdp_rxq->mem.type == MEM_TYPE_PAGE_POOL) {
++              rcu_read_lock();
++              xa = rhashtable_lookup(mem_id_ht, &id, mem_id_rht_params);
++              page_pool_destroy(xa->page_pool);
++              rcu_read_unlock();
+       }
+-      xa->defer_start = jiffies;
+-      xa->defer_warn  = jiffies + DEFER_WARN_INTERVAL;
+-
+-      INIT_DELAYED_WORK(&xa->defer_wq, mem_id_disconnect_defer_retry);
+-      mutex_unlock(&mem_id_lock);
+-      schedule_delayed_work(&xa->defer_wq, DEFER_TIME);
+ }
+ EXPORT_SYMBOL_GPL(xdp_rxq_info_unreg_mem_model);
+ 
+-/* This unregister operation will also cleanup and destroy the
+- * allocator. The page_pool_free() operation is first called when it's
+- * safe to remove, possibly deferred to a workqueue.
+- */
+ void xdp_rxq_info_unreg(struct xdp_rxq_info *xdp_rxq)
+ {
+       /* Simplify driver cleanup code paths, allow unreg "unused" */
+@@ -371,7 +345,7 @@ int xdp_rxq_info_reg_mem_model(struct xdp_rxq_info 
*xdp_rxq,
+       }
+ 
+       if (type == MEM_TYPE_PAGE_POOL)
+-              page_pool_get(xdp_alloc->page_pool);
++              page_pool_use_xdp_mem(allocator, mem_allocator_disconnect);
+ 
+       mutex_unlock(&mem_id_lock);
+ 
+@@ -402,15 +376,8 @@ static void __xdp_return(void *data, struct xdp_mem_info 
*mem, bool napi_direct,
+               /* mem->id is valid, checked in xdp_rxq_info_reg_mem_model() */
+               xa = rhashtable_lookup(mem_id_ht, &mem->id, mem_id_rht_params);
+               page = virt_to_head_page(data);
+-              if (likely(xa)) {
+-                      napi_direct &= !xdp_return_frame_no_direct();
+-                      page_pool_put_page(xa->page_pool, page, napi_direct);
+-              } else {
+-                      /* Hopefully stack show who to blame for late return */
+-                      WARN_ONCE(1, "page_pool gone mem.id=%d", mem->id);
+-                      trace_mem_return_failed(mem, page);
+-                      put_page(page);
+-              }
++              napi_direct &= !xdp_return_frame_no_direct();
++              page_pool_put_page(xa->page_pool, page, napi_direct);
+               rcu_read_unlock();
+               break;
+       case MEM_TYPE_PAGE_SHARED:
+diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
+index 25aab672fc99..1e5e08cc0bfc 100644
+--- a/net/dccp/ipv6.c
++++ b/net/dccp/ipv6.c
+@@ -210,7 +210,7 @@ static int dccp_v6_send_response(const struct sock *sk, 
struct request_sock *req
+       final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
+       rcu_read_unlock();
+ 
+-      dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
++      dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
+       if (IS_ERR(dst)) {
+               err = PTR_ERR(dst);
+               dst = NULL;
+@@ -282,7 +282,7 @@ static void dccp_v6_ctl_send_reset(const struct sock *sk, 
struct sk_buff *rxskb)
+       security_skb_classify_flow(rxskb, flowi6_to_flowi(&fl6));
+ 
+       /* sk = NULL, but it is safe for now. RST socket required. */
+-      dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
++      dst = ip6_dst_lookup_flow(sock_net(ctl_sk), ctl_sk, &fl6, NULL);
+       if (!IS_ERR(dst)) {
+               skb_dst_set(skb, dst);
+               ip6_xmit(ctl_sk, skb, &fl6, 0, NULL, 0, 0);
+@@ -912,7 +912,7 @@ static int dccp_v6_connect(struct sock *sk, struct 
sockaddr *uaddr,
+       opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
+       final_p = fl6_update_dst(&fl6, opt, &final);
+ 
+-      dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
++      dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
+       if (IS_ERR(dst)) {
+               err = PTR_ERR(dst);
+               goto failure;
+diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
+index f509b495451a..b01e1bae4ddc 100644
+--- a/net/hsr/hsr_device.c
++++ b/net/hsr/hsr_device.c
+@@ -227,8 +227,13 @@ static int hsr_dev_xmit(struct sk_buff *skb, struct 
net_device *dev)
+       struct hsr_port *master;
+ 
+       master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
+-      skb->dev = master->dev;
+-      hsr_forward_skb(skb, master);
++      if (master) {
++              skb->dev = master->dev;
++              hsr_forward_skb(skb, master);
++      } else {
++              atomic_long_inc(&dev->tx_dropped);
++              dev_kfree_skb_any(skb);
++      }
+       return NETDEV_TX_OK;
+ }
+ 
+diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
+index a4b5bd4d2c89..e4632bd2026d 100644
+--- a/net/ipv4/devinet.c
++++ b/net/ipv4/devinet.c
+@@ -1496,11 +1496,6 @@ skip:
+       }
+ }
+ 
+-static bool inetdev_valid_mtu(unsigned int mtu)
+-{
+-      return mtu >= IPV4_MIN_MTU;
+-}
+-
+ static void inetdev_send_gratuitous_arp(struct net_device *dev,
+                                       struct in_device *in_dev)
+ 
+diff --git a/net/ipv4/gre_demux.c b/net/ipv4/gre_demux.c
+index 44bfeecac33e..5fd6e8ed02b5 100644
+--- a/net/ipv4/gre_demux.c
++++ b/net/ipv4/gre_demux.c
+@@ -127,7 +127,7 @@ int gre_parse_header(struct sk_buff *skb, struct 
tnl_ptk_info *tpi,
+               if (!pskb_may_pull(skb, nhs + hdr_len + sizeof(*ershdr)))
+                       return -EINVAL;
+ 
+-              ershdr = (struct erspan_base_hdr *)options;
++              ershdr = (struct erspan_base_hdr *)(skb->data + nhs + hdr_len);
+               tpi->key = cpu_to_be32(get_session_id(ershdr));
+       }
+ 
+diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
+index 3d8baaaf7086..b268ee1c1b44 100644
+--- a/net/ipv4/ip_output.c
++++ b/net/ipv4/ip_output.c
+@@ -1258,15 +1258,18 @@ static int ip_setup_cork(struct sock *sk, struct 
inet_cork *cork,
+               cork->addr = ipc->addr;
+       }
+ 
+-      /*
+-       * We steal reference to this route, caller should not release it
+-       */
+-      *rtp = NULL;
+       cork->fragsize = ip_sk_use_pmtu(sk) ?
+-                       dst_mtu(&rt->dst) : rt->dst.dev->mtu;
++                       dst_mtu(&rt->dst) : READ_ONCE(rt->dst.dev->mtu);
++
++      if (!inetdev_valid_mtu(cork->fragsize))
++              return -ENETUNREACH;
+ 
+       cork->gso_size = ipc->gso_size;
++
+       cork->dst = &rt->dst;
++      /* We stole this route, caller should not release it. */
++      *rtp = NULL;
++
+       cork->length = 0;
+       cork->ttl = ipc->ttl;
+       cork->tos = ipc->tos;
+diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
+index 0488607c5cd3..762edd800d78 100644
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -755,8 +755,9 @@ static unsigned int tcp_established_options(struct sock 
*sk, struct sk_buff *skb
+                       min_t(unsigned int, eff_sacks,
+                             (remaining - TCPOLEN_SACK_BASE_ALIGNED) /
+                             TCPOLEN_SACK_PERBLOCK);
+-              size += TCPOLEN_SACK_BASE_ALIGNED +
+-                      opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK;
++              if (likely(opts->num_sack_blocks))
++                      size += TCPOLEN_SACK_BASE_ALIGNED +
++                              opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK;
+       }
+ 
+       return size;
+diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c
+index 2fc079284ca4..ea00ce3d4117 100644
+--- a/net/ipv6/addrconf_core.c
++++ b/net/ipv6/addrconf_core.c
+@@ -129,11 +129,12 @@ int inet6addr_validator_notifier_call_chain(unsigned 
long val, void *v)
+ }
+ EXPORT_SYMBOL(inet6addr_validator_notifier_call_chain);
+ 
+-static int eafnosupport_ipv6_dst_lookup(struct net *net, struct sock *u1,
+-                                      struct dst_entry **u2,
+-                                      struct flowi6 *u3)
++static struct dst_entry *eafnosupport_ipv6_dst_lookup_flow(struct net *net,
++                                                         const struct sock 
*sk,
++                                                         struct flowi6 *fl6,
++                                                         const struct 
in6_addr *final_dst)
+ {
+-      return -EAFNOSUPPORT;
++      return ERR_PTR(-EAFNOSUPPORT);
+ }
+ 
+ static int eafnosupport_ipv6_route_input(struct sk_buff *skb)
+@@ -190,7 +191,7 @@ static int eafnosupport_ip6_del_rt(struct net *net, struct 
fib6_info *rt)
+ }
+ 
+ const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) {
+-      .ipv6_dst_lookup   = eafnosupport_ipv6_dst_lookup,
++      .ipv6_dst_lookup_flow = eafnosupport_ipv6_dst_lookup_flow,
+       .ipv6_route_input  = eafnosupport_ipv6_route_input,
+       .fib6_get_table    = eafnosupport_fib6_get_table,
+       .fib6_table_lookup = eafnosupport_fib6_table_lookup,
+diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
+index ef37e0574f54..14ac1d911287 100644
+--- a/net/ipv6/af_inet6.c
++++ b/net/ipv6/af_inet6.c
+@@ -765,7 +765,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
+                                        &final);
+               rcu_read_unlock();
+ 
+-              dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
++              dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
+               if (IS_ERR(dst)) {
+                       sk->sk_route_caps = 0;
+                       sk->sk_err_soft = -PTR_ERR(dst);
+@@ -946,7 +946,7 @@ static int ipv6_route_input(struct sk_buff *skb)
+ static const struct ipv6_stub ipv6_stub_impl = {
+       .ipv6_sock_mc_join = ipv6_sock_mc_join,
+       .ipv6_sock_mc_drop = ipv6_sock_mc_drop,
+-      .ipv6_dst_lookup   = ip6_dst_lookup,
++      .ipv6_dst_lookup_flow = ip6_dst_lookup_flow,
+       .ipv6_route_input  = ipv6_route_input,
+       .fib6_get_table    = fib6_get_table,
+       .fib6_table_lookup = fib6_table_lookup,
+diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
+index 96f939248d2f..390bedde21a5 100644
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -85,7 +85,7 @@ int ip6_datagram_dst_update(struct sock *sk, bool 
fix_sk_saddr)
+       final_p = fl6_update_dst(&fl6, opt, &final);
+       rcu_read_unlock();
+ 
+-      dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
++      dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
+       if (IS_ERR(dst)) {
+               err = PTR_ERR(dst);
+               goto out;
+diff --git a/net/ipv6/inet6_connection_sock.c 
b/net/ipv6/inet6_connection_sock.c
+index 0a0945a5b30d..fe9cb8d1adca 100644
+--- a/net/ipv6/inet6_connection_sock.c
++++ b/net/ipv6/inet6_connection_sock.c
+@@ -48,7 +48,7 @@ struct dst_entry *inet6_csk_route_req(const struct sock *sk,
+       fl6->flowi6_uid = sk->sk_uid;
+       security_req_classify_flow(req, flowi6_to_flowi(fl6));
+ 
+-      dst = ip6_dst_lookup_flow(sk, fl6, final_p);
++      dst = ip6_dst_lookup_flow(sock_net(sk), sk, fl6, final_p);
+       if (IS_ERR(dst))
+               return NULL;
+ 
+@@ -103,7 +103,7 @@ static struct dst_entry *inet6_csk_route_socket(struct 
sock *sk,
+ 
+       dst = __inet6_csk_dst_check(sk, np->dst_cookie);
+       if (!dst) {
+-              dst = ip6_dst_lookup_flow(sk, fl6, final_p);
++              dst = ip6_dst_lookup_flow(sock_net(sk), sk, fl6, final_p);
+ 
+               if (!IS_ERR(dst))
+                       ip6_dst_store(sk, dst, NULL, NULL);
+diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
+index 71827b56c006..78d495581d69 100644
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -1144,19 +1144,19 @@ EXPORT_SYMBOL_GPL(ip6_dst_lookup);
+  *    It returns a valid dst pointer on success, or a pointer encoded
+  *    error code.
+  */
+-struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 
*fl6,
++struct dst_entry *ip6_dst_lookup_flow(struct net *net, const struct sock *sk, 
struct flowi6 *fl6,
+                                     const struct in6_addr *final_dst)
+ {
+       struct dst_entry *dst = NULL;
+       int err;
+ 
+-      err = ip6_dst_lookup_tail(sock_net(sk), sk, &dst, fl6);
++      err = ip6_dst_lookup_tail(net, sk, &dst, fl6);
+       if (err)
+               return ERR_PTR(err);
+       if (final_dst)
+               fl6->daddr = *final_dst;
+ 
+-      return xfrm_lookup_route(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 
0);
++      return xfrm_lookup_route(net, dst, flowi6_to_flowi(fl6), sk, 0);
+ }
+ EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
+ 
+@@ -1188,7 +1188,7 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock 
*sk, struct flowi6 *fl6,
+       if (dst)
+               return dst;
+ 
+-      dst = ip6_dst_lookup_flow(sk, fl6, final_dst);
++      dst = ip6_dst_lookup_flow(sock_net(sk), sk, fl6, final_dst);
+       if (connected && !IS_ERR(dst))
+               ip6_sk_dst_store_flow(sk, dst_clone(dst), fl6);
+ 
+diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
+index a77f6b7d3a7c..dfe5e603ffe1 100644
+--- a/net/ipv6/raw.c
++++ b/net/ipv6/raw.c
+@@ -925,7 +925,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr 
*msg, size_t len)
+ 
+       fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
+ 
+-      dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
++      dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
+       if (IS_ERR(dst)) {
+               err = PTR_ERR(dst);
+               goto out;
+diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
+index 16632e02e9b0..30915f6f31e3 100644
+--- a/net/ipv6/syncookies.c
++++ b/net/ipv6/syncookies.c
+@@ -235,7 +235,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct 
sk_buff *skb)
+               fl6.flowi6_uid = sk->sk_uid;
+               security_req_classify_flow(req, flowi6_to_flowi(&fl6));
+ 
+-              dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
++              dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
+               if (IS_ERR(dst))
+                       goto out_free;
+       }
+diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
+index 4804b6dc5e65..b42fa41cfceb 100644
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -275,7 +275,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr 
*uaddr,
+ 
+       security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
+ 
+-      dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
++      dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
+       if (IS_ERR(dst)) {
+               err = PTR_ERR(dst);
+               goto failure;
+@@ -906,7 +906,7 @@ static void tcp_v6_send_response(const struct sock *sk, 
struct sk_buff *skb, u32
+        * Underlying function will use this to retrieve the network
+        * namespace
+        */
+-      dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
++      dst = ip6_dst_lookup_flow(sock_net(ctl_sk), ctl_sk, &fl6, NULL);
+       if (!IS_ERR(dst)) {
+               skb_dst_set(buff, dst);
+               ip6_xmit(ctl_sk, buff, &fl6, fl6.flowi6_mark, NULL, tclass,
+diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
+index 802f19aba7e3..d148766f40d1 100644
+--- a/net/l2tp/l2tp_ip6.c
++++ b/net/l2tp/l2tp_ip6.c
+@@ -615,7 +615,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr 
*msg, size_t len)
+ 
+       fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
+ 
+-      dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
++      dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p);
+       if (IS_ERR(dst)) {
+               err = PTR_ERR(dst);
+               goto out;
+diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
+index c312741df2ce..4701edffb1f7 100644
+--- a/net/mpls/af_mpls.c
++++ b/net/mpls/af_mpls.c
+@@ -617,16 +617,15 @@ static struct net_device *inet6_fib_lookup_dev(struct 
net *net,
+       struct net_device *dev;
+       struct dst_entry *dst;
+       struct flowi6 fl6;
+-      int err;
+ 
+       if (!ipv6_stub)
+               return ERR_PTR(-EAFNOSUPPORT);
+ 
+       memset(&fl6, 0, sizeof(fl6));
+       memcpy(&fl6.daddr, addr, sizeof(struct in6_addr));
+-      err = ipv6_stub->ipv6_dst_lookup(net, NULL, &dst, &fl6);
+-      if (err)
+-              return ERR_PTR(err);
++      dst = ipv6_stub->ipv6_dst_lookup_flow(net, NULL, &fl6, NULL);
++      if (IS_ERR(dst))
++              return ERR_CAST(dst);
+ 
+       dev = dst->dev;
+       dev_hold(dev);
+diff --git a/net/netfilter/nf_tables_offload.c 
b/net/netfilter/nf_tables_offload.c
+index e25dab8128db..5f6037695dee 100644
+--- a/net/netfilter/nf_tables_offload.c
++++ b/net/netfilter/nf_tables_offload.c
+@@ -455,7 +455,7 @@ static int nft_offload_netdev_event(struct notifier_block 
*this,
+       return NOTIFY_DONE;
+ }
+ 
+-static struct flow_indr_block_ing_entry block_ing_entry = {
++static struct flow_indr_block_entry block_ing_entry = {
+       .cb     = nft_indr_block_cb,
+       .list   = LIST_HEAD_INIT(block_ing_entry.list),
+ };
+@@ -472,13 +472,13 @@ int nft_offload_init(void)
+       if (err < 0)
+               return err;
+ 
+-      flow_indr_add_block_ing_cb(&block_ing_entry);
++      flow_indr_add_block_cb(&block_ing_entry);
+ 
+       return 0;
+ }
+ 
+ void nft_offload_exit(void)
+ {
+-      flow_indr_del_block_ing_cb(&block_ing_entry);
++      flow_indr_del_block_cb(&block_ing_entry);
+       unregister_netdevice_notifier(&nft_offload_netdev_notifier);
+ }
+diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
+index 1c77f520f474..99352f09deaa 100644
+--- a/net/openvswitch/actions.c
++++ b/net/openvswitch/actions.c
+@@ -166,7 +166,8 @@ static int push_mpls(struct sk_buff *skb, struct 
sw_flow_key *key,
+       int err;
+ 
+       err = skb_mpls_push(skb, mpls->mpls_lse, mpls->mpls_ethertype,
+-                          skb->mac_len);
++                          skb->mac_len,
++                          ovs_key_mac_proto(key) == MAC_PROTO_ETHERNET);
+       if (err)
+               return err;
+ 
+@@ -179,7 +180,8 @@ static int pop_mpls(struct sk_buff *skb, struct 
sw_flow_key *key,
+ {
+       int err;
+ 
+-      err = skb_mpls_pop(skb, ethertype, skb->mac_len);
++      err = skb_mpls_pop(skb, ethertype, skb->mac_len,
++                         ovs_key_mac_proto(key) == MAC_PROTO_ETHERNET);
+       if (err)
+               return err;
+ 
+diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
+index 05249eb45082..283e8f9a5fd2 100644
+--- a/net/openvswitch/conntrack.c
++++ b/net/openvswitch/conntrack.c
+@@ -903,6 +903,17 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_key 
*key,
+       }
+       err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype);
+ 
++      if (err == NF_ACCEPT &&
++          ct->status & IPS_SRC_NAT && ct->status & IPS_DST_NAT) {
++              if (maniptype == NF_NAT_MANIP_SRC)
++                      maniptype = NF_NAT_MANIP_DST;
++              else
++                      maniptype = NF_NAT_MANIP_SRC;
++
++              err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range,
++                                       maniptype);
++      }
++
+       /* Mark NAT done if successful and update the flow key. */
+       if (err == NF_ACCEPT)
+               ovs_nat_update_key(key, skb, maniptype);
+diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c
+index fcc46025e790..f3232a00970f 100644
+--- a/net/sched/act_ct.c
++++ b/net/sched/act_ct.c
+@@ -329,6 +329,7 @@ static int tcf_ct_act_nat(struct sk_buff *skb,
+                         bool commit)
+ {
+ #if IS_ENABLED(CONFIG_NF_NAT)
++      int err;
+       enum nf_nat_manip_type maniptype;
+ 
+       if (!(ct_action & TCA_CT_ACT_NAT))
+@@ -359,7 +360,17 @@ static int tcf_ct_act_nat(struct sk_buff *skb,
+               return NF_ACCEPT;
+       }
+ 
+-      return ct_nat_execute(skb, ct, ctinfo, range, maniptype);
++      err = ct_nat_execute(skb, ct, ctinfo, range, maniptype);
++      if (err == NF_ACCEPT &&
++          ct->status & IPS_SRC_NAT && ct->status & IPS_DST_NAT) {
++              if (maniptype == NF_NAT_MANIP_SRC)
++                      maniptype = NF_NAT_MANIP_DST;
++              else
++                      maniptype = NF_NAT_MANIP_SRC;
++
++              err = ct_nat_execute(skb, ct, ctinfo, range, maniptype);
++      }
++      return err;
+ #else
+       return NF_ACCEPT;
+ #endif
+diff --git a/net/sched/act_mpls.c b/net/sched/act_mpls.c
+index 4cf6c553bb0b..db570d2bd0e0 100644
+--- a/net/sched/act_mpls.c
++++ b/net/sched/act_mpls.c
+@@ -1,6 +1,7 @@
+ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+ /* Copyright (C) 2019 Netronome Systems, Inc. */
+ 
++#include <linux/if_arp.h>
+ #include <linux/init.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+@@ -76,12 +77,14 @@ static int tcf_mpls_act(struct sk_buff *skb, const struct 
tc_action *a,
+ 
+       switch (p->tcfm_action) {
+       case TCA_MPLS_ACT_POP:
+-              if (skb_mpls_pop(skb, p->tcfm_proto, mac_len))
++              if (skb_mpls_pop(skb, p->tcfm_proto, mac_len,
++                               skb->dev && skb->dev->type == ARPHRD_ETHER))
+                       goto drop;
+               break;
+       case TCA_MPLS_ACT_PUSH:
+               new_lse = tcf_mpls_get_lse(NULL, p, !eth_p_mpls(skb->protocol));
+-              if (skb_mpls_push(skb, new_lse, p->tcfm_proto, mac_len))
++              if (skb_mpls_push(skb, new_lse, p->tcfm_proto, mac_len,
++                                skb->dev && skb->dev->type == ARPHRD_ETHER))
+                       goto drop;
+               break;
+       case TCA_MPLS_ACT_MODIFY:
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index 20d60b8fcb70..6a0eacafdb19 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -626,15 +626,15 @@ static void tcf_chain_flush(struct tcf_chain *chain, 
bool rtnl_held)
+ static int tcf_block_setup(struct tcf_block *block,
+                          struct flow_block_offload *bo);
+ 
+-static void tc_indr_block_ing_cmd(struct net_device *dev,
+-                                struct tcf_block *block,
+-                                flow_indr_block_bind_cb_t *cb,
+-                                void *cb_priv,
+-                                enum flow_block_command command)
++static void tc_indr_block_cmd(struct net_device *dev, struct tcf_block *block,
++                            flow_indr_block_bind_cb_t *cb, void *cb_priv,
++                            enum flow_block_command command, bool ingress)
+ {
+       struct flow_block_offload bo = {
+               .command        = command,
+-              .binder_type    = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS,
++              .binder_type    = ingress ?
++                                FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS :
++                                FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS,
+               .net            = dev_net(dev),
+               .block_shared   = tcf_block_non_null_shared(block),
+       };
+@@ -652,9 +652,10 @@ static void tc_indr_block_ing_cmd(struct net_device *dev,
+       up_write(&block->cb_lock);
+ }
+ 
+-static struct tcf_block *tc_dev_ingress_block(struct net_device *dev)
++static struct tcf_block *tc_dev_block(struct net_device *dev, bool ingress)
+ {
+       const struct Qdisc_class_ops *cops;
++      const struct Qdisc_ops *ops;
+       struct Qdisc *qdisc;
+ 
+       if (!dev_ingress_queue(dev))
+@@ -664,24 +665,37 @@ static struct tcf_block *tc_dev_ingress_block(struct 
net_device *dev)
+       if (!qdisc)
+               return NULL;
+ 
+-      cops = qdisc->ops->cl_ops;
++      ops = qdisc->ops;
++      if (!ops)
++              return NULL;
++
++      if (!ingress && !strcmp("ingress", ops->id))
++              return NULL;
++
++      cops = ops->cl_ops;
+       if (!cops)
+               return NULL;
+ 
+       if (!cops->tcf_block)
+               return NULL;
+ 
+-      return cops->tcf_block(qdisc, TC_H_MIN_INGRESS, NULL);
++      return cops->tcf_block(qdisc,
++                             ingress ? TC_H_MIN_INGRESS : TC_H_MIN_EGRESS,
++                             NULL);
+ }
+ 
+-static void tc_indr_block_get_and_ing_cmd(struct net_device *dev,
+-                                        flow_indr_block_bind_cb_t *cb,
+-                                        void *cb_priv,
+-                                        enum flow_block_command command)
++static void tc_indr_block_get_and_cmd(struct net_device *dev,
++                                    flow_indr_block_bind_cb_t *cb,
++                                    void *cb_priv,
++                                    enum flow_block_command command)
+ {
+-      struct tcf_block *block = tc_dev_ingress_block(dev);
++      struct tcf_block *block;
++
++      block = tc_dev_block(dev, true);
++      tc_indr_block_cmd(dev, block, cb, cb_priv, command, true);
+ 
+-      tc_indr_block_ing_cmd(dev, block, cb, cb_priv, command);
++      block = tc_dev_block(dev, false);
++      tc_indr_block_cmd(dev, block, cb, cb_priv, command, false);
+ }
+ 
+ static void tc_indr_block_call(struct tcf_block *block,
+@@ -2721,13 +2735,19 @@ static int tc_chain_tmplt_add(struct tcf_chain *chain, 
struct net *net,
+                             struct netlink_ext_ack *extack)
+ {
+       const struct tcf_proto_ops *ops;
++      char name[IFNAMSIZ];
+       void *tmplt_priv;
+ 
+       /* If kind is not set, user did not specify template. */
+       if (!tca[TCA_KIND])
+               return 0;
+ 
+-      ops = tcf_proto_lookup_ops(nla_data(tca[TCA_KIND]), true, extack);
++      if (tcf_proto_check_kind(tca[TCA_KIND], name)) {
++              NL_SET_ERR_MSG(extack, "Specified TC chain template name too 
long");
++              return -EINVAL;
++      }
++
++      ops = tcf_proto_lookup_ops(name, true, extack);
+       if (IS_ERR(ops))
+               return PTR_ERR(ops);
+       if (!ops->tmplt_create || !ops->tmplt_destroy || !ops->tmplt_dump) {
+@@ -3626,9 +3646,9 @@ static struct pernet_operations tcf_net_ops = {
+       .size = sizeof(struct tcf_net),
+ };
+ 
+-static struct flow_indr_block_ing_entry block_ing_entry = {
+-      .cb = tc_indr_block_get_and_ing_cmd,
+-      .list = LIST_HEAD_INIT(block_ing_entry.list),
++static struct flow_indr_block_entry block_entry = {
++      .cb = tc_indr_block_get_and_cmd,
++      .list = LIST_HEAD_INIT(block_entry.list),
+ };
+ 
+ static int __init tc_filter_init(void)
+@@ -3643,7 +3663,7 @@ static int __init tc_filter_init(void)
+       if (err)
+               goto err_register_pernet_subsys;
+ 
+-      flow_indr_add_block_ing_cb(&block_ing_entry);
++      flow_indr_add_block_cb(&block_entry);
+ 
+       rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_new_tfilter, NULL,
+                     RTNL_FLAG_DOIT_UNLOCKED);
+diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
+index 74221e3351c3..4ac110bf19c5 100644
+--- a/net/sched/cls_flower.c
++++ b/net/sched/cls_flower.c
+@@ -54,8 +54,13 @@ struct fl_flow_key {
+       struct flow_dissector_key_ip ip;
+       struct flow_dissector_key_ip enc_ip;
+       struct flow_dissector_key_enc_opts enc_opts;
+-      struct flow_dissector_key_ports tp_min;
+-      struct flow_dissector_key_ports tp_max;
++      union {
++              struct flow_dissector_key_ports tp;
++              struct {
++                      struct flow_dissector_key_ports tp_min;
++                      struct flow_dissector_key_ports tp_max;
++              };
++      } tp_range;
+       struct flow_dissector_key_ct ct;
+ } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as 
longs. */
+ 
+@@ -198,19 +203,19 @@ static bool fl_range_port_dst_cmp(struct cls_fl_filter 
*filter,
+ {
+       __be16 min_mask, max_mask, min_val, max_val;
+ 
+-      min_mask = htons(filter->mask->key.tp_min.dst);
+-      max_mask = htons(filter->mask->key.tp_max.dst);
+-      min_val = htons(filter->key.tp_min.dst);
+-      max_val = htons(filter->key.tp_max.dst);
++      min_mask = htons(filter->mask->key.tp_range.tp_min.dst);
++      max_mask = htons(filter->mask->key.tp_range.tp_max.dst);
++      min_val = htons(filter->key.tp_range.tp_min.dst);
++      max_val = htons(filter->key.tp_range.tp_max.dst);
+ 
+       if (min_mask && max_mask) {
+-              if (htons(key->tp.dst) < min_val ||
+-                  htons(key->tp.dst) > max_val)
++              if (htons(key->tp_range.tp.dst) < min_val ||
++                  htons(key->tp_range.tp.dst) > max_val)
+                       return false;
+ 
+               /* skb does not have min and max values */
+-              mkey->tp_min.dst = filter->mkey.tp_min.dst;
+-              mkey->tp_max.dst = filter->mkey.tp_max.dst;
++              mkey->tp_range.tp_min.dst = filter->mkey.tp_range.tp_min.dst;
++              mkey->tp_range.tp_max.dst = filter->mkey.tp_range.tp_max.dst;
+       }
+       return true;
+ }
+@@ -221,19 +226,19 @@ static bool fl_range_port_src_cmp(struct cls_fl_filter 
*filter,
+ {
+       __be16 min_mask, max_mask, min_val, max_val;
+ 
+-      min_mask = htons(filter->mask->key.tp_min.src);
+-      max_mask = htons(filter->mask->key.tp_max.src);
+-      min_val = htons(filter->key.tp_min.src);
+-      max_val = htons(filter->key.tp_max.src);
++      min_mask = htons(filter->mask->key.tp_range.tp_min.src);
++      max_mask = htons(filter->mask->key.tp_range.tp_max.src);
++      min_val = htons(filter->key.tp_range.tp_min.src);
++      max_val = htons(filter->key.tp_range.tp_max.src);
+ 
+       if (min_mask && max_mask) {
+-              if (htons(key->tp.src) < min_val ||
+-                  htons(key->tp.src) > max_val)
++              if (htons(key->tp_range.tp.src) < min_val ||
++                  htons(key->tp_range.tp.src) > max_val)
+                       return false;
+ 
+               /* skb does not have min and max values */
+-              mkey->tp_min.src = filter->mkey.tp_min.src;
+-              mkey->tp_max.src = filter->mkey.tp_max.src;
++              mkey->tp_range.tp_min.src = filter->mkey.tp_range.tp_min.src;
++              mkey->tp_range.tp_max.src = filter->mkey.tp_range.tp_max.src;
+       }
+       return true;
+ }
+@@ -715,23 +720,25 @@ static void fl_set_key_val(struct nlattr **tb,
+ static int fl_set_key_port_range(struct nlattr **tb, struct fl_flow_key *key,
+                                struct fl_flow_key *mask)
+ {
+-      fl_set_key_val(tb, &key->tp_min.dst,
+-                     TCA_FLOWER_KEY_PORT_DST_MIN, &mask->tp_min.dst,
+-                     TCA_FLOWER_UNSPEC, sizeof(key->tp_min.dst));
+-      fl_set_key_val(tb, &key->tp_max.dst,
+-                     TCA_FLOWER_KEY_PORT_DST_MAX, &mask->tp_max.dst,
+-                     TCA_FLOWER_UNSPEC, sizeof(key->tp_max.dst));
+-      fl_set_key_val(tb, &key->tp_min.src,
+-                     TCA_FLOWER_KEY_PORT_SRC_MIN, &mask->tp_min.src,
+-                     TCA_FLOWER_UNSPEC, sizeof(key->tp_min.src));
+-      fl_set_key_val(tb, &key->tp_max.src,
+-                     TCA_FLOWER_KEY_PORT_SRC_MAX, &mask->tp_max.src,
+-                     TCA_FLOWER_UNSPEC, sizeof(key->tp_max.src));
+-
+-      if ((mask->tp_min.dst && mask->tp_max.dst &&
+-           htons(key->tp_max.dst) <= htons(key->tp_min.dst)) ||
+-           (mask->tp_min.src && mask->tp_max.src &&
+-            htons(key->tp_max.src) <= htons(key->tp_min.src)))
++      fl_set_key_val(tb, &key->tp_range.tp_min.dst,
++                     TCA_FLOWER_KEY_PORT_DST_MIN, &mask->tp_range.tp_min.dst,
++                     TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_min.dst));
++      fl_set_key_val(tb, &key->tp_range.tp_max.dst,
++                     TCA_FLOWER_KEY_PORT_DST_MAX, &mask->tp_range.tp_max.dst,
++                     TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_max.dst));
++      fl_set_key_val(tb, &key->tp_range.tp_min.src,
++                     TCA_FLOWER_KEY_PORT_SRC_MIN, &mask->tp_range.tp_min.src,
++                     TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_min.src));
++      fl_set_key_val(tb, &key->tp_range.tp_max.src,
++                     TCA_FLOWER_KEY_PORT_SRC_MAX, &mask->tp_range.tp_max.src,
++                     TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_max.src));
++
++      if ((mask->tp_range.tp_min.dst && mask->tp_range.tp_max.dst &&
++           htons(key->tp_range.tp_max.dst) <=
++               htons(key->tp_range.tp_min.dst)) ||
++          (mask->tp_range.tp_min.src && mask->tp_range.tp_max.src &&
++           htons(key->tp_range.tp_max.src) <=
++               htons(key->tp_range.tp_min.src)))
+               return -EINVAL;
+ 
+       return 0;
+@@ -1320,9 +1327,10 @@ static void fl_init_dissector(struct flow_dissector 
*dissector,
+                            FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
+       FL_KEY_SET_IF_MASKED(mask, keys, cnt,
+                            FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
+-      if (FL_KEY_IS_MASKED(mask, tp) ||
+-          FL_KEY_IS_MASKED(mask, tp_min) || FL_KEY_IS_MASKED(mask, tp_max))
+-              FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_PORTS, tp);
++      FL_KEY_SET_IF_MASKED(mask, keys, cnt,
++                           FLOW_DISSECTOR_KEY_PORTS, tp);
++      FL_KEY_SET_IF_MASKED(mask, keys, cnt,
++                           FLOW_DISSECTOR_KEY_PORTS_RANGE, tp_range);
+       FL_KEY_SET_IF_MASKED(mask, keys, cnt,
+                            FLOW_DISSECTOR_KEY_IP, ip);
+       FL_KEY_SET_IF_MASKED(mask, keys, cnt,
+@@ -1371,8 +1379,10 @@ static struct fl_flow_mask *fl_create_new_mask(struct 
cls_fl_head *head,
+ 
+       fl_mask_copy(newmask, mask);
+ 
+-      if ((newmask->key.tp_min.dst && newmask->key.tp_max.dst) ||
+-          (newmask->key.tp_min.src && newmask->key.tp_max.src))
++      if ((newmask->key.tp_range.tp_min.dst &&
++           newmask->key.tp_range.tp_max.dst) ||
++          (newmask->key.tp_range.tp_min.src &&
++           newmask->key.tp_range.tp_max.src))
+               newmask->flags |= TCA_FLOWER_MASK_FLAGS_RANGE;
+ 
+       err = fl_init_mask_hashtable(newmask);
+@@ -1970,18 +1980,22 @@ static int fl_dump_key_val(struct sk_buff *skb,
+ static int fl_dump_key_port_range(struct sk_buff *skb, struct fl_flow_key 
*key,
+                                 struct fl_flow_key *mask)
+ {
+-      if (fl_dump_key_val(skb, &key->tp_min.dst, TCA_FLOWER_KEY_PORT_DST_MIN,
+-                          &mask->tp_min.dst, TCA_FLOWER_UNSPEC,
+-                          sizeof(key->tp_min.dst)) ||
+-          fl_dump_key_val(skb, &key->tp_max.dst, TCA_FLOWER_KEY_PORT_DST_MAX,
+-                          &mask->tp_max.dst, TCA_FLOWER_UNSPEC,
+-                          sizeof(key->tp_max.dst)) ||
+-          fl_dump_key_val(skb, &key->tp_min.src, TCA_FLOWER_KEY_PORT_SRC_MIN,
+-                          &mask->tp_min.src, TCA_FLOWER_UNSPEC,
+-                          sizeof(key->tp_min.src)) ||
+-          fl_dump_key_val(skb, &key->tp_max.src, TCA_FLOWER_KEY_PORT_SRC_MAX,
+-                          &mask->tp_max.src, TCA_FLOWER_UNSPEC,
+-                          sizeof(key->tp_max.src)))
++      if (fl_dump_key_val(skb, &key->tp_range.tp_min.dst,
++                          TCA_FLOWER_KEY_PORT_DST_MIN,
++                          &mask->tp_range.tp_min.dst, TCA_FLOWER_UNSPEC,
++                          sizeof(key->tp_range.tp_min.dst)) ||
++          fl_dump_key_val(skb, &key->tp_range.tp_max.dst,
++                          TCA_FLOWER_KEY_PORT_DST_MAX,
++                          &mask->tp_range.tp_max.dst, TCA_FLOWER_UNSPEC,
++                          sizeof(key->tp_range.tp_max.dst)) ||
++          fl_dump_key_val(skb, &key->tp_range.tp_min.src,
++                          TCA_FLOWER_KEY_PORT_SRC_MIN,
++                          &mask->tp_range.tp_min.src, TCA_FLOWER_UNSPEC,
++                          sizeof(key->tp_range.tp_min.src)) ||
++          fl_dump_key_val(skb, &key->tp_range.tp_max.src,
++                          TCA_FLOWER_KEY_PORT_SRC_MAX,
++                          &mask->tp_range.tp_max.src, TCA_FLOWER_UNSPEC,
++                          sizeof(key->tp_range.tp_max.src)))
+               return -1;
+ 
+       return 0;
+diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c
+index 278c0b2dc523..e79f1afe0cfd 100644
+--- a/net/sched/sch_mq.c
++++ b/net/sched/sch_mq.c
+@@ -153,6 +153,7 @@ static int mq_dump(struct Qdisc *sch, struct sk_buff *skb)
+                       __gnet_stats_copy_queue(&sch->qstats,
+                                               qdisc->cpu_qstats,
+                                               &qdisc->qstats, qlen);
++                      sch->q.qlen             += qlen;
+               } else {
+                       sch->q.qlen             += qdisc->q.qlen;
+                       sch->bstats.bytes       += qdisc->bstats.bytes;
+diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c
+index 0d0113a24962..8766ab5b8788 100644
+--- a/net/sched/sch_mqprio.c
++++ b/net/sched/sch_mqprio.c
+@@ -411,6 +411,7 @@ static int mqprio_dump(struct Qdisc *sch, struct sk_buff 
*skb)
+                       __gnet_stats_copy_queue(&sch->qstats,
+                                               qdisc->cpu_qstats,
+                                               &qdisc->qstats, qlen);
++                      sch->q.qlen             += qlen;
+               } else {
+                       sch->q.qlen             += qdisc->q.qlen;
+                       sch->bstats.bytes       += qdisc->bstats.bytes;
+@@ -433,7 +434,7 @@ static int mqprio_dump(struct Qdisc *sch, struct sk_buff 
*skb)
+               opt.offset[tc] = dev->tc_to_txq[tc].offset;
+       }
+ 
+-      if (nla_put(skb, TCA_OPTIONS, NLA_ALIGN(sizeof(opt)), &opt))
++      if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
+               goto nla_put_failure;
+ 
+       if ((priv->flags & TC_MQPRIO_F_MODE) &&
+diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
+index dd860fea0148..bc734cfaa29e 100644
+--- a/net/sctp/ipv6.c
++++ b/net/sctp/ipv6.c
+@@ -275,7 +275,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, 
union sctp_addr *saddr,
+       final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
+       rcu_read_unlock();
+ 
+-      dst = ip6_dst_lookup_flow(sk, fl6, final_p);
++      dst = ip6_dst_lookup_flow(sock_net(sk), sk, fl6, final_p);
+       if (!asoc || saddr)
+               goto out;
+ 
+@@ -328,7 +328,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, 
union sctp_addr *saddr,
+               fl6->saddr = laddr->a.v6.sin6_addr;
+               fl6->fl6_sport = laddr->a.v6.sin6_port;
+               final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
+-              bdst = ip6_dst_lookup_flow(sk, fl6, final_p);
++              bdst = ip6_dst_lookup_flow(sock_net(sk), sk, fl6, final_p);
+ 
+               if (IS_ERR(bdst))
+                       continue;
+diff --git a/net/tipc/core.c b/net/tipc/core.c
+index 8f35060a24e1..12192e7f4050 100644
+--- a/net/tipc/core.c
++++ b/net/tipc/core.c
+@@ -125,14 +125,6 @@ static int __init tipc_init(void)
+       sysctl_tipc_rmem[1] = RCVBUF_DEF;
+       sysctl_tipc_rmem[2] = RCVBUF_MAX;
+ 
+-      err = tipc_netlink_start();
+-      if (err)
+-              goto out_netlink;
+-
+-      err = tipc_netlink_compat_start();
+-      if (err)
+-              goto out_netlink_compat;
+-
+       err = tipc_register_sysctl();
+       if (err)
+               goto out_sysctl;
+@@ -153,8 +145,21 @@ static int __init tipc_init(void)
+       if (err)
+               goto out_bearer;
+ 
++      err = tipc_netlink_start();
++      if (err)
++              goto out_netlink;
++
++      err = tipc_netlink_compat_start();
++      if (err)
++              goto out_netlink_compat;
++
+       pr_info("Started in single node mode\n");
+       return 0;
++
++out_netlink_compat:
++      tipc_netlink_stop();
++out_netlink:
++      tipc_bearer_cleanup();
+ out_bearer:
+       unregister_pernet_device(&tipc_topsrv_net_ops);
+ out_pernet_topsrv:
+@@ -164,22 +169,18 @@ out_socket:
+ out_pernet:
+       tipc_unregister_sysctl();
+ out_sysctl:
+-      tipc_netlink_compat_stop();
+-out_netlink_compat:
+-      tipc_netlink_stop();
+-out_netlink:
+       pr_err("Unable to start in single node mode\n");
+       return err;
+ }
+ 
+ static void __exit tipc_exit(void)
+ {
++      tipc_netlink_compat_stop();
++      tipc_netlink_stop();
+       tipc_bearer_cleanup();
+       unregister_pernet_device(&tipc_topsrv_net_ops);
+       tipc_socket_stop();
+       unregister_pernet_device(&tipc_net_ops);
+-      tipc_netlink_stop();
+-      tipc_netlink_compat_stop();
+       tipc_unregister_sysctl();
+ 
+       pr_info("Deactivated\n");
+diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
+index 287df68721df..186c78431217 100644
+--- a/net/tipc/udp_media.c
++++ b/net/tipc/udp_media.c
+@@ -195,10 +195,13 @@ static int tipc_udp_xmit(struct net *net, struct sk_buff 
*skb,
+                               .saddr = src->ipv6,
+                               .flowi6_proto = IPPROTO_UDP
+                       };
+-                      err = ipv6_stub->ipv6_dst_lookup(net, ub->ubsock->sk,
+-                                                       &ndst, &fl6);
+-                      if (err)
++                      ndst = ipv6_stub->ipv6_dst_lookup_flow(net,
++                                                             ub->ubsock->sk,
++                                                             &fl6, NULL);
++                      if (IS_ERR(ndst)) {
++                              err = PTR_ERR(ndst);
+                               goto tx_error;
++                      }
+                       dst_cache_set_ip6(cache, ndst, &fl6.saddr);
+               }
+               ttl = ip6_dst_hoplimit(ndst);
+diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c
+index 683d00837693..3f5209e2d4ee 100644
+--- a/net/tls/tls_device.c
++++ b/net/tls/tls_device.c
+@@ -417,7 +417,7 @@ static int tls_push_data(struct sock *sk,
+ 
+       if (flags &
+           ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | MSG_SENDPAGE_NOTLAST))
+-              return -ENOTSUPP;
++              return -EOPNOTSUPP;
+ 
+       if (sk->sk_err)
+               return -sk->sk_err;
+@@ -560,7 +560,7 @@ int tls_device_sendpage(struct sock *sk, struct page *page,
+       lock_sock(sk);
+ 
+       if (flags & MSG_OOB) {
+-              rc = -ENOTSUPP;
++              rc = -EOPNOTSUPP;
+               goto out;
+       }
+ 
+@@ -999,7 +999,7 @@ int tls_set_device_offload(struct sock *sk, struct 
tls_context *ctx)
+       }
+ 
+       if (!(netdev->features & NETIF_F_HW_TLS_TX)) {
+-              rc = -ENOTSUPP;
++              rc = -EOPNOTSUPP;
+               goto release_netdev;
+       }
+ 
+@@ -1071,7 +1071,7 @@ int tls_set_device_offload_rx(struct sock *sk, struct 
tls_context *ctx)
+       }
+ 
+       if (!(netdev->features & NETIF_F_HW_TLS_RX)) {
+-              rc = -ENOTSUPP;
++              rc = -EOPNOTSUPP;
+               goto release_netdev;
+       }
+ 
+diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
+index eff444293594..82d0beed8f07 100644
+--- a/net/tls/tls_main.c
++++ b/net/tls/tls_main.c
+@@ -482,7 +482,7 @@ static int do_tls_setsockopt_conf(struct sock *sk, char 
__user *optval,
+       /* check version */
+       if (crypto_info->version != TLS_1_2_VERSION &&
+           crypto_info->version != TLS_1_3_VERSION) {
+-              rc = -ENOTSUPP;
++              rc = -EINVAL;
+               goto err_crypto_info;
+       }
+ 
+@@ -778,7 +778,7 @@ static int tls_init(struct sock *sk)
+        * share the ulp context.
+        */
+       if (sk->sk_state != TCP_ESTABLISHED)
+-              return -ENOTSUPP;
++              return -ENOTCONN;
+ 
+       tls_build_proto(sk);
+ 
+diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
+index 5dd0f01913c0..c70cf30c5492 100644
+--- a/net/tls/tls_sw.c
++++ b/net/tls/tls_sw.c
+@@ -900,7 +900,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, 
size_t size)
+       int ret = 0;
+ 
+       if (msg->msg_flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL))
+-              return -ENOTSUPP;
++              return -EOPNOTSUPP;
+ 
+       mutex_lock(&tls_ctx->tx_lock);
+       lock_sock(sk);
+@@ -1215,7 +1215,7 @@ int tls_sw_sendpage_locked(struct sock *sk, struct page 
*page,
+       if (flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL |
+                     MSG_SENDPAGE_NOTLAST | MSG_SENDPAGE_NOPOLICY |
+                     MSG_NO_SHARED_FRAGS))
+-              return -ENOTSUPP;
++              return -EOPNOTSUPP;
+ 
+       return tls_sw_do_sendpage(sk, page, offset, size, flags);
+ }
+@@ -1228,7 +1228,7 @@ int tls_sw_sendpage(struct sock *sk, struct page *page,
+ 
+       if (flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL |
+                     MSG_SENDPAGE_NOTLAST | MSG_SENDPAGE_NOPOLICY))
+-              return -ENOTSUPP;
++              return -EOPNOTSUPP;
+ 
+       mutex_lock(&tls_ctx->tx_lock);
+       lock_sock(sk);
+@@ -1927,7 +1927,7 @@ ssize_t tls_sw_splice_read(struct socket *sock,  loff_t 
*ppos,
+ 
+               /* splice does not support reading control messages */
+               if (ctx->control != TLS_RECORD_TYPE_DATA) {
+-                      err = -ENOTSUPP;
++                      err = -EINVAL;
+                       goto splice_read_end;
+               }
+ 
+diff --git a/tools/testing/selftests/net/tls.c 
b/tools/testing/selftests/net/tls.c
+index 46abcae47dee..13e5ef615026 100644
+--- a/tools/testing/selftests/net/tls.c
++++ b/tools/testing/selftests/net/tls.c
+@@ -25,10 +25,6 @@
+ #define TLS_PAYLOAD_MAX_LEN 16384
+ #define SOL_TLS 282
+ 
+-#ifndef ENOTSUPP
+-#define ENOTSUPP 524
+-#endif
+-
+ FIXTURE(tls_basic)
+ {
+       int fd, cfd;
+@@ -1205,11 +1201,11 @@ TEST(non_established) {
+       /* TLS ULP not supported */
+       if (errno == ENOENT)
+               return;
+-      EXPECT_EQ(errno, ENOTSUPP);
++      EXPECT_EQ(errno, ENOTCONN);
+ 
+       ret = setsockopt(sfd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
+       EXPECT_EQ(ret, -1);
+-      EXPECT_EQ(errno, ENOTSUPP);
++      EXPECT_EQ(errno, ENOTCONN);
+ 
+       ret = getsockname(sfd, &addr, &len);
+       ASSERT_EQ(ret, 0);

Reply via email to