Commit 3a41c64d authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso
Browse files

netfilter: nf_tables: bail out early if hardware offload is not supported



If user requests for NFT_CHAIN_HW_OFFLOAD, then check if either device
provides the .ndo_setup_tc interface or there is an indirect flow block
that has been registered. Otherwise, bail out early from the preparation
phase. Moreover, validate that family == NFPROTO_NETDEV and hook is
NF_NETDEV_INGRESS.

Fixes: c9626a2c ("netfilter: nf_tables: add hardware offload support")
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 9dd732e0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -612,5 +612,6 @@ int flow_indr_dev_setup_offload(struct net_device *dev, struct Qdisc *sch,
				enum tc_setup_type type, void *data,
				struct flow_block_offload *bo,
				void (*cleanup)(struct flow_block_cb *block_cb));
bool flow_indr_dev_exists(void);

#endif /* _NET_FLOW_OFFLOAD_H */
+1 −1
Original line number Diff line number Diff line
@@ -92,7 +92,7 @@ int nft_flow_rule_offload_commit(struct net *net);
	NFT_OFFLOAD_MATCH(__key, __base, __field, __len, __reg)		\
	memset(&(__reg)->mask, 0xff, (__reg)->len);

int nft_chain_offload_priority(struct nft_base_chain *basechain);
bool nft_chain_offload_support(const struct nft_base_chain *basechain);

int nft_offload_init(void);
void nft_offload_exit(void);
+6 −0
Original line number Diff line number Diff line
@@ -595,3 +595,9 @@ int flow_indr_dev_setup_offload(struct net_device *dev, struct Qdisc *sch,
	return (bo && list_empty(&bo->cb_list)) ? -EOPNOTSUPP : count;
}
EXPORT_SYMBOL(flow_indr_dev_setup_offload);

bool flow_indr_dev_exists(void)
{
	return !list_empty(&flow_block_indr_dev_list);
}
EXPORT_SYMBOL(flow_indr_dev_exists);
+1 −1
Original line number Diff line number Diff line
@@ -2166,7 +2166,7 @@ static int nft_basechain_init(struct nft_base_chain *basechain, u8 family,
	chain->flags |= NFT_CHAIN_BASE | flags;
	basechain->policy = NF_ACCEPT;
	if (chain->flags & NFT_CHAIN_HW_OFFLOAD &&
	    nft_chain_offload_priority(basechain) < 0)
	    !nft_chain_offload_support(basechain))
		return -EOPNOTSUPP;

	flow_block_init(&basechain->flow_block);
+22 −1
Original line number Diff line number Diff line
@@ -208,7 +208,7 @@ static int nft_setup_cb_call(enum tc_setup_type type, void *type_data,
	return 0;
}

int nft_chain_offload_priority(struct nft_base_chain *basechain)
static int nft_chain_offload_priority(const struct nft_base_chain *basechain)
{
	if (basechain->ops.priority <= 0 ||
	    basechain->ops.priority > USHRT_MAX)
@@ -217,6 +217,27 @@ int nft_chain_offload_priority(struct nft_base_chain *basechain)
	return 0;
}

bool nft_chain_offload_support(const struct nft_base_chain *basechain)
{
	struct net_device *dev;
	struct nft_hook *hook;

	if (nft_chain_offload_priority(basechain) < 0)
		return false;

	list_for_each_entry(hook, &basechain->hook_list, list) {
		if (hook->ops.pf != NFPROTO_NETDEV ||
		    hook->ops.hooknum != NF_NETDEV_INGRESS)
			return false;

		dev = hook->ops.dev;
		if (!dev->netdev_ops->ndo_setup_tc && !flow_indr_dev_exists())
			return false;
	}

	return true;
}

static void nft_flow_cls_offload_setup(struct flow_cls_offload *cls_flow,
				       const struct nft_base_chain *basechain,
				       const struct nft_rule *rule,