Commit efca91e8 authored by Przemyslaw Patynowski's avatar Przemyslaw Patynowski Committed by Tony Nguyen

i40e: Add flow director support for IPv6

Flow director for IPv6 is not supported.
1) Implementation of support for IPv6 flow director.
2) Added handlers for addition of TCP6, UDP6, SCTP6, IPv6.
3) Refactored legacy code to make it more generic.
4) Added packet templates for TCP6, UDP6, SCTP6, IPv6.
5) Added handling of IPv6 source and destination address for flow director.
6) Improved argument passing for source and destination portin TCP6, UDP6
   and SCTP6.
7) Added handling of ethtool -n for IPv6, TCP6,UDP6, SCTP6.
8) Used correct bit flag regarding FLEXOFF field of flow director data
   descriptor.

Without this patch, there would be no support for flow director on IPv6,
TCP6, UDP6, SCTP6.
Tested based on x710 datasheet by using:
ethtool -N enp133s0f0 flow-type tcp4 src-port 13 dst-port 37 user-def 0x44142 action 1
ethtool -N enp133s0f0 flow-type tcp6 src-port 13 dst-port 40 user-def 0x44142 action 2
ethtool -N enp133s0f0 flow-type udp4 src-port 20 dst-port 40 user-def 0x44142 action 3
ethtool -N enp133s0f0 flow-type udp6 src-port 25 dst-port 40 user-def 0x44142 action 4
ethtool -N enp133s0f0 flow-type sctp4 src-port 55 dst-port 65 user-def 0x44142 action 5
ethtool -N enp133s0f0 flow-type sctp6 src-port 60 dst-port 40 user-def 0x44142 action 6
ethtool -N enp133s0f0 flow-type ip4 src-ip 1.1.1.1 dst-ip 1.1.1.4 user-def 0x44142 action 7
ethtool -N enp133s0f0 flow-type ip6 src-ip fe80::3efd:feff:fe6f:bbbb dst-ip fe80::3efd:feff:fe6f:aaaa user-def 0x44142 action 8
Then send traffic from client which matches the criteria provided to ethtool.
Observe that packets are redirected to user set queues with ethtool -S <interface>
Signed-off-by: default avatarPrzemyslaw Patynowski <przemyslawx.patynowski@intel.com>
Tested-by: default avatarTony Brelinski <tonyx.brelinski@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent 95f352dc
...@@ -213,10 +213,12 @@ struct i40e_fdir_filter { ...@@ -213,10 +213,12 @@ struct i40e_fdir_filter {
struct hlist_node fdir_node; struct hlist_node fdir_node;
/* filter ipnut set */ /* filter ipnut set */
u8 flow_type; u8 flow_type;
u8 ip4_proto; u8 ipl4_proto;
/* TX packet view of src and dst */ /* TX packet view of src and dst */
__be32 dst_ip; __be32 dst_ip;
__be32 src_ip; __be32 src_ip;
__be32 dst_ip6[4];
__be32 src_ip6[4];
__be16 src_port; __be16 src_port;
__be16 dst_port; __be16 dst_port;
__be32 sctp_v_tag; __be32 sctp_v_tag;
...@@ -477,6 +479,11 @@ struct i40e_pf { ...@@ -477,6 +479,11 @@ struct i40e_pf {
u16 fd_sctp4_filter_cnt; u16 fd_sctp4_filter_cnt;
u16 fd_ip4_filter_cnt; u16 fd_ip4_filter_cnt;
u16 fd_tcp6_filter_cnt;
u16 fd_udp6_filter_cnt;
u16 fd_sctp6_filter_cnt;
u16 fd_ip6_filter_cnt;
/* Flexible filter table values that need to be programmed into /* Flexible filter table values that need to be programmed into
* hardware, which expects L3 and L4 to be programmed separately. We * hardware, which expects L3 and L4 to be programmed separately. We
* need to ensure that the values are in ascended order and don't have * need to ensure that the values are in ascended order and don't have
......
...@@ -3222,13 +3222,30 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf, ...@@ -3222,13 +3222,30 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf,
fsp->m_u.usr_ip4_spec.proto = 0; fsp->m_u.usr_ip4_spec.proto = 0;
} }
/* Reverse the src and dest notion, since the HW views them from if (fsp->flow_type == IPV6_USER_FLOW ||
* Tx perspective where as the user expects it from Rx filter view. fsp->flow_type == UDP_V6_FLOW ||
*/ fsp->flow_type == TCP_V6_FLOW ||
fsp->h_u.tcp_ip4_spec.psrc = rule->dst_port; fsp->flow_type == SCTP_V6_FLOW) {
fsp->h_u.tcp_ip4_spec.pdst = rule->src_port; /* Reverse the src and dest notion, since the HW views them
fsp->h_u.tcp_ip4_spec.ip4src = rule->dst_ip; * from Tx perspective where as the user expects it from
fsp->h_u.tcp_ip4_spec.ip4dst = rule->src_ip; * 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) { switch (rule->flow_type) {
case SCTP_V4_FLOW: case SCTP_V4_FLOW:
...@@ -3240,9 +3257,21 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf, ...@@ -3240,9 +3257,21 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf,
case UDP_V4_FLOW: case UDP_V4_FLOW:
index = I40E_FILTER_PCTYPE_NONF_IPV4_UDP; index = I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
break; 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: case IP_USER_FLOW:
index = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER; index = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
break; break;
case IPV6_USER_FLOW:
index = I40E_FILTER_PCTYPE_NONF_IPV6_OTHER;
break;
default: default:
/* If we have stored a filter with a flow type not listed here /* If we have stored a filter with a flow type not listed here
* it is almost certainly a driver bug. WARN(), and then * it is almost certainly a driver bug. WARN(), and then
...@@ -3258,6 +3287,20 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf, ...@@ -3258,6 +3287,20 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf,
input_set = i40e_read_fd_input_set(pf, index); input_set = i40e_read_fd_input_set(pf, index);
no_input_set: 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) if (input_set & I40E_L3_SRC_MASK)
fsp->m_u.tcp_ip4_spec.ip4src = htonl(0xFFFFFFFF); fsp->m_u.tcp_ip4_spec.ip4src = htonl(0xFFFFFFFF);
...@@ -3921,6 +3964,14 @@ static const char *i40e_flow_str(struct ethtool_rx_flow_spec *fsp) ...@@ -3921,6 +3964,14 @@ static const char *i40e_flow_str(struct ethtool_rx_flow_spec *fsp)
return "sctp4"; return "sctp4";
case IP_USER_FLOW: case IP_USER_FLOW:
return "ip4"; 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: default:
return "unknown"; return "unknown";
} }
...@@ -4056,9 +4107,14 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi, ...@@ -4056,9 +4107,14 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi,
struct ethtool_rx_flow_spec *fsp, struct ethtool_rx_flow_spec *fsp,
struct i40e_rx_flow_userdef *userdef) 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_tcpip4_spec *tcp_ip4_spec;
struct ethtool_usrip4_spec *usr_ip4_spec; struct ethtool_usrip4_spec *usr_ip4_spec;
struct i40e_pf *pf = vsi->back;
u64 current_mask, new_mask; u64 current_mask, new_mask;
bool new_flex_offset = false; bool new_flex_offset = false;
bool flex_l3 = false; bool flex_l3 = false;
...@@ -4080,11 +4136,28 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi, ...@@ -4080,11 +4136,28 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi,
index = I40E_FILTER_PCTYPE_NONF_IPV4_UDP; index = I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
fdir_filter_count = &pf->fd_udp4_filter_cnt; fdir_filter_count = &pf->fd_udp4_filter_cnt;
break; 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: case IP_USER_FLOW:
index = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER; index = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
fdir_filter_count = &pf->fd_ip4_filter_cnt; fdir_filter_count = &pf->fd_ip4_filter_cnt;
flex_l3 = true; flex_l3 = true;
break; 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: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -4147,6 +4220,53 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi, ...@@ -4147,6 +4220,53 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi,
return -EOPNOTSUPP; return -EOPNOTSUPP;
break; 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: case IP_USER_FLOW:
usr_ip4_spec = &fsp->m_u.usr_ip4_spec; usr_ip4_spec = &fsp->m_u.usr_ip4_spec;
...@@ -4186,6 +4306,45 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi, ...@@ -4186,6 +4306,45 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi,
if (usr_ip4_spec->proto) if (usr_ip4_spec->proto)
return -EINVAL; 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; break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -4370,7 +4529,7 @@ static bool i40e_match_fdir_filter(struct i40e_fdir_filter *a, ...@@ -4370,7 +4529,7 @@ static bool i40e_match_fdir_filter(struct i40e_fdir_filter *a,
a->dst_port != b->dst_port || a->dst_port != b->dst_port ||
a->src_port != b->src_port || a->src_port != b->src_port ||
a->flow_type != b->flow_type || a->flow_type != b->flow_type ||
a->ip4_proto != b->ip4_proto) a->ipl4_proto != b->ipl4_proto)
return false; return false;
return true; return true;
...@@ -4528,15 +4687,33 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi, ...@@ -4528,15 +4687,33 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
input->dst_ip = fsp->h_u.tcp_ip4_spec.ip4src; input->dst_ip = fsp->h_u.tcp_ip4_spec.ip4src;
input->src_ip = fsp->h_u.tcp_ip4_spec.ip4dst; input->src_ip = fsp->h_u.tcp_ip4_spec.ip4dst;
input->flow_type = fsp->flow_type & ~FLOW_EXT; 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 if (input->flow_type == IPV6_USER_FLOW ||
* Tx perspective where as the input from user is from Rx filter view. input->flow_type == UDP_V6_FLOW ||
*/ input->flow_type == TCP_V6_FLOW ||
input->dst_port = fsp->h_u.tcp_ip4_spec.psrc; input->flow_type == SCTP_V6_FLOW) {
input->src_port = fsp->h_u.tcp_ip4_spec.pdst; /* Reverse the src and dest notion, since the HW expects them
input->dst_ip = fsp->h_u.tcp_ip4_spec.ip4src; * to be from Tx perspective where as the input from user is
input->src_ip = fsp->h_u.tcp_ip4_spec.ip4dst; * 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) { if (userdef.flex_filter) {
input->flex_filter = true; input->flex_filter = true;
......
...@@ -3495,6 +3495,24 @@ static void i40e_set_vsi_rx_mode(struct i40e_vsi *vsi) ...@@ -3495,6 +3495,24 @@ static void i40e_set_vsi_rx_mode(struct i40e_vsi *vsi)
i40e_set_rx_mode(vsi->netdev); i40e_set_rx_mode(vsi->netdev);
} }
/**
* i40e_reset_fdir_filter_cnt - Reset flow director filter counters
* @pf: Pointer to the targeted PF
*
* Set all flow director counters to 0.
*/
static void i40e_reset_fdir_filter_cnt(struct i40e_pf *pf)
{
pf->fd_tcp4_filter_cnt = 0;
pf->fd_udp4_filter_cnt = 0;
pf->fd_sctp4_filter_cnt = 0;
pf->fd_ip4_filter_cnt = 0;
pf->fd_tcp6_filter_cnt = 0;
pf->fd_udp6_filter_cnt = 0;
pf->fd_sctp6_filter_cnt = 0;
pf->fd_ip6_filter_cnt = 0;
}
/** /**
* i40e_fdir_filter_restore - Restore the Sideband Flow Director filters * i40e_fdir_filter_restore - Restore the Sideband Flow Director filters
* @vsi: Pointer to the targeted VSI * @vsi: Pointer to the targeted VSI
...@@ -3512,10 +3530,7 @@ static void i40e_fdir_filter_restore(struct i40e_vsi *vsi) ...@@ -3512,10 +3530,7 @@ static void i40e_fdir_filter_restore(struct i40e_vsi *vsi)
return; return;
/* Reset FDir counters as we're replaying all existing filters */ /* Reset FDir counters as we're replaying all existing filters */
pf->fd_tcp4_filter_cnt = 0; i40e_reset_fdir_filter_cnt(pf);
pf->fd_udp4_filter_cnt = 0;
pf->fd_sctp4_filter_cnt = 0;
pf->fd_ip4_filter_cnt = 0;
hlist_for_each_entry_safe(filter, node, hlist_for_each_entry_safe(filter, node,
&pf->fdir_filter_list, fdir_node) { &pf->fdir_filter_list, fdir_node) {
...@@ -8763,32 +8778,51 @@ static void i40e_fdir_filter_exit(struct i40e_pf *pf) ...@@ -8763,32 +8778,51 @@ static void i40e_fdir_filter_exit(struct i40e_pf *pf)
INIT_LIST_HEAD(&pf->l4_flex_pit_list); INIT_LIST_HEAD(&pf->l4_flex_pit_list);
pf->fdir_pf_active_filters = 0; pf->fdir_pf_active_filters = 0;
pf->fd_tcp4_filter_cnt = 0; i40e_reset_fdir_filter_cnt(pf);
pf->fd_udp4_filter_cnt = 0;
pf->fd_sctp4_filter_cnt = 0;
pf->fd_ip4_filter_cnt = 0;
/* Reprogram the default input set for TCP/IPv4 */ /* Reprogram the default input set for TCP/IPv4 */
i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV4_TCP, i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV4_TCP,
I40E_L3_SRC_MASK | I40E_L3_DST_MASK | I40E_L3_SRC_MASK | I40E_L3_DST_MASK |
I40E_L4_SRC_MASK | I40E_L4_DST_MASK); I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
/* Reprogram the default input set for TCP/IPv6 */
i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV6_TCP,
I40E_L3_V6_SRC_MASK | I40E_L3_V6_DST_MASK |
I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
/* Reprogram the default input set for UDP/IPv4 */ /* Reprogram the default input set for UDP/IPv4 */
i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV4_UDP, i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV4_UDP,
I40E_L3_SRC_MASK | I40E_L3_DST_MASK | I40E_L3_SRC_MASK | I40E_L3_DST_MASK |
I40E_L4_SRC_MASK | I40E_L4_DST_MASK); I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
/* Reprogram the default input set for UDP/IPv6 */
i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV6_UDP,
I40E_L3_V6_SRC_MASK | I40E_L3_V6_DST_MASK |
I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
/* Reprogram the default input set for SCTP/IPv4 */ /* Reprogram the default input set for SCTP/IPv4 */
i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV4_SCTP, i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV4_SCTP,
I40E_L3_SRC_MASK | I40E_L3_DST_MASK | I40E_L3_SRC_MASK | I40E_L3_DST_MASK |
I40E_L4_SRC_MASK | I40E_L4_DST_MASK); I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
/* Reprogram the default input set for SCTP/IPv6 */
i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV6_SCTP,
I40E_L3_V6_SRC_MASK | I40E_L3_V6_DST_MASK |
I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
/* Reprogram the default input set for Other/IPv4 */ /* Reprogram the default input set for Other/IPv4 */
i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV4_OTHER, i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV4_OTHER,
I40E_L3_SRC_MASK | I40E_L3_DST_MASK); I40E_L3_SRC_MASK | I40E_L3_DST_MASK);
i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_FRAG_IPV4, i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_FRAG_IPV4,
I40E_L3_SRC_MASK | I40E_L3_DST_MASK); I40E_L3_SRC_MASK | I40E_L3_DST_MASK);
/* Reprogram the default input set for Other/IPv6 */
i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV6_OTHER,
I40E_L3_SRC_MASK | I40E_L3_DST_MASK);
i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_FRAG_IPV6,
I40E_L3_SRC_MASK | I40E_L3_DST_MASK);
} }
/** /**
...@@ -9270,8 +9304,17 @@ static void i40e_delete_invalid_filter(struct i40e_pf *pf, ...@@ -9270,8 +9304,17 @@ static void i40e_delete_invalid_filter(struct i40e_pf *pf,
case SCTP_V4_FLOW: case SCTP_V4_FLOW:
pf->fd_sctp4_filter_cnt--; pf->fd_sctp4_filter_cnt--;
break; break;
case TCP_V6_FLOW:
pf->fd_tcp6_filter_cnt--;
break;
case UDP_V6_FLOW:
pf->fd_udp6_filter_cnt--;
break;
case SCTP_V6_FLOW:
pf->fd_udp6_filter_cnt--;
break;
case IP_USER_FLOW: case IP_USER_FLOW:
switch (filter->ip4_proto) { switch (filter->ipl4_proto) {
case IPPROTO_TCP: case IPPROTO_TCP:
pf->fd_tcp4_filter_cnt--; pf->fd_tcp4_filter_cnt--;
break; break;
...@@ -9286,6 +9329,22 @@ static void i40e_delete_invalid_filter(struct i40e_pf *pf, ...@@ -9286,6 +9329,22 @@ static void i40e_delete_invalid_filter(struct i40e_pf *pf,
break; break;
} }
break; break;
case IPV6_USER_FLOW:
switch (filter->ipl4_proto) {
case IPPROTO_TCP:
pf->fd_tcp6_filter_cnt--;
break;
case IPPROTO_UDP:
pf->fd_udp6_filter_cnt--;
break;
case IPPROTO_SCTP:
pf->fd_sctp6_filter_cnt--;
break;
case IPPROTO_IP:
pf->fd_ip6_filter_cnt--;
break;
}
break;
} }
/* Remove the filter from the list and free memory */ /* Remove the filter from the list and free memory */
...@@ -9319,7 +9378,7 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf) ...@@ -9319,7 +9378,7 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
* rules active. * rules active.
*/ */
if ((fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM_FOR_ATR)) && if ((fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM_FOR_ATR)) &&
(pf->fd_tcp4_filter_cnt == 0)) pf->fd_tcp4_filter_cnt == 0 && pf->fd_tcp6_filter_cnt == 0)
i40e_reenable_fdir_atr(pf); i40e_reenable_fdir_atr(pf);
/* if hw had a problem adding a filter, delete it */ /* if hw had a problem adding a filter, delete it */
......
...@@ -42,9 +42,6 @@ static void i40e_fdir(struct i40e_ring *tx_ring, ...@@ -42,9 +42,6 @@ static void i40e_fdir(struct i40e_ring *tx_ring,
flex_ptype |= I40E_TXD_FLTR_QW0_PCTYPE_MASK & flex_ptype |= I40E_TXD_FLTR_QW0_PCTYPE_MASK &
(fdata->pctype << I40E_TXD_FLTR_QW0_PCTYPE_SHIFT); (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 */ /* Use LAN VSI Id if not programmed by user */
flex_ptype |= I40E_TXD_FLTR_QW0_DEST_VSI_MASK & flex_ptype |= I40E_TXD_FLTR_QW0_DEST_VSI_MASK &
((u32)(fdata->dest_vsi ? : pf->vsi[pf->lan_vsi]->id) << ((u32)(fdata->dest_vsi ? : pf->vsi[pf->lan_vsi]->id) <<
...@@ -160,52 +157,83 @@ static int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, ...@@ -160,52 +157,83 @@ static int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data,
return -1; return -1;
} }
#define IP_HEADER_OFFSET 14 #define IP_HEADER_OFFSET 14
#define I40E_UDPIP_DUMMY_PACKET_LEN 42 #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 * @vsi: pointer to the targeted VSI
* @fd_data: the flow director data required for the FDir descriptor * @fd_data: the flow director data required for the FDir descriptor
* @add: true adds a filter, false removes it * @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 * Returns 0 if the filters were successfully added or removed
**/ **/
static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi, static int i40e_add_del_fdir_udp(struct i40e_vsi *vsi,
struct i40e_fdir_filter *fd_data, struct i40e_fdir_filter *fd_data,
bool add) bool add,
bool ipv4)
{ {
struct i40e_pf *pf = vsi->back; struct i40e_pf *pf = vsi->back;
struct ipv6hdr *ipv6;
struct udphdr *udp; struct udphdr *udp;
struct iphdr *ip; struct iphdr *ip;
u8 *raw_packet; u8 *raw_packet;
int ret; int ret;
static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, static char packet_ipv4[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08,
0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11, 0, 0, 0, 0, 0, 0, 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, 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); raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL);
if (!raw_packet) if (!raw_packet)
return -ENOMEM; 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); ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
udp = (struct udphdr *)(raw_packet + IP_HEADER_OFFSET udp = (struct udphdr *)(raw_packet + IP_HEADER_OFFSET
+ sizeof(struct iphdr)); + 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; udp->dest = fd_data->dst_port;
ip->saddr = fd_data->src_ip;
udp->source = fd_data->src_port; udp->source = fd_data->src_port;
if (fd_data->flex_filter) { if (fd_data->flex_filter) {
u8 *payload = raw_packet + I40E_UDPIP_DUMMY_PACKET_LEN; u8 *payload;
__be16 pattern = fd_data->flex_word; __be16 pattern = fd_data->flex_word;
u16 off = fd_data->flex_offset; 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; *((__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); ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
if (ret) { if (ret) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
...@@ -225,61 +253,104 @@ static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi, ...@@ -225,61 +253,104 @@ static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
fd_data->pctype, fd_data->fd_id); fd_data->pctype, fd_data->fd_id);
} }
if (add) if (add) {
pf->fd_udp4_filter_cnt++; if (ipv4)
else pf->fd_udp4_filter_cnt++;
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; 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 * @vsi: pointer to the targeted VSI
* @fd_data: the flow director data required for the FDir descriptor * @fd_data: the flow director data required for the FDir descriptor
* @add: true adds a filter, false removes it * @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 * Returns 0 if the filters were successfully added or removed
**/ **/
static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, static int i40e_add_del_fdir_tcp(struct i40e_vsi *vsi,
struct i40e_fdir_filter *fd_data, struct i40e_fdir_filter *fd_data,
bool add) bool add,
bool ipv4)
{ {
struct i40e_pf *pf = vsi->back; struct i40e_pf *pf = vsi->back;
struct ipv6hdr *ipv6;
struct tcphdr *tcp; struct tcphdr *tcp;
struct iphdr *ip; struct iphdr *ip;
u8 *raw_packet; u8 *raw_packet;
int ret; int ret;
/* Dummy packet */ /* Dummy packet */
static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, static char packet_ipv4[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08,
0x45, 0, 0, 0x28, 0, 0, 0x40, 0, 0x40, 0x6, 0, 0, 0, 0, 0, 0, 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, 0x80, 0x11, 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}; 0x0, 0x72, 0, 0, 0, 0};
raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL);
if (!raw_packet) if (!raw_packet)
return -ENOMEM; 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); ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
tcp = (struct tcphdr *)(raw_packet + IP_HEADER_OFFSET tcp = (struct tcphdr *)(raw_packet + IP_HEADER_OFFSET
+ sizeof(struct iphdr)); + sizeof(struct iphdr));
ip->daddr = fd_data->dst_ip;
tcp->dest = fd_data->dst_port; tcp->dest = fd_data->dst_port;
ip->saddr = fd_data->src_ip;
tcp->source = fd_data->src_port; tcp->source = fd_data->src_port;
if (fd_data->flex_filter) { if (fd_data->flex_filter) {
u8 *payload = raw_packet + I40E_TCPIP_DUMMY_PACKET_LEN; u8 *payload;
__be16 pattern = fd_data->flex_word; __be16 pattern = fd_data->flex_word;
u16 off = fd_data->flex_offset; 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; *((__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); ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
if (ret) { if (ret) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
...@@ -299,65 +370,102 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, ...@@ -299,65 +370,102 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
} }
if (add) { 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) && if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
I40E_DEBUG_FD & pf->hw.debug_mask) I40E_DEBUG_FD & pf->hw.debug_mask)
dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n"); 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); set_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state);
} else { } else {
pf->fd_tcp4_filter_cnt--; if (ipv4)
pf->fd_tcp4_filter_cnt--;
else
pf->fd_tcp6_filter_cnt--;
} }
return 0; 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 * a specific flow spec
* @vsi: pointer to the targeted VSI * @vsi: pointer to the targeted VSI
* @fd_data: the flow director data required for the FDir descriptor * @fd_data: the flow director data required for the FDir descriptor
* @add: true adds a filter, false removes it * @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 * Returns 0 if the filters were successfully added or removed
**/ **/
static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi, static int i40e_add_del_fdir_sctp(struct i40e_vsi *vsi,
struct i40e_fdir_filter *fd_data, struct i40e_fdir_filter *fd_data,
bool add) bool add,
bool ipv4)
{ {
struct i40e_pf *pf = vsi->back; struct i40e_pf *pf = vsi->back;
struct ipv6hdr *ipv6;
struct sctphdr *sctp; struct sctphdr *sctp;
struct iphdr *ip; struct iphdr *ip;
u8 *raw_packet; u8 *raw_packet;
int ret; int ret;
/* Dummy packet */ /* Dummy packets */
static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, static char packet_ipv4[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08,
0x45, 0, 0, 0x20, 0, 0, 0x40, 0, 0x40, 0x84, 0, 0, 0, 0, 0, 0, 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, 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); raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL);
if (!raw_packet) if (!raw_packet)
return -ENOMEM; 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); ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
sctp = (struct sctphdr *)(raw_packet + IP_HEADER_OFFSET sctp = (struct sctphdr *)(raw_packet + IP_HEADER_OFFSET
+ sizeof(struct iphdr)); + 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; sctp->dest = fd_data->dst_port;
ip->saddr = fd_data->src_ip;
sctp->source = fd_data->src_port; sctp->source = fd_data->src_port;
if (fd_data->flex_filter) { if (fd_data->flex_filter) {
u8 *payload = raw_packet + I40E_SCTPIP_DUMMY_PACKET_LEN; u8 *payload;
__be16 pattern = fd_data->flex_word; __be16 pattern = fd_data->flex_word;
u16 off = fd_data->flex_offset; 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; *((__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); ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
if (ret) { if (ret) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
...@@ -377,54 +485,97 @@ static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi, ...@@ -377,54 +485,97 @@ static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi,
fd_data->pctype, fd_data->fd_id); fd_data->pctype, fd_data->fd_id);
} }
if (add) if (add) {
pf->fd_sctp4_filter_cnt++; if (ipv4)
else pf->fd_sctp4_filter_cnt++;
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; 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 * a specific flow spec
* @vsi: pointer to the targeted VSI * @vsi: pointer to the targeted VSI
* @fd_data: the flow director data required for the FDir descriptor * @fd_data: the flow director data required for the FDir descriptor
* @add: true adds a filter, false removes it * @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 * Returns 0 if the filters were successfully added or removed
**/ **/
static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi, static int i40e_add_del_fdir_ip(struct i40e_vsi *vsi,
struct i40e_fdir_filter *fd_data, struct i40e_fdir_filter *fd_data,
bool add) bool add,
bool ipv4)
{ {
struct i40e_pf *pf = vsi->back; struct i40e_pf *pf = vsi->back;
struct ipv6hdr *ipv6;
struct iphdr *ip; struct iphdr *ip;
u8 *raw_packet; u8 *raw_packet;
int iter_start;
int iter_end;
int ret; int ret;
int i; int i;
static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, static char packet_ipv4[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08,
0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10, 0, 0, 0, 0, 0, 0, 0, 0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10, 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, 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; for (i = iter_start; i <= iter_end; i++) {
i <= I40E_FILTER_PCTYPE_FRAG_IPV4; i++) {
raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL);
if (!raw_packet) if (!raw_packet)
return -ENOMEM; return -ENOMEM;
memcpy(raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN); if (ipv4) {
ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET); memcpy(raw_packet, packet_ipv4,
I40E_IP_DUMMY_PACKET_LEN);
ip->saddr = fd_data->src_ip; ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
ip->daddr = fd_data->dst_ip;
ip->protocol = 0; 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) { if (fd_data->flex_filter) {
u8 *payload = raw_packet + I40E_IP_DUMMY_PACKET_LEN; u8 *payload;
__be16 pattern = fd_data->flex_word; __be16 pattern = fd_data->flex_word;
u16 off = fd_data->flex_offset; 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; *((__force __be16 *)(payload + off)) = pattern;
} }
...@@ -451,10 +602,17 @@ static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi, ...@@ -451,10 +602,17 @@ static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
} }
} }
if (add) if (add) {
pf->fd_ip4_filter_cnt++; if (ipv4)
else pf->fd_ip4_filter_cnt++;
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; return 0;
} }
...@@ -469,37 +627,68 @@ static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi, ...@@ -469,37 +627,68 @@ static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
int i40e_add_del_fdir(struct i40e_vsi *vsi, int i40e_add_del_fdir(struct i40e_vsi *vsi,
struct i40e_fdir_filter *input, bool add) struct i40e_fdir_filter *input, bool add)
{ {
enum ip_ver { ipv6 = 0, ipv4 = 1 };
struct i40e_pf *pf = vsi->back; struct i40e_pf *pf = vsi->back;
int ret; int ret;
switch (input->flow_type & ~FLOW_EXT) { switch (input->flow_type & ~FLOW_EXT) {
case TCP_V4_FLOW: case TCP_V4_FLOW:
ret = i40e_add_del_fdir_tcpv4(vsi, input, add); ret = i40e_add_del_fdir_tcp(vsi, input, add, ipv4);
break; break;
case UDP_V4_FLOW: case UDP_V4_FLOW:
ret = i40e_add_del_fdir_udpv4(vsi, input, add); ret = i40e_add_del_fdir_udp(vsi, input, add, ipv4);
break; break;
case SCTP_V4_FLOW: 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; break;
case IP_USER_FLOW: case IP_USER_FLOW:
switch (input->ip4_proto) { switch (input->ipl4_proto) {
case IPPROTO_TCP: case IPPROTO_TCP:
ret = i40e_add_del_fdir_tcpv4(vsi, input, add); ret = i40e_add_del_fdir_tcp(vsi, input, add, ipv4);
break; break;
case IPPROTO_UDP: case IPPROTO_UDP:
ret = i40e_add_del_fdir_udpv4(vsi, input, add); ret = i40e_add_del_fdir_udp(vsi, input, add, ipv4);
break; break;
case IPPROTO_SCTP: case IPPROTO_SCTP:
ret = i40e_add_del_fdir_sctpv4(vsi, input, add); ret = i40e_add_del_fdir_sctp(vsi, input, add, ipv4);
break; break;
case IPPROTO_IP: case IPPROTO_IP:
ret = i40e_add_del_fdir_ipv4(vsi, input, add); ret = i40e_add_del_fdir_ip(vsi, input, add, ipv4);
break; break;
default: default:
/* We cannot support masking based on protocol */ /* We cannot support masking based on protocol */
dev_info(&pf->pdev->dev, "Unsupported IPv4 protocol 0x%02x\n", 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; return -EINVAL;
} }
break; break;
......
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