Skip to content

Commit

Permalink
Merge branch 'net-sched-multichain-filters'
Browse files Browse the repository at this point in the history
Jiri Pirko says:

====================
net: sched: introduce multichain support for filters

Currently, each classful qdisc holds one chain of filters.
This chain is traversed and each filter could be matched on, which
may lead to execution of list of actions. One of such action
could be "reclassify", which would "reset" the processing of the
filter chain.

So this filter chain could be looked at as a flat table.
Sometimes it is convenient for user to configure a hierarchy
of tables. Example usecase is encapsulation.

Hierarchy of tables is a common way how it is done in HW pipelines.
So it is much more convenient to offload this.

This patchset contains two major patches:
8/10 - This patch introduces the support for having multiple
       chains of filters.
10/10 - This patch adds new control action to allow going to specified chain

The rest of the patches are smaller or bigger depencies of those 2.
Please see individual patch descriptions for details.

Corresponding iproute2 patches are appended as a reply to this cover letter.

Simple example:
$ tc qdisc add dev eth0 ingress
$ tc filter add dev eth0 parent ffff: protocol ip pref 33 flower dst_mac 52:54:00:3d:c7:6d action goto chain 11
$ tc filter add dev eth0 parent ffff: protocol ip pref 22 chain 11 flower dst_ip 192.168.40.1 action drop
$ tc filter show dev eth0 root
filter parent ffff: protocol ip pref 33 flower chain 0
filter parent ffff: protocol ip pref 33 flower chain 0 handle 0x1
  dst_mac 52:54:00:3d:c7:6d
  eth_type ipv4
        action order 1: gact action goto chain 11
         random type none pass val 0
         index 2 ref 1 bind 1

filter parent ffff: protocol ip pref 22 flower chain 11
filter parent ffff: protocol ip pref 22 flower chain 11 handle 0x1
  eth_type ipv4
  dst_ip 192.168.40.1
        action order 1: gact action drop
         random type none pass val 0
         index 3 ref 1 bind 1
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
davem330 committed May 17, 2017
2 parents c63fbb0 + db50514 commit 656aae4
Show file tree
Hide file tree
Showing 23 changed files with 625 additions and 260 deletions.
13 changes: 7 additions & 6 deletions include/net/act_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ struct tc_action {
struct gnet_stats_basic_cpu __percpu *cpu_bstats;
struct gnet_stats_queue __percpu *cpu_qstats;
struct tc_cookie *act_cookie;
struct tcf_chain *goto_chain;
};
#define tcf_head common.tcfa_head
#define tcf_index common.tcfa_index
Expand Down Expand Up @@ -180,12 +181,12 @@ int tcf_unregister_action(struct tc_action_ops *a,
int tcf_action_destroy(struct list_head *actions, int bind);
int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
int nr_actions, struct tcf_result *res);
int tcf_action_init(struct net *net, struct nlattr *nla,
struct nlattr *est, char *n, int ovr,
int bind, struct list_head *);
struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
struct nlattr *est, char *n, int ovr,
int bind);
int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
struct nlattr *est, char *name, int ovr, int bind,
struct list_head *actions);
struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
struct nlattr *nla, struct nlattr *est,
char *name, int ovr, int bind);
int tcf_action_dump(struct sk_buff *skb, struct list_head *, int, int);
int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int);
int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
Expand Down
24 changes: 22 additions & 2 deletions include/net/pkt_cls.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,30 @@ int register_tcf_proto_ops(struct tcf_proto_ops *ops);
int unregister_tcf_proto_ops(struct tcf_proto_ops *ops);

#ifdef CONFIG_NET_CLS
void tcf_destroy_chain(struct tcf_proto __rcu **fl);
struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index);
void tcf_chain_put(struct tcf_chain *chain);
int tcf_block_get(struct tcf_block **p_block,
struct tcf_proto __rcu **p_filter_chain);
void tcf_block_put(struct tcf_block *block);
int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
struct tcf_result *res, bool compat_mode);

#else
static inline void tcf_destroy_chain(struct tcf_proto __rcu **fl)
static inline
int tcf_block_get(struct tcf_block **p_block,
struct tcf_proto __rcu **p_filter_chain)
{
return 0;
}

static inline void tcf_block_put(struct tcf_block *block)
{
}

static inline int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
struct tcf_result *res, bool compat_mode)
{
return TC_ACT_UNSPEC;
}
#endif

Expand Down
3 changes: 0 additions & 3 deletions include/net/pkt_sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,6 @@ static inline void qdisc_run(struct Qdisc *q)
__qdisc_run(q);
}

int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
struct tcf_result *res, bool compat_mode);

static inline __be16 tc_skb_protocol(const struct sk_buff *skb)
{
/* We need to take extra care in case the skb came via
Expand Down
26 changes: 23 additions & 3 deletions include/net/sch_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <linux/pkt_cls.h>
#include <linux/percpu.h>
#include <linux/dynamic_queue_limits.h>
#include <linux/list.h>
#include <net/gen_stats.h>
#include <net/rtnetlink.h>

Expand Down Expand Up @@ -153,7 +154,7 @@ struct Qdisc_class_ops {
void (*walk)(struct Qdisc *, struct qdisc_walker * arg);

/* Filter manipulation */
struct tcf_proto __rcu ** (*tcf_chain)(struct Qdisc *, unsigned long);
struct tcf_block * (*tcf_block)(struct Qdisc *, unsigned long);
bool (*tcf_cl_offload)(u32 classid);
unsigned long (*bind_tcf)(struct Qdisc *, unsigned long,
u32 classid);
Expand Down Expand Up @@ -192,8 +193,13 @@ struct Qdisc_ops {


struct tcf_result {
unsigned long class;
u32 classid;
union {
struct {
unsigned long class;
u32 classid;
};
const struct tcf_proto *goto_tp;
};
};

struct tcf_proto_ops {
Expand Down Expand Up @@ -236,6 +242,7 @@ struct tcf_proto {
struct Qdisc *q;
void *data;
const struct tcf_proto_ops *ops;
struct tcf_chain *chain;
struct rcu_head rcu;
};

Expand All @@ -247,6 +254,19 @@ struct qdisc_skb_cb {
unsigned char data[QDISC_CB_PRIV_LEN];
};

struct tcf_chain {
struct tcf_proto __rcu *filter_chain;
struct tcf_proto __rcu **p_filter_chain;
struct list_head list;
struct tcf_block *block;
u32 index; /* chain index */
unsigned int refcnt;
};

struct tcf_block {
struct list_head chain_list;
};

static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
{
struct qdisc_skb_cb *qcb;
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/pkt_cls.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ enum {
(((combined) & (~TC_ACT_EXT_VAL_MASK)) == opcode)

#define TC_ACT_JUMP __TC_ACT_EXT(1)
#define TC_ACT_GOTO_CHAIN __TC_ACT_EXT(2)

/* Action type identifiers*/
enum {
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/rtnetlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,7 @@ enum {
TCA_STAB,
TCA_PAD,
TCA_DUMP_INVISIBLE,
TCA_CHAIN,
__TCA_MAX
};

Expand Down
5 changes: 3 additions & 2 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
#include <net/dst.h>
#include <net/dst_metadata.h>
#include <net/pkt_sched.h>
#include <net/pkt_cls.h>
#include <net/checksum.h>
#include <net/xfrm.h>
#include <linux/highmem.h>
Expand Down Expand Up @@ -3178,7 +3179,7 @@ sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)
/* qdisc_skb_cb(skb)->pkt_len was already set by the caller. */
qdisc_bstats_cpu_update(cl->q, skb);

switch (tc_classify(skb, cl, &cl_res, false)) {
switch (tcf_classify(skb, cl, &cl_res, false)) {
case TC_ACT_OK:
case TC_ACT_RECLASSIFY:
skb->tc_index = TC_H_MIN(cl_res.classid);
Expand Down Expand Up @@ -3948,7 +3949,7 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,
skb->tc_at_ingress = 1;
qdisc_bstats_cpu_update(cl->q, skb);

switch (tc_classify(skb, cl, &cl_res, false)) {
switch (tcf_classify(skb, cl, &cl_res, false)) {
case TC_ACT_OK:
case TC_ACT_RECLASSIFY:
skb->tc_index = TC_H_MIN(cl_res.classid);
Expand Down
55 changes: 48 additions & 7 deletions net/sched/act_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,31 @@
#include <net/act_api.h>
#include <net/netlink.h>

static int tcf_action_goto_chain_init(struct tc_action *a, struct tcf_proto *tp)
{
u32 chain_index = a->tcfa_action & TC_ACT_EXT_VAL_MASK;

if (!tp)
return -EINVAL;
a->goto_chain = tcf_chain_get(tp->chain->block, chain_index);
if (!a->goto_chain)
return -ENOMEM;
return 0;
}

static void tcf_action_goto_chain_fini(struct tc_action *a)
{
tcf_chain_put(a->goto_chain);
}

static void tcf_action_goto_chain_exec(const struct tc_action *a,
struct tcf_result *res)
{
const struct tcf_chain *chain = a->goto_chain;

res->goto_tp = rcu_dereference_bh(chain->filter_chain);
}

static void free_tcf(struct rcu_head *head)
{
struct tc_action *p = container_of(head, struct tc_action, tcfa_rcu);
Expand All @@ -39,6 +64,8 @@ static void free_tcf(struct rcu_head *head)
kfree(p->act_cookie->data);
kfree(p->act_cookie);
}
if (p->goto_chain)
tcf_action_goto_chain_fini(p);

kfree(p);
}
Expand Down Expand Up @@ -465,6 +492,8 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
else /* faulty graph, stop pipeline */
return TC_ACT_OK;
}
} else if (TC_ACT_EXT_CMP(ret, TC_ACT_GOTO_CHAIN)) {
tcf_action_goto_chain_exec(a, res);
}

if (ret != TC_ACT_PIPE)
Expand Down Expand Up @@ -570,9 +599,9 @@ static struct tc_cookie *nla_memdup_cookie(struct nlattr **tb)
return c;
}

struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
struct nlattr *est, char *name, int ovr,
int bind)
struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
struct nlattr *nla, struct nlattr *est,
char *name, int ovr, int bind)
{
struct tc_action *a;
struct tc_action_ops *a_o;
Expand Down Expand Up @@ -657,6 +686,17 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
if (err != ACT_P_CREATED)
module_put(a_o->owner);

if (TC_ACT_EXT_CMP(a->tcfa_action, TC_ACT_GOTO_CHAIN)) {
err = tcf_action_goto_chain_init(a, tp);
if (err) {
LIST_HEAD(actions);

list_add_tail(&a->list, &actions);
tcf_action_destroy(&actions, bind);
return ERR_PTR(err);
}
}

return a;

err_mod:
Expand All @@ -680,8 +720,9 @@ static void cleanup_a(struct list_head *actions, int ovr)
a->tcfa_refcnt--;
}

int tcf_action_init(struct net *net, struct nlattr *nla, struct nlattr *est,
char *name, int ovr, int bind, struct list_head *actions)
int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
struct nlattr *est, char *name, int ovr, int bind,
struct list_head *actions)
{
struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
struct tc_action *act;
Expand All @@ -693,7 +734,7 @@ int tcf_action_init(struct net *net, struct nlattr *nla, struct nlattr *est,
return err;

for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
act = tcf_action_init_1(net, tb[i], est, name, ovr, bind);
act = tcf_action_init_1(net, tp, tb[i], est, name, ovr, bind);
if (IS_ERR(act)) {
err = PTR_ERR(act);
goto err;
Expand Down Expand Up @@ -1020,7 +1061,7 @@ static int tcf_action_add(struct net *net, struct nlattr *nla,
int ret = 0;
LIST_HEAD(actions);

ret = tcf_action_init(net, nla, NULL, NULL, ovr, 0, &actions);
ret = tcf_action_init(net, NULL, nla, NULL, NULL, ovr, 0, &actions);
if (ret)
return ret;

Expand Down
Loading

0 comments on commit 656aae4

Please sign in to comment.