enic: Add vxlan offload support for IPv6 pkts
authorGovindarajulu Varadarajan <gvaradar@cisco.com>
Thu, 1 Mar 2018 19:07:20 +0000 (11:07 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sun, 4 Mar 2018 23:19:25 +0000 (18:19 -0500)
New adaptors supports vxlan offload for inner IPv6 and outer IPv6 vxlan
pkts.

Fw sets BIT(0) & BIT(1) in a1 if hw supports ipv6 inner & outer pkt
offload.

Signed-off-by: Govindarajulu Varadarajan <gvaradar@cisco.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/cisco/enic/enic.h
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/cisco/enic/vnic_dev.c
drivers/net/ethernet/cisco/enic/vnic_dev.h
drivers/net/ethernet/cisco/enic/vnic_devcmd.h

index 9b218f0..83be9a5 100644 (file)
@@ -140,6 +140,7 @@ struct enic_rfs_flw_tbl {
 struct vxlan_offload {
        u16 vxlan_udp_port_number;
        u8 patch_level;
+       u8 flags;
 };
 
 /* Per-instance private data structure */
index 2522858..848aac4 100644 (file)
@@ -191,8 +191,16 @@ static void enic_udp_tunnel_add(struct net_device *netdev,
                goto error;
        }
 
-       if (ti->sa_family != AF_INET) {
-               netdev_info(netdev, "vxlan: only IPv4 offload supported");
+       switch (ti->sa_family) {
+       case AF_INET6:
+               if (!(enic->vxlan.flags & ENIC_VXLAN_OUTER_IPV6)) {
+                       netdev_info(netdev, "vxlan: only IPv4 offload supported");
+                       goto error;
+               }
+               /* Fall through */
+       case AF_INET:
+               break;
+       default:
                goto error;
        }
 
@@ -271,22 +279,37 @@ static netdev_features_t enic_features_check(struct sk_buff *skb,
        struct enic *enic = netdev_priv(dev);
        struct udphdr *udph;
        u16 port = 0;
-       u16 proto;
+       u8 proto;
 
        if (!skb->encapsulation)
                return features;
 
        features = vxlan_features_check(skb, features);
 
-       /* hardware only supports IPv4 vxlan tunnel */
-       if (vlan_get_protocol(skb) != htons(ETH_P_IP))
+       switch (vlan_get_protocol(skb)) {
+       case htons(ETH_P_IPV6):
+               if (!(enic->vxlan.flags & ENIC_VXLAN_OUTER_IPV6))
+                       goto out;
+               proto = ipv6_hdr(skb)->nexthdr;
+               break;
+       case htons(ETH_P_IP):
+               proto = ip_hdr(skb)->protocol;
+               break;
+       default:
                goto out;
+       }
 
-       /* hardware does not support offload of ipv6 inner pkt */
-       if (eth->h_proto != ntohs(ETH_P_IP))
+       switch (eth->h_proto) {
+       case ntohs(ETH_P_IPV6):
+               if (!(enic->vxlan.flags & ENIC_VXLAN_INNER_IPV6))
+                       goto out;
+               /* Fall through */
+       case ntohs(ETH_P_IP):
+               break;
+       default:
                goto out;
+       }
 
-       proto = ip_hdr(skb)->protocol;
 
        if (proto == IPPROTO_UDP) {
                udph = udp_hdr(skb);
@@ -2914,9 +2937,11 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                netdev->hw_features |= NETIF_F_RXCSUM;
        if (ENIC_SETTING(enic, VXLAN)) {
                u64 patch_level;
+               u64 a1 = 0;
 
                netdev->hw_enc_features |= NETIF_F_RXCSUM               |
                                           NETIF_F_TSO                  |
+                                          NETIF_F_TSO6                 |
                                           NETIF_F_TSO_ECN              |
                                           NETIF_F_GSO_UDP_TUNNEL       |
                                           NETIF_F_HW_CSUM              |
@@ -2935,9 +2960,10 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                 */
                err = vnic_dev_get_supported_feature_ver(enic->vdev,
                                                         VIC_FEATURE_VXLAN,
-                                                        &patch_level);
+                                                        &patch_level, &a1);
                if (err)
                        patch_level = 0;
+               enic->vxlan.flags = (u8)a1;
                /* mask bits that are supported by driver
                 */
                patch_level &= BIT_ULL(0) | BIT_ULL(2);
index 39bad67..b60fb6e 100644 (file)
@@ -1269,14 +1269,13 @@ int vnic_dev_overlay_offload_cfg(struct vnic_dev *vdev, u8 overlay,
 }
 
 int vnic_dev_get_supported_feature_ver(struct vnic_dev *vdev, u8 feature,
-                                      u64 *supported_versions)
+                                      u64 *supported_versions, u64 *a1)
 {
        u64 a0 = feature;
        int wait = 1000;
-       u64 a1 = 0;
        int ret;
 
-       ret = vnic_dev_cmd(vdev, CMD_GET_SUPP_FEATURE_VER, &a0, &a1, wait);
+       ret = vnic_dev_cmd(vdev, CMD_GET_SUPP_FEATURE_VER, &a0, a1, wait);
        if (!ret)
                *supported_versions = a0;
 
index 9d43d6b..db160f4 100644 (file)
@@ -183,6 +183,6 @@ int vnic_dev_overlay_offload_ctrl(struct vnic_dev *vdev, u8 overlay, u8 config);
 int vnic_dev_overlay_offload_cfg(struct vnic_dev *vdev, u8 overlay,
                                 u16 vxlan_udp_port_number);
 int vnic_dev_get_supported_feature_ver(struct vnic_dev *vdev, u8 feature,
-                                      u64 *supported_versions);
+                                      u64 *supported_versions, u64 *a1);
 
 #endif /* _VNIC_DEV_H_ */
index d83880b..69529a3 100644 (file)
@@ -697,6 +697,9 @@ enum overlay_ofld_cmd {
 
 #define OVERLAY_CFG_VXLAN_PORT_UPDATE  0
 
+#define ENIC_VXLAN_INNER_IPV6          BIT(0)
+#define ENIC_VXLAN_OUTER_IPV6          BIT(1)
+
 /* Use this enum to get the supported versions for each of these features
  * If you need to use the devcmd_get_supported_feature_version(), add
  * the new feature into this enum and install function handler in devcmd.c