* @input: unique input dword
* @common: compressed common input dword
* @queue: queue index to direct traffic to
+ *
+ * Note that the tunnel bit in input must not be set when the hardware
+ * tunneling support does not exist.
**/
s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
union ixgbe_atr_hash_dword input,
union ixgbe_atr_hash_dword common,
u8 queue)
{
- u64 fdirhashcmd;
- u32 fdircmd;
+ u64 fdirhashcmd;
+ u8 flow_type;
+ bool tunnel;
+ u32 fdircmd;
/*
* Get the flow_type in order to program FDIRCMD properly
* lowest 2 bits are FDIRCMD.L4TYPE, third lowest bit is FDIRCMD.IPV6
*/
- switch (input.formatted.flow_type) {
+ tunnel = !!(input.formatted.flow_type & IXGBE_ATR_L4TYPE_TUNNEL_MASK);
+ flow_type = input.formatted.flow_type &
+ (IXGBE_ATR_L4TYPE_TUNNEL_MASK - 1);
+ switch (flow_type) {
case IXGBE_ATR_FLOW_TYPE_TCPV4:
case IXGBE_ATR_FLOW_TYPE_UDPV4:
case IXGBE_ATR_FLOW_TYPE_SCTPV4:
/* configure FDIRCMD register */
fdircmd = IXGBE_FDIRCMD_CMD_ADD_FLOW | IXGBE_FDIRCMD_FILTER_UPDATE |
IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN;
- fdircmd |= input.formatted.flow_type << IXGBE_FDIRCMD_FLOW_TYPE_SHIFT;
+ fdircmd |= (u32)flow_type << IXGBE_FDIRCMD_FLOW_TYPE_SHIFT;
fdircmd |= (u32)queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT;
+ if (tunnel)
+ fdircmd |= IXGBE_FDIRCMD_TUNNEL_FILTER;
/*
* The lower 32-bits of fdirhashcmd is for FDIRHASH, the upper 32-bits
/*******************************************************************************
Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2014 Intel Corporation.
+ Copyright(c) 1999 - 2015 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
#include "ixgbe_common.h"
#include "ixgbe_dcb_82599.h"
#include "ixgbe_sriov.h"
+#ifdef CONFIG_IXGBE_VXLAN
+#include <net/vxlan.h>
+#endif
char ixgbe_driver_name[] = "ixgbe";
static const char ixgbe_driver_string[] =
#define DRV_VERSION "4.0.1-k"
const char ixgbe_driver_version[] = DRV_VERSION;
static const char ixgbe_copyright[] =
- "Copyright (c) 1999-2014 Intel Corporation.";
+ "Copyright (c) 1999-2015 Intel Corporation.";
static const char ixgbe_overheat_msg[] = "Network adapter has been stopped because it has over heated. Restart the computer. If the problem persists, power off the system and replace the adapter";
(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 */
}
}
+static void ixgbe_clear_vxlan_port(struct ixgbe_adapter *adapter)
+{
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_VXLANCTRL, 0);
+#ifdef CONFIG_IXGBE_VXLAN
+ adapter->vxlan_port = 0;
+#endif
+ break;
+ default:
+ break;
+ }
+}
+
#ifdef CONFIG_IXGBE_DCB
/**
* ixgbe_configure_dcb - Configure DCB hardware
case ixgbe_mac_X550:
#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:
ixgbe_up_complete(adapter);
-#if IS_ENABLED(CONFIG_IXGBE_VXLAN)
+ ixgbe_clear_vxlan_port(adapter);
+#ifdef CONFIG_IXGBE_VXLAN
vxlan_get_rx_port(netdev);
-
#endif
+
return 0;
err_set_queues:
ixgbe_service_event_complete(adapter);
return;
}
+#ifdef CONFIG_IXGBE_VXLAN
+ if (adapter->flags2 & IXGBE_FLAG2_VXLAN_REREG_NEEDED) {
+ adapter->flags2 &= ~IXGBE_FLAG2_VXLAN_REREG_NEEDED;
+ vxlan_get_rx_port(adapter->netdev);
+ }
+#endif /* CONFIG_IXGBE_VXLAN */
ixgbe_reset_subtask(adapter);
ixgbe_phy_interrupt_subtask(adapter);
ixgbe_sfp_detection_subtask(adapter);
struct ipv6hdr *ipv6;
} hdr;
struct tcphdr *th;
+ struct sk_buff *skb;
+#ifdef CONFIG_IXGBE_VXLAN
+ u8 encap = false;
+#endif /* CONFIG_IXGBE_VXLAN */
__be16 vlan_id;
/* if ring doesn't have a interrupt vector, cannot perform ATR */
ring->atr_count++;
/* snag network header to get L4 type and address */
- hdr.network = skb_network_header(first->skb);
+ skb = first->skb;
+ hdr.network = skb_network_header(skb);
+ if (skb->encapsulation) {
+#ifdef CONFIG_IXGBE_VXLAN
+ struct ixgbe_adapter *adapter = q_vector->adapter;
- /* Currently only IPv4/IPv6 with TCP is supported */
- if ((first->protocol != htons(ETH_P_IPV6) ||
- hdr.ipv6->nexthdr != IPPROTO_TCP) &&
- (first->protocol != htons(ETH_P_IP) ||
- hdr.ipv4->protocol != IPPROTO_TCP))
+ if (!adapter->vxlan_port)
+ return;
+ if (first->protocol != htons(ETH_P_IP) ||
+ hdr.ipv4->version != IPVERSION ||
+ hdr.ipv4->protocol != IPPROTO_UDP) {
+ return;
+ }
+ if (ntohs(udp_hdr(skb)->dest) != adapter->vxlan_port)
+ return;
+ encap = true;
+ hdr.network = skb_inner_network_header(skb);
+ th = inner_tcp_hdr(skb);
+#else
return;
-
- th = tcp_hdr(first->skb);
+#endif /* CONFIG_IXGBE_VXLAN */
+ } else {
+ /* Currently only IPv4/IPv6 with TCP is supported */
+ if ((first->protocol != htons(ETH_P_IPV6) ||
+ hdr.ipv6->nexthdr != IPPROTO_TCP) &&
+ (first->protocol != htons(ETH_P_IP) ||
+ hdr.ipv4->protocol != IPPROTO_TCP))
+ return;
+ th = tcp_hdr(skb);
+ }
/* skip this packet since it is invalid or the socket is closing */
if (!th || th->fin)
hdr.ipv6->daddr.s6_addr32[3];
}
+#ifdef CONFIG_IXGBE_VXLAN
+ if (encap)
+ input.formatted.flow_type |= IXGBE_ATR_L4TYPE_TUNNEL_MASK;
+#endif /* CONFIG_IXGBE_VXLAN */
+
/* This assumes the Rx queue and Tx queue are bound to the same CPU */
ixgbe_fdir_add_signature_filter_82599(&q_vector->adapter->hw,
input, common, ring->queue_index);
need_reset = true;
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);
return 0;
}
+#ifdef CONFIG_IXGBE_VXLAN
/**
* ixgbe_add_vxlan_port - Get notifications about VXLAN ports that come up
* @dev: The port's netdev
struct ixgbe_hw *hw = &adapter->hw;
u16 new_port = ntohs(port);
+ if (!(adapter->flags & IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE))
+ return;
+
if (sa_family == AF_INET6)
return;
- if (adapter->vxlan_port == new_port) {
- netdev_info(dev, "Port %d already offloaded\n", new_port);
+ if (adapter->vxlan_port == new_port)
return;
- }
if (adapter->vxlan_port) {
netdev_info(dev,
- "Hit Max num of UDP ports, not adding port %d\n",
+ "Hit Max num of VXLAN ports, not adding port %d\n",
new_port);
return;
}
__be16 port)
{
struct ixgbe_adapter *adapter = netdev_priv(dev);
- struct ixgbe_hw *hw = &adapter->hw;
u16 new_port = ntohs(port);
+ if (!(adapter->flags & IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE))
+ return;
+
if (sa_family == AF_INET6)
return;
return;
}
- adapter->vxlan_port = 0;
- IXGBE_WRITE_REG(hw, IXGBE_VXLANCTRL, 0);
+ 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,
.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_features_check = ixgbe_features_check,
};
netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->priv_flags |= IFF_SUPP_NOFCS;
+#ifdef CONFIG_IXGBE_VXLAN
switch (adapter->hw.mac.type) {
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
- netdev->hw_enc_features |= NETIF_F_RXCSUM;
+ netdev->hw_enc_features |= NETIF_F_RXCSUM |
+ NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM;
break;
default:
break;
}
+#endif /* CONFIG_IXGBE_VXLAN */
#ifdef CONFIG_IXGBE_DCB
netdev->dcbnl_ops = &dcbnl_ops;