Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / drivers / net / ethernet / intel / ixgbe / ixgbe_main.c
index 8bebd86..fdbea54 100644 (file)
@@ -50,7 +50,7 @@
 #include <linux/if_bridge.h>
 #include <linux/prefetch.h>
 #include <scsi/fc/fc_fcoe.h>
-#include <net/vxlan.h>
+#include <net/udp_tunnel.h>
 #include <net/pkt_cls.h>
 #include <net/tc_act/tc_gact.h>
 #include <net/tc_act/tc_mirred.h>
@@ -5722,9 +5722,7 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter)
 #ifdef CONFIG_IXGBE_DCA
                adapter->flags &= ~IXGBE_FLAG_DCA_CAPABLE;
 #endif
-#ifdef CONFIG_IXGBE_VXLAN
                adapter->flags |= IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE;
-#endif
                break;
        default:
                break;
@@ -6158,9 +6156,7 @@ int ixgbe_open(struct net_device *netdev)
        ixgbe_up_complete(adapter);
 
        ixgbe_clear_vxlan_port(adapter);
-#ifdef CONFIG_IXGBE_VXLAN
-       vxlan_get_rx_port(netdev);
-#endif
+       udp_tunnel_get_rx_info(netdev);
 
        return 0;
 
@@ -7262,14 +7258,12 @@ static void ixgbe_service_task(struct work_struct *work)
                ixgbe_service_event_complete(adapter);
                return;
        }
-#ifdef CONFIG_IXGBE_VXLAN
-       rtnl_lock();
        if (adapter->flags2 & IXGBE_FLAG2_VXLAN_REREG_NEEDED) {
+               rtnl_lock();
                adapter->flags2 &= ~IXGBE_FLAG2_VXLAN_REREG_NEEDED;
-               vxlan_get_rx_port(adapter->netdev);
+               udp_tunnel_get_rx_info(adapter->netdev);
+               rtnl_unlock();
        }
-       rtnl_unlock();
-#endif /* CONFIG_IXGBE_VXLAN */
        ixgbe_reset_subtask(adapter);
        ixgbe_phy_interrupt_subtask(adapter);
        ixgbe_sfp_detection_subtask(adapter);
@@ -7697,7 +7691,6 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
        /* snag network header to get L4 type and address */
        skb = first->skb;
        hdr.network = skb_network_header(skb);
-#ifdef CONFIG_IXGBE_VXLAN
        if (skb->encapsulation &&
            first->protocol == htons(ETH_P_IP) &&
            hdr.ipv4->protocol != IPPROTO_UDP) {
@@ -7708,7 +7701,6 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
                    udp_hdr(skb)->dest == adapter->vxlan_port)
                        hdr.network = skb_inner_network_header(skb);
        }
-#endif /* CONFIG_IXGBE_VXLAN */
 
        /* Currently only IPv4/IPv6 with TCP is supported */
        switch (hdr.ipv4->version) {
@@ -8308,14 +8300,53 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc)
 static int ixgbe_delete_clsu32(struct ixgbe_adapter *adapter,
                               struct tc_cls_u32_offload *cls)
 {
+       u32 hdl = cls->knode.handle;
        u32 uhtid = TC_U32_USERHTID(cls->knode.handle);
-       u32 loc;
-       int err;
+       u32 loc = cls->knode.handle & 0xfffff;
+       int err = 0, i, j;
+       struct ixgbe_jump_table *jump = NULL;
+
+       if (loc > IXGBE_MAX_HW_ENTRIES)
+               return -EINVAL;
 
        if ((uhtid != 0x800) && (uhtid >= IXGBE_MAX_LINK_HANDLE))
                return -EINVAL;
 
-       loc = cls->knode.handle & 0xfffff;
+       /* Clear this filter in the link data it is associated with */
+       if (uhtid != 0x800) {
+               jump = adapter->jump_tables[uhtid];
+               if (!jump)
+                       return -EINVAL;
+               if (!test_bit(loc - 1, jump->child_loc_map))
+                       return -EINVAL;
+               clear_bit(loc - 1, jump->child_loc_map);
+       }
+
+       /* Check if the filter being deleted is a link */
+       for (i = 1; i < IXGBE_MAX_LINK_HANDLE; i++) {
+               jump = adapter->jump_tables[i];
+               if (jump && jump->link_hdl == hdl) {
+                       /* Delete filters in the hardware in the child hash
+                        * table associated with this link
+                        */
+                       for (j = 0; j < IXGBE_MAX_HW_ENTRIES; j++) {
+                               if (!test_bit(j, jump->child_loc_map))
+                                       continue;
+                               spin_lock(&adapter->fdir_perfect_lock);
+                               err = ixgbe_update_ethtool_fdir_entry(adapter,
+                                                                     NULL,
+                                                                     j + 1);
+                               spin_unlock(&adapter->fdir_perfect_lock);
+                               clear_bit(j, jump->child_loc_map);
+                       }
+                       /* Remove resources for this link */
+                       kfree(jump->input);
+                       kfree(jump->mask);
+                       kfree(jump);
+                       adapter->jump_tables[i] = NULL;
+                       return err;
+               }
+       }
 
        spin_lock(&adapter->fdir_perfect_lock);
        err = ixgbe_update_ethtool_fdir_entry(adapter, NULL, loc);
@@ -8549,6 +8580,18 @@ static int ixgbe_configure_clsu32(struct ixgbe_adapter *adapter,
                if (!test_bit(link_uhtid - 1, &adapter->tables))
                        return err;
 
+               /* Multiple filters as links to the same hash table are not
+                * supported. To add a new filter with the same next header
+                * but different match/jump conditions, create a new hash table
+                * and link to it.
+                */
+               if (adapter->jump_tables[link_uhtid] &&
+                   (adapter->jump_tables[link_uhtid])->link_hdl) {
+                       e_err(drv, "Link filter exists for link: %x\n",
+                             link_uhtid);
+                       return err;
+               }
+
                for (i = 0; nexthdr[i].jump; i++) {
                        if (nexthdr[i].o != cls->knode.sel->offoff ||
                            nexthdr[i].s != cls->knode.sel->offshift ||
@@ -8570,6 +8613,8 @@ static int ixgbe_configure_clsu32(struct ixgbe_adapter *adapter,
                        }
                        jump->input = input;
                        jump->mask = mask;
+                       jump->link_hdl = cls->knode.handle;
+
                        err = ixgbe_clsu32_build_input(input, mask, cls,
                                                       field_ptr, &nexthdr[i]);
                        if (!err) {
@@ -8597,6 +8642,20 @@ static int ixgbe_configure_clsu32(struct ixgbe_adapter *adapter,
                if ((adapter->jump_tables[uhtid])->mask)
                        memcpy(mask, (adapter->jump_tables[uhtid])->mask,
                               sizeof(*mask));
+
+               /* Lookup in all child hash tables if this location is already
+                * filled with a filter
+                */
+               for (i = 1; i < IXGBE_MAX_LINK_HANDLE; i++) {
+                       struct ixgbe_jump_table *link = adapter->jump_tables[i];
+
+                       if (link && (test_bit(loc - 1, link->child_loc_map))) {
+                               e_err(drv, "Filter exists in location: %x\n",
+                                     loc);
+                               err = -EINVAL;
+                               goto err_out;
+                       }
+               }
        }
        err = ixgbe_clsu32_build_input(input, mask, cls, field_ptr, NULL);
        if (err)
@@ -8628,6 +8687,9 @@ static int ixgbe_configure_clsu32(struct ixgbe_adapter *adapter,
                ixgbe_update_ethtool_fdir_entry(adapter, input, input->sw_idx);
        spin_unlock(&adapter->fdir_perfect_lock);
 
+       if ((uhtid != 0x800) && (adapter->jump_tables[uhtid]))
+               set_bit(loc - 1, (adapter->jump_tables[uhtid])->child_loc_map);
+
        kfree(mask);
        return err;
 err_out_w_lock:
@@ -8770,14 +8832,12 @@ static int ixgbe_set_features(struct net_device *netdev,
 
        netdev->features = features;
 
-#ifdef CONFIG_IXGBE_VXLAN
        if ((adapter->flags & IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE)) {
                if (features & NETIF_F_RXCSUM)
                        adapter->flags2 |= IXGBE_FLAG2_VXLAN_REREG_NEEDED;
                else
                        ixgbe_clear_vxlan_port(adapter);
        }
-#endif /* CONFIG_IXGBE_VXLAN */
 
        if (need_reset)
                ixgbe_do_reset(netdev);
@@ -8788,23 +8848,25 @@ static int ixgbe_set_features(struct net_device *netdev,
        return 0;
 }
 
-#ifdef CONFIG_IXGBE_VXLAN
 /**
  * ixgbe_add_vxlan_port - Get notifications about VXLAN ports that come up
  * @dev: The port's netdev
- * @sa_family: Socket Family that VXLAN is notifiying us about
- * @port: New UDP port number that VXLAN started listening to
+ * @ti: Tunnel endpoint information
  **/
-static void ixgbe_add_vxlan_port(struct net_device *dev, sa_family_t sa_family,
-                                __be16 port)
+static void ixgbe_add_vxlan_port(struct net_device *dev,
+                                struct udp_tunnel_info *ti)
 {
        struct ixgbe_adapter *adapter = netdev_priv(dev);
        struct ixgbe_hw *hw = &adapter->hw;
+       __be16 port = ti->port;
 
-       if (!(adapter->flags & IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE))
+       if (ti->type != UDP_TUNNEL_TYPE_VXLAN)
                return;
 
-       if (sa_family == AF_INET6)
+       if (ti->sa_family != AF_INET)
+               return;
+
+       if (!(adapter->flags & IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE))
                return;
 
        if (adapter->vxlan_port == port)
@@ -8824,30 +8886,31 @@ static void ixgbe_add_vxlan_port(struct net_device *dev, sa_family_t sa_family,
 /**
  * ixgbe_del_vxlan_port - Get notifications about VXLAN ports that go away
  * @dev: The port's netdev
- * @sa_family: Socket Family that VXLAN is notifying us about
- * @port: UDP port number that VXLAN stopped listening to
+ * @ti: Tunnel endpoint information
  **/
-static void ixgbe_del_vxlan_port(struct net_device *dev, sa_family_t sa_family,
-                                __be16 port)
+static void ixgbe_del_vxlan_port(struct net_device *dev,
+                                struct udp_tunnel_info *ti)
 {
        struct ixgbe_adapter *adapter = netdev_priv(dev);
 
-       if (!(adapter->flags & IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE))
+       if (ti->type != UDP_TUNNEL_TYPE_VXLAN)
                return;
 
-       if (sa_family == AF_INET6)
+       if (ti->sa_family != AF_INET)
                return;
 
-       if (adapter->vxlan_port != port) {
+       if (!(adapter->flags & IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE))
+               return;
+
+       if (adapter->vxlan_port != ti->port) {
                netdev_info(dev, "Port %d was not found, not deleting\n",
-                           ntohs(port));
+                           ntohs(ti->port));
                return;
        }
 
        ixgbe_clear_vxlan_port(adapter);
        adapter->flags2 |= IXGBE_FLAG2_VXLAN_REREG_NEEDED;
 }
-#endif /* CONFIG_IXGBE_VXLAN */
 
 static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
                             struct net_device *dev,
@@ -9160,10 +9223,8 @@ static const struct net_device_ops ixgbe_netdev_ops = {
        .ndo_bridge_getlink     = ixgbe_ndo_bridge_getlink,
        .ndo_dfwd_add_station   = ixgbe_fwd_add,
        .ndo_dfwd_del_station   = ixgbe_fwd_del,
-#ifdef CONFIG_IXGBE_VXLAN
-       .ndo_add_vxlan_port     = ixgbe_add_vxlan_port,
-       .ndo_del_vxlan_port     = ixgbe_del_vxlan_port,
-#endif /* CONFIG_IXGBE_VXLAN */
+       .ndo_udp_tunnel_add     = ixgbe_add_vxlan_port,
+       .ndo_udp_tunnel_del     = ixgbe_del_vxlan_port,
        .ndo_features_check     = ixgbe_features_check,
 };