fsp->m_u.usr_ip4_spec.proto = 0;
        }
 
-       /* Reverse the src and dest notion, since the HW views them from
-        * Tx perspective where as the user expects it from Rx filter view.
-        */
-       fsp->h_u.tcp_ip4_spec.psrc = rule->dst_port;
-       fsp->h_u.tcp_ip4_spec.pdst = rule->src_port;
-       fsp->h_u.tcp_ip4_spec.ip4src = rule->dst_ip;
-       fsp->h_u.tcp_ip4_spec.ip4dst = rule->src_ip;
+       if (fsp->flow_type == IPV6_USER_FLOW ||
+           fsp->flow_type == UDP_V6_FLOW ||
+           fsp->flow_type == TCP_V6_FLOW ||
+           fsp->flow_type == SCTP_V6_FLOW) {
+               /* Reverse the src and dest notion, since the HW views them
+                * from Tx perspective where as the user expects it from
+                * Rx filter view.
+                */
+               fsp->h_u.tcp_ip6_spec.psrc = rule->dst_port;
+               fsp->h_u.tcp_ip6_spec.pdst = rule->src_port;
+               memcpy(fsp->h_u.tcp_ip6_spec.ip6dst, rule->src_ip6,
+                      sizeof(__be32) * 4);
+               memcpy(fsp->h_u.tcp_ip6_spec.ip6src, rule->dst_ip6,
+                      sizeof(__be32) * 4);
+       } else {
+               /* Reverse the src and dest notion, since the HW views them
+                * from Tx perspective where as the user expects it from
+                * Rx filter view.
+                */
+               fsp->h_u.tcp_ip4_spec.psrc = rule->dst_port;
+               fsp->h_u.tcp_ip4_spec.pdst = rule->src_port;
+               fsp->h_u.tcp_ip4_spec.ip4src = rule->dst_ip;
+               fsp->h_u.tcp_ip4_spec.ip4dst = rule->src_ip;
+       }
 
        switch (rule->flow_type) {
        case SCTP_V4_FLOW:
        case UDP_V4_FLOW:
                index = I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
                break;
+       case SCTP_V6_FLOW:
+               index = I40E_FILTER_PCTYPE_NONF_IPV6_SCTP;
+               break;
+       case TCP_V6_FLOW:
+               index = I40E_FILTER_PCTYPE_NONF_IPV6_TCP;
+               break;
+       case UDP_V6_FLOW:
+               index = I40E_FILTER_PCTYPE_NONF_IPV6_UDP;
+               break;
        case IP_USER_FLOW:
                index = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
                break;
+       case IPV6_USER_FLOW:
+               index = I40E_FILTER_PCTYPE_NONF_IPV6_OTHER;
+               break;
        default:
                /* If we have stored a filter with a flow type not listed here
                 * it is almost certainly a driver bug. WARN(), and then
        input_set = i40e_read_fd_input_set(pf, index);
 
 no_input_set:
+       if (input_set & I40E_L3_V6_SRC_MASK) {
+               fsp->m_u.tcp_ip6_spec.ip6src[0] = htonl(0xFFFFFFFF);
+               fsp->m_u.tcp_ip6_spec.ip6src[1] = htonl(0xFFFFFFFF);
+               fsp->m_u.tcp_ip6_spec.ip6src[2] = htonl(0xFFFFFFFF);
+               fsp->m_u.tcp_ip6_spec.ip6src[3] = htonl(0xFFFFFFFF);
+       }
+
+       if (input_set & I40E_L3_V6_DST_MASK) {
+               fsp->m_u.tcp_ip6_spec.ip6dst[0] = htonl(0xFFFFFFFF);
+               fsp->m_u.tcp_ip6_spec.ip6dst[1] = htonl(0xFFFFFFFF);
+               fsp->m_u.tcp_ip6_spec.ip6dst[2] = htonl(0xFFFFFFFF);
+               fsp->m_u.tcp_ip6_spec.ip6dst[3] = htonl(0xFFFFFFFF);
+       }
+
        if (input_set & I40E_L3_SRC_MASK)
                fsp->m_u.tcp_ip4_spec.ip4src = htonl(0xFFFFFFFF);
 
                return "sctp4";
        case IP_USER_FLOW:
                return "ip4";
+       case TCP_V6_FLOW:
+               return "tcp6";
+       case UDP_V6_FLOW:
+               return "udp6";
+       case SCTP_V6_FLOW:
+               return "sctp6";
+       case IPV6_USER_FLOW:
+               return "ip6";
        default:
                return "unknown";
        }
                                     struct ethtool_rx_flow_spec *fsp,
                                     struct i40e_rx_flow_userdef *userdef)
 {
-       struct i40e_pf *pf = vsi->back;
+       static const __be32 ipv6_full_mask[4] = {cpu_to_be32(0xffffffff),
+               cpu_to_be32(0xffffffff), cpu_to_be32(0xffffffff),
+               cpu_to_be32(0xffffffff)};
+       struct ethtool_tcpip6_spec *tcp_ip6_spec;
+       struct ethtool_usrip6_spec *usr_ip6_spec;
        struct ethtool_tcpip4_spec *tcp_ip4_spec;
        struct ethtool_usrip4_spec *usr_ip4_spec;
+       struct i40e_pf *pf = vsi->back;
        u64 current_mask, new_mask;
        bool new_flex_offset = false;
        bool flex_l3 = false;
                index = I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
                fdir_filter_count = &pf->fd_udp4_filter_cnt;
                break;
+       case SCTP_V6_FLOW:
+               index = I40E_FILTER_PCTYPE_NONF_IPV6_SCTP;
+               fdir_filter_count = &pf->fd_sctp6_filter_cnt;
+               break;
+       case TCP_V6_FLOW:
+               index = I40E_FILTER_PCTYPE_NONF_IPV6_TCP;
+               fdir_filter_count = &pf->fd_tcp6_filter_cnt;
+               break;
+       case UDP_V6_FLOW:
+               index = I40E_FILTER_PCTYPE_NONF_IPV6_UDP;
+               fdir_filter_count = &pf->fd_udp6_filter_cnt;
+               break;
        case IP_USER_FLOW:
                index = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
                fdir_filter_count = &pf->fd_ip4_filter_cnt;
                flex_l3 = true;
                break;
+       case IPV6_USER_FLOW:
+               index = I40E_FILTER_PCTYPE_NONF_IPV6_OTHER;
+               fdir_filter_count = &pf->fd_ip6_filter_cnt;
+               flex_l3 = true;
+               break;
        default:
                return -EOPNOTSUPP;
        }
                        return -EOPNOTSUPP;
 
                break;
+       case SCTP_V6_FLOW:
+               new_mask &= ~I40E_VERIFY_TAG_MASK;
+               fallthrough;
+       case TCP_V6_FLOW:
+       case UDP_V6_FLOW:
+               tcp_ip6_spec = &fsp->m_u.tcp_ip6_spec;
+
+               /* Check if user provided IPv6 source address. */
+               if (ipv6_addr_equal((struct in6_addr *)&tcp_ip6_spec->ip6src,
+                                   (struct in6_addr *)&ipv6_full_mask))
+                       new_mask |= I40E_L3_V6_SRC_MASK;
+               else if (ipv6_addr_any((struct in6_addr *)
+                                      &tcp_ip6_spec->ip6src))
+                       new_mask &= ~I40E_L3_V6_SRC_MASK;
+               else
+                       return -EOPNOTSUPP;
+
+               /* Check if user provided destination address. */
+               if (ipv6_addr_equal((struct in6_addr *)&tcp_ip6_spec->ip6dst,
+                                   (struct in6_addr *)&ipv6_full_mask))
+                       new_mask |= I40E_L3_V6_DST_MASK;
+               else if (ipv6_addr_any((struct in6_addr *)
+                                      &tcp_ip6_spec->ip6src))
+                       new_mask &= ~I40E_L3_V6_DST_MASK;
+               else
+                       return -EOPNOTSUPP;
+
+               /* L4 source port */
+               if (tcp_ip6_spec->psrc == htons(0xFFFF))
+                       new_mask |= I40E_L4_SRC_MASK;
+               else if (!tcp_ip6_spec->psrc)
+                       new_mask &= ~I40E_L4_SRC_MASK;
+               else
+                       return -EOPNOTSUPP;
+
+               /* L4 destination port */
+               if (tcp_ip6_spec->pdst == htons(0xFFFF))
+                       new_mask |= I40E_L4_DST_MASK;
+               else if (!tcp_ip6_spec->pdst)
+                       new_mask &= ~I40E_L4_DST_MASK;
+               else
+                       return -EOPNOTSUPP;
+
+               /* Filtering on Traffic Classes is not supported. */
+               if (tcp_ip6_spec->tclass)
+                       return -EOPNOTSUPP;
+               break;
        case IP_USER_FLOW:
                usr_ip4_spec = &fsp->m_u.usr_ip4_spec;
 
                if (usr_ip4_spec->proto)
                        return -EINVAL;
 
+               break;
+       case IPV6_USER_FLOW:
+               usr_ip6_spec = &fsp->m_u.usr_ip6_spec;
+
+               /* Check if user provided IPv6 source address. */
+               if (ipv6_addr_equal((struct in6_addr *)&usr_ip6_spec->ip6src,
+                                   (struct in6_addr *)&ipv6_full_mask))
+                       new_mask |= I40E_L3_V6_SRC_MASK;
+               else if (ipv6_addr_any((struct in6_addr *)
+                                      &usr_ip6_spec->ip6src))
+                       new_mask &= ~I40E_L3_V6_SRC_MASK;
+               else
+                       return -EOPNOTSUPP;
+
+               /* Check if user provided destination address. */
+               if (ipv6_addr_equal((struct in6_addr *)&usr_ip6_spec->ip6dst,
+                                   (struct in6_addr *)&ipv6_full_mask))
+                       new_mask |= I40E_L3_V6_DST_MASK;
+               else if (ipv6_addr_any((struct in6_addr *)
+                                      &usr_ip6_spec->ip6src))
+                       new_mask &= ~I40E_L3_V6_DST_MASK;
+               else
+                       return -EOPNOTSUPP;
+
+               if (usr_ip6_spec->l4_4_bytes == htonl(0xFFFFFFFF))
+                       new_mask |= I40E_L4_SRC_MASK | I40E_L4_DST_MASK;
+               else if (!usr_ip6_spec->l4_4_bytes)
+                       new_mask &= ~(I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
+               else
+                       return -EOPNOTSUPP;
+
+               /* Filtering on Traffic class is not supported. */
+               if (usr_ip6_spec->tclass)
+                       return -EOPNOTSUPP;
+
+               /* Filtering on L4 protocol is not supported */
+               if (usr_ip6_spec->l4_proto)
+                       return -EINVAL;
+
                break;
        default:
                return -EOPNOTSUPP;
            a->dst_port != b->dst_port ||
            a->src_port != b->src_port ||
            a->flow_type != b->flow_type ||
-           a->ip4_proto != b->ip4_proto)
+           a->ipl4_proto != b->ipl4_proto)
                return false;
 
        return true;
        input->dst_ip = fsp->h_u.tcp_ip4_spec.ip4src;
        input->src_ip = fsp->h_u.tcp_ip4_spec.ip4dst;
        input->flow_type = fsp->flow_type & ~FLOW_EXT;
-       input->ip4_proto = fsp->h_u.usr_ip4_spec.proto;
 
-       /* Reverse the src and dest notion, since the HW expects them to be from
-        * Tx perspective where as the input from user is from Rx filter view.
-        */
-       input->dst_port = fsp->h_u.tcp_ip4_spec.psrc;
-       input->src_port = fsp->h_u.tcp_ip4_spec.pdst;
-       input->dst_ip = fsp->h_u.tcp_ip4_spec.ip4src;
-       input->src_ip = fsp->h_u.tcp_ip4_spec.ip4dst;
+       if (input->flow_type == IPV6_USER_FLOW ||
+           input->flow_type == UDP_V6_FLOW ||
+           input->flow_type == TCP_V6_FLOW ||
+           input->flow_type == SCTP_V6_FLOW) {
+               /* Reverse the src and dest notion, since the HW expects them
+                * to be from Tx perspective where as the input from user is
+                * from Rx filter view.
+                */
+               input->ipl4_proto = fsp->h_u.usr_ip6_spec.l4_proto;
+               input->dst_port = fsp->h_u.tcp_ip6_spec.psrc;
+               input->src_port = fsp->h_u.tcp_ip6_spec.pdst;
+               memcpy(input->dst_ip6, fsp->h_u.ah_ip6_spec.ip6src,
+                      sizeof(__be32) * 4);
+               memcpy(input->src_ip6, fsp->h_u.ah_ip6_spec.ip6dst,
+                      sizeof(__be32) * 4);
+       } else {
+               /* Reverse the src and dest notion, since the HW expects them
+                * to be from Tx perspective where as the input from user is
+                * from Rx filter view.
+                */
+               input->ipl4_proto = fsp->h_u.usr_ip4_spec.proto;
+               input->dst_port = fsp->h_u.tcp_ip4_spec.psrc;
+               input->src_port = fsp->h_u.tcp_ip4_spec.pdst;
+               input->dst_ip = fsp->h_u.tcp_ip4_spec.ip4src;
+               input->src_ip = fsp->h_u.tcp_ip4_spec.ip4dst;
+       }
 
        if (userdef.flex_filter) {
                input->flex_filter = true;
 
        flex_ptype |= I40E_TXD_FLTR_QW0_PCTYPE_MASK &
                      (fdata->pctype << I40E_TXD_FLTR_QW0_PCTYPE_SHIFT);
 
-       flex_ptype |= I40E_TXD_FLTR_QW0_PCTYPE_MASK &
-                     (fdata->flex_offset << I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT);
-
        /* Use LAN VSI Id if not programmed by user */
        flex_ptype |= I40E_TXD_FLTR_QW0_DEST_VSI_MASK &
                      ((u32)(fdata->dest_vsi ? : pf->vsi[pf->lan_vsi]->id) <<
        return -1;
 }
 
-#define IP_HEADER_OFFSET 14
-#define I40E_UDPIP_DUMMY_PACKET_LEN 42
+#define IP_HEADER_OFFSET               14
+#define I40E_UDPIP_DUMMY_PACKET_LEN    42
+#define I40E_UDPIP6_DUMMY_PACKET_LEN   62
 /**
- * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 filters
+ * i40e_add_del_fdir_udp - Add/Remove UDP filters
  * @vsi: pointer to the targeted VSI
  * @fd_data: the flow director data required for the FDir descriptor
  * @add: true adds a filter, false removes it
+ * @ipv4: true is v4, false is v6
  *
  * Returns 0 if the filters were successfully added or removed
  **/
-static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
-                                  struct i40e_fdir_filter *fd_data,
-                                  bool add)
+static int i40e_add_del_fdir_udp(struct i40e_vsi *vsi,
+                                struct i40e_fdir_filter *fd_data,
+                                bool add,
+                                bool ipv4)
 {
        struct i40e_pf *pf = vsi->back;
+       struct ipv6hdr *ipv6;
        struct udphdr *udp;
        struct iphdr *ip;
        u8 *raw_packet;
        int ret;
-       static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
-               0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11, 0, 0, 0, 0, 0, 0,
-               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+       static char packet_ipv4[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08,
+               0, 0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+       static char packet_ipv6[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x86,
+               0xdd, 0x60, 0, 0, 0, 0, 0, 0x11, 0,
+               /*src address*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               /*dst address*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               /*udp header*/
+               0, 0, 0, 0, 0, 0, 0, 0};
 
        raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL);
        if (!raw_packet)
                return -ENOMEM;
-       memcpy(raw_packet, packet, I40E_UDPIP_DUMMY_PACKET_LEN);
+       if (ipv4) {
+               memcpy(raw_packet, packet_ipv4, I40E_UDPIP_DUMMY_PACKET_LEN);
 
-       ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
-       udp = (struct udphdr *)(raw_packet + IP_HEADER_OFFSET
-             + sizeof(struct iphdr));
+               ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
+               udp = (struct udphdr *)(raw_packet + IP_HEADER_OFFSET
+                     + sizeof(struct iphdr));
 
-       ip->daddr = fd_data->dst_ip;
+               ip->daddr = fd_data->dst_ip;
+               ip->saddr = fd_data->src_ip;
+       } else {
+               memcpy(raw_packet, packet_ipv6, I40E_UDPIP6_DUMMY_PACKET_LEN);
+               ipv6 = (struct ipv6hdr *)(raw_packet + IP_HEADER_OFFSET);
+               udp = (struct udphdr *)(raw_packet + IP_HEADER_OFFSET
+                     + sizeof(struct ipv6hdr));
+
+               memcpy(ipv6->saddr.in6_u.u6_addr32,
+                      fd_data->src_ip6, sizeof(__be32) * 4);
+               memcpy(ipv6->daddr.in6_u.u6_addr32,
+                      fd_data->dst_ip6, sizeof(__be32) * 4);
+       }
        udp->dest = fd_data->dst_port;
-       ip->saddr = fd_data->src_ip;
        udp->source = fd_data->src_port;
 
        if (fd_data->flex_filter) {
-               u8 *payload = raw_packet + I40E_UDPIP_DUMMY_PACKET_LEN;
+               u8 *payload;
                __be16 pattern = fd_data->flex_word;
                u16 off = fd_data->flex_offset;
 
+               if (ipv4)
+                       payload = raw_packet + I40E_UDPIP_DUMMY_PACKET_LEN;
+               else
+                       payload = raw_packet + I40E_UDPIP6_DUMMY_PACKET_LEN;
+
                *((__force __be16 *)(payload + off)) = pattern;
        }
 
-       fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
+       if (ipv4)
+               fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
+       else
+               fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV6_UDP;
+
        ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
        if (ret) {
                dev_info(&pf->pdev->dev,
                                 fd_data->pctype, fd_data->fd_id);
        }
 
-       if (add)
-               pf->fd_udp4_filter_cnt++;
-       else
-               pf->fd_udp4_filter_cnt--;
+       if (add) {
+               if (ipv4)
+                       pf->fd_udp4_filter_cnt++;
+               else
+                       pf->fd_udp6_filter_cnt++;
+       } else {
+               if (ipv4)
+                       pf->fd_udp4_filter_cnt--;
+               else
+                       pf->fd_udp6_filter_cnt--;
+       }
 
        return 0;
 }
 
-#define I40E_TCPIP_DUMMY_PACKET_LEN 54
+#define I40E_TCPIP_DUMMY_PACKET_LEN    54
+#define I40E_TCPIP6_DUMMY_PACKET_LEN   74
 /**
- * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 filters
+ * i40e_add_del_fdir_tcp - Add/Remove TCPv4 filters
  * @vsi: pointer to the targeted VSI
  * @fd_data: the flow director data required for the FDir descriptor
  * @add: true adds a filter, false removes it
+ * @ipv4: true is v4, false is v6
  *
  * Returns 0 if the filters were successfully added or removed
  **/
-static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
-                                  struct i40e_fdir_filter *fd_data,
-                                  bool add)
+static int i40e_add_del_fdir_tcp(struct i40e_vsi *vsi,
+                                struct i40e_fdir_filter *fd_data,
+                                bool add,
+                                bool ipv4)
 {
        struct i40e_pf *pf = vsi->back;
+       struct ipv6hdr *ipv6;
        struct tcphdr *tcp;
        struct iphdr *ip;
        u8 *raw_packet;
        int ret;
        /* Dummy packet */
-       static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
-               0x45, 0, 0, 0x28, 0, 0, 0x40, 0, 0x40, 0x6, 0, 0, 0, 0, 0, 0,
-               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0x11,
+       static char packet_ipv4[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08,
+               0, 0x45, 0, 0, 0x28, 0, 0, 0x40, 0, 0x40, 0x6, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x50, 0x11,
+               0x0, 0x72, 0, 0, 0, 0};
+       static char packet_ipv6[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x86,
+               0xdd, 0x60, 0, 0, 0, 0, 0, 0x6, 0,
+               /*src address*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               /*dst address*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x50, 0x11,
                0x0, 0x72, 0, 0, 0, 0};
 
        raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL);
        if (!raw_packet)
                return -ENOMEM;
-       memcpy(raw_packet, packet, I40E_TCPIP_DUMMY_PACKET_LEN);
+       if (ipv4) {
+               memcpy(raw_packet, packet_ipv4, I40E_TCPIP_DUMMY_PACKET_LEN);
+
+               ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
+               tcp = (struct tcphdr *)(raw_packet + IP_HEADER_OFFSET
+                     + sizeof(struct iphdr));
+
+               ip->daddr = fd_data->dst_ip;
+               ip->saddr = fd_data->src_ip;
+       } else {
+               memcpy(raw_packet, packet_ipv6, I40E_TCPIP6_DUMMY_PACKET_LEN);
+
+               tcp = (struct tcphdr *)(raw_packet + IP_HEADER_OFFSET
+                     + sizeof(struct ipv6hdr));
+               ipv6 = (struct ipv6hdr *)(raw_packet + IP_HEADER_OFFSET);
+
+               memcpy(ipv6->saddr.in6_u.u6_addr32,
+                      fd_data->src_ip6, sizeof(__be32) * 4);
+               memcpy(ipv6->daddr.in6_u.u6_addr32,
+                      fd_data->dst_ip6, sizeof(__be32) * 4);
+       }
 
        ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
        tcp = (struct tcphdr *)(raw_packet + IP_HEADER_OFFSET
              + sizeof(struct iphdr));
 
-       ip->daddr = fd_data->dst_ip;
        tcp->dest = fd_data->dst_port;
-       ip->saddr = fd_data->src_ip;
        tcp->source = fd_data->src_port;
 
        if (fd_data->flex_filter) {
-               u8 *payload = raw_packet + I40E_TCPIP_DUMMY_PACKET_LEN;
+               u8 *payload;
                __be16 pattern = fd_data->flex_word;
                u16 off = fd_data->flex_offset;
 
+               if (ipv4)
+                       payload = raw_packet + I40E_TCPIP_DUMMY_PACKET_LEN;
+               else
+                       payload = raw_packet + I40E_TCPIP6_DUMMY_PACKET_LEN;
+
                *((__force __be16 *)(payload + off)) = pattern;
        }
 
-       fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
+       if (ipv4)
+               fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
+       else
+               fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV6_TCP;
        ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
        if (ret) {
                dev_info(&pf->pdev->dev,
        }
 
        if (add) {
-               pf->fd_tcp4_filter_cnt++;
+               if (ipv4)
+                       pf->fd_tcp4_filter_cnt++;
+               else
+                       pf->fd_tcp6_filter_cnt++;
                if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
                    I40E_DEBUG_FD & pf->hw.debug_mask)
                        dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
                set_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state);
        } else {
-               pf->fd_tcp4_filter_cnt--;
+               if (ipv4)
+                       pf->fd_tcp4_filter_cnt--;
+               else
+                       pf->fd_tcp6_filter_cnt--;
        }
 
        return 0;
 }
 
-#define I40E_SCTPIP_DUMMY_PACKET_LEN 46
+#define I40E_SCTPIP_DUMMY_PACKET_LEN   46
+#define I40E_SCTPIP6_DUMMY_PACKET_LEN  66
 /**
- * i40e_add_del_fdir_sctpv4 - Add/Remove SCTPv4 Flow Director filters for
+ * i40e_add_del_fdir_sctp - Add/Remove SCTPv4 Flow Director filters for
  * a specific flow spec
  * @vsi: pointer to the targeted VSI
  * @fd_data: the flow director data required for the FDir descriptor
  * @add: true adds a filter, false removes it
+ * @ipv4: true is v4, false is v6
  *
  * Returns 0 if the filters were successfully added or removed
  **/
-static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi,
-                                   struct i40e_fdir_filter *fd_data,
-                                   bool add)
+static int i40e_add_del_fdir_sctp(struct i40e_vsi *vsi,
+                                 struct i40e_fdir_filter *fd_data,
+                                 bool add,
+                                 bool ipv4)
 {
        struct i40e_pf *pf = vsi->back;
+       struct ipv6hdr *ipv6;
        struct sctphdr *sctp;
        struct iphdr *ip;
        u8 *raw_packet;
        int ret;
-       /* Dummy packet */
-       static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
-               0x45, 0, 0, 0x20, 0, 0, 0x40, 0, 0x40, 0x84, 0, 0, 0, 0, 0, 0,
-               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
+       /* Dummy packets */
+       static char packet_ipv4[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08,
+               0, 0x45, 0, 0, 0x20, 0, 0, 0x40, 0, 0x40, 0x84, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+       static char packet_ipv6[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x86,
+               0xdd, 0x60, 0, 0, 0, 0, 0, 0x84, 0,
+               /*src address*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               /*dst address*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
        raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL);
        if (!raw_packet)
                return -ENOMEM;
-       memcpy(raw_packet, packet, I40E_SCTPIP_DUMMY_PACKET_LEN);
+       if (ipv4) {
+               memcpy(raw_packet, packet_ipv4, I40E_SCTPIP_DUMMY_PACKET_LEN);
 
-       ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
-       sctp = (struct sctphdr *)(raw_packet + IP_HEADER_OFFSET
-             + sizeof(struct iphdr));
+               ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
+               sctp = (struct sctphdr *)(raw_packet + IP_HEADER_OFFSET
+                      + sizeof(struct iphdr));
+
+               ip->daddr = fd_data->dst_ip;
+               ip->saddr = fd_data->src_ip;
+       } else {
+               memcpy(raw_packet, packet_ipv6, I40E_SCTPIP6_DUMMY_PACKET_LEN);
+
+               ipv6 = (struct ipv6hdr *)(raw_packet + IP_HEADER_OFFSET);
+               sctp = (struct sctphdr *)(raw_packet + IP_HEADER_OFFSET
+                      + sizeof(struct ipv6hdr));
+
+               memcpy(ipv6->saddr.in6_u.u6_addr32,
+                      fd_data->src_ip6, sizeof(__be32) * 4);
+               memcpy(ipv6->saddr.in6_u.u6_addr32,
+                      fd_data->src_ip6, sizeof(__be32) * 4);
+       }
 
-       ip->daddr = fd_data->dst_ip;
        sctp->dest = fd_data->dst_port;
-       ip->saddr = fd_data->src_ip;
        sctp->source = fd_data->src_port;
 
        if (fd_data->flex_filter) {
-               u8 *payload = raw_packet + I40E_SCTPIP_DUMMY_PACKET_LEN;
+               u8 *payload;
                __be16 pattern = fd_data->flex_word;
                u16 off = fd_data->flex_offset;
 
+               if (ipv4)
+                       payload = raw_packet + I40E_SCTPIP_DUMMY_PACKET_LEN;
+               else
+                       payload = raw_packet + I40E_SCTPIP6_DUMMY_PACKET_LEN;
                *((__force __be16 *)(payload + off)) = pattern;
        }
 
-       fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_SCTP;
+       if (ipv4)
+               fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_SCTP;
+       else
+               fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV6_SCTP;
+
        ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
        if (ret) {
                dev_info(&pf->pdev->dev,
                                 fd_data->pctype, fd_data->fd_id);
        }
 
-       if (add)
-               pf->fd_sctp4_filter_cnt++;
-       else
-               pf->fd_sctp4_filter_cnt--;
+       if (add) {
+               if (ipv4)
+                       pf->fd_sctp4_filter_cnt++;
+               else
+                       pf->fd_sctp6_filter_cnt++;
+       } else {
+               if (ipv4)
+                       pf->fd_sctp4_filter_cnt--;
+               else
+                       pf->fd_sctp6_filter_cnt--;
+       }
 
        return 0;
 }
 
-#define I40E_IP_DUMMY_PACKET_LEN 34
+#define I40E_IP_DUMMY_PACKET_LEN       34
+#define I40E_IP6_DUMMY_PACKET_LEN      54
 /**
- * i40e_add_del_fdir_ipv4 - Add/Remove IPv4 Flow Director filters for
+ * i40e_add_del_fdir_ip - Add/Remove IPv4 Flow Director filters for
  * a specific flow spec
  * @vsi: pointer to the targeted VSI
  * @fd_data: the flow director data required for the FDir descriptor
  * @add: true adds a filter, false removes it
+ * @ipv4: true is v4, false is v6
  *
  * Returns 0 if the filters were successfully added or removed
  **/
-static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
-                                 struct i40e_fdir_filter *fd_data,
-                                 bool add)
+static int i40e_add_del_fdir_ip(struct i40e_vsi *vsi,
+                               struct i40e_fdir_filter *fd_data,
+                               bool add,
+                               bool ipv4)
 {
        struct i40e_pf *pf = vsi->back;
+       struct ipv6hdr *ipv6;
        struct iphdr *ip;
        u8 *raw_packet;
+       int iter_start;
+       int iter_end;
        int ret;
        int i;
-       static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
-               0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10, 0, 0, 0, 0, 0, 0,
-               0, 0, 0, 0};
+       static char packet_ipv4[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08,
+               0, 0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0};
+       static char packet_ipv6[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x86,
+               0xdd, 0x60, 0, 0, 0, 0, 0, 0, 0,
+               /*src address*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               /*dst address*/0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+       if (ipv4) {
+               iter_start = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
+               iter_end = I40E_FILTER_PCTYPE_FRAG_IPV4;
+       } else {
+               iter_start = I40E_FILTER_PCTYPE_NONF_IPV6_OTHER;
+               iter_end = I40E_FILTER_PCTYPE_FRAG_IPV6;
+       }
 
-       for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
-            i <= I40E_FILTER_PCTYPE_FRAG_IPV4; i++) {
+       for (i = iter_start; i <= iter_end; i++) {
                raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL);
                if (!raw_packet)
                        return -ENOMEM;
-               memcpy(raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN);
-               ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
-
-               ip->saddr = fd_data->src_ip;
-               ip->daddr = fd_data->dst_ip;
-               ip->protocol = 0;
+               if (ipv4) {
+                       memcpy(raw_packet, packet_ipv4,
+                              I40E_IP_DUMMY_PACKET_LEN);
+                       ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
+
+                       ip->saddr = fd_data->src_ip;
+                       ip->daddr = fd_data->dst_ip;
+                       ip->protocol = IPPROTO_IP;
+               } else {
+                       memcpy(raw_packet, packet_ipv6,
+                              I40E_IP6_DUMMY_PACKET_LEN);
+                       ipv6 = (struct ipv6hdr *)(raw_packet +
+                                                 IP_HEADER_OFFSET);
+                       memcpy(ipv6->saddr.in6_u.u6_addr32,
+                              fd_data->src_ip6, sizeof(__be32) * 4);
+                       memcpy(ipv6->daddr.in6_u.u6_addr32,
+                              fd_data->dst_ip6, sizeof(__be32) * 4);
+
+                       ipv6->nexthdr = IPPROTO_NONE;
+               }
 
                if (fd_data->flex_filter) {
-                       u8 *payload = raw_packet + I40E_IP_DUMMY_PACKET_LEN;
+                       u8 *payload;
                        __be16 pattern = fd_data->flex_word;
                        u16 off = fd_data->flex_offset;
 
+                       if (ipv4)
+                               payload = raw_packet + I40E_IP_DUMMY_PACKET_LEN;
+                       else
+                               payload = raw_packet +
+                                         I40E_IP6_DUMMY_PACKET_LEN;
                        *((__force __be16 *)(payload + off)) = pattern;
                }
 
                }
        }
 
-       if (add)
-               pf->fd_ip4_filter_cnt++;
-       else
-               pf->fd_ip4_filter_cnt--;
+       if (add) {
+               if (ipv4)
+                       pf->fd_ip4_filter_cnt++;
+               else
+                       pf->fd_ip6_filter_cnt++;
+       } else {
+               if (ipv4)
+                       pf->fd_ip4_filter_cnt--;
+               else
+                       pf->fd_ip6_filter_cnt--;
+       }
 
        return 0;
 }
 int i40e_add_del_fdir(struct i40e_vsi *vsi,
                      struct i40e_fdir_filter *input, bool add)
 {
+       enum ip_ver { ipv6 = 0, ipv4 = 1 };
        struct i40e_pf *pf = vsi->back;
        int ret;
 
        switch (input->flow_type & ~FLOW_EXT) {
        case TCP_V4_FLOW:
-               ret = i40e_add_del_fdir_tcpv4(vsi, input, add);
+               ret = i40e_add_del_fdir_tcp(vsi, input, add, ipv4);
                break;
        case UDP_V4_FLOW:
-               ret = i40e_add_del_fdir_udpv4(vsi, input, add);
+               ret = i40e_add_del_fdir_udp(vsi, input, add, ipv4);
                break;
        case SCTP_V4_FLOW:
-               ret = i40e_add_del_fdir_sctpv4(vsi, input, add);
+               ret = i40e_add_del_fdir_sctp(vsi, input, add, ipv4);
+               break;
+       case TCP_V6_FLOW:
+               ret = i40e_add_del_fdir_tcp(vsi, input, add, ipv6);
+               break;
+       case UDP_V6_FLOW:
+               ret = i40e_add_del_fdir_udp(vsi, input, add, ipv6);
+               break;
+       case SCTP_V6_FLOW:
+               ret = i40e_add_del_fdir_sctp(vsi, input, add, ipv6);
                break;
        case IP_USER_FLOW:
-               switch (input->ip4_proto) {
+               switch (input->ipl4_proto) {
                case IPPROTO_TCP:
-                       ret = i40e_add_del_fdir_tcpv4(vsi, input, add);
+                       ret = i40e_add_del_fdir_tcp(vsi, input, add, ipv4);
                        break;
                case IPPROTO_UDP:
-                       ret = i40e_add_del_fdir_udpv4(vsi, input, add);
+                       ret = i40e_add_del_fdir_udp(vsi, input, add, ipv4);
                        break;
                case IPPROTO_SCTP:
-                       ret = i40e_add_del_fdir_sctpv4(vsi, input, add);
+                       ret = i40e_add_del_fdir_sctp(vsi, input, add, ipv4);
                        break;
                case IPPROTO_IP:
-                       ret = i40e_add_del_fdir_ipv4(vsi, input, add);
+                       ret = i40e_add_del_fdir_ip(vsi, input, add, ipv4);
                        break;
                default:
                        /* We cannot support masking based on protocol */
                        dev_info(&pf->pdev->dev, "Unsupported IPv4 protocol 0x%02x\n",
-                                input->ip4_proto);
+                                input->ipl4_proto);
+                       return -EINVAL;
+               }
+               break;
+       case IPV6_USER_FLOW:
+               switch (input->ipl4_proto) {
+               case IPPROTO_TCP:
+                       ret = i40e_add_del_fdir_tcp(vsi, input, add, ipv6);
+                       break;
+               case IPPROTO_UDP:
+                       ret = i40e_add_del_fdir_udp(vsi, input, add, ipv6);
+                       break;
+               case IPPROTO_SCTP:
+                       ret = i40e_add_del_fdir_sctp(vsi, input, add, ipv6);
+                       break;
+               case IPPROTO_IP:
+                       ret = i40e_add_del_fdir_ip(vsi, input, add, ipv6);
+                       break;
+               default:
+                       /* We cannot support masking based on protocol */
+                       dev_info(&pf->pdev->dev, "Unsupported IPv6 protocol 0x%02x\n",
+                                input->ipl4_proto);
                        return -EINVAL;
                }
                break;