Commit e90cbc25 authored by Haiyue Wang's avatar Haiyue Wang Committed by Tony Nguyen

iavf: Support IPv6 Flow Director filters

Support the addition and deletion of IPv6 filters.

Supported fields are: src-ip, dst-ip, src-port, dst-port and l4proto
Supported flow-types are: tcp6, udp6, sctp6, ip6, ah6, esp6

Example usage:
ethtool -N ens787f0v0 flow-type tcp6 src-ip 2001::2 \
  dst-ip CDCD:910A:2222:5498:8475:1111:3900:2020 \
  tclass 1 src-port 22 dst-port 23 action 7

L2TPv3 over IP with 'Session ID' 17:
ethtool -N ens787f0v0 flow-type ip6 l4proto 115 l4data 17 action 7
Signed-off-by: default avatarHaiyue Wang <haiyue.wang@intel.com>
Tested-by: default avatarChen Bo <BoX.C.Chen@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent 527691bf
...@@ -849,6 +849,18 @@ static int iavf_fltr_to_ethtool_flow(enum iavf_fdir_flow_type flow) ...@@ -849,6 +849,18 @@ static int iavf_fltr_to_ethtool_flow(enum iavf_fdir_flow_type flow)
return ESP_V4_FLOW; return ESP_V4_FLOW;
case IAVF_FDIR_FLOW_IPV4_OTHER: case IAVF_FDIR_FLOW_IPV4_OTHER:
return IPV4_USER_FLOW; return IPV4_USER_FLOW;
case IAVF_FDIR_FLOW_IPV6_TCP:
return TCP_V6_FLOW;
case IAVF_FDIR_FLOW_IPV6_UDP:
return UDP_V6_FLOW;
case IAVF_FDIR_FLOW_IPV6_SCTP:
return SCTP_V6_FLOW;
case IAVF_FDIR_FLOW_IPV6_AH:
return AH_V6_FLOW;
case IAVF_FDIR_FLOW_IPV6_ESP:
return ESP_V6_FLOW;
case IAVF_FDIR_FLOW_IPV6_OTHER:
return IPV6_USER_FLOW;
default: default:
/* 0 is undefined ethtool flow */ /* 0 is undefined ethtool flow */
return 0; return 0;
...@@ -876,6 +888,18 @@ static enum iavf_fdir_flow_type iavf_ethtool_flow_to_fltr(int eth) ...@@ -876,6 +888,18 @@ static enum iavf_fdir_flow_type iavf_ethtool_flow_to_fltr(int eth)
return IAVF_FDIR_FLOW_IPV4_ESP; return IAVF_FDIR_FLOW_IPV4_ESP;
case IPV4_USER_FLOW: case IPV4_USER_FLOW:
return IAVF_FDIR_FLOW_IPV4_OTHER; return IAVF_FDIR_FLOW_IPV4_OTHER;
case TCP_V6_FLOW:
return IAVF_FDIR_FLOW_IPV6_TCP;
case UDP_V6_FLOW:
return IAVF_FDIR_FLOW_IPV6_UDP;
case SCTP_V6_FLOW:
return IAVF_FDIR_FLOW_IPV6_SCTP;
case AH_V6_FLOW:
return IAVF_FDIR_FLOW_IPV6_AH;
case ESP_V6_FLOW:
return IAVF_FDIR_FLOW_IPV6_ESP;
case IPV6_USER_FLOW:
return IAVF_FDIR_FLOW_IPV6_OTHER;
default: default:
return IAVF_FDIR_FLOW_NONE; return IAVF_FDIR_FLOW_NONE;
} }
...@@ -952,6 +976,55 @@ iavf_get_ethtool_fdir_entry(struct iavf_adapter *adapter, ...@@ -952,6 +976,55 @@ iavf_get_ethtool_fdir_entry(struct iavf_adapter *adapter,
fsp->m_u.usr_ip4_spec.ip_ver = 0xFF; fsp->m_u.usr_ip4_spec.ip_ver = 0xFF;
fsp->m_u.usr_ip4_spec.proto = rule->ip_mask.proto; fsp->m_u.usr_ip4_spec.proto = rule->ip_mask.proto;
break; break;
case TCP_V6_FLOW:
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
memcpy(fsp->h_u.usr_ip6_spec.ip6src, &rule->ip_data.v6_addrs.src_ip,
sizeof(struct in6_addr));
memcpy(fsp->h_u.usr_ip6_spec.ip6dst, &rule->ip_data.v6_addrs.dst_ip,
sizeof(struct in6_addr));
fsp->h_u.tcp_ip6_spec.psrc = rule->ip_data.src_port;
fsp->h_u.tcp_ip6_spec.pdst = rule->ip_data.dst_port;
fsp->h_u.tcp_ip6_spec.tclass = rule->ip_data.tclass;
memcpy(fsp->m_u.usr_ip6_spec.ip6src, &rule->ip_mask.v6_addrs.src_ip,
sizeof(struct in6_addr));
memcpy(fsp->m_u.usr_ip6_spec.ip6dst, &rule->ip_mask.v6_addrs.dst_ip,
sizeof(struct in6_addr));
fsp->m_u.tcp_ip6_spec.psrc = rule->ip_mask.src_port;
fsp->m_u.tcp_ip6_spec.pdst = rule->ip_mask.dst_port;
fsp->m_u.tcp_ip6_spec.tclass = rule->ip_mask.tclass;
break;
case AH_V6_FLOW:
case ESP_V6_FLOW:
memcpy(fsp->h_u.ah_ip6_spec.ip6src, &rule->ip_data.v6_addrs.src_ip,
sizeof(struct in6_addr));
memcpy(fsp->h_u.ah_ip6_spec.ip6dst, &rule->ip_data.v6_addrs.dst_ip,
sizeof(struct in6_addr));
fsp->h_u.ah_ip6_spec.spi = rule->ip_data.spi;
fsp->h_u.ah_ip6_spec.tclass = rule->ip_data.tclass;
memcpy(fsp->m_u.ah_ip6_spec.ip6src, &rule->ip_mask.v6_addrs.src_ip,
sizeof(struct in6_addr));
memcpy(fsp->m_u.ah_ip6_spec.ip6dst, &rule->ip_mask.v6_addrs.dst_ip,
sizeof(struct in6_addr));
fsp->m_u.ah_ip6_spec.spi = rule->ip_mask.spi;
fsp->m_u.ah_ip6_spec.tclass = rule->ip_mask.tclass;
break;
case IPV6_USER_FLOW:
memcpy(fsp->h_u.usr_ip6_spec.ip6src, &rule->ip_data.v6_addrs.src_ip,
sizeof(struct in6_addr));
memcpy(fsp->h_u.usr_ip6_spec.ip6dst, &rule->ip_data.v6_addrs.dst_ip,
sizeof(struct in6_addr));
fsp->h_u.usr_ip6_spec.l4_4_bytes = rule->ip_data.l4_header;
fsp->h_u.usr_ip6_spec.tclass = rule->ip_data.tclass;
fsp->h_u.usr_ip6_spec.l4_proto = rule->ip_data.proto;
memcpy(fsp->m_u.usr_ip6_spec.ip6src, &rule->ip_mask.v6_addrs.src_ip,
sizeof(struct in6_addr));
memcpy(fsp->m_u.usr_ip6_spec.ip6dst, &rule->ip_mask.v6_addrs.dst_ip,
sizeof(struct in6_addr));
fsp->m_u.usr_ip6_spec.l4_4_bytes = rule->ip_mask.l4_header;
fsp->m_u.usr_ip6_spec.tclass = rule->ip_mask.tclass;
fsp->m_u.usr_ip6_spec.l4_proto = rule->ip_mask.proto;
break;
default: default:
ret = -EINVAL; ret = -EINVAL;
break; break;
...@@ -1075,6 +1148,55 @@ iavf_add_fdir_fltr_info(struct iavf_adapter *adapter, struct ethtool_rx_flow_spe ...@@ -1075,6 +1148,55 @@ iavf_add_fdir_fltr_info(struct iavf_adapter *adapter, struct ethtool_rx_flow_spe
fltr->ip_mask.tos = fsp->m_u.usr_ip4_spec.tos; fltr->ip_mask.tos = fsp->m_u.usr_ip4_spec.tos;
fltr->ip_mask.proto = fsp->m_u.usr_ip4_spec.proto; fltr->ip_mask.proto = fsp->m_u.usr_ip4_spec.proto;
break; break;
case TCP_V6_FLOW:
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
memcpy(&fltr->ip_data.v6_addrs.src_ip, fsp->h_u.usr_ip6_spec.ip6src,
sizeof(struct in6_addr));
memcpy(&fltr->ip_data.v6_addrs.dst_ip, fsp->h_u.usr_ip6_spec.ip6dst,
sizeof(struct in6_addr));
fltr->ip_data.src_port = fsp->h_u.tcp_ip6_spec.psrc;
fltr->ip_data.dst_port = fsp->h_u.tcp_ip6_spec.pdst;
fltr->ip_data.tclass = fsp->h_u.tcp_ip6_spec.tclass;
memcpy(&fltr->ip_mask.v6_addrs.src_ip, fsp->m_u.usr_ip6_spec.ip6src,
sizeof(struct in6_addr));
memcpy(&fltr->ip_mask.v6_addrs.dst_ip, fsp->m_u.usr_ip6_spec.ip6dst,
sizeof(struct in6_addr));
fltr->ip_mask.src_port = fsp->m_u.tcp_ip6_spec.psrc;
fltr->ip_mask.dst_port = fsp->m_u.tcp_ip6_spec.pdst;
fltr->ip_mask.tclass = fsp->m_u.tcp_ip6_spec.tclass;
break;
case AH_V6_FLOW:
case ESP_V6_FLOW:
memcpy(&fltr->ip_data.v6_addrs.src_ip, fsp->h_u.ah_ip6_spec.ip6src,
sizeof(struct in6_addr));
memcpy(&fltr->ip_data.v6_addrs.dst_ip, fsp->h_u.ah_ip6_spec.ip6dst,
sizeof(struct in6_addr));
fltr->ip_data.spi = fsp->h_u.ah_ip6_spec.spi;
fltr->ip_data.tclass = fsp->h_u.ah_ip6_spec.tclass;
memcpy(&fltr->ip_mask.v6_addrs.src_ip, fsp->m_u.ah_ip6_spec.ip6src,
sizeof(struct in6_addr));
memcpy(&fltr->ip_mask.v6_addrs.dst_ip, fsp->m_u.ah_ip6_spec.ip6dst,
sizeof(struct in6_addr));
fltr->ip_mask.spi = fsp->m_u.ah_ip6_spec.spi;
fltr->ip_mask.tclass = fsp->m_u.ah_ip6_spec.tclass;
break;
case IPV6_USER_FLOW:
memcpy(&fltr->ip_data.v6_addrs.src_ip, fsp->h_u.usr_ip6_spec.ip6src,
sizeof(struct in6_addr));
memcpy(&fltr->ip_data.v6_addrs.dst_ip, fsp->h_u.usr_ip6_spec.ip6dst,
sizeof(struct in6_addr));
fltr->ip_data.l4_header = fsp->h_u.usr_ip6_spec.l4_4_bytes;
fltr->ip_data.tclass = fsp->h_u.usr_ip6_spec.tclass;
fltr->ip_data.proto = fsp->h_u.usr_ip6_spec.l4_proto;
memcpy(&fltr->ip_mask.v6_addrs.src_ip, fsp->m_u.usr_ip6_spec.ip6src,
sizeof(struct in6_addr));
memcpy(&fltr->ip_mask.v6_addrs.dst_ip, fsp->m_u.usr_ip6_spec.ip6dst,
sizeof(struct in6_addr));
fltr->ip_mask.l4_header = fsp->m_u.usr_ip6_spec.l4_4_bytes;
fltr->ip_mask.tclass = fsp->m_u.usr_ip6_spec.tclass;
fltr->ip_mask.proto = fsp->m_u.usr_ip6_spec.l4_proto;
break;
default: default:
/* not doing un-parsed flow types */ /* not doing un-parsed flow types */
return -EINVAL; return -EINVAL;
......
...@@ -5,6 +5,15 @@ ...@@ -5,6 +5,15 @@
#include "iavf.h" #include "iavf.h"
static const struct in6_addr ipv6_addr_full_mask = {
.in6_u = {
.u6_addr8 = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
}
}
};
/** /**
* iavf_fill_fdir_ip4_hdr - fill the IPv4 protocol header * iavf_fill_fdir_ip4_hdr - fill the IPv4 protocol header
* @fltr: Flow Director filter data structure * @fltr: Flow Director filter data structure
...@@ -44,6 +53,50 @@ iavf_fill_fdir_ip4_hdr(struct iavf_fdir_fltr *fltr, ...@@ -44,6 +53,50 @@ iavf_fill_fdir_ip4_hdr(struct iavf_fdir_fltr *fltr,
return 0; return 0;
} }
/**
* iavf_fill_fdir_ip6_hdr - fill the IPv6 protocol header
* @fltr: Flow Director filter data structure
* @proto_hdrs: Flow Director protocol headers data structure
*
* Returns 0 if the IPv6 protocol header is set successfully
*/
static int
iavf_fill_fdir_ip6_hdr(struct iavf_fdir_fltr *fltr,
struct virtchnl_proto_hdrs *proto_hdrs)
{
struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
struct ipv6hdr *iph = (struct ipv6hdr *)hdr->buffer;
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV6);
if (fltr->ip_mask.tclass == U8_MAX) {
iph->priority = (fltr->ip_data.tclass >> 4) & 0xF;
iph->flow_lbl[0] = (fltr->ip_data.tclass << 4) & 0xF0;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, TC);
}
if (fltr->ip_mask.proto == U8_MAX) {
iph->nexthdr = fltr->ip_data.proto;
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, PROT);
}
if (!memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_full_mask,
sizeof(struct in6_addr))) {
memcpy(&iph->saddr, &fltr->ip_data.v6_addrs.src_ip,
sizeof(struct in6_addr));
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, SRC);
}
if (!memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_full_mask,
sizeof(struct in6_addr))) {
memcpy(&iph->daddr, &fltr->ip_data.v6_addrs.dst_ip,
sizeof(struct in6_addr));
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, DST);
}
return 0;
}
/** /**
* iavf_fill_fdir_tcp_hdr - fill the TCP protocol header * iavf_fill_fdir_tcp_hdr - fill the TCP protocol header
* @fltr: Flow Director filter data structure * @fltr: Flow Director filter data structure
...@@ -274,6 +327,30 @@ int iavf_fill_fdir_add_msg(struct iavf_adapter *adapter, struct iavf_fdir_fltr * ...@@ -274,6 +327,30 @@ int iavf_fill_fdir_add_msg(struct iavf_adapter *adapter, struct iavf_fdir_fltr *
err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) | err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_l4_hdr(fltr, proto_hdrs); iavf_fill_fdir_l4_hdr(fltr, proto_hdrs);
break; break;
case IAVF_FDIR_FLOW_IPV6_TCP:
err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_tcp_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV6_UDP:
err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_udp_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV6_SCTP:
err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_sctp_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV6_AH:
err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_ah_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV6_ESP:
err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_esp_hdr(fltr, proto_hdrs);
break;
case IAVF_FDIR_FLOW_IPV6_OTHER:
err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
iavf_fill_fdir_l4_hdr(fltr, proto_hdrs);
break;
default: default:
err = -EINVAL; err = -EINVAL;
break; break;
...@@ -298,16 +375,22 @@ static const char *iavf_fdir_flow_proto_name(enum iavf_fdir_flow_type flow_type) ...@@ -298,16 +375,22 @@ static const char *iavf_fdir_flow_proto_name(enum iavf_fdir_flow_type flow_type)
{ {
switch (flow_type) { switch (flow_type) {
case IAVF_FDIR_FLOW_IPV4_TCP: case IAVF_FDIR_FLOW_IPV4_TCP:
case IAVF_FDIR_FLOW_IPV6_TCP:
return "TCP"; return "TCP";
case IAVF_FDIR_FLOW_IPV4_UDP: case IAVF_FDIR_FLOW_IPV4_UDP:
case IAVF_FDIR_FLOW_IPV6_UDP:
return "UDP"; return "UDP";
case IAVF_FDIR_FLOW_IPV4_SCTP: case IAVF_FDIR_FLOW_IPV4_SCTP:
case IAVF_FDIR_FLOW_IPV6_SCTP:
return "SCTP"; return "SCTP";
case IAVF_FDIR_FLOW_IPV4_AH: case IAVF_FDIR_FLOW_IPV4_AH:
case IAVF_FDIR_FLOW_IPV6_AH:
return "AH"; return "AH";
case IAVF_FDIR_FLOW_IPV4_ESP: case IAVF_FDIR_FLOW_IPV4_ESP:
case IAVF_FDIR_FLOW_IPV6_ESP:
return "ESP"; return "ESP";
case IAVF_FDIR_FLOW_IPV4_OTHER: case IAVF_FDIR_FLOW_IPV4_OTHER:
case IAVF_FDIR_FLOW_IPV6_OTHER:
return "Other"; return "Other";
default: default:
return NULL; return NULL;
...@@ -357,6 +440,34 @@ void iavf_print_fdir_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *f ...@@ -357,6 +440,34 @@ void iavf_print_fdir_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *f
fltr->ip_data.proto, fltr->ip_data.proto,
ntohl(fltr->ip_data.l4_header)); ntohl(fltr->ip_data.l4_header));
break; break;
case IAVF_FDIR_FLOW_IPV6_TCP:
case IAVF_FDIR_FLOW_IPV6_UDP:
case IAVF_FDIR_FLOW_IPV6_SCTP:
dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: dst_port %hu src_port %hu\n",
fltr->loc,
&fltr->ip_data.v6_addrs.dst_ip,
&fltr->ip_data.v6_addrs.src_ip,
proto,
ntohs(fltr->ip_data.dst_port),
ntohs(fltr->ip_data.src_port));
break;
case IAVF_FDIR_FLOW_IPV6_AH:
case IAVF_FDIR_FLOW_IPV6_ESP:
dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: SPI %u\n",
fltr->loc,
&fltr->ip_data.v6_addrs.dst_ip,
&fltr->ip_data.v6_addrs.src_ip,
proto,
ntohl(fltr->ip_data.spi));
break;
case IAVF_FDIR_FLOW_IPV6_OTHER:
dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 proto: %u L4_bytes: 0x%x\n",
fltr->loc,
&fltr->ip_data.v6_addrs.dst_ip,
&fltr->ip_data.v6_addrs.src_ip,
fltr->ip_data.proto,
ntohl(fltr->ip_data.l4_header));
break;
default: default:
break; break;
} }
......
...@@ -24,6 +24,12 @@ enum iavf_fdir_flow_type { ...@@ -24,6 +24,12 @@ enum iavf_fdir_flow_type {
IAVF_FDIR_FLOW_IPV4_AH, IAVF_FDIR_FLOW_IPV4_AH,
IAVF_FDIR_FLOW_IPV4_ESP, IAVF_FDIR_FLOW_IPV4_ESP,
IAVF_FDIR_FLOW_IPV4_OTHER, IAVF_FDIR_FLOW_IPV4_OTHER,
IAVF_FDIR_FLOW_IPV6_TCP,
IAVF_FDIR_FLOW_IPV6_UDP,
IAVF_FDIR_FLOW_IPV6_SCTP,
IAVF_FDIR_FLOW_IPV6_AH,
IAVF_FDIR_FLOW_IPV6_ESP,
IAVF_FDIR_FLOW_IPV6_OTHER,
/* MAX - this must be last and add anything new just above it */ /* MAX - this must be last and add anything new just above it */
IAVF_FDIR_FLOW_PTYPE_MAX, IAVF_FDIR_FLOW_PTYPE_MAX,
}; };
...@@ -33,9 +39,15 @@ struct iavf_ipv4_addrs { ...@@ -33,9 +39,15 @@ struct iavf_ipv4_addrs {
__be32 dst_ip; __be32 dst_ip;
}; };
struct iavf_ipv6_addrs {
struct in6_addr src_ip;
struct in6_addr dst_ip;
};
struct iavf_fdir_ip { struct iavf_fdir_ip {
union { union {
struct iavf_ipv4_addrs v4_addrs; struct iavf_ipv4_addrs v4_addrs;
struct iavf_ipv6_addrs v6_addrs;
}; };
__be16 src_port; __be16 src_port;
__be16 dst_port; __be16 dst_port;
...@@ -43,6 +55,7 @@ struct iavf_fdir_ip { ...@@ -43,6 +55,7 @@ struct iavf_fdir_ip {
__be32 spi; /* security parameter index for AH/ESP */ __be32 spi; /* security parameter index for AH/ESP */
union { union {
u8 tos; u8 tos;
u8 tclass;
}; };
u8 proto; u8 proto;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment