}
 }
 
+static int be_enable_vxlan_offloads(struct be_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct device *dev = &adapter->pdev->dev;
+       struct be_vxlan_port *vxlan_port;
+       __be16 port;
+       int status;
+
+       vxlan_port = list_first_entry(&adapter->vxlan_port_list,
+                                     struct be_vxlan_port, list);
+       port = vxlan_port->port;
+
+       status = be_cmd_manage_iface(adapter, adapter->if_handle,
+                                    OP_CONVERT_NORMAL_TO_TUNNEL);
+       if (status) {
+               dev_warn(dev, "Failed to convert normal interface to tunnel\n");
+               return status;
+       }
+       adapter->flags |= BE_FLAGS_VXLAN_OFFLOADS;
+
+       status = be_cmd_set_vxlan_port(adapter, port);
+       if (status) {
+               dev_warn(dev, "Failed to add VxLAN port\n");
+               return status;
+       }
+       adapter->vxlan_port = port;
+
+       netdev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+                                  NETIF_F_TSO | NETIF_F_TSO6 |
+                                  NETIF_F_GSO_UDP_TUNNEL;
+       netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
+       netdev->features |= NETIF_F_GSO_UDP_TUNNEL;
+
+       dev_info(dev, "Enabled VxLAN offloads for UDP port %d\n",
+                be16_to_cpu(port));
+       return 0;
+}
+
 static void be_disable_vxlan_offloads(struct be_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
  * those other tunnels are unexported on the fly through ndo_features_check().
  *
  * Skyhawk supports VxLAN offloads only for one UDP dport. So, if the stack
- * adds more than one port, disable offloads and don't re-enable them again
- * until after all the tunnels are removed.
+ * adds more than one port, disable offloads and re-enable them again when
+ * there's only one port left. We maintain a list of ports for this purpose.
  */
 static void be_work_add_vxlan_port(struct work_struct *work)
 {
        struct be_cmd_work *cmd_work =
                                container_of(work, struct be_cmd_work, work);
        struct be_adapter *adapter = cmd_work->adapter;
-       struct net_device *netdev = adapter->netdev;
        struct device *dev = &adapter->pdev->dev;
        __be16 port = cmd_work->info.vxlan_port;
+       struct be_vxlan_port *vxlan_port;
        int status;
 
-       if (adapter->vxlan_port == port && adapter->vxlan_port_count) {
-               adapter->vxlan_port_aliases++;
-               goto done;
+       /* Bump up the alias count if it is an existing port */
+       list_for_each_entry(vxlan_port, &adapter->vxlan_port_list, list) {
+               if (vxlan_port->port == port) {
+                       vxlan_port->port_aliases++;
+                       goto done;
+               }
        }
 
+       /* Add a new port to our list. We don't need a lock here since port
+        * add/delete are done only in the context of a single-threaded work
+        * queue (be_wq).
+        */
+       vxlan_port = kzalloc(sizeof(*vxlan_port), GFP_KERNEL);
+       if (!vxlan_port)
+               goto done;
+
+       vxlan_port->port = port;
+       INIT_LIST_HEAD(&vxlan_port->list);
+       list_add_tail(&vxlan_port->list, &adapter->vxlan_port_list);
+       adapter->vxlan_port_count++;
+
        if (adapter->flags & BE_FLAGS_VXLAN_OFFLOADS) {
                dev_info(dev,
                         "Only one UDP port supported for VxLAN offloads\n");
                dev_info(dev, "Disabling VxLAN offloads\n");
-               adapter->vxlan_port_count++;
                goto err;
        }
 
-       if (adapter->vxlan_port_count++ >= 1)
+       if (adapter->vxlan_port_count > 1)
                goto done;
 
-       status = be_cmd_manage_iface(adapter, adapter->if_handle,
-                                    OP_CONVERT_NORMAL_TO_TUNNEL);
-       if (status) {
-               dev_warn(dev, "Failed to convert normal interface to tunnel\n");
-               goto err;
-       }
-
-       status = be_cmd_set_vxlan_port(adapter, port);
-       if (status) {
-               dev_warn(dev, "Failed to add VxLAN port\n");
-               goto err;
-       }
-       adapter->flags |= BE_FLAGS_VXLAN_OFFLOADS;
-       adapter->vxlan_port = port;
-
-       netdev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-                                  NETIF_F_TSO | NETIF_F_TSO6 |
-                                  NETIF_F_GSO_UDP_TUNNEL;
-       netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
-       netdev->features |= NETIF_F_GSO_UDP_TUNNEL;
+       status = be_enable_vxlan_offloads(adapter);
+       if (!status)
+               goto done;
 
-       dev_info(dev, "Enabled VxLAN offloads for UDP port %d\n",
-                be16_to_cpu(port));
-       goto done;
 err:
        be_disable_vxlan_offloads(adapter);
 done:
        kfree(cmd_work);
+       return;
 }
 
 static void be_work_del_vxlan_port(struct work_struct *work)
                                container_of(work, struct be_cmd_work, work);
        struct be_adapter *adapter = cmd_work->adapter;
        __be16 port = cmd_work->info.vxlan_port;
+       struct be_vxlan_port *vxlan_port;
 
-       if (adapter->vxlan_port != port)
-               goto done;
+       /* Nothing to be done if a port alias is being deleted */
+       list_for_each_entry(vxlan_port, &adapter->vxlan_port_list, list) {
+               if (vxlan_port->port == port) {
+                       if (vxlan_port->port_aliases) {
+                               vxlan_port->port_aliases--;
+                               goto done;
+                       }
+                       break;
+               }
+       }
+
+       /* No port aliases left; delete the port from the list */
+       list_del(&vxlan_port->list);
+       adapter->vxlan_port_count--;
 
-       if (adapter->vxlan_port_aliases) {
-               adapter->vxlan_port_aliases--;
+       /* Disable VxLAN offload if this is the offloaded port */
+       if (adapter->vxlan_port == vxlan_port->port) {
+               WARN_ON(adapter->vxlan_port_count);
+               be_disable_vxlan_offloads(adapter);
+               dev_info(&adapter->pdev->dev,
+                        "Disabled VxLAN offloads for UDP port %d\n",
+                        be16_to_cpu(port));
                goto out;
        }
 
-       be_disable_vxlan_offloads(adapter);
+       /* If only 1 port is left, re-enable VxLAN offload */
+       if (adapter->vxlan_port_count == 1)
+               be_enable_vxlan_offloads(adapter);
 
-       dev_info(&adapter->pdev->dev,
-                "Disabled VxLAN offloads for UDP port %d\n",
-                be16_to_cpu(port));
-done:
-       adapter->vxlan_port_count--;
 out:
+       kfree(vxlan_port);
+done:
        kfree(cmd_work);
 }
 
        /* Must be a power of 2 or else MODULO will BUG_ON */
        adapter->be_get_temp_freq = 64;
 
+       INIT_LIST_HEAD(&adapter->vxlan_port_list);
        return 0;
 
 free_rx_filter: