cxgb4: add support to create hash-filters via tc-flower offload
Determine whether the flow classifies as exact-match with respect to 4-tuple and configured tuple mask in hw. If successfully classified as exact-match, offload the flow as hash-filter in hw. Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com> Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com> Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
79e6d46a65
commit
3eb8b62d5a
@ -31,6 +31,7 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
#include <net/ipv6.h>
|
||||||
|
|
||||||
#include "cxgb4.h"
|
#include "cxgb4.h"
|
||||||
#include "t4_regs.h"
|
#include "t4_regs.h"
|
||||||
@ -765,6 +766,153 @@ static void fill_default_mask(struct ch_filter_specification *fs)
|
|||||||
fs->mask.fport = ~0;
|
fs->mask.fport = ~0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_addr_all_mask(u8 *ipmask, int family)
|
||||||
|
{
|
||||||
|
if (family == AF_INET) {
|
||||||
|
struct in_addr *addr;
|
||||||
|
|
||||||
|
addr = (struct in_addr *)ipmask;
|
||||||
|
if (addr->s_addr == 0xffffffff)
|
||||||
|
return true;
|
||||||
|
} else if (family == AF_INET6) {
|
||||||
|
struct in6_addr *addr6;
|
||||||
|
|
||||||
|
addr6 = (struct in6_addr *)ipmask;
|
||||||
|
if (addr6->s6_addr32[0] == 0xffffffff &&
|
||||||
|
addr6->s6_addr32[1] == 0xffffffff &&
|
||||||
|
addr6->s6_addr32[2] == 0xffffffff &&
|
||||||
|
addr6->s6_addr32[3] == 0xffffffff)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_inaddr_any(u8 *ip, int family)
|
||||||
|
{
|
||||||
|
int addr_type;
|
||||||
|
|
||||||
|
if (family == AF_INET) {
|
||||||
|
struct in_addr *addr;
|
||||||
|
|
||||||
|
addr = (struct in_addr *)ip;
|
||||||
|
if (addr->s_addr == htonl(INADDR_ANY))
|
||||||
|
return true;
|
||||||
|
} else if (family == AF_INET6) {
|
||||||
|
struct in6_addr *addr6;
|
||||||
|
|
||||||
|
addr6 = (struct in6_addr *)ip;
|
||||||
|
addr_type = ipv6_addr_type((const struct in6_addr *)
|
||||||
|
&addr6);
|
||||||
|
if (addr_type == IPV6_ADDR_ANY)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_filter_exact_match(struct adapter *adap,
|
||||||
|
struct ch_filter_specification *fs)
|
||||||
|
{
|
||||||
|
struct tp_params *tp = &adap->params.tp;
|
||||||
|
u64 hash_filter_mask = tp->hash_filter_mask;
|
||||||
|
u32 mask;
|
||||||
|
|
||||||
|
if (!is_hashfilter(adap))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (fs->type) {
|
||||||
|
if (is_inaddr_any(fs->val.fip, AF_INET6) ||
|
||||||
|
!is_addr_all_mask(fs->mask.fip, AF_INET6))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (is_inaddr_any(fs->val.lip, AF_INET6) ||
|
||||||
|
!is_addr_all_mask(fs->mask.lip, AF_INET6))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (is_inaddr_any(fs->val.fip, AF_INET) ||
|
||||||
|
!is_addr_all_mask(fs->mask.fip, AF_INET))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (is_inaddr_any(fs->val.lip, AF_INET) ||
|
||||||
|
!is_addr_all_mask(fs->mask.lip, AF_INET))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs->val.lport || fs->mask.lport != 0xffff)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!fs->val.fport || fs->mask.fport != 0xffff)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (tp->fcoe_shift >= 0) {
|
||||||
|
mask = (hash_filter_mask >> tp->fcoe_shift) & FT_FCOE_W;
|
||||||
|
if (mask && !fs->mask.fcoe)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tp->port_shift >= 0) {
|
||||||
|
mask = (hash_filter_mask >> tp->port_shift) & FT_PORT_W;
|
||||||
|
if (mask && !fs->mask.iport)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tp->vnic_shift >= 0) {
|
||||||
|
mask = (hash_filter_mask >> tp->vnic_shift) & FT_VNIC_ID_W;
|
||||||
|
|
||||||
|
if ((adap->params.tp.ingress_config & VNIC_F)) {
|
||||||
|
if (mask && !fs->mask.pfvf_vld)
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (mask && !fs->mask.ovlan_vld)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tp->vlan_shift >= 0) {
|
||||||
|
mask = (hash_filter_mask >> tp->vlan_shift) & FT_VLAN_W;
|
||||||
|
if (mask && !fs->mask.ivlan)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tp->tos_shift >= 0) {
|
||||||
|
mask = (hash_filter_mask >> tp->tos_shift) & FT_TOS_W;
|
||||||
|
if (mask && !fs->mask.tos)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tp->protocol_shift >= 0) {
|
||||||
|
mask = (hash_filter_mask >> tp->protocol_shift) & FT_PROTOCOL_W;
|
||||||
|
if (mask && !fs->mask.proto)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tp->ethertype_shift >= 0) {
|
||||||
|
mask = (hash_filter_mask >> tp->ethertype_shift) &
|
||||||
|
FT_ETHERTYPE_W;
|
||||||
|
if (mask && !fs->mask.ethtype)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tp->macmatch_shift >= 0) {
|
||||||
|
mask = (hash_filter_mask >> tp->macmatch_shift) & FT_MACMATCH_W;
|
||||||
|
if (mask && !fs->mask.macidx)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tp->matchtype_shift >= 0) {
|
||||||
|
mask = (hash_filter_mask >> tp->matchtype_shift) &
|
||||||
|
FT_MPSHITTYPE_W;
|
||||||
|
if (mask && !fs->mask.matchtype)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (tp->frag_shift >= 0) {
|
||||||
|
mask = (hash_filter_mask >> tp->frag_shift) &
|
||||||
|
FT_FRAGMENTATION_W;
|
||||||
|
if (mask && !fs->mask.frag)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static u64 hash_filter_ntuple(struct ch_filter_specification *fs,
|
static u64 hash_filter_ntuple(struct ch_filter_specification *fs,
|
||||||
struct net_device *dev)
|
struct net_device *dev)
|
||||||
{
|
{
|
||||||
|
@ -51,4 +51,6 @@ int delete_filter(struct adapter *adapter, unsigned int fidx);
|
|||||||
int writable_filter(struct filter_entry *f);
|
int writable_filter(struct filter_entry *f);
|
||||||
void clear_all_filters(struct adapter *adapter);
|
void clear_all_filters(struct adapter *adapter);
|
||||||
int init_hash_filter(struct adapter *adap);
|
int init_hash_filter(struct adapter *adap);
|
||||||
|
bool is_filter_exact_match(struct adapter *adap,
|
||||||
|
struct ch_filter_specification *fs);
|
||||||
#endif /* __CXGB4_FILTER_H */
|
#endif /* __CXGB4_FILTER_H */
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include <net/tc_act/tc_vlan.h>
|
#include <net/tc_act/tc_vlan.h>
|
||||||
|
|
||||||
#include "cxgb4.h"
|
#include "cxgb4.h"
|
||||||
|
#include "cxgb4_filter.h"
|
||||||
#include "cxgb4_tc_flower.h"
|
#include "cxgb4_tc_flower.h"
|
||||||
|
|
||||||
#define STATS_CHECK_PERIOD (HZ / 2)
|
#define STATS_CHECK_PERIOD (HZ / 2)
|
||||||
@ -672,12 +673,17 @@ int cxgb4_tc_flower_replace(struct net_device *dev,
|
|||||||
cxgb4_process_flow_match(dev, cls, fs);
|
cxgb4_process_flow_match(dev, cls, fs);
|
||||||
cxgb4_process_flow_actions(dev, cls, fs);
|
cxgb4_process_flow_actions(dev, cls, fs);
|
||||||
|
|
||||||
|
fs->hash = is_filter_exact_match(adap, fs);
|
||||||
|
if (fs->hash) {
|
||||||
|
fidx = 0;
|
||||||
|
} else {
|
||||||
fidx = cxgb4_get_free_ftid(dev, fs->type ? PF_INET6 : PF_INET);
|
fidx = cxgb4_get_free_ftid(dev, fs->type ? PF_INET6 : PF_INET);
|
||||||
if (fidx < 0) {
|
if (fidx < 0) {
|
||||||
netdev_err(dev, "%s: No fidx for offload.\n", __func__);
|
netdev_err(dev, "%s: No fidx for offload.\n", __func__);
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto free_entry;
|
goto free_entry;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init_completion(&ctx.completion);
|
init_completion(&ctx.completion);
|
||||||
ret = __cxgb4_set_filter(dev, fidx, fs, &ctx);
|
ret = __cxgb4_set_filter(dev, fidx, fs, &ctx);
|
||||||
|
Loading…
Reference in New Issue
Block a user