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