]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorDavid S. Miller <davem@davemloft.net>
Fri, 30 Jun 2017 16:43:08 +0000 (12:43 -0400)
committerDavid S. Miller <davem@davemloft.net>
Fri, 30 Jun 2017 16:43:08 +0000 (12:43 -0400)
A set of overlapping changes in macvlan and the rocker
driver, nothing serious.

Signed-off-by: David S. Miller <davem@davemloft.net>
33 files changed:
1  2 
MAINTAINERS
drivers/net/arcnet/arcnet.c
drivers/net/arcnet/capmode.c
drivers/net/arcnet/com20020-pci.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
drivers/net/ethernet/rocker/rocker_ofdpa.c
drivers/net/ethernet/sfc/ef10.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/macvlan.c
drivers/net/phy/micrel.c
drivers/net/usb/ax88179_178a.c
drivers/net/veth.c
drivers/net/virtio_net.c
drivers/scsi/qedi/qedi_fw.c
drivers/scsi/qedi/qedi_main.c
include/net/xfrm.h
kernel/bpf/verifier.c
net/core/dev.c
net/ipv4/tcp.c
net/ipv6/addrconf.c
net/ipv6/ip6_output.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/udp.c
net/key/af_key.c
net/sched/sch_api.c
net/xfrm/xfrm_device.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_user.c
tools/testing/selftests/bpf/test_verifier.c

diff --combined MAINTAINERS
index c324460d50423a54022b010847f71f756d0f6e92,767e9d202adf889d5ae0a746dc6dd7a9561c4a83..4c913c81cb49569a907ac0a512b058c4413d347d
@@@ -155,7 -155,7 +155,7 @@@ S: Maintaine
  F:    drivers/scsi/53c700*
  
  6LOWPAN GENERIC (BTLE/IEEE 802.15.4)
 -M:    Alexander Aring <aar@pengutronix.de>
 +M:    Alexander Aring <alex.aring@gmail.com>
  M:    Jukka Rissanen <jukka.rissanen@linux.intel.com>
  L:    linux-bluetooth@vger.kernel.org
  L:    linux-wpan@vger.kernel.org
@@@ -2964,7 -2964,7 +2964,7 @@@ F:      sound/pci/oxygen
  
  C6X ARCHITECTURE
  M:    Mark Salter <msalter@redhat.com>
- M:    Aurelien Jacquiot <a-jacquiot@ti.com>
+ M:    Aurelien Jacquiot <jacquiot.aurelien@gmail.com>
  L:    linux-c6x-dev@linux-c6x.org
  W:    http://www.linux-c6x.org/wiki/index.php/Main_Page
  S:    Maintained
@@@ -6426,7 -6426,7 +6426,7 @@@ F:      Documentation/cdrom/ide-c
  F:    drivers/ide/ide-cd*
  
  IEEE 802.15.4 SUBSYSTEM
 -M:    Alexander Aring <aar@pengutronix.de>
 +M:    Alexander Aring <alex.aring@gmail.com>
  M:    Stefan Schmidt <stefan@osg.samsung.com>
  L:    linux-wpan@vger.kernel.org
  W:    http://wpan.cakelab.org/
@@@ -6737,7 -6737,6 +6737,7 @@@ F:      Documentation/networking/i40e.tx
  F:    Documentation/networking/i40evf.txt
  F:    drivers/net/ethernet/intel/
  F:    drivers/net/ethernet/intel/*/
 +F:    include/linux/avf/virtchnl.h
  
  INTEL RDMA RNIC DRIVER
  M:     Faisal Latif <faisal.latif@intel.com>
@@@ -7978,12 -7977,6 +7978,12 @@@ S:    Maintaine
  F:    drivers/net/ethernet/marvell/mv643xx_eth.*
  F:    include/linux/mv643xx.h
  
 +MARVELL MV88X3310 PHY DRIVER
 +M:    Russell King <rmk@armlinux.org.uk>
 +L:    netdev@vger.kernel.org
 +S:    Maintained
 +F:    drivers/net/phy/marvell10g.c
 +
  MARVELL MVNETA ETHERNET DRIVER
  M:    Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
  L:    netdev@vger.kernel.org
@@@ -8317,26 -8310,6 +8317,26 @@@ W:    http://www.mellanox.co
  Q:    http://patchwork.ozlabs.org/project/netdev/list/
  F:    drivers/net/ethernet/mellanox/mlx5/core/en_*
  
 +MELLANOX ETHERNET INNOVA DRIVER
 +M:    Ilan Tayari <ilant@mellanox.com>
 +R:    Boris Pismenny <borisp@mellanox.com>
 +L:    netdev@vger.kernel.org
 +S:    Supported
 +W:    http://www.mellanox.com
 +Q:    http://patchwork.ozlabs.org/project/netdev/list/
 +F:    drivers/net/ethernet/mellanox/mlx5/core/fpga/*
 +F:    include/linux/mlx5/mlx5_ifc_fpga.h
 +
 +MELLANOX ETHERNET INNOVA IPSEC DRIVER
 +M:    Ilan Tayari <ilant@mellanox.com>
 +R:    Boris Pismenny <borisp@mellanox.com>
 +L:    netdev@vger.kernel.org
 +S:    Supported
 +W:    http://www.mellanox.com
 +Q:    http://patchwork.ozlabs.org/project/netdev/list/
 +F:    drivers/net/ethernet/mellanox/mlx5/core/en_ipsec/*
 +F:    drivers/net/ethernet/mellanox/mlx5/core/ipsec*
 +
  MELLANOX ETHERNET SWITCH DRIVERS
  M:    Jiri Pirko <jiri@mellanox.com>
  M:    Ido Schimmel <idosch@mellanox.com>
@@@ -8346,14 -8319,6 +8346,14 @@@ W:    http://www.mellanox.co
  Q:    http://patchwork.ozlabs.org/project/netdev/list/
  F:    drivers/net/ethernet/mellanox/mlxsw/
  
 +MELLANOX FIRMWARE FLASH LIBRARY (mlxfw)
 +M:    Yotam Gigi <yotamg@mellanox.com>
 +L:    netdev@vger.kernel.org
 +S:    Supported
 +W:    http://www.mellanox.com
 +Q:    http://patchwork.ozlabs.org/project/netdev/list/
 +F:    drivers/net/ethernet/mellanox/mlxfw/
 +
  MELLANOX MLXCPLD I2C AND MUX DRIVER
  M:    Vadim Pasternak <vadimp@mellanox.com>
  M:    Michael Shych <michaelsh@mellanox.com>
@@@ -8495,16 -8460,6 +8495,16 @@@ F:    drivers/media/platform/atmel/atmel-i
  F:    drivers/media/platform/atmel/atmel-isc-regs.h
  F:    devicetree/bindings/media/atmel-isc.txt
  
 +MICROCHIP KSZ SERIES ETHERNET SWITCH DRIVER
 +M:    Woojung Huh <Woojung.Huh@microchip.com>
 +M:    Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
 +L:    netdev@vger.kernel.org
 +S:    Maintained
 +F:    net/dsa/tag_ksz.c
 +F:    drivers/net/dsa/microchip/*
 +F:    include/linux/platform_data/microchip-ksz.h
 +F:    Documentation/devicetree/bindings/net/dsa/ksz.txt
 +
  MICROCHIP USB251XB DRIVER
  M:    Richard Leitner <richard.leitner@skidata.com>
  L:    linux-usb@vger.kernel.org
@@@ -8988,16 -8943,6 +8988,16 @@@ F:    net/ipv6
  F:    include/net/ip*
  F:    arch/x86/net/*
  
 +NETWORKING [TLS]
 +M:    Ilya Lesokhin <ilyal@mellanox.com>
 +M:    Aviad Yehezkel <aviadye@mellanox.com>
 +M:    Dave Watson <davejwatson@fb.com>
 +L:    netdev@vger.kernel.org
 +S:    Maintained
 +F:    net/tls/*
 +F:    include/uapi/linux/tls.h
 +F:    include/net/tls.h
 +
  NETWORKING [IPSEC]
  M:    Steffen Klassert <steffen.klassert@secunet.com>
  M:    Herbert Xu <herbert@gondor.apana.org.au>
@@@ -10653,14 -10598,6 +10653,14 @@@ L: qemu-devel@nongnu.or
  S:    Maintained
  F:    drivers/firmware/qemu_fw_cfg.c
  
 +QUANTENNA QTNFMAC WIRELESS DRIVER
 +M:   Igor Mitsyanko <imitsyanko@quantenna.com>
 +M:   Avinash Patil <avinashp@quantenna.com>
 +M:   Sergey Matyukevich <smatyukevich@quantenna.com>
 +L:   linux-wireless@vger.kernel.org
 +S:   Maintained
 +F:   drivers/net/wireless/quantenna
 +
  RADOS BLOCK DEVICE (RBD)
  M:    Ilya Dryomov <idryomov@gmail.com>
  M:    Sage Weil <sage@redhat.com>
index d87f4da29f1138f6ee24b7dcc7bd6e775d9d8d0b,53a1cb551defabe29e763e578632c33ac851547f..fcfccbb3d9a2a0e5a6a84ee0daea317e5d2b32b6
@@@ -51,7 -51,6 +51,7 @@@
  #include <net/arp.h>
  #include <linux/init.h>
  #include <linux/jiffies.h>
 +#include <linux/errqueue.h>
  
  #include <linux/leds.h>
  
@@@ -392,52 -391,6 +392,52 @@@ static void arcnet_timer(unsigned long 
        }
  }
  
 +static void arcnet_reply_tasklet(unsigned long data)
 +{
 +      struct arcnet_local *lp = (struct arcnet_local *)data;
 +
 +      struct sk_buff *ackskb, *skb;
 +      struct sock_exterr_skb *serr;
 +      struct sock *sk;
 +      int ret;
 +
 +      local_irq_disable();
 +      skb = lp->outgoing.skb;
 +      if (!skb || !skb->sk) {
 +              local_irq_enable();
 +              return;
 +      }
 +
 +      sock_hold(skb->sk);
 +      sk = skb->sk;
 +      ackskb = skb_clone_sk(skb);
 +      sock_put(skb->sk);
 +
 +      if (!ackskb) {
 +              local_irq_enable();
 +              return;
 +      }
 +
 +      serr = SKB_EXT_ERR(ackskb);
 +      memset(serr, 0, sizeof(*serr));
 +      serr->ee.ee_errno = ENOMSG;
 +      serr->ee.ee_origin = SO_EE_ORIGIN_TXSTATUS;
 +      serr->ee.ee_data = skb_shinfo(skb)->tskey;
 +      serr->ee.ee_info = lp->reply_status;
 +
 +      /* finally erasing outgoing skb */
 +      dev_kfree_skb(lp->outgoing.skb);
 +      lp->outgoing.skb = NULL;
 +
 +      ackskb->dev = lp->dev;
 +
 +      ret = sock_queue_err_skb(sk, ackskb);
 +      if (ret)
 +              kfree_skb(ackskb);
 +
 +      local_irq_enable();
 +};
 +
  struct net_device *alloc_arcdev(const char *name)
  {
        struct net_device *dev;
        if (dev) {
                struct arcnet_local *lp = netdev_priv(dev);
  
 +              lp->dev = dev;
                spin_lock_init(&lp->lock);
                init_timer(&lp->timer);
                lp->timer.data = (unsigned long) dev;
@@@ -484,9 -436,6 +484,9 @@@ int arcnet_open(struct net_device *dev
                arc_cont(D_PROTO, "\n");
        }
  
 +      tasklet_init(&lp->reply_tasklet, arcnet_reply_tasklet,
 +                   (unsigned long)lp);
 +
        arc_printk(D_INIT, dev, "arcnet_open: resetting card.\n");
  
        /* try to put the card in a defined state - if it fails the first
@@@ -578,8 -527,6 +578,8 @@@ int arcnet_close(struct net_device *dev
        netif_stop_queue(dev);
        netif_carrier_off(dev);
  
 +      tasklet_kill(&lp->reply_tasklet);
 +
        /* flush TX and disable RX */
        lp->hw.intmask(dev, 0);
        lp->hw.command(dev, NOTXcmd);   /* stop transmit */
@@@ -688,13 -635,13 +688,13 @@@ netdev_tx_t arcnet_send_packet(struct s
                txbuf = -1;
  
        if (txbuf != -1) {
 +              lp->outgoing.skb = skb;
                if (proto->prepare_tx(dev, pkt, skb->len, txbuf) &&
                    !proto->ack_tx) {
                        /* done right away and we don't want to acknowledge
                         *  the package later - forget about it now
                         */
                        dev->stats.tx_bytes += skb->len;
 -                      dev_kfree_skb(skb);
                } else {
                        /* do it the 'split' way */
                        lp->outgoing.proto = proto;
@@@ -809,6 -756,7 +809,7 @@@ irqreturn_t arcnet_interrupt(int irq, v
        struct net_device *dev = dev_id;
        struct arcnet_local *lp;
        int recbuf, status, diagstatus, didsomething, boguscount;
+       unsigned long flags;
        int retval = IRQ_NONE;
  
        arc_printk(D_DURING, dev, "\n");
        lp = netdev_priv(dev);
        BUG_ON(!lp);
  
-       spin_lock(&lp->lock);
+       spin_lock_irqsave(&lp->lock, flags);
  
        /* RESET flag was enabled - if device is not running, we must
         * clear it right away (but nothing else).
                if (lp->hw.status(dev) & RESETflag)
                        lp->hw.command(dev, CFLAGScmd | RESETclear);
                lp->hw.intmask(dev, 0);
-               spin_unlock(&lp->lock);
+               spin_unlock_irqrestore(&lp->lock, flags);
                return retval;
        }
  
  
                /* a transmit finished, and we're interested in it. */
                if ((status & lp->intmask & TXFREEflag) || lp->timed_out) {
 +                      int ackstatus;
                        lp->intmask &= ~(TXFREEflag | EXCNAKflag);
  
 +                      if (status & TXACKflag)
 +                              ackstatus = 2;
 +                      else if (lp->excnak_pending)
 +                              ackstatus = 1;
 +                      else
 +                              ackstatus = 0;
 +
                        arc_printk(D_DURING, dev, "TX IRQ (stat=%Xh)\n",
                                   status);
  
  
                                if (lp->outgoing.proto &&
                                    lp->outgoing.proto->ack_tx) {
 -                                      int ackstatus;
 -
 -                                      if (status & TXACKflag)
 -                                              ackstatus = 2;
 -                                      else if (lp->excnak_pending)
 -                                              ackstatus = 1;
 -                                      else
 -                                              ackstatus = 0;
 -
                                        lp->outgoing.proto
                                                ->ack_tx(dev, ackstatus);
                                }
 +                              lp->reply_status = ackstatus;
 +                              tasklet_hi_schedule(&lp->reply_tasklet);
                        }
                        if (lp->cur_tx != -1)
                                release_arcbuf(dev, lp->cur_tx);
        udelay(1);
        lp->hw.intmask(dev, lp->intmask);
  
-       spin_unlock(&lp->lock);
+       spin_unlock_irqrestore(&lp->lock, flags);
        return retval;
  }
  EXPORT_SYMBOL(arcnet_interrupt);
index a80f4eb9262d58305e29af45e71ba352273e8aa5,4fa2e46b48d3e561e3883fdc1a023493bc39ed30..b780be6f41ff9f72f40c2a56c3fcccaf8b877511
@@@ -101,7 -101,7 +101,7 @@@ static int build_header(struct sk_buff 
                        uint8_t daddr)
  {
        int hdr_size = ARC_HDR_SIZE;
 -      struct archdr *pkt = (struct archdr *)skb_push(skb, hdr_size);
 +      struct archdr *pkt = skb_push(skb, hdr_size);
  
        arc_printk(D_PROTO, dev, "Preparing header for cap packet %x.\n",
                   *((int *)&pkt->soft.cap.cookie[0]));
@@@ -212,7 -212,7 +212,7 @@@ static int ack_tx(struct net_device *de
        ackpkt->soft.cap.proto = 0; /* using protocol 0 for acknowledge */
        ackpkt->soft.cap.mes.ack = acked;
  
-       arc_printk(D_PROTO, dev, "Ackknowledge for cap packet %x.\n",
+       arc_printk(D_PROTO, dev, "Acknowledge for cap packet %x.\n",
                   *((int *)&ackpkt->soft.cap.cookie[0]));
  
        ackskb->protocol = cpu_to_be16(ETH_P_ARCNET);
index 24deb88a37f063fe5c9a8bae87c23f30f05a496f,47f80b83dcf42a47666f05a688a680b7690251cf..2d956cb59d06d33c2f605a988a5884b1c21a1012
@@@ -93,27 -93,6 +93,27 @@@ static void led_recon_set(struct led_cl
        outb(!!value, priv->misc + ci->leds[card->index].red);
  }
  
 +static ssize_t backplane_mode_show(struct device *dev,
 +                                 struct device_attribute *attr,
 +                                 char *buf)
 +{
 +      struct net_device *net_dev = to_net_dev(dev);
 +      struct arcnet_local *lp = netdev_priv(net_dev);
 +
 +      return sprintf(buf, "%s\n", lp->backplane ? "true" : "false");
 +}
 +static DEVICE_ATTR_RO(backplane_mode);
 +
 +static struct attribute *com20020_state_attrs[] = {
 +      &dev_attr_backplane_mode.attr,
 +      NULL,
 +};
 +
 +static struct attribute_group com20020_state_group = {
 +      .name = NULL,
 +      .attrs = com20020_state_attrs,
 +};
 +
  static void com20020pci_remove(struct pci_dev *pdev);
  
  static int com20020pci_probe(struct pci_dev *pdev,
        for (i = 0; i < ci->devcount; i++) {
                struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i];
                struct com20020_dev *card;
+               int dev_id_mask = 0xf;
  
                dev = alloc_arcdev(device);
                if (!dev) {
                arcnet_outb(0x00, ioaddr, COM20020_REG_W_COMMAND);
                arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT);
  
+               SET_NETDEV_DEV(dev, &pdev->dev);
                dev->base_addr = ioaddr;
                dev->dev_addr[0] = node;
 +              dev->sysfs_groups[0] = &com20020_state_group;
                dev->irq = pdev->irq;
                lp->card_name = "PCI COM20020";
                lp->card_flags = ci->flags;
                lp->timeout = timeout;
                lp->hw.owner = THIS_MODULE;
  
 +              lp->backplane = (inb(priv->misc) >> (2 + i)) & 0x1;
 +
 +              if (!strncmp(ci->name, "EAE PLX-PCI FB2", 15))
 +                      lp->backplane = 1;
 +
                /* Get the dev_id from the PLX rotary coder */
                if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15))
-                       dev->dev_id = 0xc;
-               dev->dev_id ^= inb(priv->misc + ci->rotary) >> 4;
+                       dev_id_mask = 0x3;
+               dev->dev_id = (inb(priv->misc + ci->rotary) >> 4) & dev_id_mask;
  
                snprintf(dev->name, sizeof(dev->name), "arc%d-%d", dev->dev_id, i);
  
@@@ -388,31 -363,6 +390,31 @@@ static struct com20020_pci_card_info ca
        .flags = ARC_CAN_10MBIT,
  };
  
 +static struct com20020_pci_card_info card_info_eae_fb2 = {
 +      .name = "EAE PLX-PCI FB2",
 +      .devcount = 1,
 +      .chan_map_tbl = {
 +              {
 +                      .bar = 2,
 +                      .offset = 0x00,
 +                      .size = 0x08,
 +              },
 +      },
 +      .misc_map = {
 +              .bar = 2,
 +              .offset = 0x10,
 +              .size = 0x04,
 +      },
 +      .leds = {
 +              {
 +                      .green = 0x0,
 +                      .red = 0x1,
 +              },
 +      },
 +      .rotary = 0x0,
 +      .flags = ARC_CAN_10MBIT,
 +};
 +
  static const struct pci_device_id com20020pci_id_table[] = {
        {
                0x1571, 0xa001,
                0, 0,
                (kernel_ulong_t)&card_info_eae_ma1
        },
 +      {
 +              0x10B5, 0x9050,
 +              0x10B5, 0x3294,
 +              0, 0,
 +              (kernel_ulong_t)&card_info_eae_fb2
 +      },
        {
                0x14BA, 0x6000,
                PCI_ANY_ID, PCI_ANY_ID,
index 14c236e5bdb1a456ece5ff135e3bbff8a86955da,349a46593abff6e4ea80ddd3a79301dac9cca517..c12b4d3e946e17d15705a3ce6b1dcd1d74924e62
@@@ -10303,7 -10303,7 +10303,7 @@@ sp_rtnl_not_reset
        }
        if (test_and_clear_bit(BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN,
                               &bp->sp_rtnl_state)){
 -              if (!test_bit(__LINK_STATE_NOCARRIER, &bp->dev->state)) {
 +              if (netif_carrier_ok(bp->dev)) {
                        bnx2x_tx_disable(bp);
                        BNX2X_ERR("PF indicated channel is not servicable anymore. This means this VF device is no longer operational\n");
                }
@@@ -12729,7 -12729,7 +12729,7 @@@ static int bnx2x_set_mc_list(struct bnx
        } else {
                /* If no mc addresses are required, flush the configuration */
                rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_DEL);
-               if (rc)
+               if (rc < 0)
                        BNX2X_ERR("Failed to clear multicast configuration %d\n",
                                  rc);
        }
@@@ -15351,7 -15351,6 +15351,7 @@@ int bnx2x_configure_ptp_filters(struct 
                break;
        case HWTSTAMP_FILTER_ALL:
        case HWTSTAMP_FILTER_SOME:
 +      case HWTSTAMP_FILTER_NTP_ALL:
                bp->rx_filter = HWTSTAMP_FILTER_NONE;
                break;
        case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
index 11e8a866a31232e123567fc539b4a1ae45a7cfad,74e8e215524d72029a4a48dfc18897a9bf369f6b..a19f68f5862d7e8632b770eb9faaae430ebeb150
@@@ -175,8 -175,6 +175,8 @@@ static const struct pci_device_id bnxt_
        { PCI_VDEVICE(BROADCOM, 0x16f1), .driver_data = BCM57452 },
        { PCI_VDEVICE(BROADCOM, 0x1614), .driver_data = BCM57454 },
  #ifdef CONFIG_BNXT_SRIOV
 +      { PCI_VDEVICE(BROADCOM, 0x1606), .driver_data = NETXTREME_E_VF },
 +      { PCI_VDEVICE(BROADCOM, 0x1609), .driver_data = NETXTREME_E_VF },
        { PCI_VDEVICE(BROADCOM, 0x16c1), .driver_data = NETXTREME_E_VF },
        { PCI_VDEVICE(BROADCOM, 0x16cb), .driver_data = NETXTREME_C_VF },
        { PCI_VDEVICE(BROADCOM, 0x16d3), .driver_data = NETXTREME_E_VF },
@@@ -463,17 -461,14 +463,17 @@@ normal_tx
        prod = NEXT_TX(prod);
        txr->tx_prod = prod;
  
 -      writel(DB_KEY_TX | prod, txr->tx_doorbell);
 -      writel(DB_KEY_TX | prod, txr->tx_doorbell);
 +      if (!skb->xmit_more || netif_xmit_stopped(txq))
 +              bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | prod);
  
  tx_done:
  
        mmiowb();
  
        if (unlikely(bnxt_tx_avail(bp, txr) <= MAX_SKB_FRAGS + 1)) {
 +              if (skb->xmit_more && !tx_buf->is_push)
 +                      bnxt_db_write(bp, txr->tx_doorbell, DB_KEY_TX | prod);
 +
                netif_tx_stop_queue(txq);
  
                /* netif_tx_stop_queue() must be done before checking
@@@ -587,8 -582,7 +587,8 @@@ static struct page *__bnxt_alloc_rx_pag
        if (!page)
                return NULL;
  
 -      *mapping = dma_map_page(dev, page, 0, PAGE_SIZE, bp->rx_dir);
 +      *mapping = dma_map_page_attrs(dev, page, 0, PAGE_SIZE, bp->rx_dir,
 +                                    DMA_ATTR_WEAK_ORDERING);
        if (dma_mapping_error(dev, *mapping)) {
                __free_page(page);
                return NULL;
@@@ -607,9 -601,8 +607,9 @@@ static inline u8 *__bnxt_alloc_rx_data(
        if (!data)
                return NULL;
  
 -      *mapping = dma_map_single(&pdev->dev, data + bp->rx_dma_offset,
 -                                bp->rx_buf_use_size, bp->rx_dir);
 +      *mapping = dma_map_single_attrs(&pdev->dev, data + bp->rx_dma_offset,
 +                                      bp->rx_buf_use_size, bp->rx_dir,
 +                                      DMA_ATTR_WEAK_ORDERING);
  
        if (dma_mapping_error(&pdev->dev, *mapping)) {
                kfree(data);
@@@ -712,9 -705,8 +712,9 @@@ static inline int bnxt_alloc_rx_page(st
                        return -ENOMEM;
        }
  
 -      mapping = dma_map_page(&pdev->dev, page, offset, BNXT_RX_PAGE_SIZE,
 -                             PCI_DMA_FROMDEVICE);
 +      mapping = dma_map_page_attrs(&pdev->dev, page, offset,
 +                                   BNXT_RX_PAGE_SIZE, PCI_DMA_FROMDEVICE,
 +                                   DMA_ATTR_WEAK_ORDERING);
        if (dma_mapping_error(&pdev->dev, mapping)) {
                __free_page(page);
                return -EIO;
@@@ -807,8 -799,7 +807,8 @@@ static struct sk_buff *bnxt_rx_page_skb
                return NULL;
        }
        dma_addr -= bp->rx_dma_offset;
 -      dma_unmap_page(&bp->pdev->dev, dma_addr, PAGE_SIZE, bp->rx_dir);
 +      dma_unmap_page_attrs(&bp->pdev->dev, dma_addr, PAGE_SIZE, bp->rx_dir,
 +                           DMA_ATTR_WEAK_ORDERING);
  
        if (unlikely(!payload))
                payload = eth_get_headlen(data_ptr, len);
@@@ -850,8 -841,8 +850,8 @@@ static struct sk_buff *bnxt_rx_skb(stru
        }
  
        skb = build_skb(data, 0);
 -      dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size,
 -                       bp->rx_dir);
 +      dma_unmap_single_attrs(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size,
 +                             bp->rx_dir, DMA_ATTR_WEAK_ORDERING);
        if (!skb) {
                kfree(data);
                return NULL;
@@@ -918,9 -909,8 +918,9 @@@ static struct sk_buff *bnxt_rx_pages(st
                        return NULL;
                }
  
 -              dma_unmap_page(&pdev->dev, mapping, BNXT_RX_PAGE_SIZE,
 -                             PCI_DMA_FROMDEVICE);
 +              dma_unmap_page_attrs(&pdev->dev, mapping, BNXT_RX_PAGE_SIZE,
 +                                   PCI_DMA_FROMDEVICE,
 +                                   DMA_ATTR_WEAK_ORDERING);
  
                skb->data_len += frag_len;
                skb->len += frag_len;
@@@ -1311,10 -1301,11 +1311,11 @@@ static inline struct sk_buff *bnxt_tpa_
                cp_cons = NEXT_CMP(cp_cons);
        }
  
-       if (unlikely(agg_bufs > MAX_SKB_FRAGS)) {
+       if (unlikely(agg_bufs > MAX_SKB_FRAGS || TPA_END_ERRORS(tpa_end1))) {
                bnxt_abort_tpa(bp, bnapi, cp_cons, agg_bufs);
-               netdev_warn(bp->dev, "TPA frags %d exceeded MAX_SKB_FRAGS %d\n",
-                           agg_bufs, (int)MAX_SKB_FRAGS);
+               if (agg_bufs > MAX_SKB_FRAGS)
+                       netdev_warn(bp->dev, "TPA frags %d exceeded MAX_SKB_FRAGS %d\n",
+                                   agg_bufs, (int)MAX_SKB_FRAGS);
                return NULL;
        }
  
                tpa_info->mapping = new_mapping;
  
                skb = build_skb(data, 0);
 -              dma_unmap_single(&bp->pdev->dev, mapping, bp->rx_buf_use_size,
 -                               bp->rx_dir);
 +              dma_unmap_single_attrs(&bp->pdev->dev, mapping,
 +                                     bp->rx_buf_use_size, bp->rx_dir,
 +                                     DMA_ATTR_WEAK_ORDERING);
  
                if (!skb) {
                        kfree(data);
@@@ -1573,6 -1563,45 +1574,45 @@@ next_rx_no_prod
        return rc;
  }
  
+ /* In netpoll mode, if we are using a combined completion ring, we need to
+  * discard the rx packets and recycle the buffers.
+  */
+ static int bnxt_force_rx_discard(struct bnxt *bp, struct bnxt_napi *bnapi,
+                                u32 *raw_cons, u8 *event)
+ {
+       struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
+       u32 tmp_raw_cons = *raw_cons;
+       struct rx_cmp_ext *rxcmp1;
+       struct rx_cmp *rxcmp;
+       u16 cp_cons;
+       u8 cmp_type;
+       cp_cons = RING_CMP(tmp_raw_cons);
+       rxcmp = (struct rx_cmp *)
+                       &cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)];
+       tmp_raw_cons = NEXT_RAW_CMP(tmp_raw_cons);
+       cp_cons = RING_CMP(tmp_raw_cons);
+       rxcmp1 = (struct rx_cmp_ext *)
+                       &cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)];
+       if (!RX_CMP_VALID(rxcmp1, tmp_raw_cons))
+               return -EBUSY;
+       cmp_type = RX_CMP_TYPE(rxcmp);
+       if (cmp_type == CMP_TYPE_RX_L2_CMP) {
+               rxcmp1->rx_cmp_cfa_code_errors_v2 |=
+                       cpu_to_le32(RX_CMPL_ERRORS_CRC_ERROR);
+       } else if (cmp_type == CMP_TYPE_RX_L2_TPA_END_CMP) {
+               struct rx_tpa_end_cmp_ext *tpa_end1;
+               tpa_end1 = (struct rx_tpa_end_cmp_ext *)rxcmp1;
+               tpa_end1->rx_tpa_end_cmp_errors_v2 |=
+                       cpu_to_le32(RX_TPA_END_CMP_ERRORS);
+       }
+       return bnxt_rx_pkt(bp, bnapi, raw_cons, event);
+ }
  #define BNXT_GET_EVENT_PORT(data)     \
        ((data) &                       \
         ASYNC_EVENT_CMPL_PORT_CONN_NOT_ALLOWED_EVENT_DATA1_PORT_ID_MASK)
@@@ -1755,7 -1784,11 +1795,11 @@@ static int bnxt_poll_work(struct bnxt *
                        if (unlikely(tx_pkts > bp->tx_wake_thresh))
                                rx_pkts = budget;
                } else if ((TX_CMP_TYPE(txcmp) & 0x30) == 0x10) {
-                       rc = bnxt_rx_pkt(bp, bnapi, &raw_cons, &event);
+                       if (likely(budget))
+                               rc = bnxt_rx_pkt(bp, bnapi, &raw_cons, &event);
+                       else
+                               rc = bnxt_force_rx_discard(bp, bnapi, &raw_cons,
+                                                          &event);
                        if (likely(rc >= 0))
                                rx_pkts += rc;
                        else if (rc == -EBUSY)  /* partial completion */
                /* Sync BD data before updating doorbell */
                wmb();
  
 -              writel(DB_KEY_TX | prod, db);
 -              writel(DB_KEY_TX | prod, db);
 +              bnxt_db_write(bp, db, DB_KEY_TX | prod);
        }
  
        cpr->cp_raw_cons = raw_cons;
        if (event & BNXT_RX_EVENT) {
                struct bnxt_rx_ring_info *rxr = bnapi->rx_ring;
  
 -              writel(DB_KEY_RX | rxr->rx_prod, rxr->rx_doorbell);
 -              writel(DB_KEY_RX | rxr->rx_prod, rxr->rx_doorbell);
 -              if (event & BNXT_AGG_EVENT) {
 -                      writel(DB_KEY_RX | rxr->rx_agg_prod,
 -                             rxr->rx_agg_doorbell);
 -                      writel(DB_KEY_RX | rxr->rx_agg_prod,
 -                             rxr->rx_agg_doorbell);
 -              }
 +              bnxt_db_write(bp, rxr->rx_doorbell, DB_KEY_RX | rxr->rx_prod);
 +              if (event & BNXT_AGG_EVENT)
 +                      bnxt_db_write(bp, rxr->rx_agg_doorbell,
 +                                    DB_KEY_RX | rxr->rx_agg_prod);
        }
        return rx_pkts;
  }
@@@ -1861,11 -1899,13 +1905,11 @@@ static int bnxt_poll_nitroa0(struct nap
  
        cpr->cp_raw_cons = raw_cons;
        BNXT_CP_DB(cpr->cp_doorbell, cpr->cp_raw_cons);
 -      writel(DB_KEY_RX | rxr->rx_prod, rxr->rx_doorbell);
 -      writel(DB_KEY_RX | rxr->rx_prod, rxr->rx_doorbell);
 +      bnxt_db_write(bp, rxr->rx_doorbell, DB_KEY_RX | rxr->rx_prod);
  
 -      if (event & BNXT_AGG_EVENT) {
 -              writel(DB_KEY_RX | rxr->rx_agg_prod, rxr->rx_agg_doorbell);
 -              writel(DB_KEY_RX | rxr->rx_agg_prod, rxr->rx_agg_doorbell);
 -      }
 +      if (event & BNXT_AGG_EVENT)
 +              bnxt_db_write(bp, rxr->rx_agg_doorbell,
 +                            DB_KEY_RX | rxr->rx_agg_prod);
  
        if (!bnxt_has_work(bp, cpr) && rx_pkts < budget) {
                napi_complete_done(napi, rx_pkts);
@@@ -1975,11 -2015,9 +2019,11 @@@ static void bnxt_free_rx_skbs(struct bn
                                if (!data)
                                        continue;
  
 -                              dma_unmap_single(&pdev->dev, tpa_info->mapping,
 -                                               bp->rx_buf_use_size,
 -                                               bp->rx_dir);
 +                              dma_unmap_single_attrs(&pdev->dev,
 +                                                     tpa_info->mapping,
 +                                                     bp->rx_buf_use_size,
 +                                                     bp->rx_dir,
 +                                                     DMA_ATTR_WEAK_ORDERING);
  
                                tpa_info->data = NULL;
  
  
                        if (BNXT_RX_PAGE_MODE(bp)) {
                                mapping -= bp->rx_dma_offset;
 -                              dma_unmap_page(&pdev->dev, mapping,
 -                                             PAGE_SIZE, bp->rx_dir);
 +                              dma_unmap_page_attrs(&pdev->dev, mapping,
 +                                                   PAGE_SIZE, bp->rx_dir,
 +                                                   DMA_ATTR_WEAK_ORDERING);
                                __free_page(data);
                        } else {
 -                              dma_unmap_single(&pdev->dev, mapping,
 -                                               bp->rx_buf_use_size,
 -                                               bp->rx_dir);
 +                              dma_unmap_single_attrs(&pdev->dev, mapping,
 +                                                     bp->rx_buf_use_size,
 +                                                     bp->rx_dir,
 +                                                     DMA_ATTR_WEAK_ORDERING);
                                kfree(data);
                        }
                }
                        if (!page)
                                continue;
  
 -                      dma_unmap_page(&pdev->dev, rx_agg_buf->mapping,
 -                                     BNXT_RX_PAGE_SIZE, PCI_DMA_FROMDEVICE);
 +                      dma_unmap_page_attrs(&pdev->dev, rx_agg_buf->mapping,
 +                                           BNXT_RX_PAGE_SIZE,
 +                                           PCI_DMA_FROMDEVICE,
 +                                           DMA_ATTR_WEAK_ORDERING);
  
                        rx_agg_buf->page = NULL;
                        __clear_bit(j, rxr->rx_agg_bmap);
@@@ -2866,32 -2900,6 +2910,32 @@@ static int bnxt_alloc_hwrm_resources(st
        return 0;
  }
  
 +static void bnxt_free_hwrm_short_cmd_req(struct bnxt *bp)
 +{
 +      if (bp->hwrm_short_cmd_req_addr) {
 +              struct pci_dev *pdev = bp->pdev;
 +
 +              dma_free_coherent(&pdev->dev, BNXT_HWRM_MAX_REQ_LEN,
 +                                bp->hwrm_short_cmd_req_addr,
 +                                bp->hwrm_short_cmd_req_dma_addr);
 +              bp->hwrm_short_cmd_req_addr = NULL;
 +      }
 +}
 +
 +static int bnxt_alloc_hwrm_short_cmd_req(struct bnxt *bp)
 +{
 +      struct pci_dev *pdev = bp->pdev;
 +
 +      bp->hwrm_short_cmd_req_addr =
 +              dma_alloc_coherent(&pdev->dev, BNXT_HWRM_MAX_REQ_LEN,
 +                                 &bp->hwrm_short_cmd_req_dma_addr,
 +                                 GFP_KERNEL);
 +      if (!bp->hwrm_short_cmd_req_addr)
 +              return -ENOMEM;
 +
 +      return 0;
 +}
 +
  static void bnxt_free_stats(struct bnxt *bp)
  {
        u32 size, i;
@@@ -3239,41 -3247,16 +3283,41 @@@ static int bnxt_hwrm_do_send_msg(struc
        __le32 *resp_len, *valid;
        u16 cp_ring_id, len = 0;
        struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr;
 +      u16 max_req_len = BNXT_HWRM_MAX_REQ_LEN;
  
        req->seq_id = cpu_to_le16(bp->hwrm_cmd_seq++);
        memset(resp, 0, PAGE_SIZE);
        cp_ring_id = le16_to_cpu(req->cmpl_ring);
        intr_process = (cp_ring_id == INVALID_HW_RING_ID) ? 0 : 1;
  
 +      if (bp->flags & BNXT_FLAG_SHORT_CMD) {
 +              void *short_cmd_req = bp->hwrm_short_cmd_req_addr;
 +              struct hwrm_short_input short_input = {0};
 +
 +              memcpy(short_cmd_req, req, msg_len);
 +              memset(short_cmd_req + msg_len, 0, BNXT_HWRM_MAX_REQ_LEN -
 +                                                 msg_len);
 +
 +              short_input.req_type = req->req_type;
 +              short_input.signature =
 +                              cpu_to_le16(SHORT_REQ_SIGNATURE_SHORT_CMD);
 +              short_input.size = cpu_to_le16(msg_len);
 +              short_input.req_addr =
 +                      cpu_to_le64(bp->hwrm_short_cmd_req_dma_addr);
 +
 +              data = (u32 *)&short_input;
 +              msg_len = sizeof(short_input);
 +
 +              /* Sync memory write before updating doorbell */
 +              wmb();
 +
 +              max_req_len = BNXT_HWRM_SHORT_REQ_LEN;
 +      }
 +
        /* Write request msg to hwrm channel */
        __iowrite32_copy(bp->bar0, data, msg_len / 4);
  
 -      for (i = msg_len; i < BNXT_HWRM_MAX_REQ_LEN; i += 4)
 +      for (i = msg_len; i < max_req_len; i += 4)
                writel(0, bp->bar0 + i);
  
        /* currently supports only one outstanding message */
@@@ -4711,7 -4694,6 +4755,7 @@@ static int bnxt_hwrm_ver_get(struct bnx
        int rc;
        struct hwrm_ver_get_input req = {0};
        struct hwrm_ver_get_output *resp = bp->hwrm_cmd_resp_addr;
 +      u32 dev_caps_cfg;
  
        bp->hwrm_max_req_len = HWRM_MAX_REQ_LEN;
        bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_VER_GET, -1, -1);
            !resp->chip_metal)
                bp->flags |= BNXT_FLAG_CHIP_NITRO_A0;
  
 +      dev_caps_cfg = le32_to_cpu(resp->dev_caps_cfg);
 +      if ((dev_caps_cfg & VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_SUPPORTED) &&
 +          (dev_caps_cfg & VER_GET_RESP_DEV_CAPS_CFG_SHORT_CMD_REQUIRED))
 +              bp->flags |= BNXT_FLAG_SHORT_CMD;
 +
  hwrm_ver_get_exit:
        mutex_unlock(&bp->hwrm_cmd_lock);
        return rc;
@@@ -6730,12 -6707,11 +6774,11 @@@ static void bnxt_poll_controller(struc
        struct bnxt *bp = netdev_priv(dev);
        int i;
  
-       for (i = 0; i < bp->cp_nr_rings; i++) {
-               struct bnxt_irq *irq = &bp->irq_tbl[i];
+       /* Only process tx rings/combined rings in netpoll mode. */
+       for (i = 0; i < bp->tx_nr_rings; i++) {
+               struct bnxt_tx_ring_info *txr = &bp->tx_ring[i];
  
-               disable_irq(irq->vector);
-               irq->handler(irq->vector, bp->bnapi[i]);
-               enable_irq(irq->vector);
+               napi_schedule(&txr->bnapi->napi);
        }
  }
  #endif
@@@ -7103,8 -7079,8 +7146,8 @@@ int bnxt_setup_mq_tc(struct net_device 
        return 0;
  }
  
 -static int bnxt_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
 -                       struct tc_to_netdev *ntc)
 +static int bnxt_setup_tc(struct net_device *dev, u32 handle, u32 chain_index,
 +                       __be16 proto, struct tc_to_netdev *ntc)
  {
        if (ntc->type != TC_SETUP_MQPRIO)
                return -EINVAL;
@@@ -7412,7 -7388,6 +7455,7 @@@ static void bnxt_remove_one(struct pci_
        bnxt_clear_int_mode(bp);
        bnxt_hwrm_func_drv_unrgtr(bp);
        bnxt_free_hwrm_resources(bp);
 +      bnxt_free_hwrm_short_cmd_req(bp);
        bnxt_ethtool_free(bp);
        bnxt_dcb_free(bp);
        kfree(bp->edev);
@@@ -7567,9 -7542,10 +7610,9 @@@ static int bnxt_get_dflt_rings(struct b
        return rc;
  }
  
 -static int bnxt_set_dflt_rings(struct bnxt *bp)
 +static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
  {
        int dflt_rings, max_rx_rings, max_tx_rings, rc;
 -      bool sh = true;
  
        if (sh)
                bp->flags |= BNXT_FLAG_SHARED_RINGS;
@@@ -7662,12 -7638,6 +7705,12 @@@ static int bnxt_init_one(struct pci_de
        if (rc)
                goto init_err_pci_clean;
  
 +      if (bp->flags & BNXT_FLAG_SHORT_CMD) {
 +              rc = bnxt_alloc_hwrm_short_cmd_req(bp);
 +              if (rc)
 +                      goto init_err_pci_clean;
 +      }
 +
        rc = bnxt_hwrm_func_reset(bp);
        if (rc)
                goto init_err_pci_clean;
        init_waitqueue_head(&bp->sriov_cfg_wait);
  #endif
        bp->gro_func = bnxt_gro_func_5730x;
 -      if (BNXT_CHIP_NUM_57X1X(bp->chip_num))
 +      if (BNXT_CHIP_P4_PLUS(bp))
                bp->gro_func = bnxt_gro_func_5731x;
 +      else
 +              bp->flags |= BNXT_FLAG_DOUBLE_DB;
  
        rc = bnxt_hwrm_func_drv_rgtr(bp);
        if (rc)
        bnxt_set_tpa_flags(bp);
        bnxt_set_ring_params(bp);
        bnxt_set_max_func_irqs(bp, max_irqs);
 -      rc = bnxt_set_dflt_rings(bp);
 +      rc = bnxt_set_dflt_rings(bp, true);
        if (rc) {
                netdev_err(bp->dev, "Not enough rings available.\n");
                rc = -ENOMEM;
                           VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4 |
                           VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 |
                           VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
 -      if (!BNXT_CHIP_NUM_57X0X(bp->chip_num) &&
 -          !BNXT_CHIP_TYPE_NITRO_A0(bp) &&
 -          bp->hwrm_spec_code >= 0x10501) {
 +      if (BNXT_CHIP_P4_PLUS(bp) && bp->hwrm_spec_code >= 0x10501) {
                bp->flags |= BNXT_FLAG_UDP_RSS_CAP;
                bp->rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4 |
                                    VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
@@@ -7832,7 -7802,6 +7875,7 @@@ static void bnxt_shutdown(struct pci_de
                dev_close(dev);
  
        if (system_state == SYSTEM_POWER_OFF) {
 +              bnxt_ulp_shutdown(bp);
                bnxt_clear_int_mode(bp);
                pci_wake_from_d3(pdev, bp->wol);
                pci_set_power_state(pdev, PCI_D3hot);
index 5984423499e62b03c985e219460e4a4d418c7801,d46a85041083c3708860b71cb661afe9123028d0..f872a7db2ca8b6ad6701158ec25a6b953936f731
@@@ -374,12 -374,16 +374,16 @@@ struct rx_tpa_end_cmp_ext 
  
        __le32 rx_tpa_end_cmp_errors_v2;
        #define RX_TPA_END_CMP_V2                               (0x1 << 0)
-       #define RX_TPA_END_CMP_ERRORS                           (0x7fff << 1)
+       #define RX_TPA_END_CMP_ERRORS                           (0x3 << 1)
        #define RX_TPA_END_CMPL_ERRORS_SHIFT                     1
  
        u32 rx_tpa_end_cmp_start_opaque;
  };
  
+ #define TPA_END_ERRORS(rx_tpa_end_ext)                                        \
+       ((rx_tpa_end_ext)->rx_tpa_end_cmp_errors_v2 &                   \
+        cpu_to_le32(RX_TPA_END_CMP_ERRORS))
  #define DB_IDX_MASK                                           0xffffff
  #define DB_IDX_VALID                                          (0x1 << 26)
  #define DB_IRQ_DIS                                            (0x1 << 27)
  #define NEXT_CMP(idx)         RING_CMP(ADV_RAW_CMP(idx, 1))
  
  #define BNXT_HWRM_MAX_REQ_LEN         (bp->hwrm_max_req_len)
 +#define BNXT_HWRM_SHORT_REQ_LEN               sizeof(struct hwrm_short_input)
  #define DFLT_HWRM_CMD_TIMEOUT         500
  #define HWRM_CMD_TIMEOUT              (bp->hwrm_cmd_timeout)
  #define HWRM_RESET_TIMEOUT            ((HWRM_CMD_TIMEOUT) * 4)
@@@ -938,45 -941,31 +942,45 @@@ struct bnxt 
  #define CHIP_NUM_57402                0x16d0
  #define CHIP_NUM_57404                0x16d1
  #define CHIP_NUM_57406                0x16d2
 +#define CHIP_NUM_57407                0x16d5
  
  #define CHIP_NUM_57311                0x16ce
  #define CHIP_NUM_57312                0x16cf
  #define CHIP_NUM_57314                0x16df
 +#define CHIP_NUM_57317                0x16e0
  #define CHIP_NUM_57412                0x16d6
  #define CHIP_NUM_57414                0x16d7
  #define CHIP_NUM_57416                0x16d8
  #define CHIP_NUM_57417                0x16d9
 +#define CHIP_NUM_57412L               0x16da
 +#define CHIP_NUM_57414L               0x16db
 +
 +#define CHIP_NUM_5745X                0xd730
  
  #define BNXT_CHIP_NUM_5730X(chip_num)         \
        ((chip_num) >= CHIP_NUM_57301 &&        \
         (chip_num) <= CHIP_NUM_57304)
  
  #define BNXT_CHIP_NUM_5740X(chip_num)         \
 -      ((chip_num) >= CHIP_NUM_57402 &&        \
 -       (chip_num) <= CHIP_NUM_57406)
 +      (((chip_num) >= CHIP_NUM_57402 &&       \
 +        (chip_num) <= CHIP_NUM_57406) ||      \
 +       (chip_num) == CHIP_NUM_57407)
  
  #define BNXT_CHIP_NUM_5731X(chip_num)         \
        ((chip_num) == CHIP_NUM_57311 ||        \
         (chip_num) == CHIP_NUM_57312 ||        \
 -       (chip_num) == CHIP_NUM_57314)
 +       (chip_num) == CHIP_NUM_57314 ||        \
 +       (chip_num) == CHIP_NUM_57317)
  
  #define BNXT_CHIP_NUM_5741X(chip_num)         \
        ((chip_num) >= CHIP_NUM_57412 &&        \
 -       (chip_num) <= CHIP_NUM_57417)
 +       (chip_num) <= CHIP_NUM_57414L)
 +
 +#define BNXT_CHIP_NUM_58700(chip_num)         \
 +       ((chip_num) == CHIP_NUM_58700)
 +
 +#define BNXT_CHIP_NUM_5745X(chip_num)         \
 +       ((chip_num) == CHIP_NUM_5745X)
  
  #define BNXT_CHIP_NUM_57X0X(chip_num)         \
        (BNXT_CHIP_NUM_5730X(chip_num) || BNXT_CHIP_NUM_5740X(chip_num))
        #define BNXT_FLAG_RX_PAGE_MODE  0x40000
        #define BNXT_FLAG_FW_LLDP_AGENT 0x80000
        #define BNXT_FLAG_MULTI_HOST    0x100000
 +      #define BNXT_FLAG_SHORT_CMD     0x200000
 +      #define BNXT_FLAG_DOUBLE_DB     0x400000
        #define BNXT_FLAG_CHIP_NITRO_A0 0x1000000
  
        #define BNXT_FLAG_ALL_CONFIG_FEATS (BNXT_FLAG_TPA |             \
  #define BNXT_CHIP_TYPE_NITRO_A0(bp) ((bp)->flags & BNXT_FLAG_CHIP_NITRO_A0)
  #define BNXT_RX_PAGE_MODE(bp) ((bp)->flags & BNXT_FLAG_RX_PAGE_MODE)
  
 +/* Chip class phase 4 and later */
 +#define BNXT_CHIP_P4_PLUS(bp)                 \
 +      (BNXT_CHIP_NUM_57X1X((bp)->chip_num) || \
 +       BNXT_CHIP_NUM_5745X((bp)->chip_num) || \
 +       (BNXT_CHIP_NUM_58700((bp)->chip_num) &&        \
 +        !BNXT_CHIP_TYPE_NITRO_A0(bp)))
 +
        struct bnxt_en_dev      *edev;
        struct bnxt_en_dev *    (*ulp_probe)(struct net_device *);
  
        u32                     hwrm_spec_code;
        u16                     hwrm_cmd_seq;
        u32                     hwrm_intr_seq_id;
 +      void                    *hwrm_short_cmd_req_addr;
 +      dma_addr_t              hwrm_short_cmd_req_dma_addr;
        void                    *hwrm_cmd_resp_addr;
        dma_addr_t              hwrm_cmd_resp_dma_addr;
        void                    *hwrm_dbg_resp_addr;
@@@ -1255,14 -1233,6 +1259,14 @@@ static inline u32 bnxt_tx_avail(struct 
                ((txr->tx_prod - txr->tx_cons) & bp->tx_ring_mask);
  }
  
 +/* For TX and RX ring doorbells */
 +static inline void bnxt_db_write(struct bnxt *bp, void __iomem *db, u32 val)
 +{
 +      writel(val, db);
 +      if (bp->flags & BNXT_FLAG_DOUBLE_DB)
 +              writel(val, db);
 +}
 +
  extern const u16 bnxt_lhint_arr[];
  
  int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
index 700cc8c6aa5be69c9c6135c0572259434143955e,0744452a0b188190a1da2fe0e14651aad31748de..192cb93e7669be9587d850bc3c5a661d9816af24
@@@ -42,7 -42,6 +42,7 @@@
  #include <linux/notifier.h>
  #include <linux/inetdevice.h>
  #include <linux/netdevice.h>
 +#include <linux/if_bridge.h>
  #include <net/netevent.h>
  #include <net/neighbour.h>
  #include <net/arp.h>
  #include "spectrum_dpipe.h"
  #include "spectrum_router.h"
  
 +struct mlxsw_sp_vr;
 +struct mlxsw_sp_lpm_tree;
 +struct mlxsw_sp_rif_ops;
 +
 +struct mlxsw_sp_router {
 +      struct mlxsw_sp *mlxsw_sp;
 +      struct mlxsw_sp_rif **rifs;
 +      struct mlxsw_sp_vr *vrs;
 +      struct rhashtable neigh_ht;
 +      struct rhashtable nexthop_group_ht;
 +      struct rhashtable nexthop_ht;
 +      struct {
 +              struct mlxsw_sp_lpm_tree *trees;
 +              unsigned int tree_count;
 +      } lpm;
 +      struct {
 +              struct delayed_work dw;
 +              unsigned long interval; /* ms */
 +      } neighs_update;
 +      struct delayed_work nexthop_probe_dw;
 +#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */
 +      struct list_head nexthop_neighs_list;
 +      bool aborted;
 +      struct notifier_block fib_nb;
 +      const struct mlxsw_sp_rif_ops **rif_ops_arr;
 +};
 +
  struct mlxsw_sp_rif {
        struct list_head nexthop_list;
        struct list_head neigh_list;
        struct net_device *dev;
 -      struct mlxsw_sp_fid *f;
 +      struct mlxsw_sp_fid *fid;
        unsigned char addr[ETH_ALEN];
        int mtu;
        u16 rif_index;
        u16 vr_id;
 +      const struct mlxsw_sp_rif_ops *ops;
 +      struct mlxsw_sp *mlxsw_sp;
 +
        unsigned int counter_ingress;
        bool counter_ingress_valid;
        unsigned int counter_egress;
        bool counter_egress_valid;
  };
  
 +struct mlxsw_sp_rif_params {
 +      struct net_device *dev;
 +      union {
 +              u16 system_port;
 +              u16 lag_id;
 +      };
 +      u16 vid;
 +      bool lag;
 +};
 +
 +struct mlxsw_sp_rif_subport {
 +      struct mlxsw_sp_rif common;
 +      union {
 +              u16 system_port;
 +              u16 lag_id;
 +      };
 +      u16 vid;
 +      bool lag;
 +};
 +
 +struct mlxsw_sp_rif_ops {
 +      enum mlxsw_sp_rif_type type;
 +      size_t rif_size;
 +
 +      void (*setup)(struct mlxsw_sp_rif *rif,
 +                    const struct mlxsw_sp_rif_params *params);
 +      int (*configure)(struct mlxsw_sp_rif *rif);
 +      void (*deconfigure)(struct mlxsw_sp_rif *rif);
 +      struct mlxsw_sp_fid * (*fid_get)(struct mlxsw_sp_rif *rif);
 +};
 +
  static unsigned int *
  mlxsw_sp_rif_p_counter_get(struct mlxsw_sp_rif *rif,
                           enum mlxsw_sp_rif_counter_dir dir)
@@@ -281,35 -219,10 +281,35 @@@ void mlxsw_sp_rif_counter_free(struct m
        mlxsw_sp_rif_counter_valid_set(rif, dir, false);
  }
  
 +static void mlxsw_sp_rif_counters_alloc(struct mlxsw_sp_rif *rif)
 +{
 +      struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
 +      struct devlink *devlink;
 +
 +      devlink = priv_to_devlink(mlxsw_sp->core);
 +      if (!devlink_dpipe_table_counter_enabled(devlink,
 +                                               MLXSW_SP_DPIPE_TABLE_NAME_ERIF))
 +              return;
 +      mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS);
 +}
 +
 +static void mlxsw_sp_rif_counters_free(struct mlxsw_sp_rif *rif)
 +{
 +      struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
 +
 +      mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS);
 +}
 +
  static struct mlxsw_sp_rif *
  mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
                         const struct net_device *dev);
  
 +#define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE)
 +
 +struct mlxsw_sp_prefix_usage {
 +      DECLARE_BITMAP(b, MLXSW_SP_PREFIX_COUNT);
 +};
 +
  #define mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) \
        for_each_set_bit(prefix, (prefix_usage)->b, MLXSW_SP_PREFIX_COUNT)
  
@@@ -374,7 -287,6 +374,7 @@@ enum mlxsw_sp_fib_entry_type 
  };
  
  struct mlxsw_sp_nexthop_group;
 +struct mlxsw_sp_fib;
  
  struct mlxsw_sp_fib_node {
        struct list_head entry_list;
@@@ -401,18 -313,6 +401,18 @@@ struct mlxsw_sp_fib_entry 
        bool offloaded;
  };
  
 +enum mlxsw_sp_l3proto {
 +      MLXSW_SP_L3_PROTO_IPV4,
 +      MLXSW_SP_L3_PROTO_IPV6,
 +};
 +
 +struct mlxsw_sp_lpm_tree {
 +      u8 id; /* tree ID */
 +      unsigned int ref_count;
 +      enum mlxsw_sp_l3proto proto;
 +      struct mlxsw_sp_prefix_usage prefix_usage;
 +};
 +
  struct mlxsw_sp_fib {
        struct rhashtable ht;
        struct list_head node_list;
        enum mlxsw_sp_l3proto proto;
  };
  
 +struct mlxsw_sp_vr {
 +      u16 id; /* virtual router ID */
 +      u32 tb_id; /* kernel fib table id */
 +      unsigned int rif_count;
 +      struct mlxsw_sp_fib *fib4;
 +};
 +
  static const struct rhashtable_params mlxsw_sp_fib_ht_params;
  
  static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp_vr *vr,
@@@ -468,8 -361,8 +468,8 @@@ mlxsw_sp_lpm_tree_find_unused(struct ml
        static struct mlxsw_sp_lpm_tree *lpm_tree;
        int i;
  
 -      for (i = 0; i < mlxsw_sp->router.lpm.tree_count; i++) {
 -              lpm_tree = &mlxsw_sp->router.lpm.trees[i];
 +      for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
 +              lpm_tree = &mlxsw_sp->router->lpm.trees[i];
                if (lpm_tree->ref_count == 0)
                        return lpm_tree;
        }
@@@ -565,8 -458,8 +565,8 @@@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *
        struct mlxsw_sp_lpm_tree *lpm_tree;
        int i;
  
 -      for (i = 0; i < mlxsw_sp->router.lpm.tree_count; i++) {
 -              lpm_tree = &mlxsw_sp->router.lpm.trees[i];
 +      for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
 +              lpm_tree = &mlxsw_sp->router->lpm.trees[i];
                if (lpm_tree->ref_count != 0 &&
                    lpm_tree->proto == proto &&
                    mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage,
@@@ -591,7 -484,7 +591,7 @@@ static int mlxsw_sp_lpm_tree_put(struc
        return 0;
  }
  
 -#define MLXSW_SP_LPM_TREE_MIN 2 /* trees 0 and 1 are reserved */
 +#define MLXSW_SP_LPM_TREE_MIN 1 /* tree 0 is reserved */
  
  static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp)
  {
                return -EIO;
  
        max_trees = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_LPM_TREES);
 -      mlxsw_sp->router.lpm.tree_count = max_trees - MLXSW_SP_LPM_TREE_MIN;
 -      mlxsw_sp->router.lpm.trees = kcalloc(mlxsw_sp->router.lpm.tree_count,
 +      mlxsw_sp->router->lpm.tree_count = max_trees - MLXSW_SP_LPM_TREE_MIN;
 +      mlxsw_sp->router->lpm.trees = kcalloc(mlxsw_sp->router->lpm.tree_count,
                                             sizeof(struct mlxsw_sp_lpm_tree),
                                             GFP_KERNEL);
 -      if (!mlxsw_sp->router.lpm.trees)
 +      if (!mlxsw_sp->router->lpm.trees)
                return -ENOMEM;
  
 -      for (i = 0; i < mlxsw_sp->router.lpm.tree_count; i++) {
 -              lpm_tree = &mlxsw_sp->router.lpm.trees[i];
 +      for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
 +              lpm_tree = &mlxsw_sp->router->lpm.trees[i];
                lpm_tree->id = i + MLXSW_SP_LPM_TREE_MIN;
        }
  
  
  static void mlxsw_sp_lpm_fini(struct mlxsw_sp *mlxsw_sp)
  {
 -      kfree(mlxsw_sp->router.lpm.trees);
 +      kfree(mlxsw_sp->router->lpm.trees);
  }
  
  static bool mlxsw_sp_vr_is_used(const struct mlxsw_sp_vr *vr)
@@@ -634,7 -527,7 +634,7 @@@ static struct mlxsw_sp_vr *mlxsw_sp_vr_
        int i;
  
        for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
 -              vr = &mlxsw_sp->router.vrs[i];
 +              vr = &mlxsw_sp->router->vrs[i];
                if (!mlxsw_sp_vr_is_used(vr))
                        return vr;
        }
@@@ -680,7 -573,7 +680,7 @@@ static struct mlxsw_sp_vr *mlxsw_sp_vr_
        tb_id = mlxsw_sp_fix_tb_id(tb_id);
  
        for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
 -              vr = &mlxsw_sp->router.vrs[i];
 +              vr = &mlxsw_sp->router->vrs[i];
                if (mlxsw_sp_vr_is_used(vr) && vr->tb_id == tb_id)
                        return vr;
        }
@@@ -787,13 -680,13 +787,13 @@@ static int mlxsw_sp_vrs_init(struct mlx
                return -EIO;
  
        max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS);
 -      mlxsw_sp->router.vrs = kcalloc(max_vrs, sizeof(struct mlxsw_sp_vr),
 -                                     GFP_KERNEL);
 -      if (!mlxsw_sp->router.vrs)
 +      mlxsw_sp->router->vrs = kcalloc(max_vrs, sizeof(struct mlxsw_sp_vr),
 +                                      GFP_KERNEL);
 +      if (!mlxsw_sp->router->vrs)
                return -ENOMEM;
  
        for (i = 0; i < max_vrs; i++) {
 -              vr = &mlxsw_sp->router.vrs[i];
 +              vr = &mlxsw_sp->router->vrs[i];
                vr->id = i;
        }
  
@@@ -813,7 -706,7 +813,7 @@@ static void mlxsw_sp_vrs_fini(struct ml
         */
        mlxsw_core_flush_owq();
        mlxsw_sp_router_fib_flush(mlxsw_sp);
 -      kfree(mlxsw_sp->router.vrs);
 +      kfree(mlxsw_sp->router->vrs);
  }
  
  struct mlxsw_sp_neigh_key {
@@@ -865,7 -758,7 +865,7 @@@ static in
  mlxsw_sp_neigh_entry_insert(struct mlxsw_sp *mlxsw_sp,
                            struct mlxsw_sp_neigh_entry *neigh_entry)
  {
 -      return rhashtable_insert_fast(&mlxsw_sp->router.neigh_ht,
 +      return rhashtable_insert_fast(&mlxsw_sp->router->neigh_ht,
                                      &neigh_entry->ht_node,
                                      mlxsw_sp_neigh_ht_params);
  }
@@@ -874,7 -767,7 +874,7 @@@ static voi
  mlxsw_sp_neigh_entry_remove(struct mlxsw_sp *mlxsw_sp,
                            struct mlxsw_sp_neigh_entry *neigh_entry)
  {
 -      rhashtable_remove_fast(&mlxsw_sp->router.neigh_ht,
 +      rhashtable_remove_fast(&mlxsw_sp->router->neigh_ht,
                               &neigh_entry->ht_node,
                               mlxsw_sp_neigh_ht_params);
  }
@@@ -922,7 -815,7 +922,7 @@@ mlxsw_sp_neigh_entry_lookup(struct mlxs
        struct mlxsw_sp_neigh_key key;
  
        key.n = n;
 -      return rhashtable_lookup_fast(&mlxsw_sp->router.neigh_ht,
 +      return rhashtable_lookup_fast(&mlxsw_sp->router->neigh_ht,
                                      &key, mlxsw_sp_neigh_ht_params);
  }
  
@@@ -931,7 -824,7 +931,7 @@@ mlxsw_sp_router_neighs_update_interval_
  {
        unsigned long interval = NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME);
  
 -      mlxsw_sp->router.neighs_update.interval = jiffies_to_msecs(interval);
 +      mlxsw_sp->router->neighs_update.interval = jiffies_to_msecs(interval);
  }
  
  static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
  
        mlxsw_reg_rauhtd_ent_ipv4_unpack(rauhtd_pl, ent_index, &rif, &dip);
  
 -      if (!mlxsw_sp->rifs[rif]) {
 +      if (!mlxsw_sp->router->rifs[rif]) {
                dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect RIF in neighbour entry\n");
                return;
        }
  
        dipn = htonl(dip);
 -      dev = mlxsw_sp->rifs[rif]->dev;
 +      dev = mlxsw_sp->router->rifs[rif]->dev;
        n = neigh_lookup(&arp_tbl, &dipn, dev);
        if (!n) {
                netdev_err(dev, "Failed to find matching neighbour for IP=%pI4h\n",
@@@ -1061,7 -954,7 +1061,7 @@@ static void mlxsw_sp_router_neighs_upda
  
        /* Take RTNL mutex here to prevent lists from changes */
        rtnl_lock();
 -      list_for_each_entry(neigh_entry, &mlxsw_sp->router.nexthop_neighs_list,
 +      list_for_each_entry(neigh_entry, &mlxsw_sp->router->nexthop_neighs_list,
                            nexthop_neighs_list_node)
                /* If this neigh have nexthops, make the kernel think this neigh
                 * is active regardless of the traffic.
  static void
  mlxsw_sp_router_neighs_update_work_schedule(struct mlxsw_sp *mlxsw_sp)
  {
 -      unsigned long interval = mlxsw_sp->router.neighs_update.interval;
 +      unsigned long interval = mlxsw_sp->router->neighs_update.interval;
  
 -      mlxsw_core_schedule_dw(&mlxsw_sp->router.neighs_update.dw,
 +      mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw,
                               msecs_to_jiffies(interval));
  }
  
  static void mlxsw_sp_router_neighs_update_work(struct work_struct *work)
  {
 -      struct mlxsw_sp *mlxsw_sp = container_of(work, struct mlxsw_sp,
 -                                               router.neighs_update.dw.work);
 +      struct mlxsw_sp_router *router;
        int err;
  
 -      err = mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp);
 +      router = container_of(work, struct mlxsw_sp_router,
 +                            neighs_update.dw.work);
 +      err = mlxsw_sp_router_neighs_update_rauhtd(router->mlxsw_sp);
        if (err)
 -              dev_err(mlxsw_sp->bus_info->dev, "Could not update kernel for neigh activity");
 +              dev_err(router->mlxsw_sp->bus_info->dev, "Could not update kernel for neigh activity");
  
 -      mlxsw_sp_router_neighs_update_nh(mlxsw_sp);
 +      mlxsw_sp_router_neighs_update_nh(router->mlxsw_sp);
  
 -      mlxsw_sp_router_neighs_update_work_schedule(mlxsw_sp);
 +      mlxsw_sp_router_neighs_update_work_schedule(router->mlxsw_sp);
  }
  
  static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work)
  {
        struct mlxsw_sp_neigh_entry *neigh_entry;
 -      struct mlxsw_sp *mlxsw_sp = container_of(work, struct mlxsw_sp,
 -                                               router.nexthop_probe_dw.work);
 +      struct mlxsw_sp_router *router;
  
 +      router = container_of(work, struct mlxsw_sp_router,
 +                            nexthop_probe_dw.work);
        /* Iterate over nexthop neighbours, find those who are unresolved and
         * send arp on them. This solves the chicken-egg problem when
         * the nexthop wouldn't get offloaded until the neighbor is resolved
         * Take RTNL mutex here to prevent lists from changes.
         */
        rtnl_lock();
 -      list_for_each_entry(neigh_entry, &mlxsw_sp->router.nexthop_neighs_list,
 +      list_for_each_entry(neigh_entry, &router->nexthop_neighs_list,
                            nexthop_neighs_list_node)
                if (!neigh_entry->connected)
                        neigh_event_send(neigh_entry->key.n, NULL);
        rtnl_unlock();
  
 -      mlxsw_core_schedule_dw(&mlxsw_sp->router.nexthop_probe_dw,
 +      mlxsw_core_schedule_dw(&router->nexthop_probe_dw,
                               MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL);
  }
  
@@@ -1239,7 -1130,7 +1239,7 @@@ int mlxsw_sp_router_netevent_event(stru
  
                mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
                interval = jiffies_to_msecs(NEIGH_VAR(p, DELAY_PROBE_TIME));
 -              mlxsw_sp->router.neighs_update.interval = interval;
 +              mlxsw_sp->router->neighs_update.interval = interval;
  
                mlxsw_sp_port_dev_put(mlxsw_sp_port);
                break;
@@@ -1280,7 -1171,7 +1280,7 @@@ static int mlxsw_sp_neigh_init(struct m
  {
        int err;
  
 -      err = rhashtable_init(&mlxsw_sp->router.neigh_ht,
 +      err = rhashtable_init(&mlxsw_sp->router->neigh_ht,
                              &mlxsw_sp_neigh_ht_params);
        if (err)
                return err;
        mlxsw_sp_router_neighs_update_interval_init(mlxsw_sp);
  
        /* Create the delayed works for the activity_update */
 -      INIT_DELAYED_WORK(&mlxsw_sp->router.neighs_update.dw,
 +      INIT_DELAYED_WORK(&mlxsw_sp->router->neighs_update.dw,
                          mlxsw_sp_router_neighs_update_work);
 -      INIT_DELAYED_WORK(&mlxsw_sp->router.nexthop_probe_dw,
 +      INIT_DELAYED_WORK(&mlxsw_sp->router->nexthop_probe_dw,
                          mlxsw_sp_router_probe_unresolved_nexthops);
 -      mlxsw_core_schedule_dw(&mlxsw_sp->router.neighs_update.dw, 0);
 -      mlxsw_core_schedule_dw(&mlxsw_sp->router.nexthop_probe_dw, 0);
 +      mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw, 0);
 +      mlxsw_core_schedule_dw(&mlxsw_sp->router->nexthop_probe_dw, 0);
        return 0;
  }
  
  static void mlxsw_sp_neigh_fini(struct mlxsw_sp *mlxsw_sp)
  {
 -      cancel_delayed_work_sync(&mlxsw_sp->router.neighs_update.dw);
 -      cancel_delayed_work_sync(&mlxsw_sp->router.nexthop_probe_dw);
 -      rhashtable_destroy(&mlxsw_sp->router.neigh_ht);
 +      cancel_delayed_work_sync(&mlxsw_sp->router->neighs_update.dw);
 +      cancel_delayed_work_sync(&mlxsw_sp->router->nexthop_probe_dw);
 +      rhashtable_destroy(&mlxsw_sp->router->neigh_ht);
  }
  
  static int mlxsw_sp_neigh_rif_flush(struct mlxsw_sp *mlxsw_sp,
@@@ -1379,7 -1270,7 +1379,7 @@@ static const struct rhashtable_params m
  static int mlxsw_sp_nexthop_group_insert(struct mlxsw_sp *mlxsw_sp,
                                         struct mlxsw_sp_nexthop_group *nh_grp)
  {
 -      return rhashtable_insert_fast(&mlxsw_sp->router.nexthop_group_ht,
 +      return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_group_ht,
                                      &nh_grp->ht_node,
                                      mlxsw_sp_nexthop_group_ht_params);
  }
  static void mlxsw_sp_nexthop_group_remove(struct mlxsw_sp *mlxsw_sp,
                                          struct mlxsw_sp_nexthop_group *nh_grp)
  {
 -      rhashtable_remove_fast(&mlxsw_sp->router.nexthop_group_ht,
 +      rhashtable_remove_fast(&mlxsw_sp->router->nexthop_group_ht,
                               &nh_grp->ht_node,
                               mlxsw_sp_nexthop_group_ht_params);
  }
@@@ -1396,7 -1287,7 +1396,7 @@@ static struct mlxsw_sp_nexthop_group 
  mlxsw_sp_nexthop_group_lookup(struct mlxsw_sp *mlxsw_sp,
                              struct mlxsw_sp_nexthop_group_key key)
  {
 -      return rhashtable_lookup_fast(&mlxsw_sp->router.nexthop_group_ht, &key,
 +      return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_group_ht, &key,
                                      mlxsw_sp_nexthop_group_ht_params);
  }
  
@@@ -1409,14 -1300,14 +1409,14 @@@ static const struct rhashtable_params m
  static int mlxsw_sp_nexthop_insert(struct mlxsw_sp *mlxsw_sp,
                                   struct mlxsw_sp_nexthop *nh)
  {
 -      return rhashtable_insert_fast(&mlxsw_sp->router.nexthop_ht,
 +      return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_ht,
                                      &nh->ht_node, mlxsw_sp_nexthop_ht_params);
  }
  
  static void mlxsw_sp_nexthop_remove(struct mlxsw_sp *mlxsw_sp,
                                    struct mlxsw_sp_nexthop *nh)
  {
 -      rhashtable_remove_fast(&mlxsw_sp->router.nexthop_ht, &nh->ht_node,
 +      rhashtable_remove_fast(&mlxsw_sp->router->nexthop_ht, &nh->ht_node,
                               mlxsw_sp_nexthop_ht_params);
  }
  
@@@ -1424,7 -1315,7 +1424,7 @@@ static struct mlxsw_sp_nexthop 
  mlxsw_sp_nexthop_lookup(struct mlxsw_sp *mlxsw_sp,
                        struct mlxsw_sp_nexthop_key key)
  {
 -      return rhashtable_lookup_fast(&mlxsw_sp->router.nexthop_ht, &key,
 +      return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_ht, &key,
                                      mlxsw_sp_nexthop_ht_params);
  }
  
@@@ -1711,7 -1602,7 +1711,7 @@@ static int mlxsw_sp_nexthop_neigh_init(
         */
        if (list_empty(&neigh_entry->nexthop_list))
                list_add_tail(&neigh_entry->nexthop_neighs_list_node,
 -                            &mlxsw_sp->router.nexthop_neighs_list);
 +                            &mlxsw_sp->router->nexthop_neighs_list);
  
        nh->neigh_entry = neigh_entry;
        list_add_tail(&nh->neigh_list_node, &neigh_entry->nexthop_list);
@@@ -1809,7 -1700,7 +1809,7 @@@ static void mlxsw_sp_nexthop_event(stru
        struct mlxsw_sp_nexthop *nh;
        struct mlxsw_sp_rif *rif;
  
 -      if (mlxsw_sp->router.aborted)
 +      if (mlxsw_sp->router->aborted)
                return;
  
        key.fib_nh = fib_nh;
@@@ -2622,7 -2513,7 +2622,7 @@@ mlxsw_sp_router_fib4_add(struct mlxsw_s
        struct mlxsw_sp_fib_node *fib_node;
        int err;
  
 -      if (mlxsw_sp->router.aborted)
 +      if (mlxsw_sp->router->aborted)
                return 0;
  
        fib_node = mlxsw_sp_fib4_node_get(mlxsw_sp, fen_info);
@@@ -2662,7 -2553,7 +2662,7 @@@ static void mlxsw_sp_router_fib4_del(st
        struct mlxsw_sp_fib_entry *fib_entry;
        struct mlxsw_sp_fib_node *fib_node;
  
 -      if (mlxsw_sp->router.aborted)
 +      if (mlxsw_sp->router->aborted)
                return;
  
        fib_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info);
@@@ -2693,7 -2584,7 +2693,7 @@@ static int mlxsw_sp_router_set_abort_tr
                return err;
  
        for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
 -              struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[i];
 +              struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
                char raltb_pl[MLXSW_REG_RALTB_LEN];
                char ralue_pl[MLXSW_REG_RALUE_LEN];
  
@@@ -2775,7 -2666,7 +2775,7 @@@ static void mlxsw_sp_router_fib_flush(s
        int i;
  
        for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
 -              struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[i];
 +              struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
  
                if (!mlxsw_sp_vr_is_used(vr))
                        continue;
@@@ -2787,11 -2678,11 +2787,11 @@@ static void mlxsw_sp_router_fib4_abort(
  {
        int err;
  
 -      if (mlxsw_sp->router.aborted)
 +      if (mlxsw_sp->router->aborted)
                return;
        dev_warn(mlxsw_sp->bus_info->dev, "FIB abort triggered. Note that FIB entries are no longer being offloaded to this device.\n");
        mlxsw_sp_router_fib_flush(mlxsw_sp);
 -      mlxsw_sp->router.aborted = true;
 +      mlxsw_sp->router->aborted = true;
        err = mlxsw_sp_router_set_abort_trap(mlxsw_sp);
        if (err)
                dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n");
@@@ -2857,9 -2748,9 +2857,9 @@@ static void mlxsw_sp_router_fib_event_w
  static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
                                     unsigned long event, void *ptr)
  {
 -      struct mlxsw_sp *mlxsw_sp = container_of(nb, struct mlxsw_sp, fib_nb);
        struct mlxsw_sp_fib_event_work *fib_work;
        struct fib_notifier_info *info = ptr;
 +      struct mlxsw_sp_router *router;
  
        if (!net_eq(info->net, &init_net))
                return NOTIFY_DONE;
                return NOTIFY_BAD;
  
        INIT_WORK(&fib_work->work, mlxsw_sp_router_fib_event_work);
 -      fib_work->mlxsw_sp = mlxsw_sp;
 +      router = container_of(nb, struct mlxsw_sp_router, fib_nb);
 +      fib_work->mlxsw_sp = router->mlxsw_sp;
        fib_work->event = event;
  
        switch (event) {
@@@ -2908,9 -2798,8 +2908,9 @@@ mlxsw_sp_rif_find_by_dev(const struct m
        int i;
  
        for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++)
 -              if (mlxsw_sp->rifs[i] && mlxsw_sp->rifs[i]->dev == dev)
 -                      return mlxsw_sp->rifs[i];
 +              if (mlxsw_sp->router->rifs[i] &&
 +                  mlxsw_sp->router->rifs[i]->dev == dev)
 +                      return mlxsw_sp->router->rifs[i];
  
        return NULL;
  }
@@@ -2960,46 -2849,77 +2960,46 @@@ static bool mlxsw_sp_rif_should_config(
        return false;
  }
  
 -#define MLXSW_SP_INVALID_INDEX_RIF 0xffff
 -static int mlxsw_sp_avail_rif_get(struct mlxsw_sp *mlxsw_sp)
 -{
 -      int i;
 -
 -      for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++)
 -              if (!mlxsw_sp->rifs[i])
 -                      return i;
 -
 -      return MLXSW_SP_INVALID_INDEX_RIF;
 -}
 -
 -static void mlxsw_sp_vport_rif_sp_attr_get(struct mlxsw_sp_port *mlxsw_sp_vport,
 -                                         bool *p_lagged, u16 *p_system_port)
 +static enum mlxsw_sp_rif_type
 +mlxsw_sp_dev_rif_type(const struct mlxsw_sp *mlxsw_sp,
 +                    const struct net_device *dev)
  {
 -      u8 local_port = mlxsw_sp_vport->local_port;
 -
 -      *p_lagged = mlxsw_sp_vport->lagged;
 -      *p_system_port = *p_lagged ? mlxsw_sp_vport->lag_id : local_port;
 -}
 -
 -static int mlxsw_sp_vport_rif_sp_op(struct mlxsw_sp_port *mlxsw_sp_vport,
 -                                  u16 vr_id, struct net_device *l3_dev,
 -                                  u16 rif_index, bool create)
 -{
 -      struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;
 -      bool lagged = mlxsw_sp_vport->lagged;
 -      char ritr_pl[MLXSW_REG_RITR_LEN];
 -      u16 system_port;
 -
 -      mlxsw_reg_ritr_pack(ritr_pl, create, MLXSW_REG_RITR_SP_IF, rif_index,
 -                          vr_id, l3_dev->mtu, l3_dev->dev_addr);
 +      enum mlxsw_sp_fid_type type;
  
 -      mlxsw_sp_vport_rif_sp_attr_get(mlxsw_sp_vport, &lagged, &system_port);
 -      mlxsw_reg_ritr_sp_if_pack(ritr_pl, lagged, system_port,
 -                                mlxsw_sp_vport_vid_get(mlxsw_sp_vport));
 -
 -      return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
 -}
 -
 -static void mlxsw_sp_vport_rif_sp_leave(struct mlxsw_sp_port *mlxsw_sp_vport);
 +      /* RIF type is derived from the type of the underlying FID */
 +      if (is_vlan_dev(dev) && netif_is_bridge_master(vlan_dev_real_dev(dev)))
 +              type = MLXSW_SP_FID_TYPE_8021Q;
 +      else if (netif_is_bridge_master(dev) && br_vlan_enabled(dev))
 +              type = MLXSW_SP_FID_TYPE_8021Q;
 +      else if (netif_is_bridge_master(dev))
 +              type = MLXSW_SP_FID_TYPE_8021D;
 +      else
 +              type = MLXSW_SP_FID_TYPE_RFID;
  
 -static u16 mlxsw_sp_rif_sp_to_fid(u16 rif_index)
 -{
 -      return MLXSW_SP_RFID_BASE + rif_index;
 +      return mlxsw_sp_fid_type_rif_type(mlxsw_sp, type);
  }
  
 -static struct mlxsw_sp_fid *
 -mlxsw_sp_rfid_alloc(u16 fid, struct net_device *l3_dev)
 +static int mlxsw_sp_rif_index_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_rif_index)
  {
 -      struct mlxsw_sp_fid *f;
 -
 -      f = kzalloc(sizeof(*f), GFP_KERNEL);
 -      if (!f)
 -              return NULL;
 +      int i;
  
 -      f->leave = mlxsw_sp_vport_rif_sp_leave;
 -      f->ref_count = 0;
 -      f->dev = l3_dev;
 -      f->fid = fid;
 +      for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
 +              if (!mlxsw_sp->router->rifs[i]) {
 +                      *p_rif_index = i;
 +                      return 0;
 +              }
 +      }
  
 -      return f;
 +      return -ENOBUFS;
  }
  
 -static struct mlxsw_sp_rif *
 -mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev,
 -                 struct mlxsw_sp_fid *f)
 +static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index,
 +                                             u16 vr_id,
 +                                             struct net_device *l3_dev)
  {
        struct mlxsw_sp_rif *rif;
  
 -      rif = kzalloc(sizeof(*rif), GFP_KERNEL);
 +      rif = kzalloc(rif_size, GFP_KERNEL);
        if (!rif)
                return NULL;
  
        rif->vr_id = vr_id;
        rif->dev = l3_dev;
        rif->rif_index = rif_index;
 -      rif->f = f;
  
        return rif;
  }
  
 +struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp,
 +                                         u16 rif_index)
 +{
 +      return mlxsw_sp->router->rifs[rif_index];
 +}
 +
  u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif)
  {
        return rif->rif_index;
@@@ -3031,199 -2946,152 +3031,199 @@@ int mlxsw_sp_rif_dev_ifindex(const stru
  }
  
  static struct mlxsw_sp_rif *
 -mlxsw_sp_vport_rif_sp_create(struct mlxsw_sp_port *mlxsw_sp_vport,
 -                           struct net_device *l3_dev)
 +mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
 +                  const struct mlxsw_sp_rif_params *params)
  {
 -      struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;
 -      u32 tb_id = l3mdev_fib_table(l3_dev);
 -      struct mlxsw_sp_vr *vr;
 -      struct mlxsw_sp_fid *f;
 +      u32 tb_id = l3mdev_fib_table(params->dev);
 +      const struct mlxsw_sp_rif_ops *ops;
 +      enum mlxsw_sp_rif_type type;
        struct mlxsw_sp_rif *rif;
 -      u16 fid, rif_index;
 +      struct mlxsw_sp_fid *fid;
 +      struct mlxsw_sp_vr *vr;
 +      u16 rif_index;
        int err;
  
 -      rif_index = mlxsw_sp_avail_rif_get(mlxsw_sp);
 -      if (rif_index == MLXSW_SP_INVALID_INDEX_RIF)
 -              return ERR_PTR(-ERANGE);
 +      type = mlxsw_sp_dev_rif_type(mlxsw_sp, params->dev);
 +      ops = mlxsw_sp->router->rif_ops_arr[type];
  
        vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN);
        if (IS_ERR(vr))
                return ERR_CAST(vr);
  
 -      err = mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, vr->id, l3_dev,
 -                                     rif_index, true);
 -      if (err)
 -              goto err_vport_rif_sp_op;
 -
 -      fid = mlxsw_sp_rif_sp_to_fid(rif_index);
 -      err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, true);
 +      err = mlxsw_sp_rif_index_alloc(mlxsw_sp, &rif_index);
        if (err)
 -              goto err_rif_fdb_op;
 -
 -      f = mlxsw_sp_rfid_alloc(fid, l3_dev);
 -      if (!f) {
 -              err = -ENOMEM;
 -              goto err_rfid_alloc;
 -      }
 +              goto err_rif_index_alloc;
  
 -      rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f);
 +      rif = mlxsw_sp_rif_alloc(ops->rif_size, rif_index, vr->id, params->dev);
        if (!rif) {
                err = -ENOMEM;
                goto err_rif_alloc;
        }
 +      rif->mlxsw_sp = mlxsw_sp;
 +      rif->ops = ops;
  
 -      if (devlink_dpipe_table_counter_enabled(priv_to_devlink(mlxsw_sp->core),
 -                                              MLXSW_SP_DPIPE_TABLE_NAME_ERIF)) {
 -              err = mlxsw_sp_rif_counter_alloc(mlxsw_sp, rif,
 -                                               MLXSW_SP_RIF_COUNTER_EGRESS);
 -              if (err)
 -                      netdev_dbg(mlxsw_sp_vport->dev,
 -                                 "Counter alloc Failed err=%d\n", err);
 +      fid = ops->fid_get(rif);
 +      if (IS_ERR(fid)) {
 +              err = PTR_ERR(fid);
 +              goto err_fid_get;
        }
 +      rif->fid = fid;
 +
 +      if (ops->setup)
 +              ops->setup(rif, params);
 +
 +      err = ops->configure(rif);
 +      if (err)
 +              goto err_configure;
 +
 +      err = mlxsw_sp_rif_fdb_op(mlxsw_sp, params->dev->dev_addr,
 +                                mlxsw_sp_fid_index(fid), true);
 +      if (err)
 +              goto err_rif_fdb_op;
  
 -      f->rif = rif;
 -      mlxsw_sp->rifs[rif_index] = rif;
 +      mlxsw_sp_rif_counters_alloc(rif);
 +      mlxsw_sp_fid_rif_set(fid, rif);
 +      mlxsw_sp->router->rifs[rif_index] = rif;
        vr->rif_count++;
  
        return rif;
  
 -err_rif_alloc:
 -      kfree(f);
 -err_rfid_alloc:
 -      mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false);
  err_rif_fdb_op:
 -      mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, vr->id, l3_dev, rif_index,
 -                               false);
 -err_vport_rif_sp_op:
 +      ops->deconfigure(rif);
 +err_configure:
 +      mlxsw_sp_fid_put(fid);
 +err_fid_get:
 +      kfree(rif);
 +err_rif_alloc:
 +err_rif_index_alloc:
        mlxsw_sp_vr_put(vr);
        return ERR_PTR(err);
  }
  
 -static void mlxsw_sp_vport_rif_sp_destroy(struct mlxsw_sp_port *mlxsw_sp_vport,
 -                                        struct mlxsw_sp_rif *rif)
 +void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)
  {
 -      struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;
 -      struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[rif->vr_id];
 -      struct net_device *l3_dev = rif->dev;
 -      struct mlxsw_sp_fid *f = rif->f;
 -      u16 rif_index = rif->rif_index;
 -      u16 fid = f->fid;
 +      const struct mlxsw_sp_rif_ops *ops = rif->ops;
 +      struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
 +      struct mlxsw_sp_fid *fid = rif->fid;
 +      struct mlxsw_sp_vr *vr;
  
        mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif);
 -
 -      mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_EGRESS);
 -      mlxsw_sp_rif_counter_free(mlxsw_sp, rif, MLXSW_SP_RIF_COUNTER_INGRESS);
 +      vr = &mlxsw_sp->router->vrs[rif->vr_id];
  
        vr->rif_count--;
 -      mlxsw_sp->rifs[rif_index] = NULL;
 -      f->rif = NULL;
 -
 +      mlxsw_sp->router->rifs[rif->rif_index] = NULL;
 +      mlxsw_sp_fid_rif_set(fid, NULL);
 +      mlxsw_sp_rif_counters_free(rif);
 +      mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->dev->dev_addr,
 +                          mlxsw_sp_fid_index(fid), false);
 +      ops->deconfigure(rif);
 +      mlxsw_sp_fid_put(fid);
        kfree(rif);
 +      mlxsw_sp_vr_put(vr);
 +}
  
 -      kfree(f);
 -
 -      mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false);
 +static void
 +mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params *params,
 +                               struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
 +{
 +      struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
  
 -      mlxsw_sp_vport_rif_sp_op(mlxsw_sp_vport, vr->id, l3_dev, rif_index,
 -                               false);
 -      mlxsw_sp_vr_put(vr);
 +      params->vid = mlxsw_sp_port_vlan->vid;
 +      params->lag = mlxsw_sp_port->lagged;
 +      if (params->lag)
 +              params->lag_id = mlxsw_sp_port->lag_id;
 +      else
 +              params->system_port = mlxsw_sp_port->local_port;
  }
  
 -static int mlxsw_sp_vport_rif_sp_join(struct mlxsw_sp_port *mlxsw_sp_vport,
 -                                    struct net_device *l3_dev)
 +static int
 +mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
 +                             struct net_device *l3_dev)
  {
 -      struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;
 +      struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
 +      struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
 +      u16 vid = mlxsw_sp_port_vlan->vid;
        struct mlxsw_sp_rif *rif;
 +      struct mlxsw_sp_fid *fid;
 +      int err;
  
        rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
        if (!rif) {
 -              rif = mlxsw_sp_vport_rif_sp_create(mlxsw_sp_vport, l3_dev);
 +              struct mlxsw_sp_rif_params params = {
 +                      .dev = l3_dev,
 +              };
 +
 +              mlxsw_sp_rif_subport_params_init(&params, mlxsw_sp_port_vlan);
 +              rif = mlxsw_sp_rif_create(mlxsw_sp, &params);
                if (IS_ERR(rif))
                        return PTR_ERR(rif);
        }
  
 -      mlxsw_sp_vport_fid_set(mlxsw_sp_vport, rif->f);
 -      rif->f->ref_count++;
 +      /* FID was already created, just take a reference */
 +      fid = rif->ops->fid_get(rif);
 +      err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid);
 +      if (err)
 +              goto err_fid_port_vid_map;
 +
 +      err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false);
 +      if (err)
 +              goto err_port_vid_learning_set;
 +
 +      err = mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid,
 +                                      BR_STATE_FORWARDING);
 +      if (err)
 +              goto err_port_vid_stp_set;
  
 -      netdev_dbg(mlxsw_sp_vport->dev, "Joined FID=%d\n", rif->f->fid);
 +      mlxsw_sp_port_vlan->fid = fid;
  
        return 0;
 +
 +err_port_vid_stp_set:
 +      mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
 +err_port_vid_learning_set:
 +      mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
 +err_fid_port_vid_map:
 +      mlxsw_sp_fid_put(fid);
 +      return err;
  }
  
 -static void mlxsw_sp_vport_rif_sp_leave(struct mlxsw_sp_port *mlxsw_sp_vport)
 +void
 +mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
  {
 -      struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport);
 +      struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
 +      struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
 +      u16 vid = mlxsw_sp_port_vlan->vid;
  
 -      netdev_dbg(mlxsw_sp_vport->dev, "Left FID=%d\n", f->fid);
 +      if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_RFID))
 +              return;
  
 -      mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL);
 -      if (--f->ref_count == 0)
 -              mlxsw_sp_vport_rif_sp_destroy(mlxsw_sp_vport, f->rif);
 +      mlxsw_sp_port_vlan->fid = NULL;
 +      mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING);
 +      mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
 +      mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid);
 +      /* If router port holds the last reference on the rFID, then the
 +       * associated Sub-port RIF will be destroyed.
 +       */
 +      mlxsw_sp_fid_put(fid);
  }
  
 -static int mlxsw_sp_inetaddr_vport_event(struct net_device *l3_dev,
 -                                       struct net_device *port_dev,
 -                                       unsigned long event, u16 vid)
 +static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev,
 +                                           struct net_device *port_dev,
 +                                           unsigned long event, u16 vid)
  {
        struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(port_dev);
 -      struct mlxsw_sp_port *mlxsw_sp_vport;
 +      struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
  
 -      mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid);
 -      if (WARN_ON(!mlxsw_sp_vport))
 +      mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
 +      if (WARN_ON(!mlxsw_sp_port_vlan))
                return -EINVAL;
  
        switch (event) {
        case NETDEV_UP:
 -              return mlxsw_sp_vport_rif_sp_join(mlxsw_sp_vport, l3_dev);
 +              return mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan,
 +                                                    l3_dev);
        case NETDEV_DOWN:
 -              mlxsw_sp_vport_rif_sp_leave(mlxsw_sp_vport);
 +              mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
                break;
        }
  
@@@ -3238,7 -3106,7 +3238,7 @@@ static int mlxsw_sp_inetaddr_port_event
            netif_is_ovs_port(port_dev))
                return 0;
  
 -      return mlxsw_sp_inetaddr_vport_event(port_dev, port_dev, event, 1);
 +      return mlxsw_sp_inetaddr_port_vlan_event(port_dev, port_dev, event, 1);
  }
  
  static int __mlxsw_sp_inetaddr_lag_event(struct net_device *l3_dev,
  
        netdev_for_each_lower_dev(lag_dev, port_dev, iter) {
                if (mlxsw_sp_port_dev_check(port_dev)) {
 -                      err = mlxsw_sp_inetaddr_vport_event(l3_dev, port_dev,
 -                                                          event, vid);
 +                      err = mlxsw_sp_inetaddr_port_vlan_event(l3_dev,
 +                                                              port_dev,
 +                                                              event, vid);
                        if (err)
                                return err;
                }
@@@ -3271,24 -3138,189 +3271,24 @@@ static int mlxsw_sp_inetaddr_lag_event(
        return __mlxsw_sp_inetaddr_lag_event(lag_dev, lag_dev, event, 1);
  }
  
 -static struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp,
 -                                                  struct net_device *l3_dev)
 -{
 -      u16 fid;
 -
 -      if (is_vlan_dev(l3_dev))
 -              fid = vlan_dev_vlan_id(l3_dev);
 -      else if (mlxsw_sp->master_bridge.dev == l3_dev)
 -              fid = 1;
 -      else
 -              return mlxsw_sp_vfid_find(mlxsw_sp, l3_dev);
 -
 -      return mlxsw_sp_fid_find(mlxsw_sp, fid);
 -}
 -
 -static u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp)
 -{
 -      return mlxsw_core_max_ports(mlxsw_sp->core) + 1;
 -}
 -
 -static enum mlxsw_flood_table_type mlxsw_sp_flood_table_type_get(u16 fid)
 -{
 -      return mlxsw_sp_fid_is_vfid(fid) ? MLXSW_REG_SFGC_TABLE_TYPE_FID :
 -             MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST;
 -}
 -
 -static u16 mlxsw_sp_flood_table_index_get(u16 fid)
 -{
 -      return mlxsw_sp_fid_is_vfid(fid) ? mlxsw_sp_fid_to_vfid(fid) : fid;
 -}
 -
 -static int mlxsw_sp_router_port_flood_set(struct mlxsw_sp *mlxsw_sp, u16 fid,
 -                                        bool set)
 -{
 -      u8 router_port = mlxsw_sp_router_port(mlxsw_sp);
 -      enum mlxsw_flood_table_type table_type;
 -      char *sftr_pl;
 -      u16 index;
 -      int err;
 -
 -      sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL);
 -      if (!sftr_pl)
 -              return -ENOMEM;
 -
 -      table_type = mlxsw_sp_flood_table_type_get(fid);
 -      index = mlxsw_sp_flood_table_index_get(fid);
 -      mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BC, index, table_type,
 -                          1, router_port, set);
 -      err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
 -
 -      kfree(sftr_pl);
 -      return err;
 -}
 -
 -static enum mlxsw_reg_ritr_if_type mlxsw_sp_rif_type_get(u16 fid)
 -{
 -      if (mlxsw_sp_fid_is_vfid(fid))
 -              return MLXSW_REG_RITR_FID_IF;
 -      else
 -              return MLXSW_REG_RITR_VLAN_IF;
 -}
 -
 -static int mlxsw_sp_rif_bridge_op(struct mlxsw_sp *mlxsw_sp, u16 vr_id,
 -                                struct net_device *l3_dev,
 -                                u16 fid, u16 rif,
 -                                bool create)
 -{
 -      enum mlxsw_reg_ritr_if_type rif_type;
 -      char ritr_pl[MLXSW_REG_RITR_LEN];
 -
 -      rif_type = mlxsw_sp_rif_type_get(fid);
 -      mlxsw_reg_ritr_pack(ritr_pl, create, rif_type, rif, vr_id, l3_dev->mtu,
 -                          l3_dev->dev_addr);
 -      mlxsw_reg_ritr_fid_set(ritr_pl, rif_type, fid);
 -
 -      return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
 -}
 -
 -static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
 -                                    struct net_device *l3_dev,
 -                                    struct mlxsw_sp_fid *f)
 -{
 -      u32 tb_id = l3mdev_fib_table(l3_dev);
 -      struct mlxsw_sp_rif *rif;
 -      struct mlxsw_sp_vr *vr;
 -      u16 rif_index;
 -      int err;
 -
 -      rif_index = mlxsw_sp_avail_rif_get(mlxsw_sp);
 -      if (rif_index == MLXSW_SP_INVALID_INDEX_RIF)
 -              return -ERANGE;
 -
 -      vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN);
 -      if (IS_ERR(vr))
 -              return PTR_ERR(vr);
 -
 -      err = mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, true);
 -      if (err)
 -              goto err_port_flood_set;
 -
 -      err = mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid,
 -                                   rif_index, true);
 -      if (err)
 -              goto err_rif_bridge_op;
 -
 -      err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, true);
 -      if (err)
 -              goto err_rif_fdb_op;
 -
 -      rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f);
 -      if (!rif) {
 -              err = -ENOMEM;
 -              goto err_rif_alloc;
 -      }
 -
 -      f->rif = rif;
 -      mlxsw_sp->rifs[rif_index] = rif;
 -      vr->rif_count++;
 -
 -      netdev_dbg(l3_dev, "RIF=%d created\n", rif_index);
 -
 -      return 0;
 -
 -err_rif_alloc:
 -      mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false);
 -err_rif_fdb_op:
 -      mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif_index,
 -                             false);
 -err_rif_bridge_op:
 -      mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false);
 -err_port_flood_set:
 -      mlxsw_sp_vr_put(vr);
 -      return err;
 -}
 -
 -void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
 -                               struct mlxsw_sp_rif *rif)
 -{
 -      struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[rif->vr_id];
 -      struct net_device *l3_dev = rif->dev;
 -      struct mlxsw_sp_fid *f = rif->f;
 -      u16 rif_index = rif->rif_index;
 -
 -      mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif);
 -
 -      vr->rif_count--;
 -      mlxsw_sp->rifs[rif_index] = NULL;
 -      f->rif = NULL;
 -
 -      kfree(rif);
 -
 -      mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false);
 -
 -      mlxsw_sp_rif_bridge_op(mlxsw_sp, vr->id, l3_dev, f->fid, rif_index,
 -                             false);
 -
 -      mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false);
 -
 -      mlxsw_sp_vr_put(vr);
 -
 -      netdev_dbg(l3_dev, "RIF=%d destroyed\n", rif_index);
 -}
 -
  static int mlxsw_sp_inetaddr_bridge_event(struct net_device *l3_dev,
 -                                        struct net_device *br_dev,
                                          unsigned long event)
  {
        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev);
 -      struct mlxsw_sp_fid *f;
 -
 -      /* FID can either be an actual FID if the L3 device is the
 -       * VLAN-aware bridge or a VLAN device on top. Otherwise, the
 -       * L3 device is a VLAN-unaware bridge and we get a vFID.
 -       */
 -      f = mlxsw_sp_bridge_fid_get(mlxsw_sp, l3_dev);
 -      if (WARN_ON(!f))
 -              return -EINVAL;
 +      struct mlxsw_sp_rif_params params = {
 +              .dev = l3_dev,
 +      };
 +      struct mlxsw_sp_rif *rif;
  
        switch (event) {
        case NETDEV_UP:
 -              return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev, f);
 +              rif = mlxsw_sp_rif_create(mlxsw_sp, &params);
 +              if (IS_ERR(rif))
 +                      return PTR_ERR(rif);
 +              break;
        case NETDEV_DOWN:
 -              mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif);
 +              rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev);
 +              mlxsw_sp_rif_destroy(rif);
                break;
        }
  
@@@ -3299,16 -3331,22 +3299,19 @@@ static int mlxsw_sp_inetaddr_vlan_event
                                        unsigned long event)
  {
        struct net_device *real_dev = vlan_dev_real_dev(vlan_dev);
 -      struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(vlan_dev);
        u16 vid = vlan_dev_vlan_id(vlan_dev);
  
+       if (netif_is_bridge_port(vlan_dev))
+               return 0;
        if (mlxsw_sp_port_dev_check(real_dev))
 -              return mlxsw_sp_inetaddr_vport_event(vlan_dev, real_dev, event,
 -                                                   vid);
 +              return mlxsw_sp_inetaddr_port_vlan_event(vlan_dev, real_dev,
 +                                                       event, vid);
        else if (netif_is_lag_master(real_dev))
                return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event,
                                                     vid);
 -      else if (netif_is_bridge_master(real_dev) &&
 -               mlxsw_sp->master_bridge.dev == real_dev)
 -              return mlxsw_sp_inetaddr_bridge_event(vlan_dev, real_dev,
 -                                                    event);
 +      else if (netif_is_bridge_master(real_dev) && br_vlan_enabled(real_dev))
 +              return mlxsw_sp_inetaddr_bridge_event(vlan_dev, event);
  
        return 0;
  }
@@@ -3321,7 -3359,7 +3324,7 @@@ static int __mlxsw_sp_inetaddr_event(st
        else if (netif_is_lag_master(dev))
                return mlxsw_sp_inetaddr_lag_event(dev, event);
        else if (netif_is_bridge_master(dev))
 -              return mlxsw_sp_inetaddr_bridge_event(dev, dev, event);
 +              return mlxsw_sp_inetaddr_bridge_event(dev, event);
        else if (is_vlan_dev(dev))
                return mlxsw_sp_inetaddr_vlan_event(dev, event);
        else
@@@ -3371,7 -3409,6 +3374,7 @@@ int mlxsw_sp_netdevice_router_port_even
  {
        struct mlxsw_sp *mlxsw_sp;
        struct mlxsw_sp_rif *rif;
 +      u16 fid_index;
        int err;
  
        mlxsw_sp = mlxsw_sp_lower_get(dev);
        rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
        if (!rif)
                return 0;
 +      fid_index = mlxsw_sp_fid_index(rif->fid);
  
 -      err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, rif->f->fid, false);
 +      err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, false);
        if (err)
                return err;
  
        if (err)
                goto err_rif_edit;
  
 -      err = mlxsw_sp_rif_fdb_op(mlxsw_sp, dev->dev_addr, rif->f->fid, true);
 +      err = mlxsw_sp_rif_fdb_op(mlxsw_sp, dev->dev_addr, fid_index, true);
        if (err)
                goto err_rif_fdb_op;
  
  err_rif_fdb_op:
        mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, rif->addr, rif->mtu);
  err_rif_edit:
 -      mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, rif->f->fid, true);
 +      mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, true);
        return err;
  }
  
@@@ -3459,225 -3495,16 +3462,225 @@@ int mlxsw_sp_netdevice_vrf_event(struc
        return err;
  }
  
 +static struct mlxsw_sp_rif_subport *
 +mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif *rif)
 +{
 +      return container_of(rif, struct mlxsw_sp_rif_subport, common);
 +}
 +
 +static void mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif *rif,
 +                                     const struct mlxsw_sp_rif_params *params)
 +{
 +      struct mlxsw_sp_rif_subport *rif_subport;
 +
 +      rif_subport = mlxsw_sp_rif_subport_rif(rif);
 +      rif_subport->vid = params->vid;
 +      rif_subport->lag = params->lag;
 +      if (params->lag)
 +              rif_subport->lag_id = params->lag_id;
 +      else
 +              rif_subport->system_port = params->system_port;
 +}
 +
 +static int mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif *rif, bool enable)
 +{
 +      struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
 +      struct mlxsw_sp_rif_subport *rif_subport;
 +      char ritr_pl[MLXSW_REG_RITR_LEN];
 +
 +      rif_subport = mlxsw_sp_rif_subport_rif(rif);
 +      mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_SP_IF,
 +                          rif->rif_index, rif->vr_id, rif->dev->mtu,
 +                          rif->dev->dev_addr);
 +      mlxsw_reg_ritr_sp_if_pack(ritr_pl, rif_subport->lag,
 +                                rif_subport->lag ? rif_subport->lag_id :
 +                                                   rif_subport->system_port,
 +                                rif_subport->vid);
 +
 +      return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
 +}
 +
 +static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif)
 +{
 +      return mlxsw_sp_rif_subport_op(rif, true);
 +}
 +
 +static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif *rif)
 +{
 +      mlxsw_sp_rif_subport_op(rif, false);
 +}
 +
 +static struct mlxsw_sp_fid *
 +mlxsw_sp_rif_subport_fid_get(struct mlxsw_sp_rif *rif)
 +{
 +      return mlxsw_sp_fid_rfid_get(rif->mlxsw_sp, rif->rif_index);
 +}
 +
 +static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_subport_ops = {
 +      .type                   = MLXSW_SP_RIF_TYPE_SUBPORT,
 +      .rif_size               = sizeof(struct mlxsw_sp_rif_subport),
 +      .setup                  = mlxsw_sp_rif_subport_setup,
 +      .configure              = mlxsw_sp_rif_subport_configure,
 +      .deconfigure            = mlxsw_sp_rif_subport_deconfigure,
 +      .fid_get                = mlxsw_sp_rif_subport_fid_get,
 +};
 +
 +static int mlxsw_sp_rif_vlan_fid_op(struct mlxsw_sp_rif *rif,
 +                                  enum mlxsw_reg_ritr_if_type type,
 +                                  u16 vid_fid, bool enable)
 +{
 +      struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
 +      char ritr_pl[MLXSW_REG_RITR_LEN];
 +
 +      mlxsw_reg_ritr_pack(ritr_pl, enable, type, rif->rif_index, rif->vr_id,
 +                          rif->dev->mtu, rif->dev->dev_addr);
 +      mlxsw_reg_ritr_fid_set(ritr_pl, type, vid_fid);
 +
 +      return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
 +}
 +
 +static u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp)
 +{
 +      return mlxsw_core_max_ports(mlxsw_sp->core) + 1;
 +}
 +
 +static int mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif *rif)
 +{
 +      struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
 +      u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
 +      int err;
 +
 +      err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, true);
 +      if (err)
 +              return err;
 +
 +      err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
 +                                   mlxsw_sp_router_port(mlxsw_sp), true);
 +      if (err)
 +              goto err_fid_bc_flood_set;
 +
 +      return 0;
 +
 +err_fid_bc_flood_set:
 +      mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, false);
 +      return err;
 +}
 +
 +static void mlxsw_sp_rif_vlan_deconfigure(struct mlxsw_sp_rif *rif)
 +{
 +      struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
 +      u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
 +
 +      mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
 +                             mlxsw_sp_router_port(mlxsw_sp), false);
 +      mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_VLAN_IF, vid, false);
 +}
 +
 +static struct mlxsw_sp_fid *
 +mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif)
 +{
 +      u16 vid = is_vlan_dev(rif->dev) ? vlan_dev_vlan_id(rif->dev) : 1;
 +
 +      return mlxsw_sp_fid_8021q_get(rif->mlxsw_sp, vid);
 +}
 +
 +static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_vlan_ops = {
 +      .type                   = MLXSW_SP_RIF_TYPE_VLAN,
 +      .rif_size               = sizeof(struct mlxsw_sp_rif),
 +      .configure              = mlxsw_sp_rif_vlan_configure,
 +      .deconfigure            = mlxsw_sp_rif_vlan_deconfigure,
 +      .fid_get                = mlxsw_sp_rif_vlan_fid_get,
 +};
 +
 +static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif)
 +{
 +      struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
 +      u16 fid_index = mlxsw_sp_fid_index(rif->fid);
 +      int err;
 +
 +      err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index,
 +                                     true);
 +      if (err)
 +              return err;
 +
 +      err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
 +                                   mlxsw_sp_router_port(mlxsw_sp), true);
 +      if (err)
 +              goto err_fid_bc_flood_set;
 +
 +      return 0;
 +
 +err_fid_bc_flood_set:
 +      mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false);
 +      return err;
 +}
 +
 +static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif *rif)
 +{
 +      struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
 +      u16 fid_index = mlxsw_sp_fid_index(rif->fid);
 +
 +      mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
 +                             mlxsw_sp_router_port(mlxsw_sp), false);
 +      mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false);
 +}
 +
 +static struct mlxsw_sp_fid *
 +mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif *rif)
 +{
 +      return mlxsw_sp_fid_8021d_get(rif->mlxsw_sp, rif->dev->ifindex);
 +}
 +
 +static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_fid_ops = {
 +      .type                   = MLXSW_SP_RIF_TYPE_FID,
 +      .rif_size               = sizeof(struct mlxsw_sp_rif),
 +      .configure              = mlxsw_sp_rif_fid_configure,
 +      .deconfigure            = mlxsw_sp_rif_fid_deconfigure,
 +      .fid_get                = mlxsw_sp_rif_fid_fid_get,
 +};
 +
 +static const struct mlxsw_sp_rif_ops *mlxsw_sp_rif_ops_arr[] = {
 +      [MLXSW_SP_RIF_TYPE_SUBPORT]     = &mlxsw_sp_rif_subport_ops,
 +      [MLXSW_SP_RIF_TYPE_VLAN]        = &mlxsw_sp_rif_vlan_ops,
 +      [MLXSW_SP_RIF_TYPE_FID]         = &mlxsw_sp_rif_fid_ops,
 +};
 +
 +static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp)
 +{
 +      u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
 +
 +      mlxsw_sp->router->rifs = kcalloc(max_rifs,
 +                                       sizeof(struct mlxsw_sp_rif *),
 +                                       GFP_KERNEL);
 +      if (!mlxsw_sp->router->rifs)
 +              return -ENOMEM;
 +
 +      mlxsw_sp->router->rif_ops_arr = mlxsw_sp_rif_ops_arr;
 +
 +      return 0;
 +}
 +
 +static void mlxsw_sp_rifs_fini(struct mlxsw_sp *mlxsw_sp)
 +{
 +      int i;
 +
 +      for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++)
 +              WARN_ON_ONCE(mlxsw_sp->router->rifs[i]);
 +
 +      kfree(mlxsw_sp->router->rifs);
 +}
 +
  static void mlxsw_sp_router_fib_dump_flush(struct notifier_block *nb)
  {
 -      struct mlxsw_sp *mlxsw_sp = container_of(nb, struct mlxsw_sp, fib_nb);
 +      struct mlxsw_sp_router *router;
  
        /* Flush pending FIB notifications and then flush the device's
         * table before requesting another dump. The FIB notification
         * block is unregistered, so no need to take RTNL.
         */
        mlxsw_core_flush_owq();
 -      mlxsw_sp_router_fib_flush(mlxsw_sp);
 +      router = container_of(nb, struct mlxsw_sp_router, fib_nb);
 +      mlxsw_sp_router_fib_flush(router->mlxsw_sp);
  }
  
  static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
  
        if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_RIFS))
                return -EIO;
 -
        max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
 -      mlxsw_sp->rifs = kcalloc(max_rifs, sizeof(struct mlxsw_sp_rif *),
 -                               GFP_KERNEL);
 -      if (!mlxsw_sp->rifs)
 -              return -ENOMEM;
  
        mlxsw_reg_rgcr_pack(rgcr_pl, true);
        mlxsw_reg_rgcr_max_router_interfaces_set(rgcr_pl, max_rifs);
        err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
        if (err)
 -              goto err_rgcr_fail;
 -
 +              return err;
        return 0;
 -
 -err_rgcr_fail:
 -      kfree(mlxsw_sp->rifs);
 -      return err;
  }
  
  static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
  {
        char rgcr_pl[MLXSW_REG_RGCR_LEN];
 -      int i;
  
        mlxsw_reg_rgcr_pack(rgcr_pl, false);
        mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
 -
 -      for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++)
 -              WARN_ON_ONCE(mlxsw_sp->rifs[i]);
 -
 -      kfree(mlxsw_sp->rifs);
  }
  
  int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
  {
 +      struct mlxsw_sp_router *router;
        int err;
  
 -      INIT_LIST_HEAD(&mlxsw_sp->router.nexthop_neighs_list);
 +      router = kzalloc(sizeof(*mlxsw_sp->router), GFP_KERNEL);
 +      if (!router)
 +              return -ENOMEM;
 +      mlxsw_sp->router = router;
 +      router->mlxsw_sp = mlxsw_sp;
 +
 +      INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_neighs_list);
        err = __mlxsw_sp_router_init(mlxsw_sp);
        if (err)
 -              return err;
 +              goto err_router_init;
 +
 +      err = mlxsw_sp_rifs_init(mlxsw_sp);
 +      if (err)
 +              goto err_rifs_init;
  
 -      err = rhashtable_init(&mlxsw_sp->router.nexthop_ht,
 +      err = rhashtable_init(&mlxsw_sp->router->nexthop_ht,
                              &mlxsw_sp_nexthop_ht_params);
        if (err)
                goto err_nexthop_ht_init;
  
 -      err = rhashtable_init(&mlxsw_sp->router.nexthop_group_ht,
 +      err = rhashtable_init(&mlxsw_sp->router->nexthop_group_ht,
                              &mlxsw_sp_nexthop_group_ht_params);
        if (err)
                goto err_nexthop_group_ht_init;
        if (err)
                goto err_neigh_init;
  
 -      mlxsw_sp->fib_nb.notifier_call = mlxsw_sp_router_fib_event;
 -      err = register_fib_notifier(&mlxsw_sp->fib_nb,
 +      mlxsw_sp->router->fib_nb.notifier_call = mlxsw_sp_router_fib_event;
 +      err = register_fib_notifier(&mlxsw_sp->router->fib_nb,
                                    mlxsw_sp_router_fib_dump_flush);
        if (err)
                goto err_register_fib_notifier;
@@@ -3763,27 -3595,21 +3766,27 @@@ err_neigh_init
  err_vrs_init:
        mlxsw_sp_lpm_fini(mlxsw_sp);
  err_lpm_init:
 -      rhashtable_destroy(&mlxsw_sp->router.nexthop_group_ht);
 +      rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht);
  err_nexthop_group_ht_init:
 -      rhashtable_destroy(&mlxsw_sp->router.nexthop_ht);
 +      rhashtable_destroy(&mlxsw_sp->router->nexthop_ht);
  err_nexthop_ht_init:
 +      mlxsw_sp_rifs_fini(mlxsw_sp);
 +err_rifs_init:
        __mlxsw_sp_router_fini(mlxsw_sp);
 +err_router_init:
 +      kfree(mlxsw_sp->router);
        return err;
  }
  
  void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
  {
 -      unregister_fib_notifier(&mlxsw_sp->fib_nb);
 +      unregister_fib_notifier(&mlxsw_sp->router->fib_nb);
        mlxsw_sp_neigh_fini(mlxsw_sp);
        mlxsw_sp_vrs_fini(mlxsw_sp);
        mlxsw_sp_lpm_fini(mlxsw_sp);
 -      rhashtable_destroy(&mlxsw_sp->router.nexthop_group_ht);
 -      rhashtable_destroy(&mlxsw_sp->router.nexthop_ht);
 +      rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht);
 +      rhashtable_destroy(&mlxsw_sp->router->nexthop_ht);
 +      mlxsw_sp_rifs_fini(mlxsw_sp);
        __mlxsw_sp_router_fini(mlxsw_sp);
 +      kfree(mlxsw_sp->router);
  }
index bd0e3f157e9e8629eaf0ebe591a475eb9e7b5979,a9ce82d3e9cf4b8875474cd62f02ccbfc322bc20..600e30e8f0be3156b764fdc7c762504cb74bab7a
@@@ -300,6 -300,64 +300,6 @@@ static bool ofdpa_flags_nowait(int flag
        return flags & OFDPA_OP_FLAG_NOWAIT;
  }
  
 -static void *__ofdpa_mem_alloc(struct switchdev_trans *trans, int flags,
 -                             size_t size)
 -{
 -      struct switchdev_trans_item *elem = NULL;
 -      gfp_t gfp_flags = (flags & OFDPA_OP_FLAG_NOWAIT) ?
 -                        GFP_ATOMIC : GFP_KERNEL;
 -
 -      /* If in transaction prepare phase, allocate the memory
 -       * and enqueue it on a transaction.  If in transaction
 -       * commit phase, dequeue the memory from the transaction
 -       * rather than re-allocating the memory.  The idea is the
 -       * driver code paths for prepare and commit are identical
 -       * so the memory allocated in the prepare phase is the
 -       * memory used in the commit phase.
 -       */
 -
 -      if (!trans) {
 -              elem = kzalloc(size + sizeof(*elem), gfp_flags);
 -      } else if (switchdev_trans_ph_prepare(trans)) {
 -              elem = kzalloc(size + sizeof(*elem), gfp_flags);
 -              if (!elem)
 -                      return NULL;
 -              switchdev_trans_item_enqueue(trans, elem, kfree, elem);
 -      } else {
 -              elem = switchdev_trans_item_dequeue(trans);
 -      }
 -
 -      return elem ? elem + 1 : NULL;
 -}
 -
 -static void *ofdpa_kzalloc(struct switchdev_trans *trans, int flags,
 -                         size_t size)
 -{
 -      return __ofdpa_mem_alloc(trans, flags, size);
 -}
 -
 -static void *ofdpa_kcalloc(struct switchdev_trans *trans, int flags,
 -                         size_t n, size_t size)
 -{
 -      return __ofdpa_mem_alloc(trans, flags, n * size);
 -}
 -
 -static void ofdpa_kfree(struct switchdev_trans *trans, const void *mem)
 -{
 -      struct switchdev_trans_item *elem;
 -
 -      /* Frees are ignored if in transaction prepare phase.  The
 -       * memory remains on the per-port list until freed in the
 -       * commit phase.
 -       */
 -
 -      if (switchdev_trans_ph_prepare(trans))
 -              return;
 -
 -      elem = (struct switchdev_trans_item *) mem - 1;
 -      kfree(elem);
 -}
 -
  /*************************************************************
   * Flow, group, FDB, internal VLAN and neigh command prepares
   *************************************************************/
@@@ -757,7 -815,8 +757,7 @@@ ofdpa_flow_tbl_find(const struct ofdpa 
  }
  
  static int ofdpa_flow_tbl_add(struct ofdpa_port *ofdpa_port,
 -                            struct switchdev_trans *trans, int flags,
 -                            struct ofdpa_flow_tbl_entry *match)
 +                            int flags, struct ofdpa_flow_tbl_entry *match)
  {
        struct ofdpa *ofdpa = ofdpa_port->ofdpa;
        struct ofdpa_flow_tbl_entry *found;
  
        if (found) {
                match->cookie = found->cookie;
 -              if (!switchdev_trans_ph_prepare(trans))
 -                      hash_del(&found->entry);
 -              ofdpa_kfree(trans, found);
 +              hash_del(&found->entry);
 +              kfree(found);
                found = match;
                found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD;
        } else {
                found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD;
        }
  
 -      if (!switchdev_trans_ph_prepare(trans))
 -              hash_add(ofdpa->flow_tbl, &found->entry, found->key_crc32);
 -
 +      hash_add(ofdpa->flow_tbl, &found->entry, found->key_crc32);
        spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, lock_flags);
  
 -      if (!switchdev_trans_ph_prepare(trans))
 -              return rocker_cmd_exec(ofdpa_port->rocker_port,
 -                                     ofdpa_flags_nowait(flags),
 -                                     ofdpa_cmd_flow_tbl_add,
 -                                     found, NULL, NULL);
 +      return rocker_cmd_exec(ofdpa_port->rocker_port,
 +                             ofdpa_flags_nowait(flags),
 +                             ofdpa_cmd_flow_tbl_add,
 +                             found, NULL, NULL);
        return 0;
  }
  
  static int ofdpa_flow_tbl_del(struct ofdpa_port *ofdpa_port,
 -                            struct switchdev_trans *trans, int flags,
 -                            struct ofdpa_flow_tbl_entry *match)
 +                            int flags, struct ofdpa_flow_tbl_entry *match)
  {
        struct ofdpa *ofdpa = ofdpa_port->ofdpa;
        struct ofdpa_flow_tbl_entry *found;
        found = ofdpa_flow_tbl_find(ofdpa, match);
  
        if (found) {
 -              if (!switchdev_trans_ph_prepare(trans))
 -                      hash_del(&found->entry);
 +              hash_del(&found->entry);
                found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL;
        }
  
        spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, lock_flags);
  
 -      ofdpa_kfree(trans, match);
 +      kfree(match);
  
        if (found) {
 -              if (!switchdev_trans_ph_prepare(trans))
 -                      err = rocker_cmd_exec(ofdpa_port->rocker_port,
 -                                            ofdpa_flags_nowait(flags),
 -                                            ofdpa_cmd_flow_tbl_del,
 -                                            found, NULL, NULL);
 -              ofdpa_kfree(trans, found);
 +              err = rocker_cmd_exec(ofdpa_port->rocker_port,
 +                                    ofdpa_flags_nowait(flags),
 +                                    ofdpa_cmd_flow_tbl_del,
 +                                    found, NULL, NULL);
 +              kfree(found);
        }
  
        return err;
  }
  
 -static int ofdpa_flow_tbl_do(struct ofdpa_port *ofdpa_port,
 -                           struct switchdev_trans *trans, int flags,
 +static int ofdpa_flow_tbl_do(struct ofdpa_port *ofdpa_port, int flags,
                             struct ofdpa_flow_tbl_entry *entry)
  {
        if (flags & OFDPA_OP_FLAG_REMOVE)
 -              return ofdpa_flow_tbl_del(ofdpa_port, trans, flags, entry);
 +              return ofdpa_flow_tbl_del(ofdpa_port, flags, entry);
        else
 -              return ofdpa_flow_tbl_add(ofdpa_port, trans, flags, entry);
 +              return ofdpa_flow_tbl_add(ofdpa_port, flags, entry);
  }
  
 -static int ofdpa_flow_tbl_ig_port(struct ofdpa_port *ofdpa_port,
 -                                struct switchdev_trans *trans, int flags,
 +static int ofdpa_flow_tbl_ig_port(struct ofdpa_port *ofdpa_port, int flags,
                                  u32 in_pport, u32 in_pport_mask,
                                  enum rocker_of_dpa_table_id goto_tbl)
  {
        struct ofdpa_flow_tbl_entry *entry;
  
 -      entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
 +      entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
                return -ENOMEM;
  
        entry->key.ig_port.in_pport_mask = in_pport_mask;
        entry->key.ig_port.goto_tbl = goto_tbl;
  
 -      return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry);
 +      return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
  }
  
  static int ofdpa_flow_tbl_vlan(struct ofdpa_port *ofdpa_port,
 -                             struct switchdev_trans *trans, int flags,
 +                             int flags,
                               u32 in_pport, __be16 vlan_id,
                               __be16 vlan_id_mask,
                               enum rocker_of_dpa_table_id goto_tbl,
  {
        struct ofdpa_flow_tbl_entry *entry;
  
 -      entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
 +      entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
                return -ENOMEM;
  
        entry->key.vlan.untagged = untagged;
        entry->key.vlan.new_vlan_id = new_vlan_id;
  
 -      return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry);
 +      return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
  }
  
  static int ofdpa_flow_tbl_term_mac(struct ofdpa_port *ofdpa_port,
 -                                 struct switchdev_trans *trans,
                                   u32 in_pport, u32 in_pport_mask,
                                   __be16 eth_type, const u8 *eth_dst,
                                   const u8 *eth_dst_mask, __be16 vlan_id,
  {
        struct ofdpa_flow_tbl_entry *entry;
  
 -      entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
 +      entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
                return -ENOMEM;
  
        entry->key.term_mac.vlan_id_mask = vlan_id_mask;
        entry->key.term_mac.copy_to_cpu = copy_to_cpu;
  
 -      return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry);
 +      return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
  }
  
  static int ofdpa_flow_tbl_bridge(struct ofdpa_port *ofdpa_port,
 -                               struct switchdev_trans *trans, int flags,
 -                               const u8 *eth_dst, const u8 *eth_dst_mask,
 -                               __be16 vlan_id, u32 tunnel_id,
 +                               int flags, const u8 *eth_dst,
 +                               const u8 *eth_dst_mask,  __be16 vlan_id,
 +                               u32 tunnel_id,
                                 enum rocker_of_dpa_table_id goto_tbl,
                                 u32 group_id, bool copy_to_cpu)
  {
        bool dflt = !eth_dst || (eth_dst && eth_dst_mask);
        bool wild = false;
  
 -      entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
 +      entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (!entry)
                return -ENOMEM;
  
        entry->key.bridge.group_id = group_id;
        entry->key.bridge.copy_to_cpu = copy_to_cpu;
  
 -      return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry);
 +      return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
  }
  
  static int ofdpa_flow_tbl_ucast4_routing(struct ofdpa_port *ofdpa_port,
 -                                       struct switchdev_trans *trans,
                                         __be16 eth_type, __be32 dst,
                                         __be32 dst_mask, u32 priority,
                                         enum rocker_of_dpa_table_id goto_tbl,
  {
        struct ofdpa_flow_tbl_entry *entry;
  
 -      entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
 +      entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
                return -ENOMEM;
  
                                  ucast_routing.group_id);
        entry->fi = fi;
  
 -      return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry);
 +      return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
  }
  
 -static int ofdpa_flow_tbl_acl(struct ofdpa_port *ofdpa_port,
 -                            struct switchdev_trans *trans, int flags,
 +static int ofdpa_flow_tbl_acl(struct ofdpa_port *ofdpa_port, int flags,
                              u32 in_pport, u32 in_pport_mask,
                              const u8 *eth_src, const u8 *eth_src_mask,
                              const u8 *eth_dst, const u8 *eth_dst_mask,
        u32 priority;
        struct ofdpa_flow_tbl_entry *entry;
  
 -      entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
 +      entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
                return -ENOMEM;
  
        entry->key.acl.ip_tos_mask = ip_tos_mask;
        entry->key.acl.group_id = group_id;
  
 -      return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry);
 +      return ofdpa_flow_tbl_do(ofdpa_port, flags, entry);
  }
  
  static struct ofdpa_group_tbl_entry *
@@@ -1063,20 -1134,22 +1063,20 @@@ ofdpa_group_tbl_find(const struct ofdp
        return NULL;
  }
  
 -static void ofdpa_group_tbl_entry_free(struct switchdev_trans *trans,
 -                                     struct ofdpa_group_tbl_entry *entry)
 +static void ofdpa_group_tbl_entry_free(struct ofdpa_group_tbl_entry *entry)
  {
        switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) {
        case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
        case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
 -              ofdpa_kfree(trans, entry->group_ids);
 +              kfree(entry->group_ids);
                break;
        default:
                break;
        }
 -      ofdpa_kfree(trans, entry);
 +      kfree(entry);
  }
  
 -static int ofdpa_group_tbl_add(struct ofdpa_port *ofdpa_port,
 -                             struct switchdev_trans *trans, int flags,
 +static int ofdpa_group_tbl_add(struct ofdpa_port *ofdpa_port, int flags,
                               struct ofdpa_group_tbl_entry *match)
  {
        struct ofdpa *ofdpa = ofdpa_port->ofdpa;
        found = ofdpa_group_tbl_find(ofdpa, match);
  
        if (found) {
 -              if (!switchdev_trans_ph_prepare(trans))
 -                      hash_del(&found->entry);
 -              ofdpa_group_tbl_entry_free(trans, found);
 +              hash_del(&found->entry);
 +              ofdpa_group_tbl_entry_free(found);
                found = match;
                found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD;
        } else {
                found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD;
        }
  
 -      if (!switchdev_trans_ph_prepare(trans))
 -              hash_add(ofdpa->group_tbl, &found->entry, found->group_id);
 +      hash_add(ofdpa->group_tbl, &found->entry, found->group_id);
  
        spin_unlock_irqrestore(&ofdpa->group_tbl_lock, lock_flags);
  
 -      if (!switchdev_trans_ph_prepare(trans))
 -              return rocker_cmd_exec(ofdpa_port->rocker_port,
 -                                     ofdpa_flags_nowait(flags),
 -                                     ofdpa_cmd_group_tbl_add,
 -                                     found, NULL, NULL);
 -      return 0;
 +      return rocker_cmd_exec(ofdpa_port->rocker_port,
 +                             ofdpa_flags_nowait(flags),
 +                             ofdpa_cmd_group_tbl_add,
 +                             found, NULL, NULL);
  }
  
 -static int ofdpa_group_tbl_del(struct ofdpa_port *ofdpa_port,
 -                             struct switchdev_trans *trans, int flags,
 +static int ofdpa_group_tbl_del(struct ofdpa_port *ofdpa_port, int flags,
                               struct ofdpa_group_tbl_entry *match)
  {
        struct ofdpa *ofdpa = ofdpa_port->ofdpa;
        found = ofdpa_group_tbl_find(ofdpa, match);
  
        if (found) {
 -              if (!switchdev_trans_ph_prepare(trans))
 -                      hash_del(&found->entry);
 +              hash_del(&found->entry);
                found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL;
        }
  
        spin_unlock_irqrestore(&ofdpa->group_tbl_lock, lock_flags);
  
 -      ofdpa_group_tbl_entry_free(trans, match);
 +      ofdpa_group_tbl_entry_free(match);
  
        if (found) {
 -              if (!switchdev_trans_ph_prepare(trans))
 -                      err = rocker_cmd_exec(ofdpa_port->rocker_port,
 -                                            ofdpa_flags_nowait(flags),
 -                                            ofdpa_cmd_group_tbl_del,
 -                                            found, NULL, NULL);
 -              ofdpa_group_tbl_entry_free(trans, found);
 +              err = rocker_cmd_exec(ofdpa_port->rocker_port,
 +                                    ofdpa_flags_nowait(flags),
 +                                    ofdpa_cmd_group_tbl_del,
 +                                    found, NULL, NULL);
 +              ofdpa_group_tbl_entry_free(found);
        }
  
        return err;
  }
  
 -static int ofdpa_group_tbl_do(struct ofdpa_port *ofdpa_port,
 -                            struct switchdev_trans *trans, int flags,
 +static int ofdpa_group_tbl_do(struct ofdpa_port *ofdpa_port, int flags,
                              struct ofdpa_group_tbl_entry *entry)
  {
        if (flags & OFDPA_OP_FLAG_REMOVE)
 -              return ofdpa_group_tbl_del(ofdpa_port, trans, flags, entry);
 +              return ofdpa_group_tbl_del(ofdpa_port, flags, entry);
        else
 -              return ofdpa_group_tbl_add(ofdpa_port, trans, flags, entry);
 +              return ofdpa_group_tbl_add(ofdpa_port, flags, entry);
  }
  
  static int ofdpa_group_l2_interface(struct ofdpa_port *ofdpa_port,
 -                                  struct switchdev_trans *trans, int flags,
 -                                  __be16 vlan_id, u32 out_pport,
 -                                  int pop_vlan)
 +                                  int flags, __be16 vlan_id,
 +                                  u32 out_pport, int pop_vlan)
  {
        struct ofdpa_group_tbl_entry *entry;
  
 -      entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
 +      entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
                return -ENOMEM;
  
        entry->group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
        entry->l2_interface.pop_vlan = pop_vlan;
  
 -      return ofdpa_group_tbl_do(ofdpa_port, trans, flags, entry);
 +      return ofdpa_group_tbl_do(ofdpa_port, flags, entry);
  }
  
  static int ofdpa_group_l2_fan_out(struct ofdpa_port *ofdpa_port,
 -                                struct switchdev_trans *trans,
                                  int flags, u8 group_count,
                                  const u32 *group_ids, u32 group_id)
  {
        struct ofdpa_group_tbl_entry *entry;
  
 -      entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
 +      entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
                return -ENOMEM;
  
        entry->group_id = group_id;
        entry->group_count = group_count;
  
 -      entry->group_ids = ofdpa_kcalloc(trans, flags,
 -                                       group_count, sizeof(u32));
 +      entry->group_ids = kcalloc(flags, group_count, sizeof(u32));
        if (!entry->group_ids) {
 -              ofdpa_kfree(trans, entry);
 +              kfree(entry);
                return -ENOMEM;
        }
        memcpy(entry->group_ids, group_ids, group_count * sizeof(u32));
  
 -      return ofdpa_group_tbl_do(ofdpa_port, trans, flags, entry);
 +      return ofdpa_group_tbl_do(ofdpa_port, flags, entry);
  }
  
  static int ofdpa_group_l2_flood(struct ofdpa_port *ofdpa_port,
 -                              struct switchdev_trans *trans, int flags,
 -                              __be16 vlan_id, u8 group_count,
 -                              const u32 *group_ids, u32 group_id)
 +                              int flags, __be16 vlan_id,
 +                              u8 group_count, const u32 *group_ids,
 +                              u32 group_id)
  {
 -      return ofdpa_group_l2_fan_out(ofdpa_port, trans, flags,
 +      return ofdpa_group_l2_fan_out(ofdpa_port, flags,
                                      group_count, group_ids,
                                      group_id);
  }
  
 -static int ofdpa_group_l3_unicast(struct ofdpa_port *ofdpa_port,
 -                                struct switchdev_trans *trans, int flags,
 +static int ofdpa_group_l3_unicast(struct ofdpa_port *ofdpa_port, int flags,
                                  u32 index, const u8 *src_mac, const u8 *dst_mac,
                                  __be16 vlan_id, bool ttl_check, u32 pport)
  {
        struct ofdpa_group_tbl_entry *entry;
  
 -      entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
 +      entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
                return -ENOMEM;
  
        entry->l3_unicast.ttl_check = ttl_check;
        entry->l3_unicast.group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, pport);
  
 -      return ofdpa_group_tbl_do(ofdpa_port, trans, flags, entry);
 +      return ofdpa_group_tbl_do(ofdpa_port, flags, entry);
  }
  
  static struct ofdpa_neigh_tbl_entry *
@@@ -1233,34 -1318,43 +1233,34 @@@ ofdpa_neigh_tbl_find(const struct ofdp
  }
  
  static void ofdpa_neigh_add(struct ofdpa *ofdpa,
 -                          struct switchdev_trans *trans,
                            struct ofdpa_neigh_tbl_entry *entry)
  {
 -      if (!switchdev_trans_ph_commit(trans))
 -              entry->index = ofdpa->neigh_tbl_next_index++;
 -      if (switchdev_trans_ph_prepare(trans))
 -              return;
 +      entry->index = ofdpa->neigh_tbl_next_index++;
        entry->ref_count++;
        hash_add(ofdpa->neigh_tbl, &entry->entry,
                 be32_to_cpu(entry->ip_addr));
  }
  
 -static void ofdpa_neigh_del(struct switchdev_trans *trans,
 -                          struct ofdpa_neigh_tbl_entry *entry)
 +static void ofdpa_neigh_del(struct ofdpa_neigh_tbl_entry *entry)
  {
 -      if (switchdev_trans_ph_prepare(trans))
 -              return;
        if (--entry->ref_count == 0) {
                hash_del(&entry->entry);
 -              ofdpa_kfree(trans, entry);
 +              kfree(entry);
        }
  }
  
  static void ofdpa_neigh_update(struct ofdpa_neigh_tbl_entry *entry,
 -                             struct switchdev_trans *trans,
                               const u8 *eth_dst, bool ttl_check)
  {
        if (eth_dst) {
                ether_addr_copy(entry->eth_dst, eth_dst);
                entry->ttl_check = ttl_check;
 -      } else if (!switchdev_trans_ph_prepare(trans)) {
 +      } else {
                entry->ref_count++;
        }
  }
  
  static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port,
 -                               struct switchdev_trans *trans,
                                 int flags, __be32 ip_addr, const u8 *eth_dst)
  {
        struct ofdpa *ofdpa = ofdpa_port->ofdpa;
        bool removing;
        int err = 0;
  
 -      entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
 +      entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
                return -ENOMEM;
  
                entry->dev = ofdpa_port->dev;
                ether_addr_copy(entry->eth_dst, eth_dst);
                entry->ttl_check = true;
 -              ofdpa_neigh_add(ofdpa, trans, entry);
 +              ofdpa_neigh_add(ofdpa, entry);
        } else if (removing) {
                memcpy(entry, found, sizeof(*entry));
 -              ofdpa_neigh_del(trans, found);
 +              ofdpa_neigh_del(found);
        } else if (updating) {
 -              ofdpa_neigh_update(found, trans, eth_dst, true);
 +              ofdpa_neigh_update(found, eth_dst, true);
                memcpy(entry, found, sizeof(*entry));
        } else {
                err = -ENOENT;
         * other routes' nexthops.
         */
  
 -      err = ofdpa_group_l3_unicast(ofdpa_port, trans, flags,
 +      err = ofdpa_group_l3_unicast(ofdpa_port, flags,
                                     entry->index,
                                     ofdpa_port->dev->dev_addr,
                                     entry->eth_dst,
  
        if (adding || removing) {
                group_id = ROCKER_GROUP_L3_UNICAST(entry->index);
 -              err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, trans,
 +              err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port,
                                                    eth_type, ip_addr,
                                                    inet_make_mask(32),
                                                    priority, goto_tbl,
  
  err_out:
        if (!adding)
 -              ofdpa_kfree(trans, entry);
 +              kfree(entry);
  
        return err;
  }
  
  static int ofdpa_port_ipv4_resolve(struct ofdpa_port *ofdpa_port,
 -                                 struct switchdev_trans *trans,
                                   __be32 ip_addr)
  {
        struct net_device *dev = ofdpa_port->dev;
         */
  
        if (n->nud_state & NUD_VALID)
 -              err = ofdpa_port_ipv4_neigh(ofdpa_port, trans, 0,
 +              err = ofdpa_port_ipv4_neigh(ofdpa_port, 0,
                                            ip_addr, n->ha);
        else
                neigh_event_send(n, NULL);
  }
  
  static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port,
 -                            struct switchdev_trans *trans, int flags,
 -                            __be32 ip_addr, u32 *index)
 +                            int flags, __be32 ip_addr, u32 *index)
  {
        struct ofdpa *ofdpa = ofdpa_port->ofdpa;
        struct ofdpa_neigh_tbl_entry *entry;
        bool resolved = true;
        int err = 0;
  
 -      entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
 +      entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
                return -ENOMEM;
  
        if (adding) {
                entry->ip_addr = ip_addr;
                entry->dev = ofdpa_port->dev;
 -              ofdpa_neigh_add(ofdpa, trans, entry);
 +              ofdpa_neigh_add(ofdpa, entry);
                *index = entry->index;
                resolved = false;
        } else if (removing) {
-               ofdpa_neigh_del(found);
                *index = found->index;
 -              ofdpa_neigh_del(trans, found);
++              ofdpa_neigh_del(found);
        } else if (updating) {
 -              ofdpa_neigh_update(found, trans, NULL, false);
 +              ofdpa_neigh_update(found, NULL, false);
                resolved = !is_zero_ether_addr(found->eth_dst);
                *index = found->index;
        } else {
        spin_unlock_irqrestore(&ofdpa->neigh_tbl_lock, lock_flags);
  
        if (!adding)
 -              ofdpa_kfree(trans, entry);
 +              kfree(entry);
  
        if (err)
                return err;
        /* Resolved means neigh ip_addr is resolved to neigh mac. */
  
        if (!resolved)
 -              err = ofdpa_port_ipv4_resolve(ofdpa_port, trans, ip_addr);
 +              err = ofdpa_port_ipv4_resolve(ofdpa_port, ip_addr);
  
        return err;
  }
@@@ -1445,6 -1541,7 +1445,6 @@@ static struct ofdpa_port *ofdpa_port_ge
  }
  
  static int ofdpa_port_vlan_flood_group(struct ofdpa_port *ofdpa_port,
 -                                     struct switchdev_trans *trans,
                                       int flags, __be16 vlan_id)
  {
        struct ofdpa_port *p;
        int err = 0;
        int i;
  
 -      group_ids = ofdpa_kcalloc(trans, flags, port_count, sizeof(u32));
 +      group_ids = kcalloc(flags, port_count, sizeof(u32));
        if (!group_ids)
                return -ENOMEM;
  
        if (group_count == 0)
                goto no_ports_in_vlan;
  
 -      err = ofdpa_group_l2_flood(ofdpa_port, trans, flags, vlan_id,
 +      err = ofdpa_group_l2_flood(ofdpa_port, flags, vlan_id,
                                   group_count, group_ids, group_id);
        if (err)
                netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 flood group\n", err);
  
  no_ports_in_vlan:
 -      ofdpa_kfree(trans, group_ids);
 +      kfree(group_ids);
        return err;
  }
  
 -static int ofdpa_port_vlan_l2_groups(struct ofdpa_port *ofdpa_port,
 -                                   struct switchdev_trans *trans, int flags,
 +static int ofdpa_port_vlan_l2_groups(struct ofdpa_port *ofdpa_port, int flags,
                                     __be16 vlan_id, bool pop_vlan)
  {
        const struct ofdpa *ofdpa = ofdpa_port->ofdpa;
        if (ofdpa_port->stp_state == BR_STATE_LEARNING ||
            ofdpa_port->stp_state == BR_STATE_FORWARDING) {
                out_pport = ofdpa_port->pport;
 -              err = ofdpa_group_l2_interface(ofdpa_port, trans, flags,
 +              err = ofdpa_group_l2_interface(ofdpa_port, flags,
                                               vlan_id, out_pport, pop_vlan);
                if (err) {
                        netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for pport %d\n",
                return 0;
  
        out_pport = 0;
 -      err = ofdpa_group_l2_interface(ofdpa_port, trans, flags,
 +      err = ofdpa_group_l2_interface(ofdpa_port, flags,
                                       vlan_id, out_pport, pop_vlan);
        if (err) {
                netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for CPU port\n", err);
@@@ -1595,7 -1693,8 +1595,7 @@@ static struct ofdpa_ctrl 
        },
  };
  
 -static int ofdpa_port_ctrl_vlan_acl(struct ofdpa_port *ofdpa_port,
 -                                  struct switchdev_trans *trans, int flags,
 +static int ofdpa_port_ctrl_vlan_acl(struct ofdpa_port *ofdpa_port, int flags,
                                    const struct ofdpa_ctrl *ctrl, __be16 vlan_id)
  {
        u32 in_pport = ofdpa_port->pport;
        u32 group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
        int err;
  
 -      err = ofdpa_flow_tbl_acl(ofdpa_port, trans, flags,
 +      err = ofdpa_flow_tbl_acl(ofdpa_port, flags,
                                 in_pport, in_pport_mask,
                                 eth_src, eth_src_mask,
                                 ctrl->eth_dst, ctrl->eth_dst_mask,
  }
  
  static int ofdpa_port_ctrl_vlan_bridge(struct ofdpa_port *ofdpa_port,
 -                                     struct switchdev_trans *trans,
 -                                     int flags,
 -                                     const struct ofdpa_ctrl *ctrl,
 +                                     int flags, const struct ofdpa_ctrl *ctrl,
                                       __be16 vlan_id)
  {
        enum rocker_of_dpa_table_id goto_tbl =
        if (!ofdpa_port_is_bridged(ofdpa_port))
                return 0;
  
 -      err = ofdpa_flow_tbl_bridge(ofdpa_port, trans, flags,
 +      err = ofdpa_flow_tbl_bridge(ofdpa_port, flags,
                                    ctrl->eth_dst, ctrl->eth_dst_mask,
                                    vlan_id, tunnel_id,
                                    goto_tbl, group_id, ctrl->copy_to_cpu);
        return err;
  }
  
 -static int ofdpa_port_ctrl_vlan_term(struct ofdpa_port *ofdpa_port,
 -                                   struct switchdev_trans *trans, int flags,
 +static int ofdpa_port_ctrl_vlan_term(struct ofdpa_port *ofdpa_port, int flags,
                                     const struct ofdpa_ctrl *ctrl, __be16 vlan_id)
  {
        u32 in_pport_mask = 0xffffffff;
        if (ntohs(vlan_id) == 0)
                vlan_id = ofdpa_port->internal_vlan_id;
  
 -      err = ofdpa_flow_tbl_term_mac(ofdpa_port, trans,
 -                                    ofdpa_port->pport, in_pport_mask,
 +      err = ofdpa_flow_tbl_term_mac(ofdpa_port, ofdpa_port->pport, in_pport_mask,
                                      ctrl->eth_type, ctrl->eth_dst,
                                      ctrl->eth_dst_mask, vlan_id,
                                      vlan_id_mask, ctrl->copy_to_cpu,
        return err;
  }
  
 -static int ofdpa_port_ctrl_vlan(struct ofdpa_port *ofdpa_port,
 -                              struct switchdev_trans *trans, int flags,
 +static int ofdpa_port_ctrl_vlan(struct ofdpa_port *ofdpa_port, int flags,
                                const struct ofdpa_ctrl *ctrl, __be16 vlan_id)
  {
        if (ctrl->acl)
 -              return ofdpa_port_ctrl_vlan_acl(ofdpa_port, trans, flags,
 +              return ofdpa_port_ctrl_vlan_acl(ofdpa_port, flags,
                                                ctrl, vlan_id);
        if (ctrl->bridge)
 -              return ofdpa_port_ctrl_vlan_bridge(ofdpa_port, trans, flags,
 +              return ofdpa_port_ctrl_vlan_bridge(ofdpa_port, flags,
                                                   ctrl, vlan_id);
  
        if (ctrl->term)
 -              return ofdpa_port_ctrl_vlan_term(ofdpa_port, trans, flags,
 +              return ofdpa_port_ctrl_vlan_term(ofdpa_port, flags,
                                                 ctrl, vlan_id);
  
        return -EOPNOTSUPP;
  }
  
 -static int ofdpa_port_ctrl_vlan_add(struct ofdpa_port *ofdpa_port,
 -                                  struct switchdev_trans *trans, int flags,
 +static int ofdpa_port_ctrl_vlan_add(struct ofdpa_port *ofdpa_port, int flags,
                                    __be16 vlan_id)
  {
        int err = 0;
  
        for (i = 0; i < OFDPA_CTRL_MAX; i++) {
                if (ofdpa_port->ctrls[i]) {
 -                      err = ofdpa_port_ctrl_vlan(ofdpa_port, trans, flags,
 +                      err = ofdpa_port_ctrl_vlan(ofdpa_port, flags,
                                                   &ofdpa_ctrls[i], vlan_id);
                        if (err)
                                return err;
        return err;
  }
  
 -static int ofdpa_port_ctrl(struct ofdpa_port *ofdpa_port,
 -                         struct switchdev_trans *trans, int flags,
 +static int ofdpa_port_ctrl(struct ofdpa_port *ofdpa_port, int flags,
                           const struct ofdpa_ctrl *ctrl)
  {
        u16 vid;
        for (vid = 1; vid < VLAN_N_VID; vid++) {
                if (!test_bit(vid, ofdpa_port->vlan_bitmap))
                        continue;
 -              err = ofdpa_port_ctrl_vlan(ofdpa_port, trans, flags,
 +              err = ofdpa_port_ctrl_vlan(ofdpa_port, flags,
                                           ctrl, htons(vid));
                if (err)
                        break;
        return err;
  }
  
 -static int ofdpa_port_vlan(struct ofdpa_port *ofdpa_port,
 -                         struct switchdev_trans *trans, int flags, u16 vid)
 +static int ofdpa_port_vlan(struct ofdpa_port *ofdpa_port, int flags,
 +                         u16 vid)
  {
        enum rocker_of_dpa_table_id goto_tbl =
                        ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
        change_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap);
  
        if (adding) {
 -              err = ofdpa_port_ctrl_vlan_add(ofdpa_port, trans, flags,
 +              err = ofdpa_port_ctrl_vlan_add(ofdpa_port, flags,
                                               internal_vlan_id);
                if (err) {
                        netdev_err(ofdpa_port->dev, "Error (%d) port ctrl vlan add\n", err);
 -                      goto err_out;
 +                      goto err_vlan_add;
                }
        }
  
 -      err = ofdpa_port_vlan_l2_groups(ofdpa_port, trans, flags,
 +      err = ofdpa_port_vlan_l2_groups(ofdpa_port, flags,
                                        internal_vlan_id, untagged);
        if (err) {
                netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 groups\n", err);
 -              goto err_out;
 +              goto err_vlan_l2_groups;
        }
  
 -      err = ofdpa_port_vlan_flood_group(ofdpa_port, trans, flags,
 +      err = ofdpa_port_vlan_flood_group(ofdpa_port, flags,
                                          internal_vlan_id);
        if (err) {
                netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 flood group\n", err);
 -              goto err_out;
 +              goto err_flood_group;
        }
  
 -      err = ofdpa_flow_tbl_vlan(ofdpa_port, trans, flags,
 +      err = ofdpa_flow_tbl_vlan(ofdpa_port, flags,
                                  in_pport, vlan_id, vlan_id_mask,
                                  goto_tbl, untagged, internal_vlan_id);
        if (err)
                netdev_err(ofdpa_port->dev, "Error (%d) port VLAN table\n", err);
  
 -err_out:
 -      if (switchdev_trans_ph_prepare(trans))
 -              change_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap);
 +      return 0;
  
 +err_vlan_add:
 +err_vlan_l2_groups:
 +err_flood_group:
 +      change_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap);
        return err;
  }
  
 -static int ofdpa_port_ig_tbl(struct ofdpa_port *ofdpa_port,
 -                           struct switchdev_trans *trans, int flags)
 +static int ofdpa_port_ig_tbl(struct ofdpa_port *ofdpa_port, int flags)
  {
        enum rocker_of_dpa_table_id goto_tbl;
        u32 in_pport;
        in_pport_mask = 0xffff0000;
        goto_tbl = ROCKER_OF_DPA_TABLE_ID_VLAN;
  
 -      err = ofdpa_flow_tbl_ig_port(ofdpa_port, trans, flags,
 +      err = ofdpa_flow_tbl_ig_port(ofdpa_port, flags,
                                     in_pport, in_pport_mask,
                                     goto_tbl);
        if (err)
  struct ofdpa_fdb_learn_work {
        struct work_struct work;
        struct ofdpa_port *ofdpa_port;
 -      struct switchdev_trans *trans;
        int flags;
        u8 addr[ETH_ALEN];
        u16 vid;
@@@ -1833,18 -1939,19 +1833,18 @@@ static void ofdpa_port_fdb_learn_work(s
  
        rtnl_lock();
        if (learned && removing)
 -              call_switchdev_notifiers(SWITCHDEV_FDB_DEL,
 +              call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE,
                                         lw->ofdpa_port->dev, &info.info);
        else if (learned && !removing)
 -              call_switchdev_notifiers(SWITCHDEV_FDB_ADD,
 +              call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE,
                                         lw->ofdpa_port->dev, &info.info);
        rtnl_unlock();
  
 -      ofdpa_kfree(lw->trans, work);
 +      kfree(work);
  }
  
  static int ofdpa_port_fdb_learn(struct ofdpa_port *ofdpa_port,
 -                              struct switchdev_trans *trans, int flags,
 -                              const u8 *addr, __be16 vlan_id)
 +                              int flags, const u8 *addr, __be16 vlan_id)
  {
        struct ofdpa_fdb_learn_work *lw;
        enum rocker_of_dpa_table_id goto_tbl =
        u32 out_pport = ofdpa_port->pport;
        u32 tunnel_id = 0;
        u32 group_id = ROCKER_GROUP_NONE;
 -      bool syncing = !!(ofdpa_port->brport_flags & BR_LEARNING_SYNC);
        bool copy_to_cpu = false;
        int err;
  
                group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
  
        if (!(flags & OFDPA_OP_FLAG_REFRESH)) {
 -              err = ofdpa_flow_tbl_bridge(ofdpa_port, trans, flags, addr,
 +              err = ofdpa_flow_tbl_bridge(ofdpa_port, flags, addr,
                                            NULL, vlan_id, tunnel_id, goto_tbl,
                                            group_id, copy_to_cpu);
                if (err)
                        return err;
        }
  
 -      if (!syncing)
 -              return 0;
 -
        if (!ofdpa_port_is_bridged(ofdpa_port))
                return 0;
  
 -      lw = ofdpa_kzalloc(trans, flags, sizeof(*lw));
 +      lw = kzalloc(sizeof(*lw), GFP_ATOMIC);
        if (!lw)
                return -ENOMEM;
  
        INIT_WORK(&lw->work, ofdpa_port_fdb_learn_work);
  
        lw->ofdpa_port = ofdpa_port;
 -      lw->trans = trans;
        lw->flags = flags;
        ether_addr_copy(lw->addr, addr);
        lw->vid = ofdpa_port_vlan_to_vid(ofdpa_port, vlan_id);
  
 -      if (switchdev_trans_ph_prepare(trans))
 -              ofdpa_kfree(trans, lw);
 -      else
 -              schedule_work(&lw->work);
 -
 +      schedule_work(&lw->work);
        return 0;
  }
  
@@@ -1898,6 -2014,7 +1898,6 @@@ ofdpa_fdb_tbl_find(const struct ofdpa *
  }
  
  static int ofdpa_port_fdb(struct ofdpa_port *ofdpa_port,
 -                        struct switchdev_trans *trans,
                          const unsigned char *addr,
                          __be16 vlan_id, int flags)
  {
        bool removing = (flags & OFDPA_OP_FLAG_REMOVE);
        unsigned long lock_flags;
  
 -      fdb = ofdpa_kzalloc(trans, flags, sizeof(*fdb));
 +      fdb = kzalloc(sizeof(*fdb), GFP_KERNEL);
        if (!fdb)
                return -ENOMEM;
  
        if (found) {
                found->touched = jiffies;
                if (removing) {
 -                      ofdpa_kfree(trans, fdb);
 -                      if (!switchdev_trans_ph_prepare(trans))
 -                              hash_del(&found->entry);
 +                      kfree(fdb);
 +                      hash_del(&found->entry);
                }
        } else if (!removing) {
 -              if (!switchdev_trans_ph_prepare(trans))
 -                      hash_add(ofdpa->fdb_tbl, &fdb->entry,
 -                               fdb->key_crc32);
 +              hash_add(ofdpa->fdb_tbl, &fdb->entry,
 +                       fdb->key_crc32);
        }
  
        spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags);
  
        /* Check if adding and already exists, or removing and can't find */
        if (!found != !removing) {
 -              ofdpa_kfree(trans, fdb);
 +              kfree(fdb);
                if (!found && removing)
                        return 0;
                /* Refreshing existing to update aging timers */
                flags |= OFDPA_OP_FLAG_REFRESH;
        }
  
 -      return ofdpa_port_fdb_learn(ofdpa_port, trans, flags, addr, vlan_id);
 +      return ofdpa_port_fdb_learn(ofdpa_port, flags, addr, vlan_id);
  }
  
 -static int ofdpa_port_fdb_flush(struct ofdpa_port *ofdpa_port,
 -                              struct switchdev_trans *trans, int flags)
 +static int ofdpa_port_fdb_flush(struct ofdpa_port *ofdpa_port, int flags)
  {
        struct ofdpa *ofdpa = ofdpa_port->ofdpa;
        struct ofdpa_fdb_tbl_entry *found;
                        continue;
                if (!found->learned)
                        continue;
 -              err = ofdpa_port_fdb_learn(ofdpa_port, trans, flags,
 +              err = ofdpa_port_fdb_learn(ofdpa_port, flags,
                                           found->key.addr,
                                           found->key.vlan_id);
                if (err)
                        goto err_out;
 -              if (!switchdev_trans_ph_prepare(trans))
 -                      hash_del(&found->entry);
 +              hash_del(&found->entry);
        }
  
  err_out:
@@@ -2004,8 -2125,8 +2004,8 @@@ static void ofdpa_fdb_cleanup(unsigned 
                ofdpa_port = entry->key.ofdpa_port;
                expires = entry->touched + ofdpa_port->ageing_time;
                if (time_before_eq(expires, jiffies)) {
 -                      ofdpa_port_fdb_learn(ofdpa_port, NULL,
 -                                           flags, entry->key.addr,
 +                      ofdpa_port_fdb_learn(ofdpa_port, flags,
 +                                           entry->key.addr,
                                             entry->key.vlan_id);
                        hash_del(&entry->entry);
                } else if (time_before(expires, next_timer)) {
  }
  
  static int ofdpa_port_router_mac(struct ofdpa_port *ofdpa_port,
 -                               struct switchdev_trans *trans, int flags,
 -                               __be16 vlan_id)
 +                               int flags, __be16 vlan_id)
  {
        u32 in_pport_mask = 0xffffffff;
        __be16 eth_type;
                vlan_id = ofdpa_port->internal_vlan_id;
  
        eth_type = htons(ETH_P_IP);
 -      err = ofdpa_flow_tbl_term_mac(ofdpa_port, trans,
 -                                    ofdpa_port->pport, in_pport_mask,
 -                                    eth_type, ofdpa_port->dev->dev_addr,
 +      err = ofdpa_flow_tbl_term_mac(ofdpa_port, ofdpa_port->pport,
 +                                    in_pport_mask, eth_type,
 +                                    ofdpa_port->dev->dev_addr,
                                      dst_mac_mask, vlan_id, vlan_id_mask,
                                      copy_to_cpu, flags);
        if (err)
                return err;
  
        eth_type = htons(ETH_P_IPV6);
 -      err = ofdpa_flow_tbl_term_mac(ofdpa_port, trans,
 -                                    ofdpa_port->pport, in_pport_mask,
 -                                    eth_type, ofdpa_port->dev->dev_addr,
 +      err = ofdpa_flow_tbl_term_mac(ofdpa_port, ofdpa_port->pport,
 +                                    in_pport_mask, eth_type,
 +                                    ofdpa_port->dev->dev_addr,
                                      dst_mac_mask, vlan_id, vlan_id_mask,
                                      copy_to_cpu, flags);
  
        return err;
  }
  
 -static int ofdpa_port_fwding(struct ofdpa_port *ofdpa_port,
 -                           struct switchdev_trans *trans, int flags)
 +static int ofdpa_port_fwding(struct ofdpa_port *ofdpa_port, int flags)
  {
        bool pop_vlan;
        u32 out_pport;
                        continue;
                vlan_id = htons(vid);
                pop_vlan = ofdpa_vlan_id_is_internal(vlan_id);
 -              err = ofdpa_group_l2_interface(ofdpa_port, trans, flags,
 +              err = ofdpa_group_l2_interface(ofdpa_port, flags,
                                               vlan_id, out_pport, pop_vlan);
                if (err) {
                        netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for pport %d\n",
  }
  
  static int ofdpa_port_stp_update(struct ofdpa_port *ofdpa_port,
 -                               struct switchdev_trans *trans,
                                 int flags, u8 state)
  {
        bool want[OFDPA_CTRL_MAX] = { 0, };
        int err;
        int i;
  
 +      memcpy(prev_ctrls, ofdpa_port->ctrls, sizeof(prev_ctrls));
        prev_state = ofdpa_port->stp_state;
 -      if (prev_state == state)
 +
 +      if (ofdpa_port->stp_state == state)
                return 0;
  
 -      memcpy(prev_ctrls, ofdpa_port->ctrls, sizeof(prev_ctrls));
        ofdpa_port->stp_state = state;
  
        switch (state) {
                if (want[i] != ofdpa_port->ctrls[i]) {
                        int ctrl_flags = flags |
                                         (want[i] ? 0 : OFDPA_OP_FLAG_REMOVE);
 -                      err = ofdpa_port_ctrl(ofdpa_port, trans, ctrl_flags,
 +                      err = ofdpa_port_ctrl(ofdpa_port, ctrl_flags,
                                              &ofdpa_ctrls[i]);
                        if (err)
 -                              goto err_out;
 +                              goto err_port_ctrl;
                        ofdpa_port->ctrls[i] = want[i];
                }
        }
  
 -      err = ofdpa_port_fdb_flush(ofdpa_port, trans, flags);
 +      err = ofdpa_port_fdb_flush(ofdpa_port, flags);
        if (err)
 -              goto err_out;
 +              goto err_fdb_flush;
  
 -      err = ofdpa_port_fwding(ofdpa_port, trans, flags);
 +      err = ofdpa_port_fwding(ofdpa_port, flags);
 +      if (err)
 +              goto err_port_fwding;
  
 -err_out:
 -      if (switchdev_trans_ph_prepare(trans)) {
 -              memcpy(ofdpa_port->ctrls, prev_ctrls, sizeof(prev_ctrls));
 -              ofdpa_port->stp_state = prev_state;
 -      }
 +      return 0;
  
 +err_port_ctrl:
 +err_fdb_flush:
 +err_port_fwding:
 +      memcpy(ofdpa_port->ctrls, prev_ctrls, sizeof(prev_ctrls));
 +      ofdpa_port->stp_state = prev_state;
        return err;
  }
  
@@@ -2164,7 -2284,7 +2164,7 @@@ static int ofdpa_port_fwd_enable(struc
                return 0;
  
        /* port is not bridged, so simulate going to FORWARDING state */
 -      return ofdpa_port_stp_update(ofdpa_port, NULL, flags,
 +      return ofdpa_port_stp_update(ofdpa_port, flags,
                                     BR_STATE_FORWARDING);
  }
  
@@@ -2175,24 -2295,25 +2175,24 @@@ static int ofdpa_port_fwd_disable(struc
                return 0;
  
        /* port is not bridged, so simulate going to DISABLED state */
 -      return ofdpa_port_stp_update(ofdpa_port, NULL, flags,
 +      return ofdpa_port_stp_update(ofdpa_port, flags,
                                     BR_STATE_DISABLED);
  }
  
  static int ofdpa_port_vlan_add(struct ofdpa_port *ofdpa_port,
 -                             struct switchdev_trans *trans,
                               u16 vid, u16 flags)
  {
        int err;
  
        /* XXX deal with flags for PVID and untagged */
  
 -      err = ofdpa_port_vlan(ofdpa_port, trans, 0, vid);
 +      err = ofdpa_port_vlan(ofdpa_port, 0, vid);
        if (err)
                return err;
  
 -      err = ofdpa_port_router_mac(ofdpa_port, trans, 0, htons(vid));
 +      err = ofdpa_port_router_mac(ofdpa_port, 0, htons(vid));
        if (err)
 -              ofdpa_port_vlan(ofdpa_port, trans,
 +              ofdpa_port_vlan(ofdpa_port,
                                OFDPA_OP_FLAG_REMOVE, vid);
  
        return err;
@@@ -2203,13 -2324,13 +2203,13 @@@ static int ofdpa_port_vlan_del(struct o
  {
        int err;
  
 -      err = ofdpa_port_router_mac(ofdpa_port, NULL,
 -                                  OFDPA_OP_FLAG_REMOVE, htons(vid));
 +      err = ofdpa_port_router_mac(ofdpa_port, OFDPA_OP_FLAG_REMOVE,
 +                                  htons(vid));
        if (err)
                return err;
  
 -      return ofdpa_port_vlan(ofdpa_port, NULL,
 -                             OFDPA_OP_FLAG_REMOVE, vid);
 +      return ofdpa_port_vlan(ofdpa_port, OFDPA_OP_FLAG_REMOVE,
 +                             vid);
  }
  
  static struct ofdpa_internal_vlan_tbl_entry *
@@@ -2268,9 -2389,10 +2268,9 @@@ found
        return found->vlan_id;
  }
  
 -static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port,
 -                             struct switchdev_trans *trans, __be32 dst,
 -                             int dst_len, struct fib_info *fi,
 -                             u32 tb_id, int flags)
 +static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port,  __be32 dst,
 +                             int dst_len, struct fib_info *fi, u32 tb_id,
 +                             int flags)
  {
        const struct fib_nh *nh;
        __be16 eth_type = htons(ETH_P_IP);
        has_gw = !!nh->nh_gw;
  
        if (has_gw && nh_on_port) {
 -              err = ofdpa_port_ipv4_nh(ofdpa_port, trans, flags,
 +              err = ofdpa_port_ipv4_nh(ofdpa_port, flags,
                                         nh->nh_gw, &index);
                if (err)
                        return err;
                group_id = ROCKER_GROUP_L2_INTERFACE(internal_vlan_id, 0);
        }
  
 -      err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, trans, eth_type, dst,
 +      err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, eth_type, dst,
                                            dst_mask, priority, goto_tbl,
                                            group_id, fi, flags);
        if (err)
@@@ -2428,7 -2550,7 +2428,7 @@@ static int ofdpa_port_pre_init(struct r
        ofdpa_port->rocker_port = rocker_port;
        ofdpa_port->dev = rocker_port->dev;
        ofdpa_port->pport = rocker_port->pport;
 -      ofdpa_port->brport_flags = BR_LEARNING | BR_LEARNING_SYNC;
 +      ofdpa_port->brport_flags = BR_LEARNING;
        ofdpa_port->ageing_time = BR_DEFAULT_AGEING_TIME;
        return 0;
  }
@@@ -2441,7 -2563,7 +2441,7 @@@ static int ofdpa_port_init(struct rocke
        rocker_port_set_learning(rocker_port,
                                 !!(ofdpa_port->brport_flags & BR_LEARNING));
  
 -      err = ofdpa_port_ig_tbl(ofdpa_port, NULL, 0);
 +      err = ofdpa_port_ig_tbl(ofdpa_port, 0);
        if (err) {
                netdev_err(ofdpa_port->dev, "install ig port table failed\n");
                return err;
                ofdpa_port_internal_vlan_id_get(ofdpa_port,
                                                ofdpa_port->dev->ifindex);
  
 -      err = ofdpa_port_vlan_add(ofdpa_port, NULL, OFDPA_UNTAGGED_VID, 0);
 +      err = ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
        if (err) {
                netdev_err(ofdpa_port->dev, "install untagged VLAN failed\n");
                goto err_untagged_vlan;
        return 0;
  
  err_untagged_vlan:
 -      ofdpa_port_ig_tbl(ofdpa_port, NULL, OFDPA_OP_FLAG_REMOVE);
 +      ofdpa_port_ig_tbl(ofdpa_port, OFDPA_OP_FLAG_REMOVE);
        return err;
  }
  
@@@ -2467,7 -2589,7 +2467,7 @@@ static void ofdpa_port_fini(struct rock
  {
        struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
  
 -      ofdpa_port_ig_tbl(ofdpa_port, NULL, OFDPA_OP_FLAG_REMOVE);
 +      ofdpa_port_ig_tbl(ofdpa_port, OFDPA_OP_FLAG_REMOVE);
  }
  
  static int ofdpa_port_open(struct rocker_port *rocker_port)
@@@ -2485,11 -2607,12 +2485,11 @@@ static void ofdpa_port_stop(struct rock
  }
  
  static int ofdpa_port_attr_stp_state_set(struct rocker_port *rocker_port,
 -                                       u8 state,
 -                                       struct switchdev_trans *trans)
 +                                       u8 state)
  {
        struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
  
 -      return ofdpa_port_stp_update(ofdpa_port, trans, 0, state);
 +      return ofdpa_port_stp_update(ofdpa_port, 0, state);
  }
  
  static int ofdpa_port_attr_bridge_flags_set(struct rocker_port *rocker_port,
@@@ -2523,16 -2646,6 +2523,16 @@@ ofdpa_port_attr_bridge_flags_get(const 
        return 0;
  }
  
 +static int
 +ofdpa_port_attr_bridge_flags_support_get(const struct rocker_port *
 +                                       rocker_port,
 +                                       unsigned long *
 +                                       p_brport_flags_support)
 +{
 +      *p_brport_flags_support = BR_LEARNING;
 +      return 0;
 +}
 +
  static int
  ofdpa_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port,
                                       u32 ageing_time,
  }
  
  static int ofdpa_port_obj_vlan_add(struct rocker_port *rocker_port,
 -                                 const struct switchdev_obj_port_vlan *vlan,
 -                                 struct switchdev_trans *trans)
 +                                 const struct switchdev_obj_port_vlan *vlan)
  {
        struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
        u16 vid;
        int err;
  
        for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
 -              err = ofdpa_port_vlan_add(ofdpa_port, trans, vid, vlan->flags);
 +              err = ofdpa_port_vlan_add(ofdpa_port, vid, vlan->flags);
                if (err)
                        return err;
        }
@@@ -2583,29 -2697,82 +2583,29 @@@ static int ofdpa_port_obj_vlan_del(stru
        return 0;
  }
  
 -static int ofdpa_port_obj_vlan_dump(const struct rocker_port *rocker_port,
 -                                  struct switchdev_obj_port_vlan *vlan,
 -                                  switchdev_obj_dump_cb_t *cb)
 -{
 -      const struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
 -      u16 vid;
 -      int err = 0;
 -
 -      for (vid = 1; vid < VLAN_N_VID; vid++) {
 -              if (!test_bit(vid, ofdpa_port->vlan_bitmap))
 -                      continue;
 -              vlan->flags = 0;
 -              if (ofdpa_vlan_id_is_internal(htons(vid)))
 -                      vlan->flags |= BRIDGE_VLAN_INFO_PVID;
 -              vlan->vid_begin = vlan->vid_end = vid;
 -              err = cb(&vlan->obj);
 -              if (err)
 -                      break;
 -      }
 -
 -      return err;
 -}
 -
  static int ofdpa_port_obj_fdb_add(struct rocker_port *rocker_port,
 -                                const struct switchdev_obj_port_fdb *fdb,
 -                                struct switchdev_trans *trans)
 +                                u16 vid, const unsigned char *addr)
  {
        struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
 -      __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, fdb->vid, NULL);
 +      __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, vid, NULL);
  
        if (!ofdpa_port_is_bridged(ofdpa_port))
                return -EINVAL;
  
 -      return ofdpa_port_fdb(ofdpa_port, trans, fdb->addr, vlan_id, 0);
 +      return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, 0);
  }
  
  static int ofdpa_port_obj_fdb_del(struct rocker_port *rocker_port,
 -                                const struct switchdev_obj_port_fdb *fdb)
 +                                u16 vid, const unsigned char *addr)
  {
        struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
 -      __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, fdb->vid, NULL);
 +      __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, vid, NULL);
        int flags = OFDPA_OP_FLAG_REMOVE;
  
        if (!ofdpa_port_is_bridged(ofdpa_port))
                return -EINVAL;
  
 -      return ofdpa_port_fdb(ofdpa_port, NULL, fdb->addr, vlan_id, flags);
 -}
 -
 -static int ofdpa_port_obj_fdb_dump(const struct rocker_port *rocker_port,
 -                                 struct switchdev_obj_port_fdb *fdb,
 -                                 switchdev_obj_dump_cb_t *cb)
 -{
 -      const struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
 -      struct ofdpa *ofdpa = ofdpa_port->ofdpa;
 -      struct ofdpa_fdb_tbl_entry *found;
 -      struct hlist_node *tmp;
 -      unsigned long lock_flags;
 -      int bkt;
 -      int err = 0;
 -
 -      spin_lock_irqsave(&ofdpa->fdb_tbl_lock, lock_flags);
 -      hash_for_each_safe(ofdpa->fdb_tbl, bkt, tmp, found, entry) {
 -              if (found->key.ofdpa_port != ofdpa_port)
 -                      continue;
 -              ether_addr_copy(fdb->addr, found->key.addr);
 -              fdb->ndm_state = NUD_REACHABLE;
 -              fdb->vid = ofdpa_port_vlan_to_vid(ofdpa_port,
 -                                                found->key.vlan_id);
 -              err = cb(&fdb->obj);
 -              if (err)
 -                      break;
 -      }
 -      spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags);
 -
 -      return err;
 +      return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, flags);
  }
  
  static int ofdpa_port_bridge_join(struct ofdpa_port *ofdpa_port,
  
        ofdpa_port->bridge_dev = bridge;
  
 -      return ofdpa_port_vlan_add(ofdpa_port, NULL, OFDPA_UNTAGGED_VID, 0);
 +      return ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
  }
  
  static int ofdpa_port_bridge_leave(struct ofdpa_port *ofdpa_port)
  
        ofdpa_port->bridge_dev = NULL;
  
 -      err = ofdpa_port_vlan_add(ofdpa_port, NULL, OFDPA_UNTAGGED_VID, 0);
 +      err = ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
        if (err)
                return err;
  
@@@ -2708,7 -2875,7 +2708,7 @@@ static int ofdpa_port_neigh_update(stru
                                                    OFDPA_OP_FLAG_NOWAIT;
        __be32 ip_addr = *(__be32 *) n->primary_key;
  
 -      return ofdpa_port_ipv4_neigh(ofdpa_port, NULL, flags, ip_addr, n->ha);
 +      return ofdpa_port_ipv4_neigh(ofdpa_port, flags, ip_addr, n->ha);
  }
  
  static int ofdpa_port_neigh_destroy(struct rocker_port *rocker_port,
        int flags = OFDPA_OP_FLAG_REMOVE | OFDPA_OP_FLAG_NOWAIT;
        __be32 ip_addr = *(__be32 *) n->primary_key;
  
 -      return ofdpa_port_ipv4_neigh(ofdpa_port, NULL, flags, ip_addr, n->ha);
 +      return ofdpa_port_ipv4_neigh(ofdpa_port, flags, ip_addr, n->ha);
  }
  
  static int ofdpa_port_ev_mac_vlan_seen(struct rocker_port *rocker_port,
            ofdpa_port->stp_state != BR_STATE_FORWARDING)
                return 0;
  
 -      return ofdpa_port_fdb(ofdpa_port, NULL, addr, vlan_id, flags);
 +      return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, flags);
  }
  
  static struct ofdpa_port *ofdpa_port_dev_lower_find(struct net_device *dev,
@@@ -2756,7 -2923,7 +2756,7 @@@ static int ofdpa_fib4_add(struct rocke
        ofdpa_port = ofdpa_port_dev_lower_find(fen_info->fi->fib_dev, rocker);
        if (!ofdpa_port)
                return 0;
 -      err = ofdpa_port_fib_ipv4(ofdpa_port, NULL, htonl(fen_info->dst),
 +      err = ofdpa_port_fib_ipv4(ofdpa_port, htonl(fen_info->dst),
                                  fen_info->dst_len, fen_info->fi,
                                  fen_info->tb_id, 0);
        if (err)
@@@ -2777,7 -2944,7 +2777,7 @@@ static int ofdpa_fib4_del(struct rocke
        if (!ofdpa_port)
                return 0;
        fib_info_offload_dec(fen_info->fi);
 -      return ofdpa_port_fib_ipv4(ofdpa_port, NULL, htonl(fen_info->dst),
 +      return ofdpa_port_fib_ipv4(ofdpa_port, htonl(fen_info->dst),
                                   fen_info->dst_len, fen_info->fi,
                                   fen_info->tb_id, OFDPA_OP_FLAG_REMOVE);
  }
@@@ -2804,7 -2971,7 +2804,7 @@@ static void ofdpa_fib4_abort(struct roc
                if (!ofdpa_port)
                        continue;
                fib_info_offload_dec(flow_entry->fi);
 -              ofdpa_flow_tbl_del(ofdpa_port, NULL, OFDPA_OP_FLAG_REMOVE,
 +              ofdpa_flow_tbl_del(ofdpa_port, OFDPA_OP_FLAG_REMOVE,
                                   flow_entry);
        }
        spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, flags);
@@@ -2826,12 -2993,13 +2826,12 @@@ struct rocker_world_ops rocker_ofdpa_op
        .port_attr_stp_state_set = ofdpa_port_attr_stp_state_set,
        .port_attr_bridge_flags_set = ofdpa_port_attr_bridge_flags_set,
        .port_attr_bridge_flags_get = ofdpa_port_attr_bridge_flags_get,
 +      .port_attr_bridge_flags_support_get = ofdpa_port_attr_bridge_flags_support_get,
        .port_attr_bridge_ageing_time_set = ofdpa_port_attr_bridge_ageing_time_set,
        .port_obj_vlan_add = ofdpa_port_obj_vlan_add,
        .port_obj_vlan_del = ofdpa_port_obj_vlan_del,
 -      .port_obj_vlan_dump = ofdpa_port_obj_vlan_dump,
        .port_obj_fdb_add = ofdpa_port_obj_fdb_add,
        .port_obj_fdb_del = ofdpa_port_obj_fdb_del,
 -      .port_obj_fdb_dump = ofdpa_port_obj_fdb_dump,
        .port_master_linked = ofdpa_port_master_linked,
        .port_master_unlinked = ofdpa_port_master_unlinked,
        .port_neigh_update = ofdpa_port_neigh_update,
index ad9c4ded2b901f2f339dafab57ec7eed0b5f8059,78f9e43420e0df217d8f118876831e54c204f191..761c518b2f92e0f91ee4671ede1185a41f5a5528
@@@ -4172,7 -4172,7 +4172,7 @@@ found
         * recipients
         */
        if (is_mc_recip) {
-               MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_IN_LEN);
+               MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_EXT_IN_LEN);
                unsigned int depth, i;
  
                memset(inbuf, 0, sizeof(inbuf));
@@@ -4320,7 -4320,7 +4320,7 @@@ static int efx_ef10_filter_remove_inter
                        efx_ef10_filter_set_entry(table, filter_idx, NULL, 0);
                } else {
                        efx_mcdi_display_error(efx, MC_CMD_FILTER_OP,
-                                              MC_CMD_FILTER_OP_IN_LEN,
+                                              MC_CMD_FILTER_OP_EXT_IN_LEN,
                                               NULL, 0, rc);
                }
        }
@@@ -4453,7 -4453,7 +4453,7 @@@ static s32 efx_ef10_filter_rfs_insert(s
                                      struct efx_filter_spec *spec)
  {
        struct efx_ef10_filter_table *table = efx->filter_state;
-       MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_IN_LEN);
+       MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_EXT_IN_LEN);
        struct efx_filter_spec *saved_spec;
        unsigned int hash, i, depth = 1;
        bool replacing = false;
@@@ -4940,7 -4940,7 +4940,7 @@@ not_restored
  static void efx_ef10_filter_table_remove(struct efx_nic *efx)
  {
        struct efx_ef10_filter_table *table = efx->filter_state;
-       MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_IN_LEN);
+       MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_EXT_IN_LEN);
        struct efx_filter_spec *spec;
        unsigned int filter_idx;
        int rc;
@@@ -5105,6 -5105,7 +5105,7 @@@ static int efx_ef10_filter_insert_addr_
  
        /* Insert/renew filters */
        for (i = 0; i < addr_count; i++) {
+               EFX_WARN_ON_PARANOID(ids[i] != EFX_EF10_FILTER_ID_INVALID);
                efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0);
                efx_filter_set_eth_local(&spec, vlan->vid, addr_list[i].addr);
                rc = efx_ef10_filter_insert(efx, &spec, true);
                                }
                                return rc;
                        } else {
-                               /* mark as not inserted, and carry on */
-                               rc = EFX_EF10_FILTER_ID_INVALID;
+                               /* keep invalid ID, and carry on */
                        }
+               } else {
+                       ids[i] = efx_ef10_filter_get_unsafe_id(rc);
                }
-               ids[i] = efx_ef10_filter_get_unsafe_id(rc);
        }
  
        if (multicast && rollback) {
@@@ -6068,7 -6069,6 +6069,7 @@@ static int efx_ef10_ptp_set_ts_config(s
        case HWTSTAMP_FILTER_PTP_V2_EVENT:
        case HWTSTAMP_FILTER_PTP_V2_SYNC:
        case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
 +      case HWTSTAMP_FILTER_NTP_ALL:
                init->rx_filter = HWTSTAMP_FILTER_ALL;
                rc = efx_ptp_change_mode(efx, true, 0);
                if (!rc)
index 9913721504630f5dcee29536407bf7ecc7f16017,643c539a08badf1c723ca3460003293395945db5..63c98bbbc596dbe11cc74ba71c384da02c5d763b
@@@ -37,8 -37,6 +37,8 @@@
  #include <net/route.h>
  #include <net/sock.h>
  #include <net/pkt_sched.h>
 +#include <net/checksum.h>
 +#include <net/ip6_checksum.h>
  
  #include "hyperv_net.h"
  
@@@ -68,8 -66,7 +68,8 @@@ static void netvsc_set_multicast_list(s
  
  static int netvsc_open(struct net_device *net)
  {
 -      struct netvsc_device *nvdev = net_device_to_netvsc_device(net);
 +      struct net_device_context *ndev_ctx = netdev_priv(net);
 +      struct netvsc_device *nvdev = ndev_ctx->nvdev;
        struct rndis_device *rdev;
        int ret = 0;
  
@@@ -85,7 -82,7 +85,7 @@@
        netif_tx_wake_all_queues(net);
  
        rdev = nvdev->extension;
 -      if (!rdev->link_state)
 +      if (!rdev->link_state && !ndev_ctx->datapath)
                netif_carrier_on(net);
  
        return ret;
@@@ -96,7 -93,7 +96,7 @@@ static int netvsc_close(struct net_devi
        struct net_device_context *net_device_ctx = netdev_priv(net);
        struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev);
        int ret;
 -      u32 aread, awrite, i, msec = 10, retry = 0, retry_max = 20;
 +      u32 aread, i, msec = 10, retry = 0, retry_max = 20;
        struct vmbus_channel *chn;
  
        netif_tx_disable(net);
                        if (!chn)
                                continue;
  
 -                      hv_get_ringbuffer_availbytes(&chn->inbound, &aread,
 -                                                   &awrite);
 -
 +                      aread = hv_get_bytes_to_read(&chn->inbound);
                        if (aread)
                                break;
  
 -                      hv_get_ringbuffer_availbytes(&chn->outbound, &aread,
 -                                                   &awrite);
 -
 +                      aread = hv_get_bytes_to_read(&chn->outbound);
                        if (aread)
                                break;
                }
@@@ -315,14 -316,34 +315,14 @@@ static u32 init_page_array(void *hdr, u
        return slots_used;
  }
  
 -static int count_skb_frag_slots(struct sk_buff *skb)
 -{
 -      int i, frags = skb_shinfo(skb)->nr_frags;
 -      int pages = 0;
 -
 -      for (i = 0; i < frags; i++) {
 -              skb_frag_t *frag = skb_shinfo(skb)->frags + i;
 -              unsigned long size = skb_frag_size(frag);
 -              unsigned long offset = frag->page_offset;
 -
 -              /* Skip unused frames from start of page */
 -              offset &= ~PAGE_MASK;
 -              pages += PFN_UP(offset + size);
 -      }
 -      return pages;
 -}
 -
 -static int netvsc_get_slots(struct sk_buff *skb)
 +/* Estimate number of page buffers neede to transmit
 + * Need at most 2 for RNDIS header plus skb body and fragments.
 + */
 +static unsigned int netvsc_get_slots(const struct sk_buff *skb)
  {
 -      char *data = skb->data;
 -      unsigned int offset = offset_in_page(data);
 -      unsigned int len = skb_headlen(skb);
 -      int slots;
 -      int frag_slots;
 -
 -      slots = DIV_ROUND_UP(offset + len, PAGE_SIZE);
 -      frag_slots = count_skb_frag_slots(skb);
 -      return slots + frag_slots;
 +      return PFN_UP(offset_in_page(skb->data) + skb_headlen(skb))
 +              + skb_shinfo(skb)->nr_frags
 +              + 2;
  }
  
  static u32 net_checksum_info(struct sk_buff *skb)
@@@ -360,18 -381,21 +360,18 @@@ static int netvsc_start_xmit(struct sk_
        struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT];
        struct hv_page_buffer *pb = page_buf;
  
 -      /* We will atmost need two pages to describe the rndis
 -       * header. We can only transmit MAX_PAGE_BUFFER_COUNT number
 +      /* We can only transmit MAX_PAGE_BUFFER_COUNT number
         * of pages in a single packet. If skb is scattered around
         * more pages we try linearizing it.
         */
 -
 -      num_data_pgs = netvsc_get_slots(skb) + 2;
 -
 +      num_data_pgs = netvsc_get_slots(skb);
        if (unlikely(num_data_pgs > MAX_PAGE_BUFFER_COUNT)) {
                ++net_device_ctx->eth_stats.tx_scattered;
  
                if (skb_linearize(skb))
                        goto no_memory;
  
 -              num_data_pgs = netvsc_get_slots(skb) + 2;
 +              num_data_pgs = netvsc_get_slots(skb);
                if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
                        ++net_device_ctx->eth_stats.tx_too_big;
                        goto drop;
@@@ -594,7 -618,7 +594,7 @@@ static struct sk_buff *netvsc_alloc_rec
         * Copy to skb. This copy is needed here since the memory pointed by
         * hv_netvsc_packet cannot be deallocated
         */
 -      memcpy(skb_put(skb, buflen), data, buflen);
 +      skb_put_data(skb, data, buflen);
  
        skb->protocol = eth_type_trans(skb, net);
  
@@@ -752,7 -776,7 +752,7 @@@ static int netvsc_set_channels(struct n
            channels->rx_count || channels->tx_count || channels->other_count)
                return -EINVAL;
  
-       if (count > net->num_tx_queues || count > net->num_rx_queues)
+       if (count > net->num_tx_queues || count > VRSS_CHANNEL_MAX)
                return -EINVAL;
  
        if (!nvdev || nvdev->destroy)
@@@ -1179,7 -1203,7 +1179,7 @@@ static int netvsc_set_rxfh(struct net_d
        rndis_dev = ndev->extension;
        if (indir) {
                for (i = 0; i < ITAB_NUM; i++)
-                       if (indir[i] >= dev->num_rx_queues)
+                       if (indir[i] >= VRSS_CHANNEL_MAX)
                                return -EINVAL;
  
                for (i = 0; i < ITAB_NUM; i++)
@@@ -1285,8 -1309,7 +1285,8 @@@ static void netvsc_link_change(struct w
        case RNDIS_STATUS_MEDIA_CONNECT:
                if (rdev->link_state) {
                        rdev->link_state = false;
 -                      netif_carrier_on(net);
 +                      if (!ndev_ctx->datapath)
 +                              netif_carrier_on(net);
                        netif_tx_wake_all_queues(net);
                } else {
                        notify = true;
diff --combined drivers/net/macvlan.c
index 9ffff0362a11ceff45ad040c95c0b6a931ef44c1,72b801803aa4d450328a5df8c4c782fbb1d5e4cc..0f581ee74fe43b5127e338ecdc1da2139b986692
  #define MACVLAN_HASH_SIZE     (1<<MACVLAN_HASH_BITS)
  #define MACVLAN_BC_QUEUE_LEN  1000
  
+ #define MACVLAN_F_PASSTHRU    1
+ #define MACVLAN_F_ADDRCHANGE  2
  struct macvlan_port {
        struct net_device       *dev;
        struct hlist_head       vlan_hash[MACVLAN_HASH_SIZE];
        struct list_head        vlans;
        struct sk_buff_head     bc_queue;
        struct work_struct      bc_work;
-       bool                    passthru;
+       u32                     flags;
        int                     count;
        struct hlist_head       vlan_source_hash[MACVLAN_HASH_SIZE];
        DECLARE_BITMAP(mc_filter, MACVLAN_MC_FILTER_SZ);
+       unsigned char           perm_addr[ETH_ALEN];
  };
  
  struct macvlan_source_entry {
@@@ -66,6 -70,31 +70,31 @@@ struct macvlan_skb_cb 
  
  static void macvlan_port_destroy(struct net_device *dev);
  
+ static inline bool macvlan_passthru(const struct macvlan_port *port)
+ {
+       return port->flags & MACVLAN_F_PASSTHRU;
+ }
+ static inline void macvlan_set_passthru(struct macvlan_port *port)
+ {
+       port->flags |= MACVLAN_F_PASSTHRU;
+ }
+ static inline bool macvlan_addr_change(const struct macvlan_port *port)
+ {
+       return port->flags & MACVLAN_F_ADDRCHANGE;
+ }
+ static inline void macvlan_set_addr_change(struct macvlan_port *port)
+ {
+       port->flags |= MACVLAN_F_ADDRCHANGE;
+ }
+ static inline void macvlan_clear_addr_change(struct macvlan_port *port)
+ {
+       port->flags &= ~MACVLAN_F_ADDRCHANGE;
+ }
  /* Hash Ethernet address */
  static u32 macvlan_eth_hash(const unsigned char *addr)
  {
@@@ -181,11 -210,12 +210,12 @@@ static void macvlan_hash_change_addr(st
  static bool macvlan_addr_busy(const struct macvlan_port *port,
                              const unsigned char *addr)
  {
-       /* Test to see if the specified multicast address is
+       /* Test to see if the specified address is
         * currently in use by the underlying device or
         * another macvlan.
         */
-       if (ether_addr_equal_64bits(port->dev->dev_addr, addr))
+       if (!macvlan_passthru(port) && !macvlan_addr_change(port) &&
+           ether_addr_equal_64bits(port->dev->dev_addr, addr))
                return true;
  
        if (macvlan_hash_lookup(port, addr))
@@@ -445,7 -475,7 +475,7 @@@ static rx_handler_result_t macvlan_hand
        }
  
        macvlan_forward_source(skb, port, eth->h_source);
-       if (port->passthru)
+       if (macvlan_passthru(port))
                vlan = list_first_or_null_rcu(&port->vlans,
                                              struct macvlan_dev, list);
        else
@@@ -574,7 -604,7 +604,7 @@@ static int macvlan_open(struct net_devi
        struct net_device *lowerdev = vlan->lowerdev;
        int err;
  
-       if (vlan->port->passthru) {
+       if (macvlan_passthru(vlan->port)) {
                if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) {
                        err = dev_set_promiscuity(lowerdev, 1);
                        if (err < 0)
@@@ -649,7 -679,7 +679,7 @@@ static int macvlan_stop(struct net_devi
        dev_uc_unsync(lowerdev, dev);
        dev_mc_unsync(lowerdev, dev);
  
-       if (vlan->port->passthru) {
+       if (macvlan_passthru(vlan->port)) {
                if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC))
                        dev_set_promiscuity(lowerdev, -1);
                goto hash_del;
@@@ -672,6 -702,7 +702,7 @@@ static int macvlan_sync_address(struct 
  {
        struct macvlan_dev *vlan = netdev_priv(dev);
        struct net_device *lowerdev = vlan->lowerdev;
+       struct macvlan_port *port = vlan->port;
        int err;
  
        if (!(dev->flags & IFF_UP)) {
                if (macvlan_addr_busy(vlan->port, addr))
                        return -EBUSY;
  
-               if (!vlan->port->passthru) {
+               if (!macvlan_passthru(port)) {
                        err = dev_uc_add(lowerdev, addr);
                        if (err)
                                return err;
  
                macvlan_hash_change_addr(vlan, addr);
        }
+       if (macvlan_passthru(port) && !macvlan_addr_change(port)) {
+               /* Since addr_change isn't set, we are here due to lower
+                * device change.  Save the lower-dev address so we can
+                * restore it later.
+                */
+               ether_addr_copy(vlan->port->perm_addr,
+                               lowerdev->dev_addr);
+       }
+       macvlan_clear_addr_change(port);
        return 0;
  }
  
@@@ -703,8 -743,15 +743,14 @@@ static int macvlan_set_mac_address(stru
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
  
-       if (vlan->mode == MACVLAN_MODE_PASSTHRU)
+       /* If the addresses are the same, this is a no-op */
+       if (ether_addr_equal(dev->dev_addr, addr->sa_data))
+               return 0;
+       if (vlan->mode == MACVLAN_MODE_PASSTHRU) {
+               macvlan_set_addr_change(vlan->port);
 -              dev_set_mac_address(vlan->lowerdev, addr);
 -              return 0;
 +              return dev_set_mac_address(vlan->lowerdev, addr);
+       }
  
        return macvlan_sync_address(dev, addr->sa_data);
  }
@@@ -926,7 -973,7 +972,7 @@@ static int macvlan_fdb_add(struct ndms
        /* Support unicast filter only on passthru devices.
         * Multicast filter should be allowed on all devices.
         */
-       if (!vlan->port->passthru && is_unicast_ether_addr(addr))
+       if (!macvlan_passthru(vlan->port) && is_unicast_ether_addr(addr))
                return -EOPNOTSUPP;
  
        if (flags & NLM_F_REPLACE)
@@@ -950,7 -997,7 +996,7 @@@ static int macvlan_fdb_del(struct ndms
        /* Support unicast filter only on passthru devices.
         * Multicast filter should be allowed on all devices.
         */
-       if (!vlan->port->passthru && is_unicast_ether_addr(addr))
+       if (!macvlan_passthru(vlan->port) && is_unicast_ether_addr(addr))
                return -EOPNOTSUPP;
  
        if (is_unicast_ether_addr(addr))
@@@ -1118,8 -1165,8 +1164,8 @@@ static int macvlan_port_create(struct n
        if (port == NULL)
                return -ENOMEM;
  
-       port->passthru = false;
        port->dev = dev;
+       ether_addr_copy(port->perm_addr, dev->dev_addr);
        INIT_LIST_HEAD(&port->vlans);
        for (i = 0; i < MACVLAN_HASH_SIZE; i++)
                INIT_HLIST_HEAD(&port->vlan_hash[i]);
@@@ -1159,11 -1206,22 +1205,23 @@@ static void macvlan_port_destroy(struc
                kfree_skb(skb);
        }
  
+       /* If the lower device address has been changed by passthru
+        * macvlan, put it back.
+        */
+       if (macvlan_passthru(port) &&
+           !ether_addr_equal(port->dev->dev_addr, port->perm_addr)) {
+               struct sockaddr sa;
+               sa.sa_family = port->dev->type;
+               memcpy(&sa.sa_data, port->perm_addr, port->dev->addr_len);
+               dev_set_mac_address(port->dev, &sa);
+       }
        kfree(port);
  }
  
 -static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
 +static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[],
 +                          struct netlink_ext_ack *extack)
  {
        if (tb[IFLA_ADDRESS]) {
                if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
@@@ -1325,7 -1383,7 +1383,7 @@@ int macvlan_common_newlink(struct net *
        port = macvlan_port_get_rtnl(lowerdev);
  
        /* Only 1 macvlan device can be created in passthru mode */
-       if (port->passthru) {
+       if (macvlan_passthru(port)) {
                /* The macvlan port must be not created this time,
                 * still goto destroy_macvlan_port for readability.
                 */
                        err = -EINVAL;
                        goto destroy_macvlan_port;
                }
-               port->passthru = true;
+               macvlan_set_passthru(port);
                eth_hw_addr_inherit(dev, lowerdev);
        }
  
@@@ -1391,8 -1449,7 +1449,8 @@@ destroy_macvlan_port
  EXPORT_SYMBOL_GPL(macvlan_common_newlink);
  
  static int macvlan_newlink(struct net *src_net, struct net_device *dev,
 -                         struct nlattr *tb[], struct nlattr *data[])
 +                         struct nlattr *tb[], struct nlattr *data[],
 +                         struct netlink_ext_ack *extack)
  {
        return macvlan_common_newlink(src_net, dev, tb, data);
  }
@@@ -1410,8 -1467,7 +1468,8 @@@ void macvlan_dellink(struct net_device 
  EXPORT_SYMBOL_GPL(macvlan_dellink);
  
  static int macvlan_changelink(struct net_device *dev,
 -              struct nlattr *tb[], struct nlattr *data[])
 +                            struct nlattr *tb[], struct nlattr *data[],
 +                            struct netlink_ext_ack *extack)
  {
        struct macvlan_dev *vlan = netdev_priv(dev);
        enum macvlan_mode mode;
        if (data && data[IFLA_MACVLAN_FLAGS]) {
                __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
                bool promisc = (flags ^ vlan->flags) & MACVLAN_FLAG_NOPROMISC;
-               if (vlan->port->passthru && promisc) {
+               if (macvlan_passthru(vlan->port) && promisc) {
                        int err;
  
                        if (flags & MACVLAN_FLAG_NOPROMISC)
@@@ -1598,7 -1654,7 +1656,7 @@@ static int macvlan_device_event(struct 
                }
                break;
        case NETDEV_CHANGEADDR:
-               if (!port->passthru)
+               if (!macvlan_passthru(port))
                        return NOTIFY_DONE;
  
                vlan = list_first_entry_or_null(&port->vlans,
diff --combined drivers/net/phy/micrel.c
index 9365b07923098c37d187ebe4c316f1d12c7ab003,8b2038844ba96a4a86c5b42aca4fa59fe96ecca2..fdb43dd9b5cd424f4dde02f1257070ffe4b50fb1
@@@ -20,7 -20,6 +20,7 @@@
   *                       ksz8081, ksz8091,
   *                       ksz8061,
   *            Switch : ksz8873, ksz886x
 + *                     ksz9477
   */
  
  #include <linux/kernel.h>
@@@ -620,6 -619,8 +620,8 @@@ static int ksz9031_read_status(struct p
        if ((regval & 0xFF) == 0xFF) {
                phy_init_hw(phydev);
                phydev->link = 0;
+               if (phydev->drv->config_intr && phy_interrupt_is_valid(phydev))
+                       phydev->drv->config_intr(phydev);
        }
  
        return 0;
@@@ -794,7 -795,7 +796,7 @@@ static struct phy_driver ksphy_driver[
        .phy_id_mask    = MICREL_PHY_ID_MASK,
        .name           = "Micrel KS8737",
        .features       = PHY_BASIC_FEATURES,
 -      .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 +      .flags          = PHY_HAS_INTERRUPT,
        .driver_data    = &ks8737_type,
        .config_init    = kszphy_config_init,
        .config_aneg    = genphy_config_aneg,
        .phy_id_mask    = 0x00ffffff,
        .name           = "Micrel KSZ8021 or KSZ8031",
        .features       = PHY_BASIC_FEATURES,
 -      .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 +      .flags          = PHY_HAS_INTERRUPT,
        .driver_data    = &ksz8021_type,
        .probe          = kszphy_probe,
        .config_init    = kszphy_config_init,
        .phy_id_mask    = 0x00ffffff,
        .name           = "Micrel KSZ8031",
        .features       = PHY_BASIC_FEATURES,
 -      .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 +      .flags          = PHY_HAS_INTERRUPT,
        .driver_data    = &ksz8021_type,
        .probe          = kszphy_probe,
        .config_init    = kszphy_config_init,
        .phy_id_mask    = MICREL_PHY_ID_MASK,
        .name           = "Micrel KSZ8041",
        .features       = PHY_BASIC_FEATURES,
 -      .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 +      .flags          = PHY_HAS_INTERRUPT,
        .driver_data    = &ksz8041_type,
        .probe          = kszphy_probe,
        .config_init    = ksz8041_config_init,
        .phy_id_mask    = MICREL_PHY_ID_MASK,
        .name           = "Micrel KSZ8041RNLI",
        .features       = PHY_BASIC_FEATURES,
 -      .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 +      .flags          = PHY_HAS_INTERRUPT,
        .driver_data    = &ksz8041_type,
        .probe          = kszphy_probe,
        .config_init    = kszphy_config_init,
        .phy_id_mask    = MICREL_PHY_ID_MASK,
        .name           = "Micrel KSZ8051",
        .features       = PHY_BASIC_FEATURES,
 -      .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 +      .flags          = PHY_HAS_INTERRUPT,
        .driver_data    = &ksz8051_type,
        .probe          = kszphy_probe,
        .config_init    = kszphy_config_init,
        .name           = "Micrel KSZ8001 or KS8721",
        .phy_id_mask    = 0x00fffffc,
        .features       = PHY_BASIC_FEATURES,
 -      .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 +      .flags          = PHY_HAS_INTERRUPT,
        .driver_data    = &ksz8041_type,
        .probe          = kszphy_probe,
        .config_init    = kszphy_config_init,
        .name           = "Micrel KSZ8081 or KSZ8091",
        .phy_id_mask    = MICREL_PHY_ID_MASK,
        .features       = PHY_BASIC_FEATURES,
 -      .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 +      .flags          = PHY_HAS_INTERRUPT,
        .driver_data    = &ksz8081_type,
        .probe          = kszphy_probe,
        .config_init    = kszphy_config_init,
        .name           = "Micrel KSZ8061",
        .phy_id_mask    = MICREL_PHY_ID_MASK,
        .features       = PHY_BASIC_FEATURES,
 -      .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 +      .flags          = PHY_HAS_INTERRUPT,
        .config_init    = kszphy_config_init,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
        .phy_id_mask    = 0x000ffffe,
        .name           = "Micrel KSZ9021 Gigabit PHY",
        .features       = PHY_GBIT_FEATURES,
 -      .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 +      .flags          = PHY_HAS_INTERRUPT,
        .driver_data    = &ksz9021_type,
        .probe          = kszphy_probe,
        .config_init    = ksz9021_config_init,
        .phy_id_mask    = MICREL_PHY_ID_MASK,
        .name           = "Micrel KSZ9031 Gigabit PHY",
        .features       = PHY_GBIT_FEATURES,
 -      .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 +      .flags          = PHY_HAS_INTERRUPT,
        .driver_data    = &ksz9021_type,
        .probe          = kszphy_probe,
        .config_init    = ksz9031_config_init,
        .phy_id         = PHY_ID_KSZ8873MLL,
        .phy_id_mask    = MICREL_PHY_ID_MASK,
        .name           = "Micrel KSZ8873MLL Switch",
 -      .flags          = PHY_HAS_MAGICANEG,
        .config_init    = kszphy_config_init,
        .config_aneg    = ksz8873mll_config_aneg,
        .read_status    = ksz8873mll_read_status,
        .phy_id_mask    = MICREL_PHY_ID_MASK,
        .name           = "Micrel KSZ886X Switch",
        .features       = PHY_BASIC_FEATURES,
 -      .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 +      .flags          = PHY_HAS_INTERRUPT,
        .config_init    = kszphy_config_init,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
        .phy_id_mask    = MICREL_PHY_ID_MASK,
        .name           = "Micrel KSZ8795",
        .features       = PHY_BASIC_FEATURES,
 -      .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 +      .flags          = PHY_HAS_INTERRUPT,
        .config_init    = kszphy_config_init,
        .config_aneg    = ksz8873mll_config_aneg,
        .read_status    = ksz8873mll_read_status,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
 +}, {
 +      .phy_id         = PHY_ID_KSZ9477,
 +      .phy_id_mask    = MICREL_PHY_ID_MASK,
 +      .name           = "Microchip KSZ9477",
 +      .features       = PHY_GBIT_FEATURES,
 +      .config_init    = kszphy_config_init,
 +      .config_aneg    = genphy_config_aneg,
 +      .read_status    = genphy_read_status,
 +      .suspend        = genphy_suspend,
 +      .resume         = genphy_resume,
  } };
  
  module_phy_driver(ksphy_driver);
index 793ce900dffa09fd5c13410d56a99382d63ca2d0,4037ab27734ae76fcfedafc8ce40f74f1549fcfb..f32261ecd2150036d3575986ab2e1971def5086f
@@@ -624,10 -624,7 +624,10 @@@ static int ax88179_get_link_ksettings(s
                                      struct ethtool_link_ksettings *cmd)
  {
        struct usbnet *dev = netdev_priv(net);
 -      return mii_ethtool_get_link_ksettings(&dev->mii, cmd);
 +
 +      mii_ethtool_get_link_ksettings(&dev->mii, cmd);
 +
 +      return 0;
  }
  
  static int ax88179_set_link_ksettings(struct net_device *net,
@@@ -1725,6 -1722,18 +1725,18 @@@ static const struct driver_info lenovo_
        .tx_fixup = ax88179_tx_fixup,
  };
  
+ static const struct driver_info belkin_info = {
+       .description = "Belkin USB Ethernet Adapter",
+       .bind   = ax88179_bind,
+       .unbind = ax88179_unbind,
+       .status = ax88179_status,
+       .link_reset = ax88179_link_reset,
+       .reset  = ax88179_reset,
+       .flags  = FLAG_ETHER | FLAG_FRAMING_AX,
+       .rx_fixup = ax88179_rx_fixup,
+       .tx_fixup = ax88179_tx_fixup,
+ };
  static const struct usb_device_id products[] = {
  {
        /* ASIX AX88179 10/100/1000 */
        /* Lenovo OneLinkDock Gigabit LAN */
        USB_DEVICE(0x17ef, 0x304b),
        .driver_info = (unsigned long)&lenovo_info,
+ }, {
+       /* Belkin B2B128 USB 3.0 Hub + Gigabit Ethernet Adapter */
+       USB_DEVICE(0x050d, 0x0128),
+       .driver_info = (unsigned long)&belkin_info,
  },
        { },
  };
diff --combined drivers/net/veth.c
index b33553b1e19cd9c89bcaf5817a4cb08d54e5c434,364fa9d11d1a1e74c59f830fe23a9b9e5b37fcee..f5438d0978cab397455e20aa66744646ffe34c5f
@@@ -329,8 -329,7 +329,8 @@@ static void veth_setup(struct net_devic
   * netlink interface
   */
  
 -static int veth_validate(struct nlattr *tb[], struct nlattr *data[])
 +static int veth_validate(struct nlattr *tb[], struct nlattr *data[],
 +                       struct netlink_ext_ack *extack)
  {
        if (tb[IFLA_ADDRESS]) {
                if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
  static struct rtnl_link_ops veth_link_ops;
  
  static int veth_newlink(struct net *src_net, struct net_device *dev,
 -                       struct nlattr *tb[], struct nlattr *data[])
 +                      struct nlattr *tb[], struct nlattr *data[],
 +                      struct netlink_ext_ack *extack)
  {
        int err;
        struct net_device *peer;
                if (err < 0)
                        return err;
  
 -              err = veth_validate(peer_tb, NULL);
 +              err = veth_validate(peer_tb, NULL, extack);
                if (err < 0)
                        return err;
  
                tbp = tb;
        }
  
-       if (tbp[IFLA_IFNAME]) {
+       if (ifmp && tbp[IFLA_IFNAME]) {
                nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ);
                name_assign_type = NET_NAME_USER;
        } else {
                return PTR_ERR(peer);
        }
  
-       if (tbp[IFLA_ADDRESS] == NULL)
+       if (!ifmp || !tbp[IFLA_ADDRESS])
                eth_hw_addr_random(peer);
  
        if (ifmp && (dev->ifindex != 0))
diff --combined drivers/net/virtio_net.c
index 5c6388fb7dd13922e310aba329325e84fb434474,143d8a95a60d97b9036cd092d15b0bd8f8e361f8..2e69bcdc5b0754827ebcada5b16f39710cab3cf1
@@@ -305,7 -305,7 +305,7 @@@ static struct sk_buff *page_to_skb(stru
        copy = len;
        if (copy > skb_tailroom(skb))
                copy = skb_tailroom(skb);
 -      memcpy(skb_put(skb, copy), p, copy);
 +      skb_put_data(skb, p, copy);
  
        len -= copy;
        offset += copy;
@@@ -1150,7 -1150,7 +1150,7 @@@ static int xmit_skb(struct send_queue *
        struct virtio_net_hdr_mrg_rxbuf *hdr;
        const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
        struct virtnet_info *vi = sq->vq->vdev->priv;
 -      unsigned num_sg;
 +      int num_sg;
        unsigned hdr_len = vi->hdr_len;
        bool can_push;
  
        if (can_push) {
                __skb_push(skb, hdr_len);
                num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len);
 +              if (unlikely(num_sg < 0))
 +                      return num_sg;
                /* Pull header back to avoid skew in tx bytes calculations. */
                __skb_pull(skb, hdr_len);
        } else {
                sg_set_buf(sq->sg, hdr, hdr_len);
 -              num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1;
 +              num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len);
 +              if (unlikely(num_sg < 0))
 +                      return num_sg;
 +              num_sg++;
        }
        return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, skb, GFP_ATOMIC);
  }
@@@ -1802,6 -1797,7 +1802,7 @@@ static void virtnet_freeze_down(struct 
        flush_work(&vi->config_work);
  
        netif_device_detach(vi->dev);
+       netif_tx_disable(vi->dev);
        cancel_delayed_work_sync(&vi->refill);
  
        if (netif_running(vi->dev)) {
@@@ -1955,18 -1951,16 +1956,18 @@@ virtio_reset_err
        return err;
  }
  
 -static bool virtnet_xdp_query(struct net_device *dev)
 +static u32 virtnet_xdp_query(struct net_device *dev)
  {
        struct virtnet_info *vi = netdev_priv(dev);
 +      const struct bpf_prog *xdp_prog;
        int i;
  
        for (i = 0; i < vi->max_queue_pairs; i++) {
 -              if (vi->rq[i].xdp_prog)
 -                      return true;
 +              xdp_prog = rtnl_dereference(vi->rq[i].xdp_prog);
 +              if (xdp_prog)
 +                      return xdp_prog->aux->id;
        }
 -      return false;
 +      return 0;
  }
  
  static int virtnet_xdp(struct net_device *dev, struct netdev_xdp *xdp)
        case XDP_SETUP_PROG:
                return virtnet_xdp_set(dev, xdp->prog, xdp->extack);
        case XDP_QUERY_PROG:
 -              xdp->prog_attached = virtnet_xdp_query(dev);
 +              xdp->prog_id = virtnet_xdp_query(dev);
 +              xdp->prog_attached = !!xdp->prog_id;
                return 0;
        default:
                return -EINVAL;
index 2ee92aa90fe93d74013d1a97eb3e59ba3389d79b,507512cc478b1dd2632e033ac7d9a2dc99b8ab5d..e937490d5d9747dd0a246169ee0af9936c5b728e
@@@ -870,7 -870,6 +870,6 @@@ static void qedi_process_cmd_cleanup_re
                QEDI_ERR(&qedi->dbg_ctx,
                         "Delayed or untracked cleanup response, itt=0x%x, tid=0x%x, cid=0x%x, task=%p\n",
                         protoitt, cqe->itid, qedi_conn->iscsi_conn_id, task);
-               WARN_ON(1);
        }
  }
  
@@@ -2101,16 -2100,14 +2100,16 @@@ int qedi_iscsi_send_ioreq(struct iscsi_
        /* Update header info */
        SET_FIELD(cmd_pdu_header.flags_attr, ISCSI_CMD_HDR_ATTR,
                  ISCSI_ATTR_SIMPLE);
 -      if (sc->sc_data_direction == DMA_TO_DEVICE) {
 -              SET_FIELD(cmd_pdu_header.flags_attr,
 -                        ISCSI_CMD_HDR_WRITE, 1);
 -              task_type = ISCSI_TASK_TYPE_INITIATOR_WRITE;
 -      } else {
 -              SET_FIELD(cmd_pdu_header.flags_attr,
 -                        ISCSI_CMD_HDR_READ, 1);
 -              task_type = ISCSI_TASK_TYPE_INITIATOR_READ;
 +      if (hdr->cdb[0] != TEST_UNIT_READY) {
 +              if (sc->sc_data_direction == DMA_TO_DEVICE) {
 +                      SET_FIELD(cmd_pdu_header.flags_attr,
 +                                ISCSI_CMD_HDR_WRITE, 1);
 +                      task_type = ISCSI_TASK_TYPE_INITIATOR_WRITE;
 +              } else {
 +                      SET_FIELD(cmd_pdu_header.flags_attr,
 +                                ISCSI_CMD_HDR_READ, 1);
 +                      task_type = ISCSI_TASK_TYPE_INITIATOR_READ;
 +              }
        }
  
        cmd_pdu_header.lun.lo = be32_to_cpu(scsi_lun[0]);
        cmd_pdu_header.expected_transfer_length = cpu_to_be32(hdr->data_length);
        cmd_pdu_header.hdr_second_dword = ntoh24(hdr->dlength);
        cmd_pdu_header.cmd_sn = be32_to_cpu(hdr->cmdsn);
 -      cmd_pdu_header.opcode = hdr->opcode;
 +      cmd_pdu_header.hdr_first_byte = hdr->opcode;
        qedi_cpy_scsi_cdb(sc, (u32 *)cmd_pdu_header.cdb);
  
        /* Fill tx AHS and rx buffer */
index f46880315ba89ab208a2f4169039773bcb521305,879d3b7462f94f38bba4618aecf51dde947aa458..5f5a4ef2e52965647e1e3db5b4cdd7bdb8021af8
@@@ -1499,11 -1499,9 +1499,9 @@@ err_idx
  
  void qedi_clear_task_idx(struct qedi_ctx *qedi, int idx)
  {
-       if (!test_and_clear_bit(idx, qedi->task_idx_map)) {
+       if (!test_and_clear_bit(idx, qedi->task_idx_map))
                QEDI_ERR(&qedi->dbg_ctx,
                         "FW task context, already cleared, tid=0x%x\n", idx);
-               WARN_ON(1);
-       }
  }
  
  void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, u32 proto_itt,
@@@ -1844,7 -1842,7 +1842,7 @@@ static int __qedi_probe(struct pci_dev 
                  qedi->mac);
  
        sprintf(host_buf, "host_%d", qedi->shost->host_no);
 -      qedi_ops->common->set_id(qedi->cdev, host_buf, QEDI_MODULE_VERSION);
 +      qedi_ops->common->set_name(qedi->cdev, host_buf);
  
        qedi_ops->register_ops(qedi->cdev, &qedi_cb_ops, qedi);
  
diff --combined include/net/xfrm.h
index 01f5bc144ee54700d27d75e9835b8ddf656e6fb0,62f5a259e597572ad4b8981ca04dd44a790760bd..01fa357e9a3290b2ea8da69ef513524af5a75442
@@@ -631,8 -631,7 +631,8 @@@ struct xfrm_mgr 
                                           u8 dir, u8 type,
                                           const struct xfrm_migrate *m,
                                           int num_bundles,
 -                                         const struct xfrm_kmaddress *k);
 +                                         const struct xfrm_kmaddress *k,
 +                                         const struct xfrm_encap_tmpl *encap);
        bool                    (*is_alive)(const struct km_event *c);
  };
  
@@@ -1676,16 -1675,13 +1676,16 @@@ int xfrm_sk_policy_insert(struct sock *
  #ifdef CONFIG_XFRM_MIGRATE
  int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
               const struct xfrm_migrate *m, int num_bundles,
 -             const struct xfrm_kmaddress *k);
 +             const struct xfrm_kmaddress *k,
 +             const struct xfrm_encap_tmpl *encap);
  struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net);
  struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
 -                                    struct xfrm_migrate *m);
 +                                    struct xfrm_migrate *m,
 +                                    struct xfrm_encap_tmpl *encap);
  int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
                 struct xfrm_migrate *m, int num_bundles,
 -               struct xfrm_kmaddress *k, struct net *net);
 +               struct xfrm_kmaddress *k, struct net *net,
 +               struct xfrm_encap_tmpl *encap);
  #endif
  
  int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
@@@ -1854,8 -1850,9 +1854,9 @@@ static inline struct xfrm_offload *xfrm
  }
  #endif
  
- #ifdef CONFIG_XFRM_OFFLOAD
  void __net_init xfrm_dev_init(void);
+ #ifdef CONFIG_XFRM_OFFLOAD
  int validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features);
  int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
                       struct xfrm_user_offload *xuo);
@@@ -1881,10 -1878,6 +1882,6 @@@ static inline void xfrm_dev_state_free(
        }
  }
  #else
- static inline void __net_init xfrm_dev_init(void)
- {
- }
  static inline int validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features)
  {
        return 0;
diff --combined kernel/bpf/verifier.c
index 74ea96ea391b38105750242ad7cb854174764afb,a8a725697bed693e8e77f225eea5dcc7db46dad0..6ea2adcb233b56d9bc3f4d16642ecbbf5556d5d9
@@@ -758,38 -758,15 +758,38 @@@ static int check_packet_access(struct b
  }
  
  /* check access to 'struct bpf_context' fields */
 -static int check_ctx_access(struct bpf_verifier_env *env, int off, int size,
 +static int check_ctx_access(struct bpf_verifier_env *env, int insn_idx, int off, int size,
                            enum bpf_access_type t, enum bpf_reg_type *reg_type)
  {
 +      struct bpf_insn_access_aux info = { .reg_type = *reg_type };
 +
        /* for analyzer ctx accesses are already validated and converted */
        if (env->analyzer_ops)
                return 0;
  
        if (env->prog->aux->ops->is_valid_access &&
 -          env->prog->aux->ops->is_valid_access(off, size, t, reg_type)) {
 +          env->prog->aux->ops->is_valid_access(off, size, t, &info)) {
 +              /* a non zero info.ctx_field_size indicates:
 +               * . For this field, the prog type specific ctx conversion algorithm
 +               *   only supports whole field access.
 +               * . This ctx access is a candiate for later verifier transformation
 +               *   to load the whole field and then apply a mask to get correct result.
 +               * a non zero info.converted_op_size indicates perceived actual converted
 +               * value width in convert_ctx_access.
 +               */
 +              if ((info.ctx_field_size && !info.converted_op_size) ||
 +                  (!info.ctx_field_size &&  info.converted_op_size)) {
 +                      verbose("verifier bug in is_valid_access prog type=%u off=%d size=%d\n",
 +                              env->prog->type, off, size);
 +                      return -EACCES;
 +              }
 +
 +              if (info.ctx_field_size) {
 +                      env->insn_aux_data[insn_idx].ctx_field_size = info.ctx_field_size;
 +                      env->insn_aux_data[insn_idx].converted_op_size = info.converted_op_size;
 +              }
 +              *reg_type = info.reg_type;
 +
                /* remember the offset of last byte accessed in ctx */
                if (env->prog->aux->max_ctx_offset < off + size)
                        env->prog->aux->max_ctx_offset = off + size;
@@@ -891,7 -868,7 +891,7 @@@ static int check_ptr_alignment(struct b
   * if t==write && value_regno==-1, some unknown value is stored into memory
   * if t==read && value_regno==-1, don't care what we read from memory
   */
 -static int check_mem_access(struct bpf_verifier_env *env, u32 regno, int off,
 +static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regno, int off,
                            int bpf_size, enum bpf_access_type t,
                            int value_regno)
  {
                        verbose("R%d leaks addr into ctx\n", value_regno);
                        return -EACCES;
                }
 -              err = check_ctx_access(env, off, size, t, &reg_type);
 +              err = check_ctx_access(env, insn_idx, off, size, t, &reg_type);
                if (!err && t == BPF_READ && value_regno >= 0) {
                        mark_reg_unknown_value_and_range(state->regs,
                                                         value_regno);
                        verbose("invalid stack off=%d size=%d\n", off, size);
                        return -EACCES;
                }
 +
 +              if (env->prog->aux->stack_depth < -off)
 +                      env->prog->aux->stack_depth = -off;
 +
                if (t == BPF_WRITE) {
                        if (!env->allow_ptr_leaks &&
                            state->stack_slot_type[MAX_BPF_STACK + off] == STACK_SPILL &&
        return err;
  }
  
 -static int check_xadd(struct bpf_verifier_env *env, struct bpf_insn *insn)
 +static int check_xadd(struct bpf_verifier_env *env, int insn_idx, struct bpf_insn *insn)
  {
        struct bpf_reg_state *regs = env->cur_state.regs;
        int err;
        if (err)
                return err;
  
+       if (is_pointer_value(env, insn->src_reg)) {
+               verbose("R%d leaks addr into mem\n", insn->src_reg);
+               return -EACCES;
+       }
        /* check whether atomic_add can read the memory */
 -      err = check_mem_access(env, insn->dst_reg, insn->off,
 +      err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
                               BPF_SIZE(insn->code), BPF_READ, -1);
        if (err)
                return err;
  
        /* check whether atomic_add can write into the same memory */
 -      return check_mem_access(env, insn->dst_reg, insn->off,
 +      return check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
                                BPF_SIZE(insn->code), BPF_WRITE, -1);
  }
  
@@@ -1059,9 -1037,6 +1064,9 @@@ static int check_stack_boundary(struct 
                return -EACCES;
        }
  
 +      if (env->prog->aux->stack_depth < -off)
 +              env->prog->aux->stack_depth = -off;
 +
        if (meta && meta->raw_mode) {
                meta->access_size = access_size;
                meta->regno = regno;
@@@ -1369,8 -1344,8 +1374,8 @@@ static void clear_all_pkt_pointers(stru
                if (reg->type != PTR_TO_PACKET &&
                    reg->type != PTR_TO_PACKET_END)
                        continue;
 -              reg->type = UNKNOWN_VALUE;
 -              reg->imm = 0;
 +              __mark_reg_unknown_value(state->spilled_regs,
 +                                       i / BPF_REG_SIZE);
        }
  }
  
@@@ -1439,7 -1414,7 +1444,7 @@@ static int check_call(struct bpf_verifi
         * is inferred from register state.
         */
        for (i = 0; i < meta.access_size; i++) {
 -              err = check_mem_access(env, meta.regno, i, BPF_B, BPF_WRITE, -1);
 +              err = check_mem_access(env, insn_idx, meta.regno, i, BPF_B, BPF_WRITE, -1);
                if (err)
                        return err;
        }
@@@ -1975,7 -1950,6 +1980,7 @@@ static int check_alu_op(struct bpf_veri
                         */
                        regs[insn->dst_reg].type = CONST_IMM;
                        regs[insn->dst_reg].imm = insn->imm;
 +                      regs[insn->dst_reg].id = 0;
                        regs[insn->dst_reg].max_value = insn->imm;
                        regs[insn->dst_reg].min_value = insn->imm;
                        regs[insn->dst_reg].min_align = calc_align(insn->imm);
@@@ -2433,7 -2407,6 +2438,7 @@@ static int check_ld_imm(struct bpf_veri
  
                regs[insn->dst_reg].type = CONST_IMM;
                regs[insn->dst_reg].imm = imm;
 +              regs[insn->dst_reg].id = 0;
                return 0;
        }
  
@@@ -2853,8 -2826,6 +2858,8 @@@ static bool states_equal(struct bpf_ver
                        return false;
                if (i % BPF_REG_SIZE)
                        continue;
 +              if (old->stack_slot_type[i] != STACK_SPILL)
 +                      continue;
                if (memcmp(&old->spilled_regs[i / BPF_REG_SIZE],
                           &cur->spilled_regs[i / BPF_REG_SIZE],
                           sizeof(old->spilled_regs[0])))
@@@ -3016,12 -2987,18 +3021,12 @@@ static int do_check(struct bpf_verifier
                        /* check that memory (src_reg + off) is readable,
                         * the state of dst_reg will be updated by this func
                         */
 -                      err = check_mem_access(env, insn->src_reg, insn->off,
 +                      err = check_mem_access(env, insn_idx, insn->src_reg, insn->off,
                                               BPF_SIZE(insn->code), BPF_READ,
                                               insn->dst_reg);
                        if (err)
                                return err;
  
 -                      if (BPF_SIZE(insn->code) != BPF_W &&
 -                          BPF_SIZE(insn->code) != BPF_DW) {
 -                              insn_idx++;
 -                              continue;
 -                      }
 -
                        prev_src_type = &env->insn_aux_data[insn_idx].ptr_type;
  
                        if (*prev_src_type == NOT_INIT) {
                        enum bpf_reg_type *prev_dst_type, dst_reg_type;
  
                        if (BPF_MODE(insn->code) == BPF_XADD) {
 -                              err = check_xadd(env, insn);
 +                              err = check_xadd(env, insn_idx, insn);
                                if (err)
                                        return err;
                                insn_idx++;
                        dst_reg_type = regs[insn->dst_reg].type;
  
                        /* check that memory (dst_reg + off) is writeable */
 -                      err = check_mem_access(env, insn->dst_reg, insn->off,
 +                      err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
                                               BPF_SIZE(insn->code), BPF_WRITE,
                                               insn->src_reg);
                        if (err)
                                return err;
  
                        /* check that memory (dst_reg + off) is writeable */
 -                      err = check_mem_access(env, insn->dst_reg, insn->off,
 +                      err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
                                               BPF_SIZE(insn->code), BPF_WRITE,
                                               -1);
                        if (err)
@@@ -3195,8 -3172,7 +3200,8 @@@ process_bpf_exit
                insn_idx++;
        }
  
 -      verbose("processed %d insns\n", insn_processed);
 +      verbose("processed %d insns, stack depth %d\n",
 +              insn_processed, env->prog->aux->stack_depth);
        return 0;
  }
  
@@@ -3400,7 -3376,7 +3405,7 @@@ static int convert_ctx_accesses(struct 
        struct bpf_insn insn_buf[16], *insn;
        struct bpf_prog *new_prog;
        enum bpf_access_type type;
 -      int i, cnt, delta = 0;
 +      int i, cnt, off, size, ctx_field_size, converted_op_size, is_narrower_load, delta = 0;
  
        if (ops->gen_prologue) {
                cnt = ops->gen_prologue(insn_buf, env->seen_direct_write,
                if (env->insn_aux_data[i + delta].ptr_type != PTR_TO_CTX)
                        continue;
  
 +              off = insn->off;
 +              size = bpf_size_to_bytes(BPF_SIZE(insn->code));
 +              ctx_field_size = env->insn_aux_data[i + delta].ctx_field_size;
 +              converted_op_size = env->insn_aux_data[i + delta].converted_op_size;
 +              is_narrower_load = type == BPF_READ && size < ctx_field_size;
 +
 +              /* If the read access is a narrower load of the field,
 +               * convert to a 4/8-byte load, to minimum program type specific
 +               * convert_ctx_access changes. If conversion is successful,
 +               * we will apply proper mask to the result.
 +               */
 +              if (is_narrower_load) {
 +                      int size_code = BPF_H;
 +
 +                      if (ctx_field_size == 4)
 +                              size_code = BPF_W;
 +                      else if (ctx_field_size == 8)
 +                              size_code = BPF_DW;
 +                      insn->off = off & ~(ctx_field_size - 1);
 +                      insn->code = BPF_LDX | BPF_MEM | size_code;
 +              }
                cnt = ops->convert_ctx_access(type, insn, insn_buf, env->prog);
                if (cnt == 0 || cnt >= ARRAY_SIZE(insn_buf)) {
                        verbose("bpf verifier is misconfigured\n");
                        return -EINVAL;
                }
 +              if (is_narrower_load && size < converted_op_size) {
 +                      if (ctx_field_size <= 4)
 +                              insn_buf[cnt++] = BPF_ALU32_IMM(BPF_AND, insn->dst_reg,
 +                                                      (1 << size * 8) - 1);
 +                      else
 +                              insn_buf[cnt++] = BPF_ALU64_IMM(BPF_AND, insn->dst_reg,
 +                                                      (1 << size * 8) - 1);
 +              }
  
                new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
                if (!new_prog)
@@@ -3520,7 -3467,6 +3525,7 @@@ static int fixup_bpf_calls(struct bpf_v
                         * the program array.
                         */
                        prog->cb_access = 1;
 +                      env->prog->aux->stack_depth = MAX_BPF_STACK;
  
                        /* mark bpf_tail_call as different opcode to avoid
                         * conditional branch in the interpeter for every normal
                         * that doesn't support bpf_tail_call yet
                         */
                        insn->imm = 0;
 -                      insn->code |= BPF_X;
 +                      insn->code = BPF_JMP | BPF_TAIL_CALL;
                        continue;
                }
  
diff --combined net/core/dev.c
index a91572aa73d58c9a11febb1810f6bec0158b63df,416137c64bf809328898f42fff41cd27ccf036d6..88927f1a3e4f838bea54d1dc8cf6ee06f79477c8
  #include <net/dst.h>
  #include <net/dst_metadata.h>
  #include <net/pkt_sched.h>
 +#include <net/pkt_cls.h>
  #include <net/checksum.h>
  #include <net/xfrm.h>
  #include <linux/highmem.h>
  #include <linux/hrtimer.h>
  #include <linux/netfilter_ingress.h>
  #include <linux/crash_dump.h>
 +#include <linux/sctp.h>
  
  #include "net-sysfs.h"
  
@@@ -163,7 -161,6 +163,7 @@@ static int netif_rx_internal(struct sk_
  static int call_netdevice_notifiers_info(unsigned long val,
                                         struct net_device *dev,
                                         struct netdev_notifier_info *info);
 +static struct napi_struct *napi_by_id(unsigned int napi_id);
  
  /*
   * The @dev_base_head list is protected by @dev_base_lock and the rtnl
@@@ -867,31 -864,6 +867,31 @@@ struct net_device *dev_get_by_index(str
  }
  EXPORT_SYMBOL(dev_get_by_index);
  
 +/**
 + *    dev_get_by_napi_id - find a device by napi_id
 + *    @napi_id: ID of the NAPI struct
 + *
 + *    Search for an interface by NAPI ID. Returns %NULL if the device
 + *    is not found or a pointer to the device. The device has not had
 + *    its reference counter increased so the caller must be careful
 + *    about locking. The caller must hold RCU lock.
 + */
 +
 +struct net_device *dev_get_by_napi_id(unsigned int napi_id)
 +{
 +      struct napi_struct *napi;
 +
 +      WARN_ON_ONCE(!rcu_read_lock_held());
 +
 +      if (napi_id < MIN_NAPI_ID)
 +              return NULL;
 +
 +      napi = napi_by_id(napi_id);
 +
 +      return napi ? napi->dev : NULL;
 +}
 +EXPORT_SYMBOL(dev_get_by_napi_id);
 +
  /**
   *    netdev_get_name - get a netdevice name, knowing its ifindex.
   *    @net: network namespace
  }
  EXPORT_SYMBOL(skb_checksum_help);
  
 +int skb_crc32c_csum_help(struct sk_buff *skb)
 +{
 +      __le32 crc32c_csum;
 +      int ret = 0, offset, start;
 +
 +      if (skb->ip_summed != CHECKSUM_PARTIAL)
 +              goto out;
 +
 +      if (unlikely(skb_is_gso(skb)))
 +              goto out;
 +
 +      /* Before computing a checksum, we should make sure no frag could
 +       * be modified by an external entity : checksum could be wrong.
 +       */
 +      if (unlikely(skb_has_shared_frag(skb))) {
 +              ret = __skb_linearize(skb);
 +              if (ret)
 +                      goto out;
 +      }
 +      start = skb_checksum_start_offset(skb);
 +      offset = start + offsetof(struct sctphdr, checksum);
 +      if (WARN_ON_ONCE(offset >= skb_headlen(skb))) {
 +              ret = -EINVAL;
 +              goto out;
 +      }
 +      if (skb_cloned(skb) &&
 +          !skb_clone_writable(skb, offset + sizeof(__le32))) {
 +              ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
 +              if (ret)
 +                      goto out;
 +      }
 +      crc32c_csum = cpu_to_le32(~__skb_checksum(skb, start,
 +                                                skb->len - start, ~(__u32)0,
 +                                                crc32c_csum_stub));
 +      *(__le32 *)(skb->data + offset) = crc32c_csum;
 +      skb->ip_summed = CHECKSUM_NONE;
 +      skb->csum_not_inet = 0;
 +out:
 +      return ret;
 +}
 +
  __be16 skb_network_protocol(struct sk_buff *skb, int *depth)
  {
        __be16 type = skb->protocol;
@@@ -3023,17 -2954,6 +3023,17 @@@ static struct sk_buff *validate_xmit_vl
        return skb;
  }
  
 +int skb_csum_hwoffload_help(struct sk_buff *skb,
 +                          const netdev_features_t features)
 +{
 +      if (unlikely(skb->csum_not_inet))
 +              return !!(features & NETIF_F_SCTP_CRC) ? 0 :
 +                      skb_crc32c_csum_help(skb);
 +
 +      return !!(features & NETIF_F_CSUM_MASK) ? 0 : skb_checksum_help(skb);
 +}
 +EXPORT_SYMBOL(skb_csum_hwoffload_help);
 +
  static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev)
  {
        netdev_features_t features;
                        else
                                skb_set_transport_header(skb,
                                                         skb_checksum_start_offset(skb));
 -                      if (!(features & NETIF_F_CSUM_MASK) &&
 -                          skb_checksum_help(skb))
 +                      if (skb_csum_hwoffload_help(skb, features))
                                goto out_kfree_skb;
                }
        }
@@@ -3258,7 -3179,7 +3258,7 @@@ sch_handle_egress(struct sk_buff *skb, 
        /* qdisc_skb_cb(skb)->pkt_len was already set by the caller. */
        qdisc_bstats_cpu_update(cl->q, skb);
  
 -      switch (tc_classify(skb, cl, &cl_res, false)) {
 +      switch (tcf_classify(skb, cl, &cl_res, false)) {
        case TC_ACT_OK:
        case TC_ACT_RECLASSIFY:
                skb->tc_index = TC_H_MIN(cl_res.classid);
                return NULL;
        case TC_ACT_STOLEN:
        case TC_ACT_QUEUED:
 +      case TC_ACT_TRAP:
                *ret = NET_XMIT_SUCCESS;
                consume_skb(skb);
                return NULL;
@@@ -4029,7 -3949,7 +4029,7 @@@ sch_handle_ingress(struct sk_buff *skb
        skb->tc_at_ingress = 1;
        qdisc_bstats_cpu_update(cl->q, skb);
  
 -      switch (tc_classify(skb, cl, &cl_res, false)) {
 +      switch (tcf_classify(skb, cl, &cl_res, false)) {
        case TC_ACT_OK:
        case TC_ACT_RECLASSIFY:
                skb->tc_index = TC_H_MIN(cl_res.classid);
                return NULL;
        case TC_ACT_STOLEN:
        case TC_ACT_QUEUED:
 +      case TC_ACT_TRAP:
                consume_skb(skb);
                return NULL;
        case TC_ACT_REDIRECT:
@@@ -4342,12 -4261,13 +4342,12 @@@ static struct static_key generic_xdp_ne
  
  static int generic_xdp_install(struct net_device *dev, struct netdev_xdp *xdp)
  {
 +      struct bpf_prog *old = rtnl_dereference(dev->xdp_prog);
        struct bpf_prog *new = xdp->prog;
        int ret = 0;
  
        switch (xdp->command) {
 -      case XDP_SETUP_PROG: {
 -              struct bpf_prog *old = rtnl_dereference(dev->xdp_prog);
 -
 +      case XDP_SETUP_PROG:
                rcu_assign_pointer(dev->xdp_prog, new);
                if (old)
                        bpf_prog_put(old);
                        dev_disable_lro(dev);
                }
                break;
 -      }
  
        case XDP_QUERY_PROG:
 -              xdp->prog_attached = !!rcu_access_pointer(dev->xdp_prog);
 +              xdp->prog_attached = !!old;
 +              xdp->prog_id = old ? old->aux->id : 0;
                break;
  
        default:
@@@ -4717,6 -4637,9 +4717,6 @@@ static enum gro_result dev_gro_receive(
        if (netif_elide_gro(skb->dev))
                goto normal;
  
 -      if (skb->csum_bad)
 -              goto normal;
 -
        gro_list_prepare(napi, skb);
  
        rcu_read_lock();
@@@ -4844,6 -4767,13 +4844,13 @@@ struct packet_offload *gro_find_complet
  }
  EXPORT_SYMBOL(gro_find_complete_by_type);
  
+ static void napi_skb_free_stolen_head(struct sk_buff *skb)
+ {
+       skb_dst_drop(skb);
+       secpath_reset(skb);
+       kmem_cache_free(skbuff_head_cache, skb);
+ }
  static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb)
  {
        switch (ret) {
                break;
  
        case GRO_MERGED_FREE:
-               if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) {
-                       skb_dst_drop(skb);
-                       secpath_reset(skb);
-                       kmem_cache_free(skbuff_head_cache, skb);
-               } else {
+               if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD)
+                       napi_skb_free_stolen_head(skb);
+               else
                        __kfree_skb(skb);
-               }
                break;
  
        case GRO_HELD:
@@@ -4935,10 -4862,16 +4939,16 @@@ static gro_result_t napi_frags_finish(s
                break;
  
        case GRO_DROP:
-       case GRO_MERGED_FREE:
                napi_reuse_skb(napi, skb);
                break;
  
+       case GRO_MERGED_FREE:
+               if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD)
+                       napi_skb_free_stolen_head(skb);
+               else
+                       napi_reuse_skb(napi, skb);
+               break;
        case GRO_MERGED:
        case GRO_CONSUMED:
                break;
@@@ -6934,7 -6867,7 +6944,7 @@@ int dev_change_proto_down(struct net_de
  }
  EXPORT_SYMBOL(dev_change_proto_down);
  
 -bool __dev_xdp_attached(struct net_device *dev, xdp_op_t xdp_op)
 +u8 __dev_xdp_attached(struct net_device *dev, xdp_op_t xdp_op, u32 *prog_id)
  {
        struct netdev_xdp xdp;
  
  
        /* Query must always succeed. */
        WARN_ON(xdp_op(dev, &xdp) < 0);
 +      if (prog_id)
 +              *prog_id = xdp.prog_id;
 +
        return xdp.prog_attached;
  }
  
  static int dev_xdp_install(struct net_device *dev, xdp_op_t xdp_op,
 -                         struct netlink_ext_ack *extack,
 +                         struct netlink_ext_ack *extack, u32 flags,
                           struct bpf_prog *prog)
  {
        struct netdev_xdp xdp;
  
        memset(&xdp, 0, sizeof(xdp));
 -      xdp.command = XDP_SETUP_PROG;
 +      if (flags & XDP_FLAGS_HW_MODE)
 +              xdp.command = XDP_SETUP_PROG_HW;
 +      else
 +              xdp.command = XDP_SETUP_PROG;
        xdp.extack = extack;
 +      xdp.flags = flags;
        xdp.prog = prog;
  
        return xdp_op(dev, &xdp);
@@@ -6987,7 -6913,7 +6997,7 @@@ int dev_change_xdp_fd(struct net_devic
        ASSERT_RTNL();
  
        xdp_op = xdp_chk = ops->ndo_xdp;
 -      if (!xdp_op && (flags & XDP_FLAGS_DRV_MODE))
 +      if (!xdp_op && (flags & (XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE)))
                return -EOPNOTSUPP;
        if (!xdp_op || (flags & XDP_FLAGS_SKB_MODE))
                xdp_op = generic_xdp_install;
                xdp_chk = generic_xdp_install;
  
        if (fd >= 0) {
 -              if (xdp_chk && __dev_xdp_attached(dev, xdp_chk))
 +              if (xdp_chk && __dev_xdp_attached(dev, xdp_chk, NULL))
                        return -EEXIST;
                if ((flags & XDP_FLAGS_UPDATE_IF_NOEXIST) &&
 -                  __dev_xdp_attached(dev, xdp_op))
 +                  __dev_xdp_attached(dev, xdp_op, NULL))
                        return -EBUSY;
  
                prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP);
                        return PTR_ERR(prog);
        }
  
 -      err = dev_xdp_install(dev, xdp_op, extack, prog);
 +      err = dev_xdp_install(dev, xdp_op, extack, flags, prog);
        if (err < 0 && prog)
                bpf_prog_put(prog);
  
@@@ -7097,7 -7023,7 +7107,7 @@@ static void rollback_registered_many(st
  
                if (!dev->rtnl_link_ops ||
                    dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
 -                      skb = rtmsg_ifinfo_build_skb(RTM_DELLINK, dev, ~0U,
 +                      skb = rtmsg_ifinfo_build_skb(RTM_DELLINK, dev, ~0U, 0,
                                                     GFP_KERNEL);
  
                /*
@@@ -7867,9 -7793,9 +7877,9 @@@ struct rtnl_link_stats64 *dev_get_stats
        } else {
                netdev_stats_to_stats64(storage, &dev->stats);
        }
-       storage->rx_dropped += atomic_long_read(&dev->rx_dropped);
-       storage->tx_dropped += atomic_long_read(&dev->tx_dropped);
-       storage->rx_nohandler += atomic_long_read(&dev->rx_nohandler);
+       storage->rx_dropped += (unsigned long)atomic_long_read(&dev->rx_dropped);
+       storage->tx_dropped += (unsigned long)atomic_long_read(&dev->tx_dropped);
+       storage->rx_nohandler += (unsigned long)atomic_long_read(&dev->rx_nohandler);
        return storage;
  }
  EXPORT_SYMBOL(dev_get_stats);
@@@ -8682,6 -8608,7 +8692,6 @@@ static int __init net_dev_init(void
        rc = cpuhp_setup_state_nocalls(CPUHP_NET_DEV_DEAD, "net/dev:dead",
                                       NULL, dev_cpu_dead);
        WARN_ON(rc < 0);
 -      dst_subsys_init();
        rc = 0;
  out:
        return rc;
diff --combined net/ipv4/tcp.c
index 4c88d20d91d4fa7b6b5d43d5791c2c2d100f44ee,40aca7803cf2db25361dc7ef5c83ee6ea955c335..4793fb78d93b2dff2e01e6129d4541904706a49c
@@@ -320,36 -320,17 +320,36 @@@ struct tcp_splice_state 
   * All the __sk_mem_schedule() is of this nature: accounting
   * is strict, actions are advisory and have some latency.
   */
 -int tcp_memory_pressure __read_mostly;
 -EXPORT_SYMBOL(tcp_memory_pressure);
 +unsigned long tcp_memory_pressure __read_mostly;
 +EXPORT_SYMBOL_GPL(tcp_memory_pressure);
  
  void tcp_enter_memory_pressure(struct sock *sk)
  {
 -      if (!tcp_memory_pressure) {
 +      unsigned long val;
 +
 +      if (tcp_memory_pressure)
 +              return;
 +      val = jiffies;
 +
 +      if (!val)
 +              val--;
 +      if (!cmpxchg(&tcp_memory_pressure, 0, val))
                NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMEMORYPRESSURES);
 -              tcp_memory_pressure = 1;
 -      }
  }
 -EXPORT_SYMBOL(tcp_enter_memory_pressure);
 +EXPORT_SYMBOL_GPL(tcp_enter_memory_pressure);
 +
 +void tcp_leave_memory_pressure(struct sock *sk)
 +{
 +      unsigned long val;
 +
 +      if (!tcp_memory_pressure)
 +              return;
 +      val = xchg(&tcp_memory_pressure, 0);
 +      if (val)
 +              NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPMEMORYPRESSURESCHRONO,
 +                            jiffies_to_msecs(jiffies - val));
 +}
 +EXPORT_SYMBOL_GPL(tcp_leave_memory_pressure);
  
  /* Convert seconds to retransmits based on initial and max timeout */
  static u8 secs_to_retrans(int seconds, int timeout, int rto_max)
@@@ -405,7 -386,7 +405,7 @@@ void tcp_init_sock(struct sock *sk
  
        icsk->icsk_rto = TCP_TIMEOUT_INIT;
        tp->mdev_us = jiffies_to_usecs(TCP_TIMEOUT_INIT);
 -      minmax_reset(&tp->rtt_min, tcp_time_stamp, ~0U);
 +      minmax_reset(&tp->rtt_min, tcp_jiffies32, ~0U);
  
        /* So many TCP implementations out there (incorrectly) count the
         * initial SYN frame in their delayed-ACK and congestion control
@@@ -901,8 -882,8 +901,8 @@@ static int tcp_send_mss(struct sock *sk
        return mss_now;
  }
  
 -static ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
 -                              size_t size, int flags)
 +ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
 +                       size_t size, int flags)
  {
        struct tcp_sock *tp = tcp_sk(sk);
        int mss_now, size_goal;
@@@ -1032,7 -1013,6 +1032,7 @@@ out_err
        }
        return sk_stream_error(sk, flags, err);
  }
 +EXPORT_SYMBOL_GPL(do_tcp_sendpages);
  
  int tcp_sendpage(struct sock *sk, struct page *page, int offset,
                 size_t size, int flags)
@@@ -2206,7 -2186,7 +2206,7 @@@ adjudge_to_death
  
  
        /* Now socket is owned by kernel and we acquire BH lock
 -         to finish close. No need to check for user refs.
 +       *  to finish close. No need to check for user refs.
         */
        local_bh_disable();
        bh_lock_sock(sk);
@@@ -2350,6 -2330,8 +2350,8 @@@ int tcp_disconnect(struct sock *sk, in
        tcp_init_send_head(sk);
        memset(&tp->rx_opt, 0, sizeof(tp->rx_opt));
        __sk_dst_reset(sk);
+       dst_release(sk->sk_rx_dst);
+       sk->sk_rx_dst = NULL;
        tcp_saved_syn_free(tp);
  
        /* Clean up fastopen related fields */
@@@ -2483,24 -2465,6 +2485,24 @@@ static int do_tcp_setsockopt(struct soc
                release_sock(sk);
                return err;
        }
 +      case TCP_ULP: {
 +              char name[TCP_ULP_NAME_MAX];
 +
 +              if (optlen < 1)
 +                      return -EINVAL;
 +
 +              val = strncpy_from_user(name, optval,
 +                                      min_t(long, TCP_ULP_NAME_MAX - 1,
 +                                            optlen));
 +              if (val < 0)
 +                      return -EFAULT;
 +              name[val] = 0;
 +
 +              lock_sock(sk);
 +              err = tcp_set_ulp(sk, name);
 +              release_sock(sk);
 +              return err;
 +      }
        default:
                /* fallthru */
                break;
        case TCP_MAXSEG:
                /* Values greater than interface MTU won't take effect. However
                 * at the point when this call is done we typically don't yet
 -               * know which interface is going to be used */
 +               * know which interface is going to be used
 +               */
                if (val && (val < TCP_MIN_MSS || val > MAX_TCP_WINDOW)) {
                        err = -EINVAL;
                        break;
  
  #ifdef CONFIG_TCP_MD5SIG
        case TCP_MD5SIG:
 +      case TCP_MD5SIG_EXT:
                /* Read the IP->Key mappings from userspace */
 -              err = tp->af_specific->md5_parse(sk, optval, optlen);
 +              err = tp->af_specific->md5_parse(sk, optname, optval, optlen);
                break;
  #endif
        case TCP_USER_TIMEOUT:
                if (!tp->repair)
                        err = -EPERM;
                else
 -                      tp->tsoffset = val - tcp_time_stamp;
 +                      tp->tsoffset = val - tcp_time_stamp_raw();
                break;
        case TCP_REPAIR_WINDOW:
                err = tcp_repair_set_window(tp, optval, optlen);
@@@ -2806,7 -2768,7 +2808,7 @@@ static void tcp_get_info_chrono_stats(c
        for (i = TCP_CHRONO_BUSY; i < __TCP_CHRONO_MAX; ++i) {
                stats[i] = tp->chrono_stat[i - 1];
                if (i == tp->chrono_type)
 -                      stats[i] += tcp_time_stamp - tp->chrono_start;
 +                      stats[i] += tcp_jiffies32 - tp->chrono_start;
                stats[i] *= USEC_PER_SEC / HZ;
                total += stats[i];
        }
@@@ -2890,7 -2852,7 +2892,7 @@@ void tcp_get_info(struct sock *sk, stru
        info->tcpi_retrans = tp->retrans_out;
        info->tcpi_fackets = tp->fackets_out;
  
 -      now = tcp_time_stamp;
 +      now = tcp_jiffies32;
        info->tcpi_last_data_sent = jiffies_to_msecs(now - tp->lsndtime);
        info->tcpi_last_data_recv = jiffies_to_msecs(now - icsk->icsk_ack.lrcvtime);
        info->tcpi_last_ack_recv = jiffies_to_msecs(now - tp->rcv_tstamp);
@@@ -3058,21 -3020,6 +3060,21 @@@ static int do_tcp_getsockopt(struct soc
                        return -EFAULT;
                return 0;
  
 +      case TCP_ULP:
 +              if (get_user(len, optlen))
 +                      return -EFAULT;
 +              len = min_t(unsigned int, len, TCP_ULP_NAME_MAX);
 +              if (!icsk->icsk_ulp_ops) {
 +                      if (put_user(0, optlen))
 +                              return -EFAULT;
 +                      return 0;
 +              }
 +              if (put_user(len, optlen))
 +                      return -EFAULT;
 +              if (copy_to_user(optval, icsk->icsk_ulp_ops->name, len))
 +                      return -EFAULT;
 +              return 0;
 +
        case TCP_THIN_LINEAR_TIMEOUTS:
                val = tp->thin_lto;
                break;
                break;
  
        case TCP_TIMESTAMP:
 -              val = tcp_time_stamp + tp->tsoffset;
 +              val = tcp_time_stamp_raw() + tp->tsoffset;
                break;
        case TCP_NOTSENT_LOWAT:
                val = tp->notsent_lowat;
diff --combined net/ipv6/addrconf.c
index a885ffcf097317659e5aabaca9036eadc9e5287e,1d2dbace42ffadda98d6b324170101bd31d7c9a7..5bea601aa3f59c2f974781f1ca6243e6d0f6086f
@@@ -963,7 -963,6 +963,7 @@@ ipv6_add_addr(struct inet6_dev *idev, c
        struct net *net = dev_net(idev->dev);
        struct inet6_ifaddr *ifa = NULL;
        struct rt6_info *rt;
 +      struct in6_validator_info i6vi;
        unsigned int hash;
        int err = 0;
        int addr_type = ipv6_addr_type(addr);
                return ERR_PTR(-EADDRNOTAVAIL);
  
        rcu_read_lock_bh();
 +
 +      in6_dev_hold(idev);
 +
        if (idev->dead) {
                err = -ENODEV;                  /*XXX*/
                goto out2;
                goto out2;
        }
  
 +      i6vi.i6vi_addr = *addr;
 +      i6vi.i6vi_dev = idev;
 +      rcu_read_unlock_bh();
 +
 +      err = inet6addr_validator_notifier_call_chain(NETDEV_UP, &i6vi);
 +
 +      rcu_read_lock_bh();
 +      err = notifier_to_errno(err);
 +      if (err)
 +              goto out2;
 +
        spin_lock(&addrconf_hash_lock);
  
        /* Ignore adding duplicate addresses on an interface */
        ifa->rt = rt;
  
        ifa->idev = idev;
 -      in6_dev_hold(idev);
        /* For caller */
        in6_ifa_hold(ifa);
  
@@@ -1076,7 -1062,6 +1076,7 @@@ out2
                inet6addr_notifier_call_chain(NETDEV_UP, ifa);
        else {
                kfree(ifa);
 +              in6_dev_put(idev);
                ifa = ERR_PTR(err);
        }
  
@@@ -2295,7 -2280,7 +2295,7 @@@ addrconf_prefix_route(struct in6_addr *
                cfg.fc_flags |= RTF_NONEXTHOP;
  #endif
  
 -      ip6_route_add(&cfg);
 +      ip6_route_add(&cfg, NULL);
  }
  
  
@@@ -2350,7 -2335,7 +2350,7 @@@ static void addrconf_add_mroute(struct 
  
        ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0);
  
 -      ip6_route_add(&cfg);
 +      ip6_route_add(&cfg, NULL);
  }
  
  static struct inet6_dev *addrconf_add_dev(struct net_device *dev)
@@@ -3384,6 -3369,7 +3384,7 @@@ static int addrconf_notify(struct notif
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
        struct netdev_notifier_changeupper_info *info;
        struct inet6_dev *idev = __in6_dev_get(dev);
+       struct net *net = dev_net(dev);
        int run_pending = 0;
        int err;
  
        case NETDEV_CHANGEMTU:
                /* if MTU under IPV6_MIN_MTU stop IPv6 on this interface. */
                if (dev->mtu < IPV6_MIN_MTU) {
-                       addrconf_ifdown(dev, 1);
+                       addrconf_ifdown(dev, dev != net->loopback_dev);
                        break;
                }
  
                         * IPV6_MIN_MTU stop IPv6 on this interface.
                         */
                        if (dev->mtu < IPV6_MIN_MTU)
-                               addrconf_ifdown(dev, 1);
+                               addrconf_ifdown(dev, dev != net->loopback_dev);
                }
                break;
  
@@@ -5576,8 -5562,8 +5577,8 @@@ static void __ipv6_ifa_notify(int event
                                ip6_del_rt(rt);
                }
                if (ifp->rt) {
 -                      dst_hold(&ifp->rt->dst);
 -                      ip6_del_rt(ifp->rt);
 +                      if (dst_hold_safe(&ifp->rt->dst))
 +                              ip6_del_rt(ifp->rt);
                }
                rt_genid_bump_ipv6(net);
                break;
diff --combined net/ipv6/ip6_output.c
index 5baa6fab4b9745d28f1dc3295dfe6684dfbd7df6,1699acb2fa2c835cb9fb18cee9148f2732878c5d..5f2657d98e82a792e02ba9b372790e13e2d4c947
@@@ -67,6 -67,9 +67,6 @@@ static int ip6_finish_output2(struct ne
        struct in6_addr *nexthop;
        int ret;
  
 -      skb->protocol = htons(ETH_P_IPV6);
 -      skb->dev = dev;
 -
        if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) {
                struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
  
@@@ -151,9 -154,6 +151,9 @@@ int ip6_output(struct net *net, struct 
        struct net_device *dev = skb_dst(skb)->dev;
        struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
  
 +      skb->protocol = htons(ETH_P_IPV6);
 +      skb->dev = dev;
 +
        if (unlikely(idev->cnf.disable_ipv6)) {
                IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
                kfree_skb(skb);
@@@ -682,7 -682,7 +682,7 @@@ int ip6_fragment(struct net *net, struc
                skb_frag_list_init(skb);
  
                __skb_pull(skb, hlen);
 -              fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr));
 +              fh = __skb_push(skb, sizeof(struct frag_hdr));
                __skb_push(skb, hlen);
                skb_reset_network_header(skb);
                memcpy(skb_network_header(skb), tmp_hdr, hlen);
                ipv6_hdr(skb)->payload_len = htons(first_len -
                                                   sizeof(struct ipv6hdr));
  
 -              dst_hold(&rt->dst);
 -
                for (;;) {
                        /* Prepare header of the next frame,
                         * before previous one went down. */
                        if (frag) {
                                frag->ip_summed = CHECKSUM_NONE;
                                skb_reset_transport_header(frag);
 -                              fh = (struct frag_hdr *)__skb_push(frag, sizeof(struct frag_hdr));
 +                              fh = __skb_push(frag, sizeof(struct frag_hdr));
                                __skb_push(frag, hlen);
                                skb_reset_network_header(frag);
                                memcpy(skb_network_header(frag), tmp_hdr,
                if (err == 0) {
                        IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
                                      IPSTATS_MIB_FRAGOKS);
 -                      ip6_rt_put(rt);
                        return 0;
                }
  
  
                IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
                              IPSTATS_MIB_FRAGFAILS);
 -              ip6_rt_put(rt);
                return err;
  
  slow_path_clean:
@@@ -865,6 -869,7 +865,6 @@@ fail_toobig
        if (skb->sk && dst_allfrag(skb_dst(skb)))
                sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK);
  
 -      skb->dev = skb_dst(skb)->dev;
        icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
        err = -EMSGSIZE;
  
@@@ -1385,7 -1390,7 +1385,7 @@@ emsgsize
         */
  
        cork->length += length;
-       if ((((length + fragheaderlen) > mtu) ||
+       if ((((length + (skb ? skb->len : headersize)) > mtu) ||
             (skb && skb_is_gso(skb))) &&
            (sk->sk_protocol == IPPROTO_UDP) &&
            (rt->dst.dev->features & NETIF_F_UFO) && !dst_xfrm(&rt->dst) &&
diff --combined net/ipv6/route.c
index 2e44900760611f062f62a10b7f09378ef1ef02a2,322bd62e688bfb5d2a88766a9537af51db0a69e8..0488a24c2a4425657f2e851aa3cd78fcd1dcea98
@@@ -128,6 -128,7 +128,6 @@@ static void rt6_uncached_list_add(struc
  {
        struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
  
 -      rt->dst.flags |= DST_NOCACHE;
        rt->rt6i_uncached_list = ul;
  
        spin_lock_bh(&ul->lock);
@@@ -353,7 -354,7 +353,7 @@@ static struct rt6_info *__ip6_dst_alloc
                                        int flags)
  {
        struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
 -                                      0, DST_OBSOLETE_FORCE_CHK, flags);
 +                                      1, DST_OBSOLETE_FORCE_CHK, flags);
  
        if (rt)
                rt6_info_init(rt);
@@@ -380,7 -381,7 +380,7 @@@ struct rt6_info *ip6_dst_alloc(struct n
                                *p =  NULL;
                        }
                } else {
 -                      dst_destroy((struct dst_entry *)rt);
 +                      dst_release_immediate(&rt->dst);
                        return NULL;
                }
        }
@@@ -931,21 -932,20 +931,21 @@@ struct rt6_info *rt6_lookup(struct net 
  EXPORT_SYMBOL(rt6_lookup);
  
  /* ip6_ins_rt is called with FREE table->tb6_lock.
 -   It takes new route entry, the addition fails by any reason the
 -   route is freed. In any case, if caller does not hold it, it may
 -   be destroyed.
 + * It takes new route entry, the addition fails by any reason the
 + * route is released.
 + * Caller must hold dst before calling it.
   */
  
  static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info,
 -                      struct mx6_config *mxc)
 +                      struct mx6_config *mxc,
 +                      struct netlink_ext_ack *extack)
  {
        int err;
        struct fib6_table *table;
  
        table = rt->rt6i_table;
        write_lock_bh(&table->tb6_lock);
 -      err = fib6_add(&table->tb6_root, rt, info, mxc);
 +      err = fib6_add(&table->tb6_root, rt, info, mxc, extack);
        write_unlock_bh(&table->tb6_lock);
  
        return err;
@@@ -956,9 -956,7 +956,9 @@@ int ip6_ins_rt(struct rt6_info *rt
        struct nl_info info = { .nl_net = dev_net(rt->dst.dev), };
        struct mx6_config mxc = { .mx = NULL, };
  
 -      return __ip6_ins_rt(rt, &info, &mxc);
 +      /* Hold dst to account for the reference from the fib6 tree */
 +      dst_hold(&rt->dst);
 +      return __ip6_ins_rt(rt, &info, &mxc, NULL);
  }
  
  static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
@@@ -1050,7 -1048,7 +1050,7 @@@ static struct rt6_info *rt6_make_pcpu_r
                prev = cmpxchg(p, NULL, pcpu_rt);
                if (prev) {
                        /* If someone did it before us, return prev instead */
 -                      dst_destroy(&pcpu_rt->dst);
 +                      dst_release_immediate(&pcpu_rt->dst);
                        pcpu_rt = prev;
                }
        } else {
                 * since rt is going away anyway.  The next
                 * dst_check() will trigger a re-lookup.
                 */
 -              dst_destroy(&pcpu_rt->dst);
 +              dst_release_immediate(&pcpu_rt->dst);
                pcpu_rt = rt;
        }
        dst_hold(&pcpu_rt->dst);
@@@ -1130,15 -1128,12 +1130,15 @@@ redo_rt6_select
                uncached_rt = ip6_rt_cache_alloc(rt, &fl6->daddr, NULL);
                dst_release(&rt->dst);
  
 -              if (uncached_rt)
 +              if (uncached_rt) {
 +                      /* Uncached_rt's refcnt is taken during ip6_rt_cache_alloc()
 +                       * No need for another dst_hold()
 +                       */
                        rt6_uncached_list_add(uncached_rt);
 -              else
 +              } else {
                        uncached_rt = net->ipv6.ip6_null_entry;
 -
 -              dst_hold(&uncached_rt->dst);
 +                      dst_hold(&uncached_rt->dst);
 +              }
  
                trace_fib6_table_lookup(net, uncached_rt, table->tb6_id, fl6);
                return uncached_rt;
@@@ -1249,11 -1244,9 +1249,11 @@@ EXPORT_SYMBOL_GPL(ip6_route_output_flag
  struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
  {
        struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
 +      struct net_device *loopback_dev = net->loopback_dev;
        struct dst_entry *new = NULL;
  
 -      rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
 +      rt = dst_alloc(&ip6_dst_blackhole_ops, loopback_dev, 1,
 +                     DST_OBSOLETE_NONE, 0);
        if (rt) {
                rt6_info_init(rt);
  
                new->output = dst_discard_out;
  
                dst_copy_metrics(new, &ort->dst);
 -              rt->rt6i_idev = ort->rt6i_idev;
 -              if (rt->rt6i_idev)
 -                      in6_dev_hold(rt->rt6i_idev);
  
 +              rt->rt6i_idev = in6_dev_get(loopback_dev);
                rt->rt6i_gateway = ort->rt6i_gateway;
                rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU;
                rt->rt6i_metric = 0;
  #ifdef CONFIG_IPV6_SUBTREES
                memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
  #endif
 -
 -              dst_free(new);
        }
  
        dst_release(dst_orig);
@@@ -1325,7 -1322,7 +1325,7 @@@ static struct dst_entry *ip6_dst_check(
        rt6_dst_from_metrics_check(rt);
  
        if (rt->rt6i_flags & RTF_PCPU ||
 -          (unlikely(dst->flags & DST_NOCACHE) && rt->dst.from))
 +          (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->dst.from))
                return rt6_dst_from_check(rt, cookie);
        else
                return rt6_check(rt, cookie);
@@@ -1358,8 -1355,8 +1358,8 @@@ static void ip6_link_failure(struct sk_
        rt = (struct rt6_info *) skb_dst(skb);
        if (rt) {
                if (rt->rt6i_flags & RTF_CACHE) {
 -                      dst_hold(&rt->dst);
 -                      ip6_del_rt(rt);
 +                      if (dst_hold_safe(&rt->dst))
 +                              ip6_del_rt(rt);
                } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
                        rt->rt6i_node->fn_sernum = -1;
                }
@@@ -1423,10 -1420,6 +1423,10 @@@ static void __ip6_rt_update_pmtu(struc
                         * invalidate the sk->sk_dst_cache.
                         */
                        ip6_ins_rt(nrt6);
 +                      /* Release the reference taken in
 +                       * ip6_rt_cache_alloc()
 +                       */
 +                      dst_release(&nrt6->dst);
                }
        }
  }
@@@ -1655,6 -1648,9 +1655,6 @@@ out
        return mtu - lwtunnel_headroom(dst->lwtstate, mtu);
  }
  
 -static struct dst_entry *icmp6_dst_gc_list;
 -static DEFINE_SPINLOCK(icmp6_dst_lock);
 -
  struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
                                  struct flowi6 *fl6)
  {
  
        rt->dst.flags |= DST_HOST;
        rt->dst.output  = ip6_output;
 -      atomic_set(&rt->dst.__refcnt, 1);
        rt->rt6i_gateway  = fl6->daddr;
        rt->rt6i_dst.addr = fl6->daddr;
        rt->rt6i_dst.plen = 128;
        rt->rt6i_idev     = idev;
        dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
  
 -      spin_lock_bh(&icmp6_dst_lock);
 -      rt->dst.next = icmp6_dst_gc_list;
 -      icmp6_dst_gc_list = &rt->dst;
 -      spin_unlock_bh(&icmp6_dst_lock);
 -
 -      fib6_force_start_gc(net);
 +      /* Add this dst into uncached_list so that rt6_ifdown() can
 +       * do proper release of the net_device
 +       */
 +      rt6_uncached_list_add(rt);
  
        dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0);
  
@@@ -1692,6 -1691,48 +1692,6 @@@ out
        return dst;
  }
  
 -int icmp6_dst_gc(void)
 -{
 -      struct dst_entry *dst, **pprev;
 -      int more = 0;
 -
 -      spin_lock_bh(&icmp6_dst_lock);
 -      pprev = &icmp6_dst_gc_list;
 -
 -      while ((dst = *pprev) != NULL) {
 -              if (!atomic_read(&dst->__refcnt)) {
 -                      *pprev = dst->next;
 -                      dst_free(dst);
 -              } else {
 -                      pprev = &dst->next;
 -                      ++more;
 -              }
 -      }
 -
 -      spin_unlock_bh(&icmp6_dst_lock);
 -
 -      return more;
 -}
 -
 -static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
 -                          void *arg)
 -{
 -      struct dst_entry *dst, **pprev;
 -
 -      spin_lock_bh(&icmp6_dst_lock);
 -      pprev = &icmp6_dst_gc_list;
 -      while ((dst = *pprev) != NULL) {
 -              struct rt6_info *rt = (struct rt6_info *) dst;
 -              if (func(rt, arg)) {
 -                      *pprev = dst->next;
 -                      dst_free(dst);
 -              } else {
 -                      pprev = &dst->next;
 -              }
 -      }
 -      spin_unlock_bh(&icmp6_dst_lock);
 -}
 -
  static int ip6_dst_gc(struct dst_ops *ops)
  {
        struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
@@@ -1803,8 -1844,7 +1803,8 @@@ static struct rt6_info *ip6_nh_lookup_t
        return rt;
  }
  
 -static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg)
 +static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
 +                                            struct netlink_ext_ack *extack)
  {
        struct net *net = cfg->fc_nlinfo.nl_net;
        struct rt6_info *rt = NULL;
        int err = -EINVAL;
  
        /* RTF_PCPU is an internal flag; can not be set by userspace */
 -      if (cfg->fc_flags & RTF_PCPU)
 +      if (cfg->fc_flags & RTF_PCPU) {
 +              NL_SET_ERR_MSG(extack, "Userspace can not set RTF_PCPU");
                goto out;
 +      }
  
 -      if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
 +      if (cfg->fc_dst_len > 128) {
 +              NL_SET_ERR_MSG(extack, "Invalid prefix length");
 +              goto out;
 +      }
 +      if (cfg->fc_src_len > 128) {
 +              NL_SET_ERR_MSG(extack, "Invalid source address length");
                goto out;
 +      }
  #ifndef CONFIG_IPV6_SUBTREES
 -      if (cfg->fc_src_len)
 +      if (cfg->fc_src_len) {
 +              NL_SET_ERR_MSG(extack,
 +                             "Specifying source address requires IPV6_SUBTREES to be enabled");
                goto out;
 +      }
  #endif
        if (cfg->fc_ifindex) {
                err = -ENODEV;
  
                err = lwtunnel_build_state(cfg->fc_encap_type,
                                           cfg->fc_encap, AF_INET6, cfg,
 -                                         &lwtstate);
 +                                         &lwtstate, extack);
                if (err)
                        goto out;
                rt->dst.lwtstate = lwtstate_get(lwtstate);
                err = -EINVAL;
                if (ipv6_chk_addr_and_flags(net, gw_addr,
                                            gwa_type & IPV6_ADDR_LINKLOCAL ?
 -                                          dev : NULL, 0, 0))
 +                                          dev : NULL, 0, 0)) {
 +                      NL_SET_ERR_MSG(extack, "Invalid gateway address");
                        goto out;
 -
 +              }
                rt->rt6i_gateway = *gw_addr;
  
                if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {
                           addressing
                         */
                        if (!(gwa_type & (IPV6_ADDR_UNICAST |
 -                                        IPV6_ADDR_MAPPED)))
 +                                        IPV6_ADDR_MAPPED))) {
 +                              NL_SET_ERR_MSG(extack,
 +                                             "Invalid gateway address");
                                goto out;
 +                      }
  
                        if (cfg->fc_table) {
                                grt = ip6_nh_lookup_table(net, cfg, gw_addr);
                                goto out;
                }
                err = -EINVAL;
 -              if (!dev || (dev->flags & IFF_LOOPBACK))
 +              if (!dev) {
 +                      NL_SET_ERR_MSG(extack, "Egress device not specified");
                        goto out;
 +              } else if (dev->flags & IFF_LOOPBACK) {
 +                      NL_SET_ERR_MSG(extack,
 +                                     "Egress device can not be loopback device for this route");
 +                      goto out;
 +              }
        }
  
        err = -ENODEV;
  
        if (!ipv6_addr_any(&cfg->fc_prefsrc)) {
                if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
 +                      NL_SET_ERR_MSG(extack, "Invalid source address");
                        err = -EINVAL;
                        goto out;
                }
        if (idev)
                in6_dev_put(idev);
        if (rt)
 -              dst_free(&rt->dst);
 +              dst_release_immediate(&rt->dst);
  
        return ERR_PTR(err);
  }
  
 -int ip6_route_add(struct fib6_config *cfg)
 +int ip6_route_add(struct fib6_config *cfg,
 +                struct netlink_ext_ack *extack)
  {
        struct mx6_config mxc = { .mx = NULL, };
        struct rt6_info *rt;
        int err;
  
 -      rt = ip6_route_info_create(cfg);
 +      rt = ip6_route_info_create(cfg, extack);
        if (IS_ERR(rt)) {
                err = PTR_ERR(rt);
                rt = NULL;
        if (err)
                goto out;
  
 -      err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc);
 +      err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc, extack);
  
        kfree(mxc.mx);
  
        return err;
  out:
        if (rt)
 -              dst_free(&rt->dst);
 +              dst_release_immediate(&rt->dst);
  
        return err;
  }
@@@ -2129,7 -2146,8 +2129,7 @@@ static int __ip6_del_rt(struct rt6_inf
        struct fib6_table *table;
        struct net *net = dev_net(rt->dst.dev);
  
 -      if (rt == net->ipv6.ip6_null_entry ||
 -          rt->dst.flags & DST_NOCACHE) {
 +      if (rt == net->ipv6.ip6_null_entry) {
                err = -ENOENT;
                goto out;
        }
@@@ -2204,8 -2222,7 +2204,8 @@@ out_put
        return err;
  }
  
 -static int ip6_route_del(struct fib6_config *cfg)
 +static int ip6_route_del(struct fib6_config *cfg,
 +                       struct netlink_ext_ack *extack)
  {
        struct fib6_table *table;
        struct fib6_node *fn;
        int err = -ESRCH;
  
        table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
 -      if (!table)
 +      if (!table) {
 +              NL_SET_ERR_MSG(extack, "FIB table does not exist");
                return err;
 +      }
  
        read_lock_bh(&table->tb6_lock);
  
@@@ -2354,7 -2369,7 +2354,7 @@@ static void rt6_do_redirect(struct dst_
        nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
  
        if (ip6_ins_rt(nrt))
 -              goto out;
 +              goto out_release;
  
        netevent.old = &rt->dst;
        netevent.new = &nrt->dst;
                ip6_del_rt(rt);
        }
  
 +out_release:
 +      /* Release the reference taken in
 +       * ip6_rt_cache_alloc()
 +       */
 +      dst_release(&nrt->dst);
 +
  out:
        neigh_release(neigh);
  }
@@@ -2474,7 -2483,7 +2474,7 @@@ static struct rt6_info *rt6_add_route_i
        if (!prefixlen)
                cfg.fc_flags |= RTF_DEFAULT;
  
 -      ip6_route_add(&cfg);
 +      ip6_route_add(&cfg, NULL);
  
        return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev);
  }
@@@ -2520,7 -2529,7 +2520,7 @@@ struct rt6_info *rt6_add_dflt_router(co
  
        cfg.fc_gateway = *gwaddr;
  
 -      if (!ip6_route_add(&cfg)) {
 +      if (!ip6_route_add(&cfg, NULL)) {
                struct fib6_table *table;
  
                table = fib6_get_table(dev_net(dev), cfg.fc_table);
@@@ -2613,10 -2622,10 +2613,10 @@@ int ipv6_route_ioctl(struct net *net, u
                rtnl_lock();
                switch (cmd) {
                case SIOCADDRT:
 -                      err = ip6_route_add(&cfg);
 +                      err = ip6_route_add(&cfg, NULL);
                        break;
                case SIOCDELRT:
 -                      err = ip6_route_del(&cfg);
 +                      err = ip6_route_del(&cfg, NULL);
                        break;
                default:
                        err = -EINVAL;
@@@ -2720,6 -2729,9 +2720,6 @@@ struct rt6_info *addrconf_dst_alloc(str
        rt->rt6i_dst.plen = 128;
        tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
        rt->rt6i_table = fib6_get_table(net, tb_id);
 -      rt->dst.flags |= DST_NOCACHE;
 -
 -      atomic_set(&rt->dst.__refcnt, 1);
  
        return rt;
  }
@@@ -2807,6 -2819,7 +2807,6 @@@ void rt6_ifdown(struct net *net, struc
        };
  
        fib6_clean_all(net, fib6_ifdown, &adn);
 -      icmp6_clean_all(fib6_ifdown, &adn);
        if (dev)
                rt6_uncached_list_flush_dev(net, dev);
  }
@@@ -2891,8 -2904,7 +2891,8 @@@ static const struct nla_policy rtm_ipv6
  };
  
  static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
 -                            struct fib6_config *cfg)
 +                            struct fib6_config *cfg,
 +                            struct netlink_ext_ack *extack)
  {
        struct rtmsg *rtm;
        struct nlattr *tb[RTA_MAX+1];
                cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
  
                err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
 -                                                   cfg->fc_mp_len);
 +                                                   cfg->fc_mp_len, extack);
                if (err < 0)
                        goto errout;
        }
        if (tb[RTA_ENCAP_TYPE]) {
                cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
  
 -              err = lwtunnel_valid_encap_type(cfg->fc_encap_type);
 +              err = lwtunnel_valid_encap_type(cfg->fc_encap_type, extack);
                if (err < 0)
                        goto errout;
        }
@@@ -3086,8 -3098,7 +3086,8 @@@ static void ip6_route_mpath_notify(stru
                inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
  }
  
 -static int ip6_route_multipath_add(struct fib6_config *cfg)
 +static int ip6_route_multipath_add(struct fib6_config *cfg,
 +                                 struct netlink_ext_ack *extack)
  {
        struct rt6_info *rt_notif = NULL, *rt_last = NULL;
        struct nl_info *info = &cfg->fc_nlinfo;
                                r_cfg.fc_encap_type = nla_get_u16(nla);
                }
  
 -              rt = ip6_route_info_create(&r_cfg);
 +              rt = ip6_route_info_create(&r_cfg, extack);
                if (IS_ERR(rt)) {
                        err = PTR_ERR(rt);
                        rt = NULL;
  
                err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg);
                if (err) {
 -                      dst_free(&rt->dst);
 +                      dst_release_immediate(&rt->dst);
                        goto cleanup;
                }
  
        err_nh = NULL;
        list_for_each_entry(nh, &rt6_nh_list, next) {
                rt_last = nh->rt6_info;
 -              err = __ip6_ins_rt(nh->rt6_info, info, &nh->mxc);
 +              err = __ip6_ins_rt(nh->rt6_info, info, &nh->mxc, extack);
                /* save reference to first route for notification */
                if (!rt_notif && !err)
                        rt_notif = nh->rt6_info;
@@@ -3202,13 -3213,13 +3202,13 @@@ add_errout
        list_for_each_entry(nh, &rt6_nh_list, next) {
                if (err_nh == nh)
                        break;
 -              ip6_route_del(&nh->r_cfg);
 +              ip6_route_del(&nh->r_cfg, extack);
        }
  
  cleanup:
        list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
                if (nh->rt6_info)
 -                      dst_free(&nh->rt6_info->dst);
 +                      dst_release_immediate(&nh->rt6_info->dst);
                kfree(nh->mxc.mx);
                list_del(&nh->next);
                kfree(nh);
        return err;
  }
  
 -static int ip6_route_multipath_del(struct fib6_config *cfg)
 +static int ip6_route_multipath_del(struct fib6_config *cfg,
 +                                 struct netlink_ext_ack *extack)
  {
        struct fib6_config r_cfg;
        struct rtnexthop *rtnh;
                                r_cfg.fc_flags |= RTF_GATEWAY;
                        }
                }
 -              err = ip6_route_del(&r_cfg);
 +              err = ip6_route_del(&r_cfg, extack);
                if (err)
                        last_err = err;
  
@@@ -3261,15 -3271,15 +3261,15 @@@ static int inet6_rtm_delroute(struct sk
        struct fib6_config cfg;
        int err;
  
 -      err = rtm_to_fib6_config(skb, nlh, &cfg);
 +      err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
        if (err < 0)
                return err;
  
        if (cfg.fc_mp)
 -              return ip6_route_multipath_del(&cfg);
 +              return ip6_route_multipath_del(&cfg, extack);
        else {
                cfg.fc_delete_all_nh = 1;
 -              return ip6_route_del(&cfg);
 +              return ip6_route_del(&cfg, extack);
        }
  }
  
@@@ -3279,14 -3289,14 +3279,14 @@@ static int inet6_rtm_newroute(struct sk
        struct fib6_config cfg;
        int err;
  
 -      err = rtm_to_fib6_config(skb, nlh, &cfg);
 +      err = rtm_to_fib6_config(skb, nlh, &cfg, extack);
        if (err < 0)
                return err;
  
        if (cfg.fc_mp)
 -              return ip6_route_multipath_add(&cfg);
 +              return ip6_route_multipath_add(&cfg, extack);
        else
 -              return ip6_route_add(&cfg);
 +              return ip6_route_add(&cfg, extack);
  }
  
  static size_t rt6_nlmsg_size(struct rt6_info *rt)
@@@ -3567,13 -3577,11 +3567,13 @@@ static int inet6_rtm_getroute(struct sk
  {
        struct net *net = sock_net(in_skb->sk);
        struct nlattr *tb[RTA_MAX+1];
 +      int err, iif = 0, oif = 0;
 +      struct dst_entry *dst;
        struct rt6_info *rt;
        struct sk_buff *skb;
        struct rtmsg *rtm;
        struct flowi6 fl6;
 -      int err, iif = 0, oif = 0;
 +      bool fibmatch;
  
        err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
                          extack);
        memset(&fl6, 0, sizeof(fl6));
        rtm = nlmsg_data(nlh);
        fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
 +      fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
  
        if (tb[RTA_SRC]) {
                if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
                if (!ipv6_addr_any(&fl6.saddr))
                        flags |= RT6_LOOKUP_F_HAS_SADDR;
  
 -              rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
 -                                                             flags);
 +              if (!fibmatch)
 +                      dst = ip6_route_input_lookup(net, dev, &fl6, flags);
        } else {
                fl6.flowi6_oif = oif;
  
 -              rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
 +              if (!fibmatch)
 +                      dst = ip6_route_output(net, NULL, &fl6);
 +      }
 +
 +      if (fibmatch)
 +              dst = ip6_route_lookup(net, &fl6, 0);
 +
 +      rt = container_of(dst, struct rt6_info, dst);
 +      if (rt->dst.error) {
 +              err = rt->dst.error;
 +              ip6_rt_put(rt);
 +              goto errout;
        }
  
        if (rt == net->ipv6.ip6_null_entry) {
        }
  
        skb_dst_set(skb, &rt->dst);
 -
 -      err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
 -                          RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
 -                          nlh->nlmsg_seq, 0);
 +      if (fibmatch)
 +              err = rt6_fill_node(net, skb, rt, NULL, NULL, iif,
 +                                  RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
 +                                  nlh->nlmsg_seq, 0);
 +      else
 +              err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
 +                                  RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
 +                                  nlh->nlmsg_seq, 0);
        if (err < 0) {
                kfree_skb(skb);
                goto errout;
@@@ -3730,7 -3722,11 +3730,11 @@@ static int ip6_route_dev_notify(struct 
                net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
                net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
  #endif
-        } else if (event == NETDEV_UNREGISTER) {
+        } else if (event == NETDEV_UNREGISTER &&
+                   dev->reg_state != NETREG_UNREGISTERED) {
+               /* NETDEV_UNREGISTER could be fired for multiple times by
+                * netdev_wait_allrefs(). Make sure we only call this once.
+                */
                in6_dev_put(net->ipv6.ip6_null_entry->rt6i_idev);
  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
                in6_dev_put(net->ipv6.ip6_prohibit_entry->rt6i_idev);
diff --combined net/ipv6/sit.c
index e9958b1398cb9edb54078c88bac2c921c79b3edd,f8ad15891cd75576765560bd76b45417b5836f57..ac912bb217471c048df3b76aa3d7b82886221dc1
@@@ -305,7 -305,7 +305,7 @@@ static int ipip6_tunnel_get_prl(struct 
         * we try harder to allocate.
         */
        kp = (cmax <= 1 || capable(CAP_NET_ADMIN)) ?
-               kcalloc(cmax, sizeof(*kp), GFP_KERNEL) :
+               kcalloc(cmax, sizeof(*kp), GFP_KERNEL | __GFP_NOWARN) :
                NULL;
  
        rcu_read_lock();
@@@ -1406,8 -1406,7 +1406,8 @@@ static void __net_init ipip6_fb_tunnel_
        rcu_assign_pointer(sitn->tunnels_wc[0], tunnel);
  }
  
 -static int ipip6_validate(struct nlattr *tb[], struct nlattr *data[])
 +static int ipip6_validate(struct nlattr *tb[], struct nlattr *data[],
 +                        struct netlink_ext_ack *extack)
  {
        u8 proto;
  
@@@ -1538,8 -1537,7 +1538,8 @@@ static bool ipip6_netlink_6rd_parms(str
  #endif
  
  static int ipip6_newlink(struct net *src_net, struct net_device *dev,
 -                       struct nlattr *tb[], struct nlattr *data[])
 +                       struct nlattr *tb[], struct nlattr *data[],
 +                       struct netlink_ext_ack *extack)
  {
        struct net *net = dev_net(dev);
        struct ip_tunnel *nt;
  }
  
  static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
 -                        struct nlattr *data[])
 +                          struct nlattr *data[],
 +                          struct netlink_ext_ack *extack)
  {
        struct ip_tunnel *t = netdev_priv(dev);
        struct ip_tunnel_parm p;
diff --combined net/ipv6/udp.c
index 450829dd6384fb250d6caf4840092c189f5b9715,75703fda23e7703b0df9f379d48208c0bf202c69..319aa8ed9cf8a60df9ba5a9365c811ea75a44ca7
@@@ -362,7 -362,7 +362,7 @@@ try_again
        if (!skb)
                return err;
  
 -      ulen = skb->len;
 +      ulen = udp_skb_len(skb);
        copied = len;
        if (copied > ulen - off)
                copied = ulen - off;
  
        if (copied < ulen || peeking ||
            (is_udplite && UDP_SKB_CB(skb)->partial_cov)) {
 -              checksum_valid = !udp_lib_checksum_complete(skb);
 +              checksum_valid = udp_skb_csum_unnecessary(skb) ||
 +                              !__udp_lib_checksum_complete(skb);
                if (!checksum_valid)
                        goto csum_copy_err;
        }
  
 -      if (checksum_valid || skb_csum_unnecessary(skb))
 -              err = skb_copy_datagram_msg(skb, off, msg, copied);
 -      else {
 +      if (checksum_valid || udp_skb_csum_unnecessary(skb)) {
 +              if (udp_skb_is_linear(skb))
 +                      err = copy_linear_skb(skb, copied, off, &msg->msg_iter);
 +              else
 +                      err = skb_copy_datagram_msg(skb, off, msg, copied);
 +      } else {
                err = skb_copy_and_csum_datagram_msg(skb, off, msg);
                if (err == -EINVAL)
                        goto csum_copy_err;
        return err;
  
  csum_copy_err:
 -      if (!__sk_queue_drop_skb(sk, skb, flags, udp_skb_destructor)) {
 +      if (!__sk_queue_drop_skb(sk, &udp_sk(sk)->reader_queue, skb, flags,
 +                               udp_skb_destructor)) {
                if (is_udp4) {
                        UDP_INC_STATS(sock_net(sk),
                                      UDP_MIB_CSUMERRORS, is_udplite);
@@@ -634,7 -629,6 +634,7 @@@ static int udpv6_queue_rcv_skb(struct s
                }
        }
  
 +      prefetch(&sk->sk_rmem_alloc);
        if (rcu_access_pointer(sk->sk_filter) &&
            udp_lib_checksum_complete(skb))
                goto csum_error;
@@@ -885,7 -879,8 +885,8 @@@ static struct sock *__udp6_lib_demux_lo
        struct sock *sk;
  
        udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
-               if (INET6_MATCH(sk, net, rmt_addr, loc_addr, ports, dif))
+               if (sk->sk_state == TCP_ESTABLISHED &&
+                   INET6_MATCH(sk, net, rmt_addr, loc_addr, ports, dif))
                        return sk;
                /* Only check first socket in chain */
                break;
@@@ -925,11 -920,12 +926,11 @@@ static void udp_v6_early_demux(struct s
        if (dst)
                dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie);
        if (dst) {
 -              if (dst->flags & DST_NOCACHE) {
 -                      if (likely(atomic_inc_not_zero(&dst->__refcnt)))
 -                              skb_dst_set(skb, dst);
 -              } else {
 -                      skb_dst_set_noref(skb, dst);
 -              }
 +              /* set noref for now.
 +               * any place which wants to hold dst has to call
 +               * dst_hold_safe()
 +               */
 +              skb_dst_set_noref(skb, dst);
        }
  }
  
diff --combined net/key/af_key.c
index ce9b8565d82516ae8a440ff8ed45c184e76d2e14,b1432b6680338cf60942f3dd5567a6c7a11a603f..376fdcf7a6b9ba598c0f14e20647f54902380861
@@@ -349,7 -349,7 +349,7 @@@ static int pfkey_error(const struct sad
                err = EINVAL;
        BUG_ON(err <= 0 || err >= 256);
  
 -      hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
 +      hdr = skb_put(skb, sizeof(struct sadb_msg));
        pfkey_hdr_dup(hdr, orig);
        hdr->sadb_msg_errno = (uint8_t) err;
        hdr->sadb_msg_len = (sizeof(struct sadb_msg) /
@@@ -810,12 -810,12 +810,12 @@@ static struct sk_buff *__pfkey_xfrm_sta
                return ERR_PTR(-ENOBUFS);
  
        /* call should fill header later */
 -      hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
 +      hdr = skb_put(skb, sizeof(struct sadb_msg));
        memset(hdr, 0, size);   /* XXX do we need this ? */
        hdr->sadb_msg_len = size / sizeof(uint64_t);
  
        /* sa */
 -      sa = (struct sadb_sa *)  skb_put(skb, sizeof(struct sadb_sa));
 +      sa = skb_put(skb, sizeof(struct sadb_sa));
        sa->sadb_sa_len = sizeof(struct sadb_sa)/sizeof(uint64_t);
        sa->sadb_sa_exttype = SADB_EXT_SA;
        sa->sadb_sa_spi = x->id.spi;
  
        /* hard time */
        if (hsc & 2) {
 -              lifetime = (struct sadb_lifetime *)  skb_put(skb,
 -                                                           sizeof(struct sadb_lifetime));
 +              lifetime = skb_put(skb, sizeof(struct sadb_lifetime));
                lifetime->sadb_lifetime_len =
                        sizeof(struct sadb_lifetime)/sizeof(uint64_t);
                lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
        }
        /* soft time */
        if (hsc & 1) {
 -              lifetime = (struct sadb_lifetime *)  skb_put(skb,
 -                                                           sizeof(struct sadb_lifetime));
 +              lifetime = skb_put(skb, sizeof(struct sadb_lifetime));
                lifetime->sadb_lifetime_len =
                        sizeof(struct sadb_lifetime)/sizeof(uint64_t);
                lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
                lifetime->sadb_lifetime_usetime = x->lft.soft_use_expires_seconds;
        }
        /* current time */
 -      lifetime = (struct sadb_lifetime *)  skb_put(skb,
 -                                                   sizeof(struct sadb_lifetime));
 +      lifetime = skb_put(skb, sizeof(struct sadb_lifetime));
        lifetime->sadb_lifetime_len =
                sizeof(struct sadb_lifetime)/sizeof(uint64_t);
        lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT;
        lifetime->sadb_lifetime_addtime = x->curlft.add_time;
        lifetime->sadb_lifetime_usetime = x->curlft.use_time;
        /* src address */
 -      addr = (struct sadb_address*) skb_put(skb,
 -                                            sizeof(struct sadb_address)+sockaddr_size);
 +      addr = skb_put(skb, sizeof(struct sadb_address) + sockaddr_size);
        addr->sadb_address_len =
                (sizeof(struct sadb_address)+sockaddr_size)/
                        sizeof(uint64_t);
                BUG();
  
        /* dst address */
 -      addr = (struct sadb_address*) skb_put(skb,
 -                                            sizeof(struct sadb_address)+sockaddr_size);
 +      addr = skb_put(skb, sizeof(struct sadb_address) + sockaddr_size);
        addr->sadb_address_len =
                (sizeof(struct sadb_address)+sockaddr_size)/
                        sizeof(uint64_t);
  
        if (!xfrm_addr_equal(&x->sel.saddr, &x->props.saddr,
                             x->props.family)) {
 -              addr = (struct sadb_address*) skb_put(skb,
 -                      sizeof(struct sadb_address)+sockaddr_size);
 +              addr = skb_put(skb,
 +                             sizeof(struct sadb_address) + sockaddr_size);
                addr->sadb_address_len =
                        (sizeof(struct sadb_address)+sockaddr_size)/
                        sizeof(uint64_t);
  
        /* auth key */
        if (add_keys && auth_key_size) {
 -              key = (struct sadb_key *) skb_put(skb,
 -                                                sizeof(struct sadb_key)+auth_key_size);
 +              key = skb_put(skb, sizeof(struct sadb_key) + auth_key_size);
                key->sadb_key_len = (sizeof(struct sadb_key) + auth_key_size) /
                        sizeof(uint64_t);
                key->sadb_key_exttype = SADB_EXT_KEY_AUTH;
        }
        /* encrypt key */
        if (add_keys && encrypt_key_size) {
 -              key = (struct sadb_key *) skb_put(skb,
 -                                                sizeof(struct sadb_key)+encrypt_key_size);
 +              key = skb_put(skb, sizeof(struct sadb_key) + encrypt_key_size);
                key->sadb_key_len = (sizeof(struct sadb_key) +
                                     encrypt_key_size) / sizeof(uint64_t);
                key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
        }
  
        /* sa */
 -      sa2 = (struct sadb_x_sa2 *)  skb_put(skb, sizeof(struct sadb_x_sa2));
 +      sa2 = skb_put(skb, sizeof(struct sadb_x_sa2));
        sa2->sadb_x_sa2_len = sizeof(struct sadb_x_sa2)/sizeof(uint64_t);
        sa2->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
        if ((mode = pfkey_mode_from_xfrm(x->props.mode)) < 0) {
                struct sadb_x_nat_t_port *n_port;
  
                /* type */
 -              n_type = (struct sadb_x_nat_t_type*) skb_put(skb, sizeof(*n_type));
 +              n_type = skb_put(skb, sizeof(*n_type));
                n_type->sadb_x_nat_t_type_len = sizeof(*n_type)/sizeof(uint64_t);
                n_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
                n_type->sadb_x_nat_t_type_type = natt->encap_type;
                n_type->sadb_x_nat_t_type_reserved[2] = 0;
  
                /* source port */
 -              n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port));
 +              n_port = skb_put(skb, sizeof(*n_port));
                n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t);
                n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT;
                n_port->sadb_x_nat_t_port_port = natt->encap_sport;
                n_port->sadb_x_nat_t_port_reserved = 0;
  
                /* dest port */
 -              n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port));
 +              n_port = skb_put(skb, sizeof(*n_port));
                n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t);
                n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT;
                n_port->sadb_x_nat_t_port_port = natt->encap_dport;
  
        /* security context */
        if (xfrm_ctx) {
 -              sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb,
 -                              sizeof(struct sadb_x_sec_ctx) + ctx_size);
 +              sec_ctx = skb_put(skb,
 +                                sizeof(struct sadb_x_sec_ctx) + ctx_size);
                sec_ctx->sadb_x_sec_len =
                  (sizeof(struct sadb_x_sec_ctx) + ctx_size) / sizeof(uint64_t);
                sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX;
@@@ -1150,6 -1157,7 +1150,7 @@@ static struct xfrm_state * pfkey_msg2xf
                        goto out;
        }
  
+       err = -ENOBUFS;
        key = ext_hdrs[SADB_EXT_KEY_AUTH - 1];
        if (sa->sadb_sa_auth) {
                int keysize = 0;
                if (key)
                        keysize = (key->sadb_key_bits + 7) / 8;
                x->aalg = kmalloc(sizeof(*x->aalg) + keysize, GFP_KERNEL);
-               if (!x->aalg)
+               if (!x->aalg) {
+                       err = -ENOMEM;
                        goto out;
+               }
                strcpy(x->aalg->alg_name, a->name);
                x->aalg->alg_key_len = 0;
                if (key) {
                                goto out;
                        }
                        x->calg = kmalloc(sizeof(*x->calg), GFP_KERNEL);
-                       if (!x->calg)
+                       if (!x->calg) {
+                               err = -ENOMEM;
                                goto out;
+                       }
                        strcpy(x->calg->alg_name, a->name);
                        x->props.calgo = sa->sadb_sa_encrypt;
                } else {
                        if (key)
                                keysize = (key->sadb_key_bits + 7) / 8;
                        x->ealg = kmalloc(sizeof(*x->ealg) + keysize, GFP_KERNEL);
-                       if (!x->ealg)
+                       if (!x->ealg) {
+                               err = -ENOMEM;
                                goto out;
+                       }
                        strcpy(x->ealg->alg_name, a->name);
                        x->ealg->alg_key_len = 0;
                        if (key) {
                struct xfrm_encap_tmpl *natt;
  
                x->encap = kmalloc(sizeof(*x->encap), GFP_KERNEL);
-               if (!x->encap)
+               if (!x->encap) {
+                       err = -ENOMEM;
                        goto out;
+               }
  
                natt = x->encap;
                n_type = ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1];
@@@ -1610,7 -1626,7 +1619,7 @@@ static struct sk_buff *compose_sadb_sup
        if (!skb)
                goto out_put_algs;
  
 -      hdr = (struct sadb_msg *) skb_put(skb, sizeof(*hdr));
 +      hdr = skb_put(skb, sizeof(*hdr));
        pfkey_hdr_dup(hdr, orig);
        hdr->sadb_msg_errno = 0;
        hdr->sadb_msg_len = len / sizeof(uint64_t);
                struct sadb_supported *sp;
                struct sadb_alg *ap;
  
 -              sp = (struct sadb_supported *) skb_put(skb, auth_len);
 +              sp = skb_put(skb, auth_len);
                ap = (struct sadb_alg *) (sp + 1);
  
                sp->sadb_supported_len = auth_len / sizeof(uint64_t);
                struct sadb_supported *sp;
                struct sadb_alg *ap;
  
 -              sp = (struct sadb_supported *) skb_put(skb, enc_len);
 +              sp = skb_put(skb, enc_len);
                ap = (struct sadb_alg *) (sp + 1);
  
                sp->sadb_supported_len = enc_len / sizeof(uint64_t);
@@@ -1699,7 -1715,8 +1708,7 @@@ static int unicast_flush_resp(struct so
        if (!skb)
                return -ENOBUFS;
  
 -      hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
 -      memcpy(hdr, ihdr, sizeof(struct sadb_msg));
 +      hdr = skb_put_data(skb, ihdr, sizeof(struct sadb_msg));
        hdr->sadb_msg_errno = (uint8_t) 0;
        hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
  
@@@ -1714,7 -1731,7 +1723,7 @@@ static int key_notify_sa_flush(const st
        skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
        if (!skb)
                return -ENOBUFS;
 -      hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
 +      hdr = skb_put(skb, sizeof(struct sadb_msg));
        hdr->sadb_msg_satype = pfkey_proto2satype(c->data.proto);
        hdr->sadb_msg_type = SADB_FLUSH;
        hdr->sadb_msg_seq = c->seq;
@@@ -2039,11 -2056,12 +2048,11 @@@ static int pfkey_xfrm_policy2msg(struc
        size = pfkey_xfrm_policy2msg_size(xp);
  
        /* call should fill header later */
 -      hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
 +      hdr = skb_put(skb, sizeof(struct sadb_msg));
        memset(hdr, 0, size);   /* XXX do we need this ? */
  
        /* src address */
 -      addr = (struct sadb_address*) skb_put(skb,
 -                                            sizeof(struct sadb_address)+sockaddr_size);
 +      addr = skb_put(skb, sizeof(struct sadb_address) + sockaddr_size);
        addr->sadb_address_len =
                (sizeof(struct sadb_address)+sockaddr_size)/
                        sizeof(uint64_t);
                BUG();
  
        /* dst address */
 -      addr = (struct sadb_address*) skb_put(skb,
 -                                            sizeof(struct sadb_address)+sockaddr_size);
 +      addr = skb_put(skb, sizeof(struct sadb_address) + sockaddr_size);
        addr->sadb_address_len =
                (sizeof(struct sadb_address)+sockaddr_size)/
                        sizeof(uint64_t);
                            xp->family);
  
        /* hard time */
 -      lifetime = (struct sadb_lifetime *)  skb_put(skb,
 -                                                   sizeof(struct sadb_lifetime));
 +      lifetime = skb_put(skb, sizeof(struct sadb_lifetime));
        lifetime->sadb_lifetime_len =
                sizeof(struct sadb_lifetime)/sizeof(uint64_t);
        lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
        lifetime->sadb_lifetime_addtime = xp->lft.hard_add_expires_seconds;
        lifetime->sadb_lifetime_usetime = xp->lft.hard_use_expires_seconds;
        /* soft time */
 -      lifetime = (struct sadb_lifetime *)  skb_put(skb,
 -                                                   sizeof(struct sadb_lifetime));
 +      lifetime = skb_put(skb, sizeof(struct sadb_lifetime));
        lifetime->sadb_lifetime_len =
                sizeof(struct sadb_lifetime)/sizeof(uint64_t);
        lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
        lifetime->sadb_lifetime_addtime = xp->lft.soft_add_expires_seconds;
        lifetime->sadb_lifetime_usetime = xp->lft.soft_use_expires_seconds;
        /* current time */
 -      lifetime = (struct sadb_lifetime *)  skb_put(skb,
 -                                                   sizeof(struct sadb_lifetime));
 +      lifetime = skb_put(skb, sizeof(struct sadb_lifetime));
        lifetime->sadb_lifetime_len =
                sizeof(struct sadb_lifetime)/sizeof(uint64_t);
        lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT;
        lifetime->sadb_lifetime_addtime = xp->curlft.add_time;
        lifetime->sadb_lifetime_usetime = xp->curlft.use_time;
  
 -      pol = (struct sadb_x_policy *)  skb_put(skb, sizeof(struct sadb_x_policy));
 +      pol = skb_put(skb, sizeof(struct sadb_x_policy));
        pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t);
        pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
        pol->sadb_x_policy_type = IPSEC_POLICY_DISCARD;
                } else {
                        size -= 2*socklen;
                }
 -              rq = (void*)skb_put(skb, req_size);
 +              rq = skb_put(skb, req_size);
                pol->sadb_x_policy_len += req_size/8;
                memset(rq, 0, sizeof(*rq));
                rq->sadb_x_ipsecrequest_len = req_size;
        if ((xfrm_ctx = xp->security)) {
                int ctx_size = pfkey_xfrm_policy2sec_ctx_size(xp);
  
 -              sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb, ctx_size);
 +              sec_ctx = skb_put(skb, ctx_size);
                sec_ctx->sadb_x_sec_len = ctx_size / sizeof(uint64_t);
                sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX;
                sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi;
@@@ -2589,7 -2611,7 +2598,7 @@@ static int pfkey_migrate(struct sock *s
        }
  
        return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i,
 -                          kma ? &k : NULL, net);
 +                          kma ? &k : NULL, net, NULL);
  
   out:
        return err;
@@@ -2721,7 -2743,7 +2730,7 @@@ static int key_notify_policy_flush(cons
        skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
        if (!skb_out)
                return -ENOBUFS;
 -      hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
 +      hdr = skb_put(skb_out, sizeof(struct sadb_msg));
        hdr->sadb_msg_type = SADB_X_SPDFLUSH;
        hdr->sadb_msg_seq = c->seq;
        hdr->sadb_msg_pid = c->portid;
@@@ -2742,6 -2764,8 +2751,8 @@@ static int pfkey_spdflush(struct sock *
        int err, err2;
  
        err = xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, true);
+       if (!err)
+               xfrm_garbage_collect(net);
        err2 = unicast_flush_resp(sk, hdr);
        if (err || err2) {
                if (err == -ESRCH) /* empty table - old silent behavior */
@@@ -2905,7 -2929,7 +2916,7 @@@ static void dump_ah_combs(struct sk_buf
        struct sadb_prop *p;
        int i;
  
 -      p = (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop));
 +      p = skb_put(skb, sizeof(struct sadb_prop));
        p->sadb_prop_len = sizeof(struct sadb_prop)/8;
        p->sadb_prop_exttype = SADB_EXT_PROPOSAL;
        p->sadb_prop_replay = 32;
  
                if (aalg_tmpl_set(t, aalg) && aalg->available) {
                        struct sadb_comb *c;
 -                      c = (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb));
 -                      memset(c, 0, sizeof(*c));
 +                      c = skb_put_zero(skb, sizeof(struct sadb_comb));
                        p->sadb_prop_len += sizeof(struct sadb_comb)/8;
                        c->sadb_comb_auth = aalg->desc.sadb_alg_id;
                        c->sadb_comb_auth_minbits = aalg->desc.sadb_alg_minbits;
@@@ -2939,7 -2964,7 +2950,7 @@@ static void dump_esp_combs(struct sk_bu
        struct sadb_prop *p;
        int i, k;
  
 -      p = (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop));
 +      p = skb_put(skb, sizeof(struct sadb_prop));
        p->sadb_prop_len = sizeof(struct sadb_prop)/8;
        p->sadb_prop_exttype = SADB_EXT_PROPOSAL;
        p->sadb_prop_replay = 32;
                                continue;
                        if (!(aalg_tmpl_set(t, aalg) && aalg->available))
                                continue;
 -                      c = (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb));
 +                      c = skb_put(skb, sizeof(struct sadb_comb));
                        memset(c, 0, sizeof(*c));
                        p->sadb_prop_len += sizeof(struct sadb_comb)/8;
                        c->sadb_comb_auth = aalg->desc.sadb_alg_id;
@@@ -3132,7 -3157,7 +3143,7 @@@ static int pfkey_send_acquire(struct xf
        if (skb == NULL)
                return -ENOMEM;
  
 -      hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
 +      hdr = skb_put(skb, sizeof(struct sadb_msg));
        hdr->sadb_msg_version = PF_KEY_V2;
        hdr->sadb_msg_type = SADB_ACQUIRE;
        hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
        hdr->sadb_msg_pid = 0;
  
        /* src address */
 -      addr = (struct sadb_address*) skb_put(skb,
 -                                            sizeof(struct sadb_address)+sockaddr_size);
 +      addr = skb_put(skb, sizeof(struct sadb_address) + sockaddr_size);
        addr->sadb_address_len =
                (sizeof(struct sadb_address)+sockaddr_size)/
                        sizeof(uint64_t);
                BUG();
  
        /* dst address */
 -      addr = (struct sadb_address*) skb_put(skb,
 -                                            sizeof(struct sadb_address)+sockaddr_size);
 +      addr = skb_put(skb, sizeof(struct sadb_address) + sockaddr_size);
        addr->sadb_address_len =
                (sizeof(struct sadb_address)+sockaddr_size)/
                        sizeof(uint64_t);
        if (!addr->sadb_address_prefixlen)
                BUG();
  
 -      pol = (struct sadb_x_policy *)  skb_put(skb, sizeof(struct sadb_x_policy));
 +      pol = skb_put(skb, sizeof(struct sadb_x_policy));
        pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t);
        pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
        pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
  
        /* security context */
        if (xfrm_ctx) {
 -              sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb,
 -                              sizeof(struct sadb_x_sec_ctx) + ctx_size);
 +              sec_ctx = skb_put(skb,
 +                                sizeof(struct sadb_x_sec_ctx) + ctx_size);
                sec_ctx->sadb_x_sec_len =
                  (sizeof(struct sadb_x_sec_ctx) + ctx_size) / sizeof(uint64_t);
                sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX;
@@@ -3332,7 -3359,7 +3343,7 @@@ static int pfkey_send_new_mapping(struc
        if (skb == NULL)
                return -ENOMEM;
  
 -      hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
 +      hdr = skb_put(skb, sizeof(struct sadb_msg));
        hdr->sadb_msg_version = PF_KEY_V2;
        hdr->sadb_msg_type = SADB_X_NAT_T_NEW_MAPPING;
        hdr->sadb_msg_satype = satype;
        hdr->sadb_msg_pid = 0;
  
        /* SA */
 -      sa = (struct sadb_sa *) skb_put(skb, sizeof(struct sadb_sa));
 +      sa = skb_put(skb, sizeof(struct sadb_sa));
        sa->sadb_sa_len = sizeof(struct sadb_sa)/sizeof(uint64_t);
        sa->sadb_sa_exttype = SADB_EXT_SA;
        sa->sadb_sa_spi = x->id.spi;
        sa->sadb_sa_flags = 0;
  
        /* ADDRESS_SRC (old addr) */
 -      addr = (struct sadb_address*)
 -              skb_put(skb, sizeof(struct sadb_address)+sockaddr_size);
 +      addr = skb_put(skb, sizeof(struct sadb_address) + sockaddr_size);
        addr->sadb_address_len =
                (sizeof(struct sadb_address)+sockaddr_size)/
                        sizeof(uint64_t);
                BUG();
  
        /* NAT_T_SPORT (old port) */
 -      n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port));
 +      n_port = skb_put(skb, sizeof(*n_port));
        n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t);
        n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT;
        n_port->sadb_x_nat_t_port_port = natt->encap_sport;
        n_port->sadb_x_nat_t_port_reserved = 0;
  
        /* ADDRESS_DST (new addr) */
 -      addr = (struct sadb_address*)
 -              skb_put(skb, sizeof(struct sadb_address)+sockaddr_size);
 +      addr = skb_put(skb, sizeof(struct sadb_address) + sockaddr_size);
        addr->sadb_address_len =
                (sizeof(struct sadb_address)+sockaddr_size)/
                        sizeof(uint64_t);
                BUG();
  
        /* NAT_T_DPORT (new port) */
 -      n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port));
 +      n_port = skb_put(skb, sizeof(*n_port));
        n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t);
        n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT;
        n_port->sadb_x_nat_t_port_port = sport;
@@@ -3405,7 -3434,7 +3416,7 @@@ static int set_sadb_address(struct sk_b
                            const struct xfrm_selector *sel)
  {
        struct sadb_address *addr;
 -      addr = (struct sadb_address *)skb_put(skb, sizeof(struct sadb_address) + sasize);
 +      addr = skb_put(skb, sizeof(struct sadb_address) + sasize);
        addr->sadb_address_len = (sizeof(struct sadb_address) + sasize)/8;
        addr->sadb_address_exttype = type;
        addr->sadb_address_proto = sel->proto;
@@@ -3443,7 -3472,8 +3454,7 @@@ static int set_sadb_kmaddress(struct sk
        size_req = (sizeof(struct sadb_x_kmaddress) +
                    pfkey_sockaddr_pair_size(family));
  
 -      kma = (struct sadb_x_kmaddress *)skb_put(skb, size_req);
 -      memset(kma, 0, size_req);
 +      kma = skb_put_zero(skb, size_req);
        kma->sadb_x_kmaddress_len = size_req / 8;
        kma->sadb_x_kmaddress_exttype = SADB_X_EXT_KMADDRESS;
        kma->sadb_x_kmaddress_reserved = k->reserved;
@@@ -3469,7 -3499,8 +3480,7 @@@ static int set_ipsecrequest(struct sk_b
        size_req = sizeof(struct sadb_x_ipsecrequest) +
                   pfkey_sockaddr_pair_size(family);
  
 -      rq = (struct sadb_x_ipsecrequest *)skb_put(skb, size_req);
 -      memset(rq, 0, size_req);
 +      rq = skb_put_zero(skb, size_req);
        rq->sadb_x_ipsecrequest_len = size_req;
        rq->sadb_x_ipsecrequest_proto = proto;
        rq->sadb_x_ipsecrequest_mode = mode;
  #ifdef CONFIG_NET_KEY_MIGRATE
  static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
                              const struct xfrm_migrate *m, int num_bundles,
 -                            const struct xfrm_kmaddress *k)
 +                            const struct xfrm_kmaddress *k,
 +                            const struct xfrm_encap_tmpl *encap)
  {
        int i;
        int sasize_sel;
        if (skb == NULL)
                return -ENOMEM;
  
 -      hdr = (struct sadb_msg *)skb_put(skb, sizeof(struct sadb_msg));
 +      hdr = skb_put(skb, sizeof(struct sadb_msg));
        hdr->sadb_msg_version = PF_KEY_V2;
        hdr->sadb_msg_type = SADB_X_MIGRATE;
        hdr->sadb_msg_satype = pfkey_proto2satype(m->proto);
        set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_DST, sel);
  
        /* policy information */
 -      pol = (struct sadb_x_policy *)skb_put(skb, sizeof(struct sadb_x_policy));
 +      pol = skb_put(skb, sizeof(struct sadb_x_policy));
        pol->sadb_x_policy_len = size_pol / 8;
        pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
        pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
@@@ -3599,8 -3629,7 +3610,8 @@@ err
  #else
  static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
                              const struct xfrm_migrate *m, int num_bundles,
 -                            const struct xfrm_kmaddress *k)
 +                            const struct xfrm_kmaddress *k,
 +                            const struct xfrm_encap_tmpl *encap)
  {
        return -ENOPROTOOPT;
  }
diff --combined net/sched/sch_api.c
index 5d95401bbc021343cef1d8b094062ec8ddfcd85c,cfdbfa18a95eb01deceecdad56be7de07547db2a..43b94c7b69bdb0d25d10a79c05e789a2388888da
@@@ -163,7 -163,7 +163,7 @@@ int register_qdisc(struct Qdisc_ops *qo
                if (!(cops->get && cops->put && cops->walk && cops->leaf))
                        goto out_einval;
  
 -              if (cops->tcf_chain && !(cops->bind_tcf && cops->unbind_tcf))
 +              if (cops->tcf_block && !(cops->bind_tcf && cops->unbind_tcf))
                        goto out_einval;
        }
  
@@@ -1019,7 -1019,8 +1019,8 @@@ static struct Qdisc *qdisc_create(struc
                return sch;
        }
        /* ops->init() failed, we call ->destroy() like qdisc_create_dflt() */
-       ops->destroy(sch);
+       if (ops->destroy)
+               ops->destroy(sch);
  err_out3:
        dev_put(dev);
        kfree((char *) sch - sch->padded);
@@@ -1878,6 -1879,54 +1879,6 @@@ done
        return skb->len;
  }
  
 -/* Main classifier routine: scans classifier chain attached
 - * to this qdisc, (optionally) tests for protocol and asks
 - * specific classifiers.
 - */
 -int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
 -              struct tcf_result *res, bool compat_mode)
 -{
 -      __be16 protocol = tc_skb_protocol(skb);
 -#ifdef CONFIG_NET_CLS_ACT
 -      const int max_reclassify_loop = 4;
 -      const struct tcf_proto *old_tp = tp;
 -      int limit = 0;
 -
 -reclassify:
 -#endif
 -      for (; tp; tp = rcu_dereference_bh(tp->next)) {
 -              int err;
 -
 -              if (tp->protocol != protocol &&
 -                  tp->protocol != htons(ETH_P_ALL))
 -                      continue;
 -
 -              err = tp->classify(skb, tp, res);
 -#ifdef CONFIG_NET_CLS_ACT
 -              if (unlikely(err == TC_ACT_RECLASSIFY && !compat_mode))
 -                      goto reset;
 -#endif
 -              if (err >= 0)
 -                      return err;
 -      }
 -
 -      return TC_ACT_UNSPEC; /* signal: continue lookup */
 -#ifdef CONFIG_NET_CLS_ACT
 -reset:
 -      if (unlikely(limit++ >= max_reclassify_loop)) {
 -              net_notice_ratelimited("%s: reclassify loop, rule prio %u, protocol %02x\n",
 -                                     tp->q->ops->id, tp->prio & 0xffff,
 -                                     ntohs(tp->protocol));
 -              return TC_ACT_SHOT;
 -      }
 -
 -      tp = old_tp;
 -      protocol = tc_skb_protocol(skb);
 -      goto reclassify;
 -#endif
 -}
 -EXPORT_SYMBOL(tc_classify);
 -
  #ifdef CONFIG_PROC_FS
  static int psched_show(struct seq_file *seq, void *v)
  {
diff --combined net/xfrm/xfrm_device.c
index 6d4a60d1bf19f84716c0fe4f9857468dac26cf74,5aba03685d7da54931c9287c071a13403c6edec5..5f7e8bfa0c2dca6d811616aa7002b768d1bb51ae
@@@ -22,6 -22,7 +22,7 @@@
  #include <net/xfrm.h>
  #include <linux/notifier.h>
  
+ #ifdef CONFIG_XFRM_OFFLOAD
  int validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features)
  {
        int err;
@@@ -137,8 -138,9 +138,9 @@@ ok
        return true;
  }
  EXPORT_SYMBOL_GPL(xfrm_dev_offload_ok);
+ #endif
  
 -int xfrm_dev_register(struct net_device *dev)
 +static int xfrm_dev_register(struct net_device *dev)
  {
        if ((dev->features & NETIF_F_HW_ESP) && !dev->xfrmdev_ops)
                return NOTIFY_BAD;
diff --combined net/xfrm/xfrm_policy.c
index a3dc7ab0b7ede1f74f6361b2da26224ef539b250,643a18f720321c52f0103baf010f3c5921d68482..4706df61217052d63868416072d15e12344acc03
@@@ -1006,10 -1006,6 +1006,6 @@@ int xfrm_policy_flush(struct net *net, 
                err = -ESRCH;
  out:
        spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
-       if (cnt)
-               xfrm_garbage_collect(net);
        return err;
  }
  EXPORT_SYMBOL(xfrm_policy_flush);
@@@ -1590,9 -1586,7 +1586,9 @@@ static void xfrm_bundle_flo_delete(stru
        struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo);
        struct dst_entry *dst = &xdst->u.dst;
  
 -      dst_free(dst);
 +      /* Mark DST_OBSOLETE_DEAD to fail the next xfrm_dst_check() */
 +      dst->obsolete = DST_OBSOLETE_DEAD;
 +      dst_release_immediate(dst);
  }
  
  static const struct flow_cache_ops xfrm_bundle_fc_ops = {
@@@ -1622,7 -1616,7 +1618,7 @@@ static inline struct xfrm_dst *xfrm_all
        default:
                BUG();
        }
 -      xdst = dst_alloc(dst_ops, NULL, 0, DST_OBSOLETE_NONE, 0);
 +      xdst = dst_alloc(dst_ops, NULL, 1, DST_OBSOLETE_NONE, 0);
  
        if (likely(xdst)) {
                struct dst_entry *dst = &xdst->u.dst;
@@@ -1725,11 -1719,10 +1721,11 @@@ static struct dst_entry *xfrm_bundle_cr
  
                if (!dst_prev)
                        dst0 = dst1;
 -              else {
 -                      dst_prev->child = dst_clone(dst1);
 -                      dst1->flags |= DST_NOHASH;
 -              }
 +              else
 +                      /* Ref count is taken during xfrm_alloc_dst()
 +                       * No need to do dst_clone() on dst1
 +                       */
 +                      dst_prev->child = dst1;
  
                xdst->route = dst;
                dst_copy_metrics(dst1, dst);
@@@ -1795,7 -1788,7 +1791,7 @@@ put_states
                xfrm_state_put(xfrm[i]);
  free_dst:
        if (dst0)
 -              dst_free(dst0);
 +              dst_release_immediate(dst0);
        dst0 = ERR_PTR(err);
        goto out;
  }
@@@ -2076,11 -2069,7 +2072,11 @@@ xfrm_bundle_lookup(struct net *net, con
                        pol_dead |= pols[i]->walk.dead;
                }
                if (pol_dead) {
 -                      dst_free(&xdst->u.dst);
 +                      /* Mark DST_OBSOLETE_DEAD to fail the next
 +                       * xfrm_dst_check()
 +                       */
 +                      xdst->u.dst.obsolete = DST_OBSOLETE_DEAD;
 +                      dst_release_immediate(&xdst->u.dst);
                        xdst = NULL;
                        num_pols = 0;
                        num_xfrms = 0;
        if (xdst) {
                /* The policies were stolen for newly generated bundle */
                xdst->num_pols = 0;
 -              dst_free(&xdst->u.dst);
 +              /* Mark DST_OBSOLETE_DEAD to fail the next xfrm_dst_check() */
 +              xdst->u.dst.obsolete = DST_OBSOLETE_DEAD;
 +              dst_release_immediate(&xdst->u.dst);
        }
  
 -      /* Flow cache does not have reference, it dst_free()'s,
 -       * but we do need to return one reference for original caller */
 +      /* We do need to return one reference for original caller */
        dst_hold(&new_xdst->u.dst);
        return &new_xdst->flo;
  
@@@ -2155,11 -2143,9 +2151,11 @@@ make_dummy_bundle
  inc_error:
        XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
  error:
 -      if (xdst != NULL)
 -              dst_free(&xdst->u.dst);
 -      else
 +      if (xdst != NULL) {
 +              /* Mark DST_OBSOLETE_DEAD to fail the next xfrm_dst_check() */
 +              xdst->u.dst.obsolete = DST_OBSOLETE_DEAD;
 +              dst_release_immediate(&xdst->u.dst);
 +      } else
                xfrm_pols_put(pols, num_pols);
        return ERR_PTR(err);
  }
@@@ -2231,6 -2217,7 +2227,6 @@@ struct dst_entry *xfrm_lookup(struct ne
                        }
  
                        dst_hold(&xdst->u.dst);
 -                      xdst->u.dst.flags |= DST_NOCACHE;
                        route = xdst->route;
                }
        }
@@@ -2645,12 -2632,10 +2641,12 @@@ static struct dst_entry *xfrm_dst_check
         * notice.  That's what we are validating here via the
         * stale_bundle() check.
         *
 -       * When a policy's bundle is pruned, we dst_free() the XFRM
 -       * dst which causes it's ->obsolete field to be set to
 -       * DST_OBSOLETE_DEAD.  If an XFRM dst has been pruned like
 -       * this, we want to force a new route lookup.
 +       * When an xdst is removed from flow cache, DST_OBSOLETE_DEAD will
 +       * be marked on it.
 +       * When a dst is removed from the fib tree, DST_OBSOLETE_DEAD will
 +       * be marked on it.
 +       * Both will force stable_bundle() to fail on any xdst bundle with
 +       * this dst linked in it.
         */
        if (dst->obsolete < 0 && !stale_bundle(dst))
                return dst;
@@@ -3279,6 -3264,11 +3275,6 @@@ static int xfrm_migrate_check(const str
                return -EINVAL;
  
        for (i = 0; i < num_migrate; i++) {
 -              if (xfrm_addr_equal(&m[i].old_daddr, &m[i].new_daddr,
 -                                  m[i].old_family) &&
 -                  xfrm_addr_equal(&m[i].old_saddr, &m[i].new_saddr,
 -                                  m[i].old_family))
 -                      return -EINVAL;
                if (xfrm_addr_any(&m[i].new_daddr, m[i].new_family) ||
                    xfrm_addr_any(&m[i].new_saddr, m[i].new_family))
                        return -EINVAL;
  
  int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
                 struct xfrm_migrate *m, int num_migrate,
 -               struct xfrm_kmaddress *k, struct net *net)
 +               struct xfrm_kmaddress *k, struct net *net,
 +               struct xfrm_encap_tmpl *encap)
  {
        int i, err, nx_cur = 0, nx_new = 0;
        struct xfrm_policy *pol = NULL;
                if ((x = xfrm_migrate_state_find(mp, net))) {
                        x_cur[nx_cur] = x;
                        nx_cur++;
 -                      if ((xc = xfrm_state_migrate(x, mp))) {
 +                      xc = xfrm_state_migrate(x, mp, encap);
 +                      if (xc) {
                                x_new[nx_new] = xc;
                                nx_new++;
                        } else {
        }
  
        /* Stage 5 - announce */
 -      km_migrate(sel, dir, type, m, num_migrate, k);
 +      km_migrate(sel, dir, type, m, num_migrate, k, encap);
  
        xfrm_pol_put(pol);
  
diff --combined net/xfrm/xfrm_user.c
index 6197c7231bc75ead01cfe12d3573a909fffe3058,86116e9aaf3d9cee13b7c96d4d420e33842c1270..2be4c6af008a7917ae5cc1e3306c5466cae387e4
@@@ -2027,6 -2027,7 +2027,7 @@@ static int xfrm_flush_policy(struct sk_
                        return 0;
                return err;
        }
+       xfrm_garbage_collect(net);
  
        c.data.type = type;
        c.event = nlh->nlmsg_type;
@@@ -2243,7 -2244,6 +2244,7 @@@ static int xfrm_do_migrate(struct sk_bu
        int err;
        int n = 0;
        struct net *net = sock_net(skb->sk);
 +      struct xfrm_encap_tmpl  *encap = NULL;
  
        if (attrs[XFRMA_MIGRATE] == NULL)
                return -EINVAL;
        if (!n)
                return 0;
  
 -      xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net);
 +      if (attrs[XFRMA_ENCAP]) {
 +              encap = kmemdup(nla_data(attrs[XFRMA_ENCAP]),
 +                              sizeof(*encap), GFP_KERNEL);
 +              if (!encap)
 +                      return 0;
 +      }
  
 -      return 0;
 +      err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap);
 +
 +      kfree(encap);
 +
 +      return err;
  }
  #else
  static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
@@@ -2314,20 -2305,17 +2315,20 @@@ static int copy_to_user_kmaddress(cons
        return nla_put(skb, XFRMA_KMADDRESS, sizeof(uk), &uk);
  }
  
 -static inline size_t xfrm_migrate_msgsize(int num_migrate, int with_kma)
 +static inline size_t xfrm_migrate_msgsize(int num_migrate, int with_kma,
 +                                        int with_encp)
  {
        return NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_id))
              + (with_kma ? nla_total_size(sizeof(struct xfrm_kmaddress)) : 0)
 +            + (with_encp ? nla_total_size(sizeof(struct xfrm_encap_tmpl)) : 0)
              + nla_total_size(sizeof(struct xfrm_user_migrate) * num_migrate)
              + userpolicy_type_attrsize();
  }
  
  static int build_migrate(struct sk_buff *skb, const struct xfrm_migrate *m,
                         int num_migrate, const struct xfrm_kmaddress *k,
 -                       const struct xfrm_selector *sel, u8 dir, u8 type)
 +                       const struct xfrm_selector *sel,
 +                       const struct xfrm_encap_tmpl *encap, u8 dir, u8 type)
  {
        const struct xfrm_migrate *mp;
        struct xfrm_userpolicy_id *pol_id;
                if (err)
                        goto out_cancel;
        }
 +      if (encap) {
 +              err = nla_put(skb, XFRMA_ENCAP, sizeof(*encap), encap);
 +              if (err)
 +                      goto out_cancel;
 +      }
        err = copy_to_user_policy_type(type, skb);
        if (err)
                goto out_cancel;
@@@ -2373,19 -2356,17 +2374,19 @@@ out_cancel
  
  static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
                             const struct xfrm_migrate *m, int num_migrate,
 -                           const struct xfrm_kmaddress *k)
 +                           const struct xfrm_kmaddress *k,
 +                           const struct xfrm_encap_tmpl *encap)
  {
        struct net *net = &init_net;
        struct sk_buff *skb;
  
 -      skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k), GFP_ATOMIC);
 +      skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k, !!encap),
 +                      GFP_ATOMIC);
        if (skb == NULL)
                return -ENOMEM;
  
        /* build migrate */
 -      if (build_migrate(skb, m, num_migrate, k, sel, dir, type) < 0)
 +      if (build_migrate(skb, m, num_migrate, k, sel, encap, dir, type) < 0)
                BUG();
  
        return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_MIGRATE);
  #else
  static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
                             const struct xfrm_migrate *m, int num_migrate,
 -                           const struct xfrm_kmaddress *k)
 +                           const struct xfrm_kmaddress *k,
 +                           const struct xfrm_encap_tmpl *encap)
  {
        return -ENOPROTOOPT;
  }
index c0af0195432f5a3ee52df7f8c739c5499b3d687a,0ff8c55c0464a62bddd2bf6bd99ffc5041798ac3..26f1eefdc782f48007d7ab9c2c407fe8d61dfda0
@@@ -1073,75 -1073,44 +1073,75 @@@ static struct bpf_test tests[] = 
                .result = ACCEPT,
        },
        {
 -              "check cb access: byte, oob 1",
 +              "__sk_buff->hash, offset 0, byte store not permitted",
                .insns = {
                        BPF_MOV64_IMM(BPF_REG_0, 0),
                        BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0,
 -                                  offsetof(struct __sk_buff, cb[4]) + 4),
 +                                  offsetof(struct __sk_buff, hash)),
                        BPF_EXIT_INSN(),
                },
                .errstr = "invalid bpf_context access",
                .result = REJECT,
        },
        {
 -              "check cb access: byte, oob 2",
 +              "__sk_buff->tc_index, offset 3, byte store not permitted",
                .insns = {
                        BPF_MOV64_IMM(BPF_REG_0, 0),
                        BPF_STX_MEM(BPF_B, BPF_REG_1, BPF_REG_0,
 -                                  offsetof(struct __sk_buff, cb[0]) - 1),
 +                                  offsetof(struct __sk_buff, tc_index) + 3),
                        BPF_EXIT_INSN(),
                },
                .errstr = "invalid bpf_context access",
                .result = REJECT,
        },
        {
 -              "check cb access: byte, oob 3",
 +              "check skb->hash byte load permitted",
                .insns = {
                        BPF_MOV64_IMM(BPF_REG_0, 0),
 +#ifdef __LITTLE_ENDIAN
                        BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
 -                                  offsetof(struct __sk_buff, cb[4]) + 4),
 +                                  offsetof(struct __sk_buff, hash)),
 +#else
 +                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct __sk_buff, hash) + 3),
 +#endif
 +                      BPF_EXIT_INSN(),
 +              },
 +              .result = ACCEPT,
 +      },
 +      {
 +              "check skb->hash byte load not permitted 1",
 +              .insns = {
 +                      BPF_MOV64_IMM(BPF_REG_0, 0),
 +                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct __sk_buff, hash) + 1),
                        BPF_EXIT_INSN(),
                },
                .errstr = "invalid bpf_context access",
                .result = REJECT,
        },
        {
 -              "check cb access: byte, oob 4",
 +              "check skb->hash byte load not permitted 2",
                .insns = {
                        BPF_MOV64_IMM(BPF_REG_0, 0),
                        BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
 -                                  offsetof(struct __sk_buff, cb[0]) - 1),
 +                                  offsetof(struct __sk_buff, hash) + 2),
 +                      BPF_EXIT_INSN(),
 +              },
 +              .errstr = "invalid bpf_context access",
 +              .result = REJECT,
 +      },
 +      {
 +              "check skb->hash byte load not permitted 3",
 +              .insns = {
 +                      BPF_MOV64_IMM(BPF_REG_0, 0),
 +#ifdef __LITTLE_ENDIAN
 +                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct __sk_buff, hash) + 3),
 +#else
 +                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct __sk_buff, hash)),
 +#endif
                        BPF_EXIT_INSN(),
                },
                .errstr = "invalid bpf_context access",
                .result = REJECT,
        },
        {
 -              "check cb access: half, oob 1",
 +              "check __sk_buff->hash, offset 0, half store not permitted",
                .insns = {
                        BPF_MOV64_IMM(BPF_REG_0, 0),
                        BPF_STX_MEM(BPF_H, BPF_REG_1, BPF_REG_0,
 -                                  offsetof(struct __sk_buff, cb[4]) + 4),
 +                                  offsetof(struct __sk_buff, hash)),
                        BPF_EXIT_INSN(),
                },
                .errstr = "invalid bpf_context access",
                .result = REJECT,
        },
        {
 -              "check cb access: half, oob 2",
 +              "check __sk_buff->tc_index, offset 2, half store not permitted",
                .insns = {
                        BPF_MOV64_IMM(BPF_REG_0, 0),
                        BPF_STX_MEM(BPF_H, BPF_REG_1, BPF_REG_0,
 -                                  offsetof(struct __sk_buff, cb[0]) - 2),
 +                                  offsetof(struct __sk_buff, tc_index) + 2),
                        BPF_EXIT_INSN(),
                },
                .errstr = "invalid bpf_context access",
                .result = REJECT,
        },
        {
 -              "check cb access: half, oob 3",
 +              "check skb->hash half load permitted",
                .insns = {
                        BPF_MOV64_IMM(BPF_REG_0, 0),
 +#ifdef __LITTLE_ENDIAN
                        BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
 -                                  offsetof(struct __sk_buff, cb[4]) + 4),
 +                                  offsetof(struct __sk_buff, hash)),
 +#else
 +                      BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct __sk_buff, hash) + 2),
 +#endif
                        BPF_EXIT_INSN(),
                },
 -              .errstr = "invalid bpf_context access",
 -              .result = REJECT,
 +              .result = ACCEPT,
        },
        {
 -              "check cb access: half, oob 4",
 +              "check skb->hash half load not permitted",
                .insns = {
                        BPF_MOV64_IMM(BPF_REG_0, 0),
 +#ifdef __LITTLE_ENDIAN
 +                      BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct __sk_buff, hash) + 2),
 +#else
                        BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
 -                                  offsetof(struct __sk_buff, cb[0]) - 2),
 +                                  offsetof(struct __sk_buff, hash)),
 +#endif
                        BPF_EXIT_INSN(),
                },
                .errstr = "invalid bpf_context access",
        },
        {
                "check cb access: double, oob 2",
 -              .insns = {
 -                      BPF_MOV64_IMM(BPF_REG_0, 0),
 -                      BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
 -                                  offsetof(struct __sk_buff, cb[4]) + 8),
 -                      BPF_EXIT_INSN(),
 -              },
 -              .errstr = "invalid bpf_context access",
 -              .result = REJECT,
 -      },
 -      {
 -              "check cb access: double, oob 3",
 -              .insns = {
 -                      BPF_MOV64_IMM(BPF_REG_0, 0),
 -                      BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
 -                                  offsetof(struct __sk_buff, cb[0]) - 8),
 -                      BPF_EXIT_INSN(),
 -              },
 -              .errstr = "invalid bpf_context access",
 -              .result = REJECT,
 -      },
 -      {
 -              "check cb access: double, oob 4",
                .insns = {
                        BPF_MOV64_IMM(BPF_REG_0, 0),
                        BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1,
                .result = REJECT,
        },
        {
 -              "check cb access: double, oob 5",
 +              "check __sk_buff->ifindex dw store not permitted",
                .insns = {
                        BPF_MOV64_IMM(BPF_REG_0, 0),
 -                      BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1,
 -                                  offsetof(struct __sk_buff, cb[4]) + 8),
 +                      BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
 +                                  offsetof(struct __sk_buff, ifindex)),
                        BPF_EXIT_INSN(),
                },
                .errstr = "invalid bpf_context access",
                .result = REJECT,
        },
        {
 -              "check cb access: double, oob 6",
 +              "check __sk_buff->ifindex dw load not permitted",
                .insns = {
                        BPF_MOV64_IMM(BPF_REG_0, 0),
                        BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1,
 -                                  offsetof(struct __sk_buff, cb[0]) - 8),
 +                                  offsetof(struct __sk_buff, ifindex)),
                        BPF_EXIT_INSN(),
                },
                .errstr = "invalid bpf_context access",
                .result = REJECT,
                .errstr = "invalid bpf_context access",
        },
+       {
+               "leak pointer into ctx 1",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
+                                   offsetof(struct __sk_buff, cb[0])),
+                       BPF_LD_MAP_FD(BPF_REG_2, 0),
+                       BPF_STX_XADD(BPF_DW, BPF_REG_1, BPF_REG_2,
+                                     offsetof(struct __sk_buff, cb[0])),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 2 },
+               .errstr_unpriv = "R2 leaks addr into mem",
+               .result_unpriv = REJECT,
+               .result = ACCEPT,
+       },
+       {
+               "leak pointer into ctx 2",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0,
+                                   offsetof(struct __sk_buff, cb[0])),
+                       BPF_STX_XADD(BPF_DW, BPF_REG_1, BPF_REG_10,
+                                     offsetof(struct __sk_buff, cb[0])),
+                       BPF_EXIT_INSN(),
+               },
+               .errstr_unpriv = "R10 leaks addr into mem",
+               .result_unpriv = REJECT,
+               .result = ACCEPT,
+       },
+       {
+               "leak pointer into ctx 3",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_LD_MAP_FD(BPF_REG_2, 0),
+                       BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_2,
+                                     offsetof(struct __sk_buff, cb[0])),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 1 },
+               .errstr_unpriv = "R2 leaks addr into ctx",
+               .result_unpriv = REJECT,
+               .result = ACCEPT,
+       },
+       {
+               "leak pointer into map val",
+               .insns = {
+                       BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+                       BPF_MOV64_IMM(BPF_REG_3, 0),
+                       BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_3, 0),
+                       BPF_STX_XADD(BPF_DW, BPF_REG_0, BPF_REG_6, 0),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 4 },
+               .errstr_unpriv = "R6 leaks addr into mem",
+               .result_unpriv = REJECT,
+               .result = ACCEPT,
+       },
        {
                "helper access to map: full range",
                .insns = {
                },
                .result = ACCEPT,
        },
 +      {
 +              "check bpf_perf_event_data->sample_period byte load permitted",
 +              .insns = {
 +                      BPF_MOV64_IMM(BPF_REG_0, 0),
 +#ifdef __LITTLE_ENDIAN
 +                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct bpf_perf_event_data, sample_period)),
 +#else
 +                      BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct bpf_perf_event_data, sample_period) + 7),
 +#endif
 +                      BPF_EXIT_INSN(),
 +              },
 +              .result = ACCEPT,
 +              .prog_type = BPF_PROG_TYPE_PERF_EVENT,
 +      },
 +      {
 +              "check bpf_perf_event_data->sample_period half load permitted",
 +              .insns = {
 +                      BPF_MOV64_IMM(BPF_REG_0, 0),
 +#ifdef __LITTLE_ENDIAN
 +                      BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct bpf_perf_event_data, sample_period)),
 +#else
 +                      BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct bpf_perf_event_data, sample_period) + 6),
 +#endif
 +                      BPF_EXIT_INSN(),
 +              },
 +              .result = ACCEPT,
 +              .prog_type = BPF_PROG_TYPE_PERF_EVENT,
 +      },
 +      {
 +              "check bpf_perf_event_data->sample_period word load permitted",
 +              .insns = {
 +                      BPF_MOV64_IMM(BPF_REG_0, 0),
 +#ifdef __LITTLE_ENDIAN
 +                      BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct bpf_perf_event_data, sample_period)),
 +#else
 +                      BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct bpf_perf_event_data, sample_period) + 4),
 +#endif
 +                      BPF_EXIT_INSN(),
 +              },
 +              .result = ACCEPT,
 +              .prog_type = BPF_PROG_TYPE_PERF_EVENT,
 +      },
 +      {
 +              "check bpf_perf_event_data->sample_period dword load permitted",
 +              .insns = {
 +                      BPF_MOV64_IMM(BPF_REG_0, 0),
 +                      BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct bpf_perf_event_data, sample_period)),
 +                      BPF_EXIT_INSN(),
 +              },
 +              .result = ACCEPT,
 +              .prog_type = BPF_PROG_TYPE_PERF_EVENT,
 +      },
 +      {
 +              "check skb->data half load not permitted",
 +              .insns = {
 +                      BPF_MOV64_IMM(BPF_REG_0, 0),
 +#ifdef __LITTLE_ENDIAN
 +                      BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct __sk_buff, data)),
 +#else
 +                      BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct __sk_buff, data) + 2),
 +#endif
 +                      BPF_EXIT_INSN(),
 +              },
 +              .result = REJECT,
 +              .errstr = "invalid bpf_context access",
 +      },
 +      {
 +              "check skb->tc_classid half load not permitted for lwt prog",
 +              .insns = {
 +                      BPF_MOV64_IMM(BPF_REG_0, 0),
 +#ifdef __LITTLE_ENDIAN
 +                      BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct __sk_buff, tc_classid)),
 +#else
 +                      BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
 +                                  offsetof(struct __sk_buff, tc_classid) + 2),
 +#endif
 +                      BPF_EXIT_INSN(),
 +              },
 +              .result = REJECT,
 +              .errstr = "invalid bpf_context access",
 +              .prog_type = BPF_PROG_TYPE_LWT_IN,
 +      },
  };
  
  static int probe_filter_length(const struct bpf_insn *fp)
@@@ -5528,7 -5484,7 +5594,7 @@@ static int do_test(bool unpriv, unsigne
        }
  
        printf("Summary: %d PASSED, %d FAILED\n", passes, errors);
 -      return errors ? -errors : 0;
 +      return errors ? EXIT_FAILURE : EXIT_SUCCESS;
  }
  
  int main(int argc, char **argv)