|
@@ -50,6 +50,7 @@
|
|
|
#include <linux/if_bridge.h>
|
|
|
#include <linux/prefetch.h>
|
|
|
#include <scsi/fc/fc_fcoe.h>
|
|
|
+#include <net/vxlan.h>
|
|
|
|
|
|
#ifdef CONFIG_OF
|
|
|
#include <linux/of_net.h>
|
|
@@ -1396,12 +1397,23 @@ static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring,
|
|
|
union ixgbe_adv_rx_desc *rx_desc,
|
|
|
struct sk_buff *skb)
|
|
|
{
|
|
|
+ __le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
|
|
|
+ __le16 hdr_info = rx_desc->wb.lower.lo_dword.hs_rss.hdr_info;
|
|
|
+ bool encap_pkt = false;
|
|
|
+
|
|
|
skb_checksum_none_assert(skb);
|
|
|
|
|
|
/* Rx csum disabled */
|
|
|
if (!(ring->netdev->features & NETIF_F_RXCSUM))
|
|
|
return;
|
|
|
|
|
|
+ if ((pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_VXLAN)) &&
|
|
|
+ (hdr_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_TUNNEL >> 16))) {
|
|
|
+ encap_pkt = true;
|
|
|
+ skb->encapsulation = 1;
|
|
|
+ skb->ip_summed = CHECKSUM_NONE;
|
|
|
+ }
|
|
|
+
|
|
|
/* if IP and error */
|
|
|
if (ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_IPCS) &&
|
|
|
ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_IPE)) {
|
|
@@ -1413,8 +1425,6 @@ static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring,
|
|
|
return;
|
|
|
|
|
|
if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_TCPE)) {
|
|
|
- __le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
|
|
|
-
|
|
|
/*
|
|
|
* 82599 errata, UDP frames with a 0 checksum can be marked as
|
|
|
* checksum errors.
|
|
@@ -1429,6 +1439,17 @@ static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring,
|
|
|
|
|
|
/* It must be a TCP or UDP packet with a valid checksum */
|
|
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
|
+ if (encap_pkt) {
|
|
|
+ if (!ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_OUTERIPCS))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_OUTERIPER)) {
|
|
|
+ ring->rx_stats.csum_err++;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ /* If we checked the outer header let the stack know */
|
|
|
+ skb->csum_level = 1;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static bool ixgbe_alloc_mapped_page(struct ixgbe_ring *rx_ring,
|
|
@@ -5627,6 +5648,10 @@ static int ixgbe_open(struct net_device *netdev)
|
|
|
|
|
|
ixgbe_up_complete(adapter);
|
|
|
|
|
|
+#if IS_ENABLED(CONFIG_IXGBE_VXLAN)
|
|
|
+ vxlan_get_rx_port(netdev);
|
|
|
+
|
|
|
+#endif
|
|
|
return 0;
|
|
|
|
|
|
err_set_queues:
|
|
@@ -7771,6 +7796,64 @@ static int ixgbe_set_features(struct net_device *netdev,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 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
|
|
|
+ **/
|
|
|
+static void ixgbe_add_vxlan_port(struct net_device *dev, sa_family_t sa_family,
|
|
|
+ __be16 port)
|
|
|
+{
|
|
|
+ struct ixgbe_adapter *adapter = netdev_priv(dev);
|
|
|
+ struct ixgbe_hw *hw = &adapter->hw;
|
|
|
+ u16 new_port = ntohs(port);
|
|
|
+
|
|
|
+ if (sa_family == AF_INET6)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (adapter->vxlan_port == new_port) {
|
|
|
+ netdev_info(dev, "Port %d already offloaded\n", new_port);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (adapter->vxlan_port) {
|
|
|
+ netdev_info(dev,
|
|
|
+ "Hit Max num of UDP ports, not adding port %d\n",
|
|
|
+ new_port);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ adapter->vxlan_port = new_port;
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_VXLANCTRL, new_port);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 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
|
|
|
+ **/
|
|
|
+static void ixgbe_del_vxlan_port(struct net_device *dev, sa_family_t sa_family,
|
|
|
+ __be16 port)
|
|
|
+{
|
|
|
+ struct ixgbe_adapter *adapter = netdev_priv(dev);
|
|
|
+ struct ixgbe_hw *hw = &adapter->hw;
|
|
|
+ u16 new_port = ntohs(port);
|
|
|
+
|
|
|
+ if (sa_family == AF_INET6)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (adapter->vxlan_port != new_port) {
|
|
|
+ netdev_info(dev, "Port %d was not found, not deleting\n",
|
|
|
+ new_port);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ adapter->vxlan_port = 0;
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_VXLANCTRL, 0);
|
|
|
+}
|
|
|
+
|
|
|
static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
|
|
|
struct net_device *dev,
|
|
|
const unsigned char *addr, u16 vid,
|
|
@@ -7982,6 +8065,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,
|
|
|
+ .ndo_add_vxlan_port = ixgbe_add_vxlan_port,
|
|
|
+ .ndo_del_vxlan_port = ixgbe_del_vxlan_port,
|
|
|
};
|
|
|
|
|
|
/**
|
|
@@ -8339,6 +8424,15 @@ skip_sriov:
|
|
|
netdev->priv_flags |= IFF_UNICAST_FLT;
|
|
|
netdev->priv_flags |= IFF_SUPP_NOFCS;
|
|
|
|
|
|
+ switch (adapter->hw.mac.type) {
|
|
|
+ case ixgbe_mac_X550:
|
|
|
+ case ixgbe_mac_X550EM_x:
|
|
|
+ netdev->hw_enc_features |= NETIF_F_RXCSUM;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
#ifdef CONFIG_IXGBE_DCB
|
|
|
netdev->dcbnl_ops = &dcbnl_ops;
|
|
|
#endif
|