Skip to content

Commit

Permalink
net: sched: introduce per-block callbacks
Browse files Browse the repository at this point in the history
Introduce infrastructure that allows drivers to register callbacks that
are called whenever tc would offload inserted rule for a specific block.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jiri Pirko authored and David S. Miller committed Oct 21, 2017
1 parent 6e40cf2 commit acb6744
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 0 deletions.
81 changes: 81 additions & 0 deletions include/net/pkt_cls.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ struct tcf_block_ext_info {
enum tcf_block_binder_type binder_type;
};

struct tcf_block_cb;

#ifdef CONFIG_NET_CLS
struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
bool create);
Expand All @@ -51,6 +53,21 @@ static inline struct net_device *tcf_block_dev(struct tcf_block *block)
return tcf_block_q(block)->dev_queue->dev;
}

void *tcf_block_cb_priv(struct tcf_block_cb *block_cb);
struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident);
void tcf_block_cb_incref(struct tcf_block_cb *block_cb);
unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb);
struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident,
void *cb_priv);
int tcf_block_cb_register(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident,
void *cb_priv);
void __tcf_block_cb_unregister(struct tcf_block_cb *block_cb);
void tcf_block_cb_unregister(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident);

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

Expand Down Expand Up @@ -91,6 +108,70 @@ static inline struct net_device *tcf_block_dev(struct tcf_block *block)
return NULL;
}

static inline
int tc_setup_cb_block_register(struct tcf_block *block, tc_setup_cb_t *cb,
void *cb_priv)
{
return 0;
}

static inline
void tc_setup_cb_block_unregister(struct tcf_block *block, tc_setup_cb_t *cb,
void *cb_priv)
{
}

static inline
void *tcf_block_cb_priv(struct tcf_block_cb *block_cb)
{
return NULL;
}

static inline
struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident)
{
return NULL;
}

static inline
void tcf_block_cb_incref(struct tcf_block_cb *block_cb)
{
}

static inline
unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb)
{
return 0;
}

static inline
struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident,
void *cb_priv)
{
return NULL;
}

static inline
int tcf_block_cb_register(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident,
void *cb_priv)
{
return 0;
}

static inline
void __tcf_block_cb_unregister(struct tcf_block_cb *block_cb)
{
}

static inline
void tcf_block_cb_unregister(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident)
{
}

static inline int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
struct tcf_result *res, bool compat_mode)
{
Expand Down
1 change: 1 addition & 0 deletions include/net/sch_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ struct tcf_block {
struct list_head chain_list;
struct net *net;
struct Qdisc *q;
struct list_head cb_list;
};

static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
Expand Down
105 changes: 105 additions & 0 deletions net/sched/cls_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ int tcf_block_get_ext(struct tcf_block **p_block,
if (!block)
return -ENOMEM;
INIT_LIST_HEAD(&block->chain_list);
INIT_LIST_HEAD(&block->cb_list);

/* Create chain 0 by default, it has to be always present. */
chain = tcf_chain_create(block, 0);
if (!chain) {
Expand Down Expand Up @@ -354,6 +356,109 @@ void tcf_block_put(struct tcf_block *block)
}
EXPORT_SYMBOL(tcf_block_put);

struct tcf_block_cb {
struct list_head list;
tc_setup_cb_t *cb;
void *cb_ident;
void *cb_priv;
unsigned int refcnt;
};

void *tcf_block_cb_priv(struct tcf_block_cb *block_cb)
{
return block_cb->cb_priv;
}
EXPORT_SYMBOL(tcf_block_cb_priv);

struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident)
{ struct tcf_block_cb *block_cb;

list_for_each_entry(block_cb, &block->cb_list, list)
if (block_cb->cb == cb && block_cb->cb_ident == cb_ident)
return block_cb;
return NULL;
}
EXPORT_SYMBOL(tcf_block_cb_lookup);

void tcf_block_cb_incref(struct tcf_block_cb *block_cb)
{
block_cb->refcnt++;
}
EXPORT_SYMBOL(tcf_block_cb_incref);

unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb)
{
return --block_cb->refcnt;
}
EXPORT_SYMBOL(tcf_block_cb_decref);

struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident,
void *cb_priv)
{
struct tcf_block_cb *block_cb;

block_cb = kzalloc(sizeof(*block_cb), GFP_KERNEL);
if (!block_cb)
return NULL;
block_cb->cb = cb;
block_cb->cb_ident = cb_ident;
block_cb->cb_priv = cb_priv;
list_add(&block_cb->list, &block->cb_list);
return block_cb;
}
EXPORT_SYMBOL(__tcf_block_cb_register);

int tcf_block_cb_register(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident,
void *cb_priv)
{
struct tcf_block_cb *block_cb;

block_cb = __tcf_block_cb_register(block, cb, cb_ident, cb_priv);
return block_cb ? 0 : -ENOMEM;
}
EXPORT_SYMBOL(tcf_block_cb_register);

void __tcf_block_cb_unregister(struct tcf_block_cb *block_cb)
{
list_del(&block_cb->list);
kfree(block_cb);
}
EXPORT_SYMBOL(__tcf_block_cb_unregister);

void tcf_block_cb_unregister(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident)
{
struct tcf_block_cb *block_cb;

block_cb = tcf_block_cb_lookup(block, cb, cb_ident);
if (!block_cb)
return;
__tcf_block_cb_unregister(block_cb);
}
EXPORT_SYMBOL(tcf_block_cb_unregister);

static int tcf_block_cb_call(struct tcf_block *block, enum tc_setup_type type,
void *type_data, bool err_stop)
{
struct tcf_block_cb *block_cb;
int ok_count = 0;
int err;

list_for_each_entry(block_cb, &block->cb_list, list) {
err = block_cb->cb(type, type_data, block_cb->cb_priv);
if (err) {
if (err_stop)
return err;
} else {
ok_count++;
}
}
return ok_count;
}

/* Main classifier routine: scans classifier chain attached
* to this qdisc, (optionally) tests for protocol and asks
* specific classifiers.
Expand Down

0 comments on commit acb6744

Please sign in to comment.