Merge branch 'ct-offload' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
#include <linux/idr.h>
|
||||
#include <linux/rhashtable.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/netlink.h>
|
||||
@@ -354,7 +355,7 @@ static struct tcf_chain *tcf_chain_create(struct tcf_block *block,
|
||||
chain = kzalloc(sizeof(*chain), GFP_KERNEL);
|
||||
if (!chain)
|
||||
return NULL;
|
||||
list_add_tail(&chain->list, &block->chain_list);
|
||||
list_add_tail_rcu(&chain->list, &block->chain_list);
|
||||
mutex_init(&chain->filter_chain_lock);
|
||||
chain->block = block;
|
||||
chain->index = chain_index;
|
||||
@@ -394,7 +395,7 @@ static bool tcf_chain_detach(struct tcf_chain *chain)
|
||||
|
||||
ASSERT_BLOCK_LOCKED(block);
|
||||
|
||||
list_del(&chain->list);
|
||||
list_del_rcu(&chain->list);
|
||||
if (!chain->index)
|
||||
block->chain0.chain = NULL;
|
||||
|
||||
@@ -453,6 +454,20 @@ static struct tcf_chain *tcf_chain_lookup(struct tcf_block *block,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
|
||||
static struct tcf_chain *tcf_chain_lookup_rcu(const struct tcf_block *block,
|
||||
u32 chain_index)
|
||||
{
|
||||
struct tcf_chain *chain;
|
||||
|
||||
list_for_each_entry_rcu(chain, &block->chain_list, list) {
|
||||
if (chain->index == chain_index)
|
||||
return chain;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tc_chain_notify(struct tcf_chain *chain, struct sk_buff *oskb,
|
||||
u32 seq, u16 flags, int event, bool unicast);
|
||||
|
||||
@@ -1559,12 +1574,15 @@ static int tcf_block_setup(struct tcf_block *block,
|
||||
* to this qdisc, (optionally) tests for protocol and asks
|
||||
* specific classifiers.
|
||||
*/
|
||||
int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
|
||||
struct tcf_result *res, bool compat_mode)
|
||||
static inline int __tcf_classify(struct sk_buff *skb,
|
||||
const struct tcf_proto *tp,
|
||||
const struct tcf_proto *orig_tp,
|
||||
struct tcf_result *res,
|
||||
bool compat_mode,
|
||||
u32 *last_executed_chain)
|
||||
{
|
||||
#ifdef CONFIG_NET_CLS_ACT
|
||||
const int max_reclassify_loop = 4;
|
||||
const struct tcf_proto *orig_tp = tp;
|
||||
const struct tcf_proto *first_tp;
|
||||
int limit = 0;
|
||||
|
||||
@@ -1582,21 +1600,11 @@ reclassify:
|
||||
#ifdef CONFIG_NET_CLS_ACT
|
||||
if (unlikely(err == TC_ACT_RECLASSIFY && !compat_mode)) {
|
||||
first_tp = orig_tp;
|
||||
*last_executed_chain = first_tp->chain->index;
|
||||
goto reset;
|
||||
} else if (unlikely(TC_ACT_EXT_CMP(err, TC_ACT_GOTO_CHAIN))) {
|
||||
first_tp = res->goto_tp;
|
||||
|
||||
#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
|
||||
{
|
||||
struct tc_skb_ext *ext;
|
||||
|
||||
ext = skb_ext_add(skb, TC_SKB_EXT);
|
||||
if (WARN_ON_ONCE(!ext))
|
||||
return TC_ACT_SHOT;
|
||||
|
||||
ext->chain = err & TC_ACT_EXT_VAL_MASK;
|
||||
}
|
||||
#endif
|
||||
*last_executed_chain = err & TC_ACT_EXT_VAL_MASK;
|
||||
goto reset;
|
||||
}
|
||||
#endif
|
||||
@@ -1619,8 +1627,64 @@ reset:
|
||||
goto reclassify;
|
||||
#endif
|
||||
}
|
||||
|
||||
int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
|
||||
struct tcf_result *res, bool compat_mode)
|
||||
{
|
||||
u32 last_executed_chain = 0;
|
||||
|
||||
return __tcf_classify(skb, tp, tp, res, compat_mode,
|
||||
&last_executed_chain);
|
||||
}
|
||||
EXPORT_SYMBOL(tcf_classify);
|
||||
|
||||
int tcf_classify_ingress(struct sk_buff *skb,
|
||||
const struct tcf_block *ingress_block,
|
||||
const struct tcf_proto *tp,
|
||||
struct tcf_result *res, bool compat_mode)
|
||||
{
|
||||
#if !IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
|
||||
u32 last_executed_chain = 0;
|
||||
|
||||
return __tcf_classify(skb, tp, tp, res, compat_mode,
|
||||
&last_executed_chain);
|
||||
#else
|
||||
u32 last_executed_chain = tp ? tp->chain->index : 0;
|
||||
const struct tcf_proto *orig_tp = tp;
|
||||
struct tc_skb_ext *ext;
|
||||
int ret;
|
||||
|
||||
ext = skb_ext_find(skb, TC_SKB_EXT);
|
||||
|
||||
if (ext && ext->chain) {
|
||||
struct tcf_chain *fchain;
|
||||
|
||||
fchain = tcf_chain_lookup_rcu(ingress_block, ext->chain);
|
||||
if (!fchain)
|
||||
return TC_ACT_SHOT;
|
||||
|
||||
/* Consume, so cloned/redirect skbs won't inherit ext */
|
||||
skb_ext_del(skb, TC_SKB_EXT);
|
||||
|
||||
tp = rcu_dereference_bh(fchain->filter_chain);
|
||||
}
|
||||
|
||||
ret = __tcf_classify(skb, tp, orig_tp, res, compat_mode,
|
||||
&last_executed_chain);
|
||||
|
||||
/* If we missed on some chain */
|
||||
if (ret == TC_ACT_UNSPEC && last_executed_chain) {
|
||||
ext = skb_ext_add(skb, TC_SKB_EXT);
|
||||
if (WARN_ON_ONCE(!ext))
|
||||
return TC_ACT_SHOT;
|
||||
ext->chain = last_executed_chain;
|
||||
}
|
||||
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(tcf_classify_ingress);
|
||||
|
||||
struct tcf_chain_info {
|
||||
struct tcf_proto __rcu **pprev;
|
||||
struct tcf_proto __rcu *next;
|
||||
|
@@ -1391,6 +1391,14 @@ void mini_qdisc_pair_swap(struct mini_Qdisc_pair *miniqp,
|
||||
}
|
||||
EXPORT_SYMBOL(mini_qdisc_pair_swap);
|
||||
|
||||
void mini_qdisc_pair_block_init(struct mini_Qdisc_pair *miniqp,
|
||||
struct tcf_block *block)
|
||||
{
|
||||
miniqp->miniq1.block = block;
|
||||
miniqp->miniq2.block = block;
|
||||
}
|
||||
EXPORT_SYMBOL(mini_qdisc_pair_block_init);
|
||||
|
||||
void mini_qdisc_pair_init(struct mini_Qdisc_pair *miniqp, struct Qdisc *qdisc,
|
||||
struct mini_Qdisc __rcu **p_miniq)
|
||||
{
|
||||
|
@@ -78,6 +78,7 @@ static int ingress_init(struct Qdisc *sch, struct nlattr *opt,
|
||||
{
|
||||
struct ingress_sched_data *q = qdisc_priv(sch);
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
int err;
|
||||
|
||||
net_inc_ingress_queue();
|
||||
|
||||
@@ -87,7 +88,13 @@ static int ingress_init(struct Qdisc *sch, struct nlattr *opt,
|
||||
q->block_info.chain_head_change = clsact_chain_head_change;
|
||||
q->block_info.chain_head_change_priv = &q->miniqp;
|
||||
|
||||
return tcf_block_get_ext(&q->block, sch, &q->block_info, extack);
|
||||
err = tcf_block_get_ext(&q->block, sch, &q->block_info, extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mini_qdisc_pair_block_init(&q->miniqp, q->block);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ingress_destroy(struct Qdisc *sch)
|
||||
@@ -226,6 +233,8 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mini_qdisc_pair_block_init(&q->miniqp_ingress, q->ingress_block);
|
||||
|
||||
mini_qdisc_pair_init(&q->miniqp_egress, sch, &dev->miniq_egress);
|
||||
|
||||
q->egress_block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS;
|
||||
|
Reference in New Issue
Block a user